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

Please select the desired protocol below to get the URL.

This URL has Read-Only access.

Statistics
| Branch: | Revision:

main_repo / deps / v8 / src / stub-cache.h @ f230a1cf

History | View | Annotate | Download (42.2 KB)

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

    
28
#ifndef V8_STUB_CACHE_H_
29
#define V8_STUB_CACHE_H_
30

    
31
#include "allocation.h"
32
#include "arguments.h"
33
#include "code-stubs.h"
34
#include "ic-inl.h"
35
#include "macro-assembler.h"
36
#include "objects.h"
37
#include "zone-inl.h"
38

    
39
namespace v8 {
40
namespace internal {
41

    
42

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

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

    
51

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

    
56

    
57
class SCTableReference {
58
 public:
59
  Address address() const { return address_; }
60

    
61
 private:
62
  explicit SCTableReference(Address address) : address_(address) {}
63

    
64
  Address address_;
65

    
66
  friend class StubCache;
67
};
68

    
69

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

    
78
  void Initialize();
79

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

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

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

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

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

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

    
108
  Handle<Code> ComputeLoadGlobal(Handle<Name> name,
109
                                 Handle<JSObject> object,
110
                                 Handle<GlobalObject> holder,
111
                                 Handle<PropertyCell> cell,
112
                                 bool is_dont_delete);
113

    
114
  // ---
115

    
116
  Handle<Code> ComputeKeyedLoadField(Handle<Name> name,
117
                                     Handle<JSObject> object,
118
                                     Handle<JSObject> holder,
119
                                     PropertyIndex field_index,
120
                                     Representation representation);
121

    
122
  Handle<Code> ComputeKeyedLoadCallback(
123
      Handle<Name> name,
124
      Handle<JSObject> object,
125
      Handle<JSObject> holder,
126
      Handle<ExecutableAccessorInfo> callback);
127

    
128
  Handle<Code> ComputeKeyedLoadCallback(
129
      Handle<Name> name,
130
      Handle<JSObject> object,
131
      Handle<JSObject> holder,
132
      const CallOptimization& call_optimization);
133

    
134
  Handle<Code> ComputeKeyedLoadConstant(Handle<Name> name,
135
                                        Handle<JSObject> object,
136
                                        Handle<JSObject> holder,
137
                                        Handle<Object> value);
138

    
139
  Handle<Code> ComputeKeyedLoadInterceptor(Handle<Name> name,
140
                                           Handle<JSObject> object,
141
                                           Handle<JSObject> holder);
142

    
143
  Handle<Code> ComputeStoreGlobal(Handle<Name> name,
144
                                  Handle<GlobalObject> object,
145
                                  Handle<PropertyCell> cell,
146
                                  Handle<Object> value,
147
                                  StrictModeFlag strict_mode);
148

    
149
  Handle<Code> ComputeKeyedLoadElement(Handle<Map> receiver_map);
150

    
151
  Handle<Code> ComputeKeyedStoreElement(Handle<Map> receiver_map,
152
                                        StrictModeFlag strict_mode,
153
                                        KeyedAccessStoreMode store_mode);
154

    
155
  Handle<Code> ComputeCallField(int argc,
156
                                Code::Kind,
157
                                Code::ExtraICState extra_state,
158
                                Handle<Name> name,
159
                                Handle<Object> object,
160
                                Handle<JSObject> holder,
161
                                PropertyIndex index);
162

    
163
  Handle<Code> ComputeCallConstant(int argc,
164
                                   Code::Kind,
165
                                   Code::ExtraICState extra_state,
166
                                   Handle<Name> name,
167
                                   Handle<Object> object,
168
                                   Handle<JSObject> holder,
169
                                   Handle<JSFunction> function);
170

    
171
  Handle<Code> ComputeCallInterceptor(int argc,
172
                                      Code::Kind,
173
                                      Code::ExtraICState extra_state,
174
                                      Handle<Name> name,
175
                                      Handle<Object> object,
176
                                      Handle<JSObject> holder);
177

    
178
  Handle<Code> ComputeCallGlobal(int argc,
179
                                 Code::Kind,
180
                                 Code::ExtraICState extra_state,
181
                                 Handle<Name> name,
182
                                 Handle<JSObject> object,
183
                                 Handle<GlobalObject> holder,
184
                                 Handle<PropertyCell> cell,
185
                                 Handle<JSFunction> function);
186

    
187
  // ---
188

    
189
  Handle<Code> ComputeCallInitialize(int argc, RelocInfo::Mode mode);
190

    
191
  Handle<Code> ComputeKeyedCallInitialize(int argc);
192

    
193
  Handle<Code> ComputeCallPreMonomorphic(int argc,
194
                                         Code::Kind kind,
195
                                         Code::ExtraICState extra_state);
196

    
197
  Handle<Code> ComputeCallNormal(int argc,
198
                                 Code::Kind kind,
199
                                 Code::ExtraICState state);
200

    
201
  Handle<Code> ComputeCallArguments(int argc);
202

    
203
  Handle<Code> ComputeCallMegamorphic(int argc,
204
                                      Code::Kind kind,
205
                                      Code::ExtraICState state);
206

    
207
  Handle<Code> ComputeCallMiss(int argc,
208
                               Code::Kind kind,
209
                               Code::ExtraICState state);
210

    
211
  // ---
212

    
213
  Handle<Code> ComputeCompareNil(Handle<Map> receiver_map,
214
                                 CompareNilICStub& stub);
215

    
216
  // ---
217

    
218
  Handle<Code> ComputeLoadElementPolymorphic(MapHandleList* receiver_maps);
219
  Handle<Code> ComputeStoreElementPolymorphic(MapHandleList* receiver_maps,
220
                                              KeyedAccessStoreMode store_mode,
221
                                              StrictModeFlag strict_mode);
222

    
223
  Handle<Code> ComputePolymorphicIC(MapHandleList* receiver_maps,
224
                                    CodeHandleList* handlers,
225
                                    int number_of_valid_maps,
226
                                    Handle<Name> name,
227
                                    StrictModeFlag strict_mode);
228

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

    
232
#ifdef ENABLE_DEBUGGER_SUPPORT
233
  Handle<Code> ComputeCallDebugBreak(int argc, Code::Kind kind);
234

    
235
  Handle<Code> ComputeCallDebugPrepareStepIn(int argc, Code::Kind kind);
236
#endif
237

    
238
  // Update cache for entry hash(name, map).
239
  Code* Set(Name* name, Map* map, Code* code);
240

    
241
  // Clear the lookup table (@ mark compact collection).
242
  void Clear();
243

    
244
  // Collect all maps that match the name and flags.
245
  void CollectMatchingMaps(SmallMapList* types,
246
                           Handle<Name> name,
247
                           Code::Flags flags,
248
                           Handle<Context> native_context,
249
                           Zone* zone);
250

    
251
  // Generate code for probing the stub cache table.
252
  // Arguments extra, extra2 and extra3 may be used to pass additional scratch
253
  // registers. Set to no_reg if not needed.
254
  void GenerateProbe(MacroAssembler* masm,
255
                     Code::Flags flags,
256
                     Register receiver,
257
                     Register name,
258
                     Register scratch,
259
                     Register extra,
260
                     Register extra2 = no_reg,
261
                     Register extra3 = no_reg);
262

    
263
  enum Table {
264
    kPrimary,
265
    kSecondary
266
  };
267

    
268

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

    
274

    
275
  SCTableReference map_reference(StubCache::Table table) {
276
    return SCTableReference(
277
        reinterpret_cast<Address>(&first_entry(table)->map));
278
  }
279

    
280

    
281
  SCTableReference value_reference(StubCache::Table table) {
282
    return SCTableReference(
283
        reinterpret_cast<Address>(&first_entry(table)->value));
284
  }
285

    
286

    
287
  StubCache::Entry* first_entry(StubCache::Table table) {
288
    switch (table) {
289
      case StubCache::kPrimary: return StubCache::primary_;
290
      case StubCache::kSecondary: return StubCache::secondary_;
291
    }
292
    UNREACHABLE();
293
    return NULL;
294
  }
295

    
296
  Isolate* isolate() { return isolate_; }
297
  Heap* heap() { return isolate()->heap(); }
298
  Factory* factory() { return isolate()->factory(); }
299

    
300
  // These constants describe the structure of the interceptor arguments on the
301
  // stack. The arguments are pushed by the (platform-specific)
302
  // PushInterceptorArguments and read by LoadPropertyWithInterceptorOnly and
303
  // LoadWithInterceptor.
304
  static const int kInterceptorArgsNameIndex = 0;
305
  static const int kInterceptorArgsInfoIndex = 1;
306
  static const int kInterceptorArgsThisIndex = 2;
307
  static const int kInterceptorArgsHolderIndex = 3;
308
  static const int kInterceptorArgsLength = 4;
309

    
310
 private:
311
  explicit StubCache(Isolate* isolate);
312

    
313
  Handle<Code> ComputeCallInitialize(int argc,
314
                                     RelocInfo::Mode mode,
315
                                     Code::Kind kind);
316

    
317
  // The stub cache has a primary and secondary level.  The two levels have
318
  // different hashing algorithms in order to avoid simultaneous collisions
319
  // in both caches.  Unlike a probing strategy (quadratic or otherwise) the
320
  // update strategy on updates is fairly clear and simple:  Any existing entry
321
  // in the primary cache is moved to the secondary cache, and secondary cache
322
  // entries are overwritten.
323

    
324
  // Hash algorithm for the primary table.  This algorithm is replicated in
325
  // assembler for every architecture.  Returns an index into the table that
326
  // is scaled by 1 << kHeapObjectTagSize.
327
  static int PrimaryOffset(Name* name, Code::Flags flags, Map* map) {
328
    // This works well because the heap object tag size and the hash
329
    // shift are equal.  Shifting down the length field to get the
330
    // hash code would effectively throw away two bits of the hash
331
    // code.
332
    STATIC_ASSERT(kHeapObjectTagSize == Name::kHashShift);
333
    // Compute the hash of the name (use entire hash field).
334
    ASSERT(name->HasHashCode());
335
    uint32_t field = name->hash_field();
336
    // Using only the low bits in 64-bit mode is unlikely to increase the
337
    // risk of collision even if the heap is spread over an area larger than
338
    // 4Gb (and not at all if it isn't).
339
    uint32_t map_low32bits =
340
        static_cast<uint32_t>(reinterpret_cast<uintptr_t>(map));
341
    // We always set the in_loop bit to zero when generating the lookup code
342
    // so do it here too so the hash codes match.
343
    uint32_t iflags =
344
        (static_cast<uint32_t>(flags) & ~Code::kFlagsNotUsedInLookup);
345
    // Base the offset on a simple combination of name, flags, and map.
346
    uint32_t key = (map_low32bits + field) ^ iflags;
347
    return key & ((kPrimaryTableSize - 1) << kHeapObjectTagSize);
348
  }
349

    
350
  // Hash algorithm for the secondary table.  This algorithm is replicated in
351
  // assembler for every architecture.  Returns an index into the table that
352
  // is scaled by 1 << kHeapObjectTagSize.
353
  static int SecondaryOffset(Name* name, Code::Flags flags, int seed) {
354
    // Use the seed from the primary cache in the secondary cache.
355
    uint32_t name_low32bits =
356
        static_cast<uint32_t>(reinterpret_cast<uintptr_t>(name));
357
    // We always set the in_loop bit to zero when generating the lookup code
358
    // so do it here too so the hash codes match.
359
    uint32_t iflags =
360
        (static_cast<uint32_t>(flags) & ~Code::kFlagsNotUsedInLookup);
361
    uint32_t key = (seed - name_low32bits) + iflags;
362
    return key & ((kSecondaryTableSize - 1) << kHeapObjectTagSize);
363
  }
364

    
365
  // Compute the entry for a given offset in exactly the same way as
366
  // we do in generated code.  We generate an hash code that already
367
  // ends in Name::kHashShift 0s.  Then we multiply it so it is a multiple
368
  // of sizeof(Entry).  This makes it easier to avoid making mistakes
369
  // in the hashed offset computations.
370
  static Entry* entry(Entry* table, int offset) {
371
    const int multiplier = sizeof(*table) >> Name::kHashShift;
372
    return reinterpret_cast<Entry*>(
373
        reinterpret_cast<Address>(table) + offset * multiplier);
374
  }
375

    
376
  static const int kPrimaryTableBits = 11;
377
  static const int kPrimaryTableSize = (1 << kPrimaryTableBits);
378
  static const int kSecondaryTableBits = 9;
379
  static const int kSecondaryTableSize = (1 << kSecondaryTableBits);
380

    
381
  Entry primary_[kPrimaryTableSize];
382
  Entry secondary_[kSecondaryTableSize];
383
  Isolate* isolate_;
384

    
385
  friend class Isolate;
386
  friend class SCTableReference;
387

    
388
  DISALLOW_COPY_AND_ASSIGN(StubCache);
389
};
390

    
391

    
392
// ------------------------------------------------------------------------
393

    
394

    
395
// Support functions for IC stubs for callbacks.
396
DECLARE_RUNTIME_FUNCTION(MaybeObject*, StoreCallbackProperty);
397

    
398

    
399
// Support functions for IC stubs for interceptors.
400
DECLARE_RUNTIME_FUNCTION(MaybeObject*, LoadPropertyWithInterceptorOnly);
401
DECLARE_RUNTIME_FUNCTION(MaybeObject*, LoadPropertyWithInterceptorForLoad);
402
DECLARE_RUNTIME_FUNCTION(MaybeObject*, LoadPropertyWithInterceptorForCall);
403
DECLARE_RUNTIME_FUNCTION(MaybeObject*, StoreInterceptorProperty);
404
DECLARE_RUNTIME_FUNCTION(MaybeObject*, CallInterceptorProperty);
405
DECLARE_RUNTIME_FUNCTION(MaybeObject*, KeyedLoadPropertyWithInterceptor);
406

    
407

    
408
enum PrototypeCheckType { CHECK_ALL_MAPS, SKIP_RECEIVER };
409
enum IcCheckType { ELEMENT, PROPERTY };
410

    
411

    
412
// The stub compilers compile stubs for the stub cache.
413
class StubCompiler BASE_EMBEDDED {
414
 public:
415
  explicit StubCompiler(Isolate* isolate)
416
      : isolate_(isolate), masm_(isolate, NULL, 256), failure_(NULL) { }
417

    
418
  // Functions to compile either CallIC or KeyedCallIC.  The specific kind
419
  // is extracted from the code flags.
420
  Handle<Code> CompileCallInitialize(Code::Flags flags);
421
  Handle<Code> CompileCallPreMonomorphic(Code::Flags flags);
422
  Handle<Code> CompileCallNormal(Code::Flags flags);
423
  Handle<Code> CompileCallMegamorphic(Code::Flags flags);
424
  Handle<Code> CompileCallArguments(Code::Flags flags);
425
  Handle<Code> CompileCallMiss(Code::Flags flags);
426

    
427
#ifdef ENABLE_DEBUGGER_SUPPORT
428
  Handle<Code> CompileCallDebugBreak(Code::Flags flags);
429
  Handle<Code> CompileCallDebugPrepareStepIn(Code::Flags flags);
430
#endif
431

    
432
  // Static functions for generating parts of stubs.
433
  static void GenerateLoadGlobalFunctionPrototype(MacroAssembler* masm,
434
                                                  int index,
435
                                                  Register prototype);
436

    
437
  // Generates prototype loading code that uses the objects from the
438
  // context we were in when this function was called. If the context
439
  // has changed, a jump to miss is performed. This ties the generated
440
  // code to a particular context and so must not be used in cases
441
  // where the generated code is not allowed to have references to
442
  // objects from a context.
443
  static void GenerateDirectLoadGlobalFunctionPrototype(MacroAssembler* masm,
444
                                                        int index,
445
                                                        Register prototype,
446
                                                        Label* miss);
447

    
448
  static void GenerateFastPropertyLoad(MacroAssembler* masm,
449
                                       Register dst,
450
                                       Register src,
451
                                       bool inobject,
452
                                       int index,
453
                                       Representation representation);
454

    
455
  static void GenerateLoadArrayLength(MacroAssembler* masm,
456
                                      Register receiver,
457
                                      Register scratch,
458
                                      Label* miss_label);
459

    
460
  static void GenerateLoadStringLength(MacroAssembler* masm,
461
                                       Register receiver,
462
                                       Register scratch1,
463
                                       Register scratch2,
464
                                       Label* miss_label);
465

    
466
  static void GenerateLoadFunctionPrototype(MacroAssembler* masm,
467
                                            Register receiver,
468
                                            Register scratch1,
469
                                            Register scratch2,
470
                                            Label* miss_label);
471

    
472
  static void TailCallBuiltin(MacroAssembler* masm, Builtins::Name name);
473

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

    
502
  Register CheckPrototypes(Handle<JSObject> object,
503
                           Register object_reg,
504
                           Handle<JSObject> holder,
505
                           Register holder_reg,
506
                           Register scratch1,
507
                           Register scratch2,
508
                           Handle<Name> name,
509
                           int save_at_depth,
510
                           Label* miss,
511
                           PrototypeCheckType check = CHECK_ALL_MAPS);
512

    
513

    
514
 protected:
515
  Handle<Code> GetCodeWithFlags(Code::Flags flags, const char* name);
516
  Handle<Code> GetCodeWithFlags(Code::Flags flags, Handle<Name> name);
517

    
518
  MacroAssembler* masm() { return &masm_; }
519
  void set_failure(Failure* failure) { failure_ = failure; }
520

    
521
  static void LookupPostInterceptor(Handle<JSObject> holder,
522
                                    Handle<Name> name,
523
                                    LookupResult* lookup);
524

    
525
  Isolate* isolate() { return isolate_; }
526
  Heap* heap() { return isolate()->heap(); }
527
  Factory* factory() { return isolate()->factory(); }
528

    
529
  static void GenerateTailCall(MacroAssembler* masm, Handle<Code> code);
530

    
531
 private:
532
  Isolate* isolate_;
533
  MacroAssembler masm_;
534
  Failure* failure_;
535
};
536

    
537

    
538
enum FrontendCheckType { PERFORM_INITIAL_CHECKS, SKIP_INITIAL_CHECKS };
539

    
540

    
541
class BaseLoadStoreStubCompiler: public StubCompiler {
542
 public:
543
  BaseLoadStoreStubCompiler(Isolate* isolate, Code::Kind kind)
544
      : StubCompiler(isolate), kind_(kind) {
545
    InitializeRegisters();
546
  }
547
  virtual ~BaseLoadStoreStubCompiler() { }
548

    
549
  Handle<Code> CompileMonomorphicIC(Handle<Map> receiver_map,
550
                                    Handle<Code> handler,
551
                                    Handle<Name> name);
552

    
553
  Handle<Code> CompilePolymorphicIC(MapHandleList* receiver_maps,
554
                                    CodeHandleList* handlers,
555
                                    Handle<Name> name,
556
                                    Code::StubType type,
557
                                    IcCheckType check);
558

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

    
563
  static Builtins::Name MissBuiltin(Code::Kind kind) {
564
    switch (kind) {
565
      case Code::LOAD_IC: return Builtins::kLoadIC_Miss;
566
      case Code::STORE_IC: return Builtins::kStoreIC_Miss;
567
      case Code::KEYED_LOAD_IC: return Builtins::kKeyedLoadIC_Miss;
568
      case Code::KEYED_STORE_IC: return Builtins::kKeyedStoreIC_Miss;
569
      default: UNREACHABLE();
570
    }
571
    return Builtins::kLoadIC_Miss;
572
  }
573

    
574
 protected:
575
  virtual Register HandlerFrontendHeader(Handle<JSObject> object,
576
                                         Register object_reg,
577
                                         Handle<JSObject> holder,
578
                                         Handle<Name> name,
579
                                         Label* miss) = 0;
580

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

    
585
  Register HandlerFrontend(Handle<JSObject> object,
586
                           Register object_reg,
587
                           Handle<JSObject> holder,
588
                           Handle<Name> name,
589
                           Label* success);
590

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

    
595
  Handle<Code> GetICCode(Code::Kind kind,
596
                         Code::StubType type,
597
                         Handle<Name> name,
598
                         InlineCacheState state = MONOMORPHIC);
599
  Code::Kind kind() { return kind_; }
600

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

    
619
  virtual Code::ExtraICState extra_state() { return Code::kNoExtraICState; }
620
  virtual Register receiver() = 0;
621
  virtual Register name() = 0;
622
  virtual Register scratch1() = 0;
623
  virtual Register scratch2() = 0;
624
  virtual Register scratch3() = 0;
625

    
626
  void InitializeRegisters();
627

    
628
  Code::Kind kind_;
629
  Register* registers_;
630
};
631

    
632

    
633
class LoadStubCompiler: public BaseLoadStoreStubCompiler {
634
 public:
635
  LoadStubCompiler(Isolate* isolate, Code::Kind kind = Code::LOAD_IC)
636
      : BaseLoadStoreStubCompiler(isolate, kind) { }
637
  virtual ~LoadStubCompiler() { }
638

    
639
  Handle<Code> CompileLoadField(Handle<JSObject> object,
640
                                Handle<JSObject> holder,
641
                                Handle<Name> name,
642
                                PropertyIndex index,
643
                                Representation representation);
644

    
645
  Handle<Code> CompileLoadCallback(Handle<JSObject> object,
646
                                   Handle<JSObject> holder,
647
                                   Handle<Name> name,
648
                                   Handle<ExecutableAccessorInfo> callback);
649

    
650
  Handle<Code> CompileLoadCallback(Handle<JSObject> object,
651
                                   Handle<JSObject> holder,
652
                                   Handle<Name> name,
653
                                   const CallOptimization& call_optimization);
654

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

    
660
  Handle<Code> CompileLoadInterceptor(Handle<JSObject> object,
661
                                      Handle<JSObject> holder,
662
                                      Handle<Name> name);
663

    
664
  Handle<Code> CompileLoadViaGetter(Handle<JSObject> object,
665
                                    Handle<JSObject> holder,
666
                                    Handle<Name> name,
667
                                    Handle<JSFunction> getter);
668

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

    
673
  Handle<Code> CompileLoadNonexistent(Handle<JSObject> object,
674
                                      Handle<JSObject> last,
675
                                      Handle<Name> name,
676
                                      Handle<GlobalObject> global);
677

    
678
  Handle<Code> CompileLoadGlobal(Handle<JSObject> object,
679
                                 Handle<GlobalObject> holder,
680
                                 Handle<PropertyCell> cell,
681
                                 Handle<Name> name,
682
                                 bool is_dont_delete);
683

    
684
  static Register* registers();
685

    
686
 protected:
687
  virtual Register HandlerFrontendHeader(Handle<JSObject> object,
688
                                         Register object_reg,
689
                                         Handle<JSObject> holder,
690
                                         Handle<Name> name,
691
                                         Label* miss);
692

    
693
  virtual void HandlerFrontendFooter(Handle<Name> name,
694
                                     Label* success,
695
                                     Label* miss);
696

    
697
  Register CallbackHandlerFrontend(Handle<JSObject> object,
698
                                   Register object_reg,
699
                                   Handle<JSObject> holder,
700
                                   Handle<Name> name,
701
                                   Label* success,
702
                                   Handle<Object> callback);
703
  void NonexistentHandlerFrontend(Handle<JSObject> object,
704
                                  Handle<JSObject> last,
705
                                  Handle<Name> name,
706
                                  Label* success,
707
                                  Handle<GlobalObject> global);
708

    
709
  void GenerateLoadField(Register reg,
710
                         Handle<JSObject> holder,
711
                         PropertyIndex field,
712
                         Representation representation);
713
  void GenerateLoadConstant(Handle<Object> value);
714
  void GenerateLoadCallback(Register reg,
715
                            Handle<ExecutableAccessorInfo> callback);
716
  void GenerateLoadCallback(const CallOptimization& call_optimization);
717
  void GenerateLoadInterceptor(Register holder_reg,
718
                               Handle<JSObject> object,
719
                               Handle<JSObject> holder,
720
                               LookupResult* lookup,
721
                               Handle<Name> name);
722
  void GenerateLoadPostInterceptor(Register reg,
723
                                   Handle<JSObject> interceptor_holder,
724
                                   Handle<Name> name,
725
                                   LookupResult* lookup);
726

    
727
  virtual Register receiver() { return registers_[0]; }
728
  virtual Register name()     { return registers_[1]; }
729
  virtual Register scratch1() { return registers_[2]; }
730
  virtual Register scratch2() { return registers_[3]; }
731
  virtual Register scratch3() { return registers_[4]; }
732
  Register scratch4() { return registers_[5]; }
733
};
734

    
735

    
736
class KeyedLoadStubCompiler: public LoadStubCompiler {
737
 public:
738
  explicit KeyedLoadStubCompiler(Isolate* isolate)
739
      : LoadStubCompiler(isolate, Code::KEYED_LOAD_IC) { }
740

    
741
  Handle<Code> CompileLoadElement(Handle<Map> receiver_map);
742

    
743
  void CompileElementHandlers(MapHandleList* receiver_maps,
744
                              CodeHandleList* handlers);
745

    
746
  static void GenerateLoadDictionaryElement(MacroAssembler* masm);
747

    
748
 protected:
749
  static Register* registers();
750

    
751
 private:
752
  virtual void GenerateNameCheck(Handle<Name> name,
753
                                 Register name_reg,
754
                                 Label* miss);
755
  friend class BaseLoadStoreStubCompiler;
756
};
757

    
758

    
759
class StoreStubCompiler: public BaseLoadStoreStubCompiler {
760
 public:
761
  StoreStubCompiler(Isolate* isolate,
762
                    StrictModeFlag strict_mode,
763
                    Code::Kind kind = Code::STORE_IC)
764
      : BaseLoadStoreStubCompiler(isolate, kind),
765
        strict_mode_(strict_mode) { }
766

    
767
  virtual ~StoreStubCompiler() { }
768

    
769
  Handle<Code> CompileStoreTransition(Handle<JSObject> object,
770
                                      LookupResult* lookup,
771
                                      Handle<Map> transition,
772
                                      Handle<Name> name);
773

    
774
  Handle<Code> CompileStoreField(Handle<JSObject> object,
775
                                 LookupResult* lookup,
776
                                 Handle<Name> name);
777

    
778
  void GenerateNegativeHolderLookup(MacroAssembler* masm,
779
                                    Handle<JSObject> holder,
780
                                    Register holder_reg,
781
                                    Handle<Name> name,
782
                                    Label* miss);
783

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

    
798
  void GenerateStoreField(MacroAssembler* masm,
799
                          Handle<JSObject> object,
800
                          LookupResult* lookup,
801
                          Register receiver_reg,
802
                          Register name_reg,
803
                          Register value_reg,
804
                          Register scratch1,
805
                          Register scratch2,
806
                          Label* miss_label);
807

    
808
  Handle<Code> CompileStoreCallback(Handle<JSObject> object,
809
                                    Handle<JSObject> holder,
810
                                    Handle<Name> name,
811
                                    Handle<ExecutableAccessorInfo> callback);
812

    
813
  Handle<Code> CompileStoreCallback(Handle<JSObject> object,
814
                                    Handle<JSObject> holder,
815
                                    Handle<Name> name,
816
                                    const CallOptimization& call_optimization);
817

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

    
821
  Handle<Code> CompileStoreViaSetter(Handle<JSObject> object,
822
                                     Handle<JSObject> holder,
823
                                     Handle<Name> name,
824
                                     Handle<JSFunction> setter);
825

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

    
829
  static Builtins::Name SlowBuiltin(Code::Kind kind) {
830
    switch (kind) {
831
      case Code::STORE_IC: return Builtins::kStoreIC_Slow;
832
      case Code::KEYED_STORE_IC: return Builtins::kKeyedStoreIC_Slow;
833
      default: UNREACHABLE();
834
    }
835
    return Builtins::kStoreIC_Slow;
836
  }
837

    
838
 protected:
839
  virtual Register HandlerFrontendHeader(Handle<JSObject> object,
840
                                         Register object_reg,
841
                                         Handle<JSObject> holder,
842
                                         Handle<Name> name,
843
                                         Label* miss);
844

    
845
  virtual void HandlerFrontendFooter(Handle<Name> name,
846
                                     Label* success,
847
                                     Label* miss);
848
  void GenerateRestoreName(MacroAssembler* masm,
849
                           Label* label,
850
                           Handle<Name> name);
851

    
852
  virtual Register receiver() { return registers_[0]; }
853
  virtual Register name()     { return registers_[1]; }
854
  Register value()    { return registers_[2]; }
855
  virtual Register scratch1() { return registers_[3]; }
856
  virtual Register scratch2() { return registers_[4]; }
857
  virtual Register scratch3() { return registers_[5]; }
858
  StrictModeFlag strict_mode() { return strict_mode_; }
859
  virtual Code::ExtraICState extra_state() { return strict_mode_; }
860

    
861
 protected:
862
  static Register* registers();
863

    
864
 private:
865
  StrictModeFlag strict_mode_;
866
  friend class BaseLoadStoreStubCompiler;
867
};
868

    
869

    
870
class KeyedStoreStubCompiler: public StoreStubCompiler {
871
 public:
872
  KeyedStoreStubCompiler(Isolate* isolate,
873
                         StrictModeFlag strict_mode,
874
                         KeyedAccessStoreMode store_mode)
875
      : StoreStubCompiler(isolate, strict_mode, Code::KEYED_STORE_IC),
876
        store_mode_(store_mode) { }
877

    
878
  Handle<Code> CompileStoreElement(Handle<Map> receiver_map);
879

    
880
  Handle<Code> CompileStorePolymorphic(MapHandleList* receiver_maps,
881
                                       CodeHandleList* handler_stubs,
882
                                       MapHandleList* transitioned_maps);
883

    
884
  Handle<Code> CompileStoreElementPolymorphic(MapHandleList* receiver_maps);
885

    
886
  static void GenerateStoreDictionaryElement(MacroAssembler* masm);
887

    
888
 protected:
889
  virtual Code::ExtraICState extra_state() {
890
    return Code::ComputeExtraICState(store_mode_, strict_mode());
891
  }
892
  static Register* registers();
893

    
894
 private:
895
  Register transition_map() {
896
    return registers()[3];
897
  }
898

    
899
  virtual void GenerateNameCheck(Handle<Name> name,
900
                                 Register name_reg,
901
                                 Label* miss);
902
  KeyedAccessStoreMode store_mode_;
903
  friend class BaseLoadStoreStubCompiler;
904
};
905

    
906

    
907
// Subset of FUNCTIONS_WITH_ID_LIST with custom constant/global call
908
// IC stubs.
909
#define CUSTOM_CALL_IC_GENERATORS(V)            \
910
  V(ArrayPush)                                  \
911
  V(ArrayPop)                                   \
912
  V(StringCharCodeAt)                           \
913
  V(StringCharAt)                               \
914
  V(StringFromCharCode)                         \
915
  V(MathFloor)                                  \
916
  V(MathAbs)                                    \
917
  V(ArrayCode)
918

    
919

    
920
#define SITE_SPECIFIC_CALL_GENERATORS(V)        \
921
  V(ArrayCode)
922

    
923

    
924
class CallStubCompiler: public StubCompiler {
925
 public:
926
  CallStubCompiler(Isolate* isolate,
927
                   int argc,
928
                   Code::Kind kind,
929
                   Code::ExtraICState extra_state,
930
                   InlineCacheHolderFlag cache_holder = OWN_MAP);
931

    
932
  Handle<Code> CompileCallField(Handle<JSObject> object,
933
                                Handle<JSObject> holder,
934
                                PropertyIndex index,
935
                                Handle<Name> name);
936

    
937
  void CompileHandlerFrontend(Handle<Object> object,
938
                              Handle<JSObject> holder,
939
                              Handle<Name> name,
940
                              CheckType check,
941
                              Label* success);
942

    
943
  void CompileHandlerBackend(Handle<JSFunction> function);
944

    
945
  Handle<Code> CompileCallConstant(Handle<Object> object,
946
                                   Handle<JSObject> holder,
947
                                   Handle<Name> name,
948
                                   CheckType check,
949
                                   Handle<JSFunction> function);
950

    
951
  Handle<Code> CompileCallInterceptor(Handle<JSObject> object,
952
                                      Handle<JSObject> holder,
953
                                      Handle<Name> name);
954

    
955
  Handle<Code> CompileCallGlobal(Handle<JSObject> object,
956
                                 Handle<GlobalObject> holder,
957
                                 Handle<PropertyCell> cell,
958
                                 Handle<JSFunction> function,
959
                                 Handle<Name> name);
960

    
961
  static bool HasCustomCallGenerator(Handle<JSFunction> function);
962
  static bool CanBeCached(Handle<JSFunction> function);
963

    
964
 private:
965
  // Compiles a custom call constant/global IC.  For constant calls cell is
966
  // NULL.  Returns an empty handle if there is no custom call code for the
967
  // given function.
968
  Handle<Code> CompileCustomCall(Handle<Object> object,
969
                                 Handle<JSObject> holder,
970
                                 Handle<Cell> cell,
971
                                 Handle<JSFunction> function,
972
                                 Handle<String> name,
973
                                 Code::StubType type);
974

    
975
#define DECLARE_CALL_GENERATOR(name)                                    \
976
  Handle<Code> Compile##name##Call(Handle<Object> object,               \
977
                                   Handle<JSObject> holder,             \
978
                                   Handle<Cell> cell,                   \
979
                                   Handle<JSFunction> function,         \
980
                                   Handle<String> fname,                \
981
                                   Code::StubType type);
982
  CUSTOM_CALL_IC_GENERATORS(DECLARE_CALL_GENERATOR)
983
#undef DECLARE_CALL_GENERATOR
984

    
985
  Handle<Code> CompileFastApiCall(const CallOptimization& optimization,
986
                                  Handle<Object> object,
987
                                  Handle<JSObject> holder,
988
                                  Handle<Cell> cell,
989
                                  Handle<JSFunction> function,
990
                                  Handle<String> name);
991

    
992
  Handle<Code> GetCode(Code::StubType type, Handle<Name> name);
993
  Handle<Code> GetCode(Handle<JSFunction> function);
994

    
995
  const ParameterCount& arguments() { return arguments_; }
996

    
997
  void GenerateNameCheck(Handle<Name> name, Label* miss);
998

    
999
  void GenerateGlobalReceiverCheck(Handle<JSObject> object,
1000
                                   Handle<JSObject> holder,
1001
                                   Handle<Name> name,
1002
                                   Label* miss);
1003

    
1004
  // Generates code to load the function from the cell checking that
1005
  // it still contains the same function.
1006
  void GenerateLoadFunctionFromCell(Handle<Cell> cell,
1007
                                    Handle<JSFunction> function,
1008
                                    Label* miss);
1009

    
1010
  // Generates a jump to CallIC miss stub.
1011
  void GenerateMissBranch();
1012

    
1013
  const ParameterCount arguments_;
1014
  const Code::Kind kind_;
1015
  const Code::ExtraICState extra_state_;
1016
  const InlineCacheHolderFlag cache_holder_;
1017
};
1018

    
1019

    
1020
// Holds information about possible function call optimizations.
1021
class CallOptimization BASE_EMBEDDED {
1022
 public:
1023
  explicit CallOptimization(LookupResult* lookup);
1024

    
1025
  explicit CallOptimization(Handle<JSFunction> function);
1026

    
1027
  bool is_constant_call() const {
1028
    return !constant_function_.is_null();
1029
  }
1030

    
1031
  Handle<JSFunction> constant_function() const {
1032
    ASSERT(is_constant_call());
1033
    return constant_function_;
1034
  }
1035

    
1036
  bool is_simple_api_call() const {
1037
    return is_simple_api_call_;
1038
  }
1039

    
1040
  Handle<FunctionTemplateInfo> expected_receiver_type() const {
1041
    ASSERT(is_simple_api_call());
1042
    return expected_receiver_type_;
1043
  }
1044

    
1045
  Handle<CallHandlerInfo> api_call_info() const {
1046
    ASSERT(is_simple_api_call());
1047
    return api_call_info_;
1048
  }
1049

    
1050
  // Returns the depth of the object having the expected type in the
1051
  // prototype chain between the two arguments.
1052
  int GetPrototypeDepthOfExpectedType(Handle<JSObject> object,
1053
                                      Handle<JSObject> holder) const;
1054

    
1055
  bool IsCompatibleReceiver(Object* receiver) {
1056
    ASSERT(is_simple_api_call());
1057
    if (expected_receiver_type_.is_null()) return true;
1058
    return receiver->IsInstanceOf(*expected_receiver_type_);
1059
  }
1060

    
1061
 private:
1062
  void Initialize(Handle<JSFunction> function);
1063

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

    
1068
  Handle<JSFunction> constant_function_;
1069
  bool is_simple_api_call_;
1070
  Handle<FunctionTemplateInfo> expected_receiver_type_;
1071
  Handle<CallHandlerInfo> api_call_info_;
1072
};
1073

    
1074

    
1075
} }  // namespace v8::internal
1076

    
1077
#endif  // V8_STUB_CACHE_H_