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.cc @ f230a1cf

History | View | Annotate | Download (65.3 KB)

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

    
28
#include "v8.h"
29

    
30
#include "api.h"
31
#include "arguments.h"
32
#include "ast.h"
33
#include "code-stubs.h"
34
#include "cpu-profiler.h"
35
#include "gdb-jit.h"
36
#include "ic-inl.h"
37
#include "stub-cache.h"
38
#include "vm-state-inl.h"
39

    
40
namespace v8 {
41
namespace internal {
42

    
43
// -----------------------------------------------------------------------
44
// StubCache implementation.
45

    
46

    
47
StubCache::StubCache(Isolate* isolate)
48
    : isolate_(isolate) { }
49

    
50

    
51
void StubCache::Initialize() {
52
  ASSERT(IsPowerOf2(kPrimaryTableSize));
53
  ASSERT(IsPowerOf2(kSecondaryTableSize));
54
  Clear();
55
}
56

    
57

    
58
Code* StubCache::Set(Name* name, Map* map, Code* code) {
59
  // Get the flags from the code.
60
  Code::Flags flags = Code::RemoveTypeFromFlags(code->flags());
61

    
62
  // Validate that the name does not move on scavenge, and that we
63
  // can use identity checks instead of structural equality checks.
64
  ASSERT(!heap()->InNewSpace(name));
65
  ASSERT(name->IsUniqueName());
66

    
67
  // The state bits are not important to the hash function because
68
  // the stub cache only contains monomorphic stubs. Make sure that
69
  // the bits are the least significant so they will be the ones
70
  // masked out.
71
  ASSERT(Code::ExtractICStateFromFlags(flags) == MONOMORPHIC);
72
  STATIC_ASSERT((Code::ICStateField::kMask & 1) == 1);
73

    
74
  // Make sure that the code type is not included in the hash.
75
  ASSERT(Code::ExtractTypeFromFlags(flags) == 0);
76

    
77
  // Compute the primary entry.
78
  int primary_offset = PrimaryOffset(name, flags, map);
79
  Entry* primary = entry(primary_, primary_offset);
80
  Code* old_code = primary->value;
81

    
82
  // If the primary entry has useful data in it, we retire it to the
83
  // secondary cache before overwriting it.
84
  if (old_code != isolate_->builtins()->builtin(Builtins::kIllegal)) {
85
    Map* old_map = primary->map;
86
    Code::Flags old_flags = Code::RemoveTypeFromFlags(old_code->flags());
87
    int seed = PrimaryOffset(primary->key, old_flags, old_map);
88
    int secondary_offset = SecondaryOffset(primary->key, old_flags, seed);
89
    Entry* secondary = entry(secondary_, secondary_offset);
90
    *secondary = *primary;
91
  }
92

    
93
  // Update primary cache.
94
  primary->key = name;
95
  primary->value = code;
96
  primary->map = map;
97
  isolate()->counters()->megamorphic_stub_cache_updates()->Increment();
98
  return code;
99
}
100

    
101

    
102
Handle<Code> StubCache::FindIC(Handle<Name> name,
103
                               Handle<Map> stub_holder_map,
104
                               Code::Kind kind,
105
                               Code::ExtraICState extra_state) {
106
  Code::Flags flags = Code::ComputeMonomorphicFlags(kind, extra_state);
107
  Handle<Object> probe(stub_holder_map->FindInCodeCache(*name, flags),
108
                       isolate_);
109
  if (probe->IsCode()) return Handle<Code>::cast(probe);
110
  return Handle<Code>::null();
111
}
112

    
113

    
114
Handle<Code> StubCache::FindIC(Handle<Name> name,
115
                               Handle<JSObject> stub_holder,
116
                               Code::Kind kind,
117
                               Code::ExtraICState extra_ic_state) {
118
  return FindIC(name, Handle<Map>(stub_holder->map()), kind, extra_ic_state);
119
}
120

    
121

    
122
Handle<Code> StubCache::FindHandler(Handle<Name> name,
123
                                    Handle<JSObject> receiver,
124
                                    Code::Kind kind,
125
                                    StrictModeFlag strict_mode) {
126
  Code::ExtraICState extra_ic_state = Code::kNoExtraICState;
127
  if (kind == Code::STORE_IC || kind == Code::KEYED_STORE_IC) {
128
    extra_ic_state = Code::ComputeExtraICState(
129
        STANDARD_STORE, strict_mode);
130
  }
131
  Code::Flags flags = Code::ComputeMonomorphicFlags(
132
      Code::HANDLER, extra_ic_state, Code::NORMAL, kind);
133
  Handle<Object> probe(receiver->map()->FindInCodeCache(*name, flags),
134
                       isolate_);
135
  if (probe->IsCode()) return Handle<Code>::cast(probe);
136
  return Handle<Code>::null();
137
}
138

    
139

    
140
Handle<Code> StubCache::ComputeMonomorphicIC(Handle<HeapObject> receiver,
141
                                             Handle<Code> handler,
142
                                             Handle<Name> name,
143
                                             StrictModeFlag strict_mode) {
144
  Code::Kind kind = handler->handler_kind();
145
  Handle<Map> map(receiver->map());
146
  Handle<Code> ic = FindIC(name, map, kind, strict_mode);
147
  if (!ic.is_null()) return ic;
148

    
149
  if (kind == Code::LOAD_IC) {
150
    LoadStubCompiler ic_compiler(isolate());
151
    ic = ic_compiler.CompileMonomorphicIC(map, handler, name);
152
  } else if (kind == Code::KEYED_LOAD_IC) {
153
    KeyedLoadStubCompiler ic_compiler(isolate());
154
    ic = ic_compiler.CompileMonomorphicIC(map, handler, name);
155
  } else if (kind == Code::STORE_IC) {
156
    StoreStubCompiler ic_compiler(isolate(), strict_mode);
157
    ic = ic_compiler.CompileMonomorphicIC(map, handler, name);
158
  } else {
159
    ASSERT(kind == Code::KEYED_STORE_IC);
160
    KeyedStoreStubCompiler ic_compiler(isolate(), strict_mode, STANDARD_STORE);
161
    ic = ic_compiler.CompileMonomorphicIC(map, handler, name);
162
  }
163

    
164
  HeapObject::UpdateMapCodeCache(receiver, name, ic);
165
  return ic;
166
}
167

    
168

    
169
Handle<Code> StubCache::ComputeLoadNonexistent(Handle<Name> name,
170
                                               Handle<JSObject> receiver) {
171
  // If no global objects are present in the prototype chain, the load
172
  // nonexistent IC stub can be shared for all names for a given map
173
  // and we use the empty string for the map cache in that case.  If
174
  // there are global objects involved, we need to check global
175
  // property cells in the stub and therefore the stub will be
176
  // specific to the name.
177
  Handle<Name> cache_name = factory()->empty_string();
178
  Handle<JSObject> current;
179
  Handle<Object> next = receiver;
180
  Handle<GlobalObject> global;
181
  do {
182
    current = Handle<JSObject>::cast(next);
183
    next = Handle<Object>(current->GetPrototype(), isolate_);
184
    if (current->IsGlobalObject()) {
185
      global = Handle<GlobalObject>::cast(current);
186
      cache_name = name;
187
    } else if (!current->HasFastProperties()) {
188
      cache_name = name;
189
    }
190
  } while (!next->IsNull());
191

    
192
  // Compile the stub that is either shared for all names or
193
  // name specific if there are global objects involved.
194
  Handle<Code> handler = FindHandler(cache_name, receiver, Code::LOAD_IC);
195
  if (!handler.is_null()) return handler;
196

    
197
  LoadStubCompiler compiler(isolate_);
198
  handler =
199
      compiler.CompileLoadNonexistent(receiver, current, cache_name, global);
200
  HeapObject::UpdateMapCodeCache(receiver, cache_name, handler);
201
  return handler;
202
}
203

    
204

    
205
Handle<Code> StubCache::ComputeLoadGlobal(Handle<Name> name,
206
                                          Handle<JSObject> receiver,
207
                                          Handle<GlobalObject> holder,
208
                                          Handle<PropertyCell> cell,
209
                                          bool is_dont_delete) {
210
  Handle<Code> stub = FindIC(name, receiver, Code::LOAD_IC);
211
  if (!stub.is_null()) return stub;
212

    
213
  LoadStubCompiler compiler(isolate_);
214
  Handle<Code> ic =
215
      compiler.CompileLoadGlobal(receiver, holder, cell, name, is_dont_delete);
216
  HeapObject::UpdateMapCodeCache(receiver, name, ic);
217
  return ic;
218
}
219

    
220

    
221
Handle<Code> StubCache::ComputeKeyedLoadElement(Handle<Map> receiver_map) {
222
  Code::Flags flags = Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC);
223
  Handle<Name> name =
224
      isolate()->factory()->KeyedLoadElementMonomorphic_string();
225

    
226
  Handle<Object> probe(receiver_map->FindInCodeCache(*name, flags), isolate_);
227
  if (probe->IsCode()) return Handle<Code>::cast(probe);
228

    
229
  KeyedLoadStubCompiler compiler(isolate());
230
  Handle<Code> code = compiler.CompileLoadElement(receiver_map);
231

    
232
  Map::UpdateCodeCache(receiver_map, name, code);
233
  return code;
234
}
235

    
236

    
237
Handle<Code> StubCache::ComputeKeyedStoreElement(
238
    Handle<Map> receiver_map,
239
    StrictModeFlag strict_mode,
240
    KeyedAccessStoreMode store_mode) {
241
  Code::ExtraICState extra_state =
242
      Code::ComputeExtraICState(store_mode, strict_mode);
243
  Code::Flags flags = Code::ComputeMonomorphicFlags(
244
      Code::KEYED_STORE_IC, extra_state);
245

    
246
  ASSERT(store_mode == STANDARD_STORE ||
247
         store_mode == STORE_AND_GROW_NO_TRANSITION ||
248
         store_mode == STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS ||
249
         store_mode == STORE_NO_TRANSITION_HANDLE_COW);
250

    
251
  Handle<String> name =
252
      isolate()->factory()->KeyedStoreElementMonomorphic_string();
253
  Handle<Object> probe(receiver_map->FindInCodeCache(*name, flags), isolate_);
254
  if (probe->IsCode()) return Handle<Code>::cast(probe);
255

    
256
  KeyedStoreStubCompiler compiler(isolate(), strict_mode, store_mode);
257
  Handle<Code> code = compiler.CompileStoreElement(receiver_map);
258

    
259
  Map::UpdateCodeCache(receiver_map, name, code);
260
  ASSERT(Code::GetKeyedAccessStoreMode(code->extra_ic_state()) == store_mode);
261
  return code;
262
}
263

    
264

    
265
Handle<Code> StubCache::ComputeStoreGlobal(Handle<Name> name,
266
                                           Handle<GlobalObject> receiver,
267
                                           Handle<PropertyCell> cell,
268
                                           Handle<Object> value,
269
                                           StrictModeFlag strict_mode) {
270
  Handle<Type> union_type = PropertyCell::UpdatedType(cell, value);
271
  bool is_constant = union_type->IsConstant();
272
  StoreGlobalStub stub(strict_mode, is_constant);
273

    
274
  Handle<Code> code = FindIC(
275
      name, Handle<JSObject>::cast(receiver),
276
      Code::STORE_IC, stub.GetExtraICState());
277
  if (!code.is_null()) return code;
278

    
279
  // Replace the placeholder cell and global object map with the actual global
280
  // cell and receiver map.
281
  Handle<Map> meta_map(isolate_->heap()->meta_map());
282
  Handle<Object> receiver_map(receiver->map(), isolate_);
283
  code = stub.GetCodeCopyFromTemplate(isolate_);
284
  code->ReplaceNthObject(1, *meta_map, *receiver_map);
285
  Handle<Map> cell_map(isolate_->heap()->global_property_cell_map());
286
  code->ReplaceNthObject(1, *cell_map, *cell);
287

    
288
  HeapObject::UpdateMapCodeCache(receiver, name, code);
289

    
290
  return code;
291
}
292

    
293

    
294
#define CALL_LOGGER_TAG(kind, type) \
295
    (kind == Code::CALL_IC ? Logger::type : Logger::KEYED_##type)
296

    
297
Handle<Code> StubCache::ComputeCallConstant(int argc,
298
                                            Code::Kind kind,
299
                                            Code::ExtraICState extra_state,
300
                                            Handle<Name> name,
301
                                            Handle<Object> object,
302
                                            Handle<JSObject> holder,
303
                                            Handle<JSFunction> function) {
304
  // Compute the check type and the map.
305
  InlineCacheHolderFlag cache_holder =
306
      IC::GetCodeCacheForObject(*object, *holder);
307
  Handle<JSObject> stub_holder(IC::GetCodeCacheHolder(
308
      isolate_, *object, cache_holder));
309

    
310
  // Compute check type based on receiver/holder.
311
  CheckType check = RECEIVER_MAP_CHECK;
312
  if (object->IsString()) {
313
    check = STRING_CHECK;
314
  } else if (object->IsSymbol()) {
315
    check = SYMBOL_CHECK;
316
  } else if (object->IsNumber()) {
317
    check = NUMBER_CHECK;
318
  } else if (object->IsBoolean()) {
319
    check = BOOLEAN_CHECK;
320
  }
321

    
322
  if (check != RECEIVER_MAP_CHECK &&
323
      !function->IsBuiltin() &&
324
      function->shared()->is_classic_mode()) {
325
    // Calling non-strict non-builtins with a value as the receiver
326
    // requires boxing.
327
    return Handle<Code>::null();
328
  }
329

    
330
  Code::Flags flags = Code::ComputeMonomorphicFlags(
331
      kind, extra_state, Code::CONSTANT, argc, cache_holder);
332
  Handle<Object> probe(stub_holder->map()->FindInCodeCache(*name, flags),
333
                       isolate_);
334
  if (probe->IsCode()) return Handle<Code>::cast(probe);
335

    
336
  CallStubCompiler compiler(isolate_, argc, kind, extra_state, cache_holder);
337
  Handle<Code> code =
338
      compiler.CompileCallConstant(object, holder, name, check, function);
339
  code->set_check_type(check);
340
  ASSERT(flags == code->flags());
341
  PROFILE(isolate_,
342
          CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_IC_TAG), *code, *name));
343
  GDBJIT(AddCode(GDBJITInterface::CALL_IC, *name, *code));
344

    
345
  if (CallStubCompiler::CanBeCached(function)) {
346
    HeapObject::UpdateMapCodeCache(stub_holder, name, code);
347
  }
348
  return code;
349
}
350

    
351

    
352
Handle<Code> StubCache::ComputeCallField(int argc,
353
                                         Code::Kind kind,
354
                                         Code::ExtraICState extra_state,
355
                                         Handle<Name> name,
356
                                         Handle<Object> object,
357
                                         Handle<JSObject> holder,
358
                                         PropertyIndex index) {
359
  // Compute the check type and the map.
360
  InlineCacheHolderFlag cache_holder =
361
      IC::GetCodeCacheForObject(*object, *holder);
362
  Handle<JSObject> stub_holder(IC::GetCodeCacheHolder(
363
      isolate_, *object, cache_holder));
364

    
365
  // TODO(1233596): We cannot do receiver map check for non-JS objects
366
  // because they may be represented as immediates without a
367
  // map. Instead, we check against the map in the holder.
368
  if (object->IsNumber() || object->IsSymbol() ||
369
      object->IsBoolean() || object->IsString()) {
370
    object = holder;
371
  }
372

    
373
  Code::Flags flags = Code::ComputeMonomorphicFlags(
374
      kind, extra_state, Code::FIELD, argc, cache_holder);
375
  Handle<Object> probe(stub_holder->map()->FindInCodeCache(*name, flags),
376
                       isolate_);
377
  if (probe->IsCode()) return Handle<Code>::cast(probe);
378

    
379
  CallStubCompiler compiler(isolate_, argc, kind, extra_state, cache_holder);
380
  Handle<Code> code =
381
      compiler.CompileCallField(Handle<JSObject>::cast(object),
382
                                holder, index, name);
383
  ASSERT(flags == code->flags());
384
  PROFILE(isolate_,
385
          CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_IC_TAG), *code, *name));
386
  GDBJIT(AddCode(GDBJITInterface::CALL_IC, *name, *code));
387
  HeapObject::UpdateMapCodeCache(stub_holder, name, code);
388
  return code;
389
}
390

    
391

    
392
Handle<Code> StubCache::ComputeCallInterceptor(int argc,
393
                                               Code::Kind kind,
394
                                               Code::ExtraICState extra_state,
395
                                               Handle<Name> name,
396
                                               Handle<Object> object,
397
                                               Handle<JSObject> holder) {
398
  // Compute the check type and the map.
399
  InlineCacheHolderFlag cache_holder =
400
      IC::GetCodeCacheForObject(*object, *holder);
401
  Handle<JSObject> stub_holder(IC::GetCodeCacheHolder(
402
      isolate_, *object, cache_holder));
403

    
404
  // TODO(1233596): We cannot do receiver map check for non-JS objects
405
  // because they may be represented as immediates without a
406
  // map. Instead, we check against the map in the holder.
407
  if (object->IsNumber() || object->IsSymbol() ||
408
      object->IsBoolean() || object->IsString()) {
409
    object = holder;
410
  }
411

    
412
  Code::Flags flags = Code::ComputeMonomorphicFlags(
413
      kind, extra_state, Code::INTERCEPTOR, argc, cache_holder);
414
  Handle<Object> probe(stub_holder->map()->FindInCodeCache(*name, flags),
415
                       isolate_);
416
  if (probe->IsCode()) return Handle<Code>::cast(probe);
417

    
418
  CallStubCompiler compiler(isolate(), argc, kind, extra_state, cache_holder);
419
  Handle<Code> code =
420
      compiler.CompileCallInterceptor(Handle<JSObject>::cast(object),
421
                                      holder, name);
422
  ASSERT(flags == code->flags());
423
  PROFILE(isolate(),
424
          CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_IC_TAG), *code, *name));
425
  GDBJIT(AddCode(GDBJITInterface::CALL_IC, *name, *code));
426
  HeapObject::UpdateMapCodeCache(stub_holder, name, code);
427
  return code;
428
}
429

    
430

    
431
Handle<Code> StubCache::ComputeCallGlobal(int argc,
432
                                          Code::Kind kind,
433
                                          Code::ExtraICState extra_state,
434
                                          Handle<Name> name,
435
                                          Handle<JSObject> receiver,
436
                                          Handle<GlobalObject> holder,
437
                                          Handle<PropertyCell> cell,
438
                                          Handle<JSFunction> function) {
439
  Code::Flags flags = Code::ComputeMonomorphicFlags(
440
      kind, extra_state, Code::NORMAL, argc);
441
  Handle<Object> probe(receiver->map()->FindInCodeCache(*name, flags),
442
                       isolate_);
443
  if (probe->IsCode()) return Handle<Code>::cast(probe);
444

    
445
  CallStubCompiler compiler(isolate(), argc, kind, extra_state);
446
  Handle<Code> code =
447
      compiler.CompileCallGlobal(receiver, holder, cell, function, name);
448
  ASSERT(flags == code->flags());
449
  PROFILE(isolate(),
450
          CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_IC_TAG), *code, *name));
451
  GDBJIT(AddCode(GDBJITInterface::CALL_IC, *name, *code));
452
  if (CallStubCompiler::CanBeCached(function)) {
453
    HeapObject::UpdateMapCodeCache(receiver, name, code);
454
  }
455
  return code;
456
}
457

    
458

    
459
static void FillCache(Isolate* isolate, Handle<Code> code) {
460
  Handle<UnseededNumberDictionary> dictionary =
461
      UnseededNumberDictionary::Set(isolate->factory()->non_monomorphic_cache(),
462
                                    code->flags(),
463
                                    code);
464
  isolate->heap()->public_set_non_monomorphic_cache(*dictionary);
465
}
466

    
467

    
468
Code* StubCache::FindCallInitialize(int argc,
469
                                    RelocInfo::Mode mode,
470
                                    Code::Kind kind) {
471
  Code::ExtraICState extra_state =
472
      CallICBase::StringStubState::encode(DEFAULT_STRING_STUB) |
473
      CallICBase::Contextual::encode(mode == RelocInfo::CODE_TARGET_CONTEXT);
474
  Code::Flags flags =
475
      Code::ComputeFlags(kind, UNINITIALIZED, extra_state, Code::NORMAL, argc);
476
  UnseededNumberDictionary* dictionary =
477
      isolate()->heap()->non_monomorphic_cache();
478
  int entry = dictionary->FindEntry(isolate(), flags);
479
  ASSERT(entry != -1);
480
  Object* code = dictionary->ValueAt(entry);
481
  // This might be called during the marking phase of the collector
482
  // hence the unchecked cast.
483
  return reinterpret_cast<Code*>(code);
484
}
485

    
486

    
487
Handle<Code> StubCache::ComputeCallInitialize(int argc,
488
                                              RelocInfo::Mode mode,
489
                                              Code::Kind kind) {
490
  Code::ExtraICState extra_state =
491
      CallICBase::StringStubState::encode(DEFAULT_STRING_STUB) |
492
      CallICBase::Contextual::encode(mode == RelocInfo::CODE_TARGET_CONTEXT);
493
  Code::Flags flags =
494
      Code::ComputeFlags(kind, UNINITIALIZED, extra_state, Code::NORMAL, argc);
495
  Handle<UnseededNumberDictionary> cache =
496
      isolate_->factory()->non_monomorphic_cache();
497
  int entry = cache->FindEntry(isolate_, flags);
498
  if (entry != -1) return Handle<Code>(Code::cast(cache->ValueAt(entry)));
499

    
500
  StubCompiler compiler(isolate_);
501
  Handle<Code> code = compiler.CompileCallInitialize(flags);
502
  FillCache(isolate_, code);
503
  return code;
504
}
505

    
506

    
507
Handle<Code> StubCache::ComputeCallInitialize(int argc, RelocInfo::Mode mode) {
508
  return ComputeCallInitialize(argc, mode, Code::CALL_IC);
509
}
510

    
511

    
512
Handle<Code> StubCache::ComputeKeyedCallInitialize(int argc) {
513
  return ComputeCallInitialize(argc, RelocInfo::CODE_TARGET,
514
                               Code::KEYED_CALL_IC);
515
}
516

    
517

    
518
Handle<Code> StubCache::ComputeCallPreMonomorphic(
519
    int argc,
520
    Code::Kind kind,
521
    Code::ExtraICState extra_state) {
522
  Code::Flags flags =
523
      Code::ComputeFlags(kind, PREMONOMORPHIC, extra_state, Code::NORMAL, argc);
524
  Handle<UnseededNumberDictionary> cache =
525
      isolate_->factory()->non_monomorphic_cache();
526
  int entry = cache->FindEntry(isolate_, flags);
527
  if (entry != -1) return Handle<Code>(Code::cast(cache->ValueAt(entry)));
528

    
529
  StubCompiler compiler(isolate_);
530
  Handle<Code> code = compiler.CompileCallPreMonomorphic(flags);
531
  FillCache(isolate_, code);
532
  return code;
533
}
534

    
535

    
536
Handle<Code> StubCache::ComputeCallNormal(int argc,
537
                                          Code::Kind kind,
538
                                          Code::ExtraICState extra_state) {
539
  Code::Flags flags =
540
      Code::ComputeFlags(kind, MONOMORPHIC, extra_state, Code::NORMAL, argc);
541
  Handle<UnseededNumberDictionary> cache =
542
      isolate_->factory()->non_monomorphic_cache();
543
  int entry = cache->FindEntry(isolate_, flags);
544
  if (entry != -1) return Handle<Code>(Code::cast(cache->ValueAt(entry)));
545

    
546
  StubCompiler compiler(isolate_);
547
  Handle<Code> code = compiler.CompileCallNormal(flags);
548
  FillCache(isolate_, code);
549
  return code;
550
}
551

    
552

    
553
Handle<Code> StubCache::ComputeCallArguments(int argc) {
554
  Code::Flags flags =
555
      Code::ComputeFlags(Code::KEYED_CALL_IC, MEGAMORPHIC,
556
                         Code::kNoExtraICState, Code::NORMAL, argc);
557
  Handle<UnseededNumberDictionary> cache =
558
      isolate_->factory()->non_monomorphic_cache();
559
  int entry = cache->FindEntry(isolate_, flags);
560
  if (entry != -1) return Handle<Code>(Code::cast(cache->ValueAt(entry)));
561

    
562
  StubCompiler compiler(isolate_);
563
  Handle<Code> code = compiler.CompileCallArguments(flags);
564
  FillCache(isolate_, code);
565
  return code;
566
}
567

    
568

    
569
Handle<Code> StubCache::ComputeCallMegamorphic(
570
    int argc,
571
    Code::Kind kind,
572
    Code::ExtraICState extra_state) {
573
  Code::Flags flags =
574
      Code::ComputeFlags(kind, MEGAMORPHIC, extra_state,
575
                         Code::NORMAL, argc);
576
  Handle<UnseededNumberDictionary> cache =
577
      isolate_->factory()->non_monomorphic_cache();
578
  int entry = cache->FindEntry(isolate_, flags);
579
  if (entry != -1) return Handle<Code>(Code::cast(cache->ValueAt(entry)));
580

    
581
  StubCompiler compiler(isolate_);
582
  Handle<Code> code = compiler.CompileCallMegamorphic(flags);
583
  FillCache(isolate_, code);
584
  return code;
585
}
586

    
587

    
588
Handle<Code> StubCache::ComputeCallMiss(int argc,
589
                                        Code::Kind kind,
590
                                        Code::ExtraICState extra_state) {
591
  // MONOMORPHIC_PROTOTYPE_FAILURE state is used to make sure that miss stubs
592
  // and monomorphic stubs are not mixed up together in the stub cache.
593
  Code::Flags flags =
594
      Code::ComputeFlags(kind, MONOMORPHIC_PROTOTYPE_FAILURE, extra_state,
595
                         Code::NORMAL, argc, OWN_MAP);
596
  Handle<UnseededNumberDictionary> cache =
597
      isolate_->factory()->non_monomorphic_cache();
598
  int entry = cache->FindEntry(isolate_, flags);
599
  if (entry != -1) return Handle<Code>(Code::cast(cache->ValueAt(entry)));
600

    
601
  StubCompiler compiler(isolate_);
602
  Handle<Code> code = compiler.CompileCallMiss(flags);
603
  FillCache(isolate_, code);
604
  return code;
605
}
606

    
607

    
608
Handle<Code> StubCache::ComputeCompareNil(Handle<Map> receiver_map,
609
                                          CompareNilICStub& stub) {
610
  Handle<String> name(isolate_->heap()->empty_string());
611
  if (!receiver_map->is_shared()) {
612
    Handle<Code> cached_ic = FindIC(name, receiver_map, Code::COMPARE_NIL_IC,
613
                                    stub.GetExtraICState());
614
    if (!cached_ic.is_null()) return cached_ic;
615
  }
616

    
617
  Handle<Code> ic = stub.GetCodeCopyFromTemplate(isolate_);
618
  ic->ReplaceNthObject(1, isolate_->heap()->meta_map(), *receiver_map);
619

    
620
  if (!receiver_map->is_shared()) {
621
    Map::UpdateCodeCache(receiver_map, name, ic);
622
  }
623

    
624
  return ic;
625
}
626

    
627

    
628
Handle<Code> StubCache::ComputeLoadElementPolymorphic(
629
    MapHandleList* receiver_maps) {
630
  Code::Flags flags = Code::ComputeFlags(Code::KEYED_LOAD_IC, POLYMORPHIC);
631
  Handle<PolymorphicCodeCache> cache =
632
      isolate_->factory()->polymorphic_code_cache();
633
  Handle<Object> probe = cache->Lookup(receiver_maps, flags);
634
  if (probe->IsCode()) return Handle<Code>::cast(probe);
635

    
636
  CodeHandleList handlers(receiver_maps->length());
637
  KeyedLoadStubCompiler compiler(isolate_);
638
  compiler.CompileElementHandlers(receiver_maps, &handlers);
639
  Handle<Code> code = compiler.CompilePolymorphicIC(
640
      receiver_maps, &handlers, factory()->empty_string(),
641
      Code::NORMAL, ELEMENT);
642

    
643
  isolate()->counters()->keyed_load_polymorphic_stubs()->Increment();
644

    
645
  PolymorphicCodeCache::Update(cache, receiver_maps, flags, code);
646
  return code;
647
}
648

    
649

    
650
Handle<Code> StubCache::ComputePolymorphicIC(MapHandleList* receiver_maps,
651
                                             CodeHandleList* handlers,
652
                                             int number_of_valid_maps,
653
                                             Handle<Name> name,
654
                                             StrictModeFlag strict_mode) {
655
  Handle<Code> handler = handlers->at(0);
656
  Code::Kind kind = handler->handler_kind();
657
  Code::StubType type = number_of_valid_maps == 1 ? handler->type()
658
                                                  : Code::NORMAL;
659
  if (kind == Code::LOAD_IC) {
660
    LoadStubCompiler ic_compiler(isolate_);
661
    return ic_compiler.CompilePolymorphicIC(
662
        receiver_maps, handlers, name, type, PROPERTY);
663
  } else {
664
    ASSERT(kind == Code::STORE_IC);
665
    StoreStubCompiler ic_compiler(isolate_, strict_mode);
666
    return ic_compiler.CompilePolymorphicIC(
667
        receiver_maps, handlers, name, type, PROPERTY);
668
  }
669
}
670

    
671

    
672
Handle<Code> StubCache::ComputeStoreElementPolymorphic(
673
    MapHandleList* receiver_maps,
674
    KeyedAccessStoreMode store_mode,
675
    StrictModeFlag strict_mode) {
676
  ASSERT(store_mode == STANDARD_STORE ||
677
         store_mode == STORE_AND_GROW_NO_TRANSITION ||
678
         store_mode == STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS ||
679
         store_mode == STORE_NO_TRANSITION_HANDLE_COW);
680
  Handle<PolymorphicCodeCache> cache =
681
      isolate_->factory()->polymorphic_code_cache();
682
  Code::ExtraICState extra_state = Code::ComputeExtraICState(store_mode,
683
                                                             strict_mode);
684
  Code::Flags flags =
685
      Code::ComputeFlags(Code::KEYED_STORE_IC, POLYMORPHIC, extra_state);
686
  Handle<Object> probe = cache->Lookup(receiver_maps, flags);
687
  if (probe->IsCode()) return Handle<Code>::cast(probe);
688

    
689
  KeyedStoreStubCompiler compiler(isolate_, strict_mode, store_mode);
690
  Handle<Code> code = compiler.CompileStoreElementPolymorphic(receiver_maps);
691
  PolymorphicCodeCache::Update(cache, receiver_maps, flags, code);
692
  return code;
693
}
694

    
695

    
696
#ifdef ENABLE_DEBUGGER_SUPPORT
697
Handle<Code> StubCache::ComputeCallDebugBreak(int argc,
698
                                              Code::Kind kind) {
699
  // Extra IC state is irrelevant for debug break ICs. They jump to
700
  // the actual call ic to carry out the work.
701
  Code::Flags flags =
702
      Code::ComputeFlags(kind, DEBUG_STUB, DEBUG_BREAK,
703
                         Code::NORMAL, argc);
704
  Handle<UnseededNumberDictionary> cache =
705
      isolate_->factory()->non_monomorphic_cache();
706
  int entry = cache->FindEntry(isolate_, flags);
707
  if (entry != -1) return Handle<Code>(Code::cast(cache->ValueAt(entry)));
708

    
709
  StubCompiler compiler(isolate_);
710
  Handle<Code> code = compiler.CompileCallDebugBreak(flags);
711
  FillCache(isolate_, code);
712
  return code;
713
}
714

    
715

    
716
Handle<Code> StubCache::ComputeCallDebugPrepareStepIn(int argc,
717
                                                      Code::Kind kind) {
718
  // Extra IC state is irrelevant for debug break ICs. They jump to
719
  // the actual call ic to carry out the work.
720
  Code::Flags flags =
721
      Code::ComputeFlags(kind, DEBUG_STUB, DEBUG_PREPARE_STEP_IN,
722
                         Code::NORMAL, argc);
723
  Handle<UnseededNumberDictionary> cache =
724
      isolate_->factory()->non_monomorphic_cache();
725
  int entry = cache->FindEntry(isolate_, flags);
726
  if (entry != -1) return Handle<Code>(Code::cast(cache->ValueAt(entry)));
727

    
728
  StubCompiler compiler(isolate_);
729
  Handle<Code> code = compiler.CompileCallDebugPrepareStepIn(flags);
730
  FillCache(isolate_, code);
731
  return code;
732
}
733
#endif
734

    
735

    
736
void StubCache::Clear() {
737
  Code* empty = isolate_->builtins()->builtin(Builtins::kIllegal);
738
  for (int i = 0; i < kPrimaryTableSize; i++) {
739
    primary_[i].key = heap()->empty_string();
740
    primary_[i].map = NULL;
741
    primary_[i].value = empty;
742
  }
743
  for (int j = 0; j < kSecondaryTableSize; j++) {
744
    secondary_[j].key = heap()->empty_string();
745
    secondary_[j].map = NULL;
746
    secondary_[j].value = empty;
747
  }
748
}
749

    
750

    
751
void StubCache::CollectMatchingMaps(SmallMapList* types,
752
                                    Handle<Name> name,
753
                                    Code::Flags flags,
754
                                    Handle<Context> native_context,
755
                                    Zone* zone) {
756
  for (int i = 0; i < kPrimaryTableSize; i++) {
757
    if (primary_[i].key == *name) {
758
      Map* map = primary_[i].map;
759
      // Map can be NULL, if the stub is constant function call
760
      // with a primitive receiver.
761
      if (map == NULL) continue;
762

    
763
      int offset = PrimaryOffset(*name, flags, map);
764
      if (entry(primary_, offset) == &primary_[i] &&
765
          !TypeFeedbackOracle::CanRetainOtherContext(map, *native_context)) {
766
        types->AddMapIfMissing(Handle<Map>(map), zone);
767
      }
768
    }
769
  }
770

    
771
  for (int i = 0; i < kSecondaryTableSize; i++) {
772
    if (secondary_[i].key == *name) {
773
      Map* map = secondary_[i].map;
774
      // Map can be NULL, if the stub is constant function call
775
      // with a primitive receiver.
776
      if (map == NULL) continue;
777

    
778
      // Lookup in primary table and skip duplicates.
779
      int primary_offset = PrimaryOffset(*name, flags, map);
780

    
781
      // Lookup in secondary table and add matches.
782
      int offset = SecondaryOffset(*name, flags, primary_offset);
783
      if (entry(secondary_, offset) == &secondary_[i] &&
784
          !TypeFeedbackOracle::CanRetainOtherContext(map, *native_context)) {
785
        types->AddMapIfMissing(Handle<Map>(map), zone);
786
      }
787
    }
788
  }
789
}
790

    
791

    
792
// ------------------------------------------------------------------------
793
// StubCompiler implementation.
794

    
795

    
796
RUNTIME_FUNCTION(MaybeObject*, StoreCallbackProperty) {
797
  JSObject* recv = JSObject::cast(args[0]);
798
  ExecutableAccessorInfo* callback = ExecutableAccessorInfo::cast(args[1]);
799
  Address setter_address = v8::ToCData<Address>(callback->setter());
800
  v8::AccessorSetterCallback fun =
801
      FUNCTION_CAST<v8::AccessorSetterCallback>(setter_address);
802
  ASSERT(fun != NULL);
803
  ASSERT(callback->IsCompatibleReceiver(recv));
804
  Handle<Name> name = args.at<Name>(2);
805
  Handle<Object> value = args.at<Object>(3);
806
  HandleScope scope(isolate);
807

    
808
  // TODO(rossberg): Support symbols in the API.
809
  if (name->IsSymbol()) return *value;
810
  Handle<String> str = Handle<String>::cast(name);
811

    
812
  LOG(isolate, ApiNamedPropertyAccess("store", recv, *name));
813
  PropertyCallbackArguments
814
      custom_args(isolate, callback->data(), recv, recv);
815
  custom_args.Call(fun, v8::Utils::ToLocal(str), v8::Utils::ToLocal(value));
816
  RETURN_IF_SCHEDULED_EXCEPTION(isolate);
817
  return *value;
818
}
819

    
820

    
821
/**
822
 * Attempts to load a property with an interceptor (which must be present),
823
 * but doesn't search the prototype chain.
824
 *
825
 * Returns |Heap::no_interceptor_result_sentinel()| if interceptor doesn't
826
 * provide any value for the given name.
827
 */
828
RUNTIME_FUNCTION(MaybeObject*, LoadPropertyWithInterceptorOnly) {
829
  ASSERT(args.length() == StubCache::kInterceptorArgsLength);
830
  Handle<Name> name_handle =
831
      args.at<Name>(StubCache::kInterceptorArgsNameIndex);
832
  Handle<InterceptorInfo> interceptor_info =
833
      args.at<InterceptorInfo>(StubCache::kInterceptorArgsInfoIndex);
834

    
835
  // TODO(rossberg): Support symbols in the API.
836
  if (name_handle->IsSymbol())
837
    return isolate->heap()->no_interceptor_result_sentinel();
838
  Handle<String> name = Handle<String>::cast(name_handle);
839

    
840
  Address getter_address = v8::ToCData<Address>(interceptor_info->getter());
841
  v8::NamedPropertyGetterCallback getter =
842
      FUNCTION_CAST<v8::NamedPropertyGetterCallback>(getter_address);
843
  ASSERT(getter != NULL);
844

    
845
  Handle<JSObject> receiver =
846
      args.at<JSObject>(StubCache::kInterceptorArgsThisIndex);
847
  Handle<JSObject> holder =
848
      args.at<JSObject>(StubCache::kInterceptorArgsHolderIndex);
849
  PropertyCallbackArguments callback_args(
850
      isolate, interceptor_info->data(), *receiver, *holder);
851
  {
852
    // Use the interceptor getter.
853
    HandleScope scope(isolate);
854
    v8::Handle<v8::Value> r =
855
        callback_args.Call(getter, v8::Utils::ToLocal(name));
856
    RETURN_IF_SCHEDULED_EXCEPTION(isolate);
857
    if (!r.IsEmpty()) {
858
      Handle<Object> result = v8::Utils::OpenHandle(*r);
859
      result->VerifyApiCallResultType();
860
      return *v8::Utils::OpenHandle(*r);
861
    }
862
  }
863

    
864
  return isolate->heap()->no_interceptor_result_sentinel();
865
}
866

    
867

    
868
static MaybeObject* ThrowReferenceError(Isolate* isolate, Name* name) {
869
  // If the load is non-contextual, just return the undefined result.
870
  // Note that both keyed and non-keyed loads may end up here, so we
871
  // can't use either LoadIC or KeyedLoadIC constructors.
872
  HandleScope scope(isolate);
873
  IC ic(IC::NO_EXTRA_FRAME, isolate);
874
  ASSERT(ic.target()->is_load_stub() || ic.target()->is_keyed_load_stub());
875
  if (!ic.SlowIsUndeclaredGlobal()) return isolate->heap()->undefined_value();
876

    
877
  // Throw a reference error.
878
  Handle<Name> name_handle(name);
879
  Handle<Object> error =
880
      isolate->factory()->NewReferenceError("not_defined",
881
                                            HandleVector(&name_handle, 1));
882
  return isolate->Throw(*error);
883
}
884

    
885

    
886
static Handle<Object> LoadWithInterceptor(Arguments* args,
887
                                          PropertyAttributes* attrs) {
888
  ASSERT(args->length() == StubCache::kInterceptorArgsLength);
889
  Handle<Name> name_handle =
890
      args->at<Name>(StubCache::kInterceptorArgsNameIndex);
891
  Handle<InterceptorInfo> interceptor_info =
892
      args->at<InterceptorInfo>(StubCache::kInterceptorArgsInfoIndex);
893
  Handle<JSObject> receiver_handle =
894
      args->at<JSObject>(StubCache::kInterceptorArgsThisIndex);
895
  Handle<JSObject> holder_handle =
896
      args->at<JSObject>(StubCache::kInterceptorArgsHolderIndex);
897

    
898
  Isolate* isolate = receiver_handle->GetIsolate();
899

    
900
  // TODO(rossberg): Support symbols in the API.
901
  if (name_handle->IsSymbol()) {
902
    return JSObject::GetPropertyPostInterceptor(
903
        holder_handle, receiver_handle, name_handle, attrs);
904
  }
905
  Handle<String> name = Handle<String>::cast(name_handle);
906

    
907
  Address getter_address = v8::ToCData<Address>(interceptor_info->getter());
908
  v8::NamedPropertyGetterCallback getter =
909
      FUNCTION_CAST<v8::NamedPropertyGetterCallback>(getter_address);
910
  ASSERT(getter != NULL);
911

    
912
  PropertyCallbackArguments callback_args(isolate,
913
                                          interceptor_info->data(),
914
                                          *receiver_handle,
915
                                          *holder_handle);
916
  {
917
    HandleScope scope(isolate);
918
    // Use the interceptor getter.
919
    v8::Handle<v8::Value> r =
920
        callback_args.Call(getter, v8::Utils::ToLocal(name));
921
    RETURN_HANDLE_IF_SCHEDULED_EXCEPTION(isolate, Object);
922
    if (!r.IsEmpty()) {
923
      *attrs = NONE;
924
      Handle<Object> result = v8::Utils::OpenHandle(*r);
925
      result->VerifyApiCallResultType();
926
      return scope.CloseAndEscape(result);
927
    }
928
  }
929

    
930
  Handle<Object> result = JSObject::GetPropertyPostInterceptor(
931
      holder_handle, receiver_handle, name_handle, attrs);
932
  return result;
933
}
934

    
935

    
936
/**
937
 * Loads a property with an interceptor performing post interceptor
938
 * lookup if interceptor failed.
939
 */
940
RUNTIME_FUNCTION(MaybeObject*, LoadPropertyWithInterceptorForLoad) {
941
  PropertyAttributes attr = NONE;
942
  HandleScope scope(isolate);
943
  Handle<Object> result = LoadWithInterceptor(&args, &attr);
944
  RETURN_IF_EMPTY_HANDLE(isolate, result);
945

    
946
  // If the property is present, return it.
947
  if (attr != ABSENT) return *result;
948
  return ThrowReferenceError(isolate, Name::cast(args[0]));
949
}
950

    
951

    
952
RUNTIME_FUNCTION(MaybeObject*, LoadPropertyWithInterceptorForCall) {
953
  PropertyAttributes attr;
954
  HandleScope scope(isolate);
955
  Handle<Object> result = LoadWithInterceptor(&args, &attr);
956
  RETURN_IF_EMPTY_HANDLE(isolate, result);
957
  // This is call IC. In this case, we simply return the undefined result which
958
  // will lead to an exception when trying to invoke the result as a
959
  // function.
960
  return *result;
961
}
962

    
963

    
964
RUNTIME_FUNCTION(MaybeObject*, StoreInterceptorProperty) {
965
  HandleScope scope(isolate);
966
  ASSERT(args.length() == 4);
967
  Handle<JSObject> recv(JSObject::cast(args[0]));
968
  Handle<Name> name(Name::cast(args[1]));
969
  Handle<Object> value(args[2], isolate);
970
  ASSERT(args.smi_at(3) == kStrictMode || args.smi_at(3) == kNonStrictMode);
971
  StrictModeFlag strict_mode = static_cast<StrictModeFlag>(args.smi_at(3));
972
  ASSERT(recv->HasNamedInterceptor());
973
  PropertyAttributes attr = NONE;
974
  Handle<Object> result = JSObject::SetPropertyWithInterceptor(
975
      recv, name, value, attr, strict_mode);
976
  RETURN_IF_EMPTY_HANDLE(isolate, result);
977
  return *result;
978
}
979

    
980

    
981
RUNTIME_FUNCTION(MaybeObject*, KeyedLoadPropertyWithInterceptor) {
982
  JSObject* receiver = JSObject::cast(args[0]);
983
  ASSERT(args.smi_at(1) >= 0);
984
  uint32_t index = args.smi_at(1);
985
  return receiver->GetElementWithInterceptor(receiver, index);
986
}
987

    
988

    
989
Handle<Code> StubCompiler::CompileCallInitialize(Code::Flags flags) {
990
  int argc = Code::ExtractArgumentsCountFromFlags(flags);
991
  Code::Kind kind = Code::ExtractKindFromFlags(flags);
992
  Code::ExtraICState extra_state = Code::ExtractExtraICStateFromFlags(flags);
993
  if (kind == Code::CALL_IC) {
994
    CallIC::GenerateInitialize(masm(), argc, extra_state);
995
  } else {
996
    KeyedCallIC::GenerateInitialize(masm(), argc);
997
  }
998
  Handle<Code> code = GetCodeWithFlags(flags, "CompileCallInitialize");
999
  isolate()->counters()->call_initialize_stubs()->Increment();
1000
  PROFILE(isolate(),
1001
          CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_INITIALIZE_TAG),
1002
                          *code, code->arguments_count()));
1003
  GDBJIT(AddCode(GDBJITInterface::CALL_INITIALIZE, *code));
1004
  return code;
1005
}
1006

    
1007

    
1008
Handle<Code> StubCompiler::CompileCallPreMonomorphic(Code::Flags flags) {
1009
  int argc = Code::ExtractArgumentsCountFromFlags(flags);
1010
  // The code of the PreMonomorphic stub is the same as the code
1011
  // of the Initialized stub.  They just differ on the code object flags.
1012
  Code::Kind kind = Code::ExtractKindFromFlags(flags);
1013
  Code::ExtraICState extra_state = Code::ExtractExtraICStateFromFlags(flags);
1014
  if (kind == Code::CALL_IC) {
1015
    CallIC::GenerateInitialize(masm(), argc, extra_state);
1016
  } else {
1017
    KeyedCallIC::GenerateInitialize(masm(), argc);
1018
  }
1019
  Handle<Code> code = GetCodeWithFlags(flags, "CompileCallPreMonomorphic");
1020
  isolate()->counters()->call_premonomorphic_stubs()->Increment();
1021
  PROFILE(isolate(),
1022
          CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_PRE_MONOMORPHIC_TAG),
1023
                          *code, code->arguments_count()));
1024
  GDBJIT(AddCode(GDBJITInterface::CALL_PRE_MONOMORPHIC, *code));
1025
  return code;
1026
}
1027

    
1028

    
1029
Handle<Code> StubCompiler::CompileCallNormal(Code::Flags flags) {
1030
  int argc = Code::ExtractArgumentsCountFromFlags(flags);
1031
  Code::Kind kind = Code::ExtractKindFromFlags(flags);
1032
  if (kind == Code::CALL_IC) {
1033
    // Call normal is always with a explict receiver.
1034
    ASSERT(!CallIC::Contextual::decode(
1035
        Code::ExtractExtraICStateFromFlags(flags)));
1036
    CallIC::GenerateNormal(masm(), argc);
1037
  } else {
1038
    KeyedCallIC::GenerateNormal(masm(), argc);
1039
  }
1040
  Handle<Code> code = GetCodeWithFlags(flags, "CompileCallNormal");
1041
  isolate()->counters()->call_normal_stubs()->Increment();
1042
  PROFILE(isolate(),
1043
          CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_NORMAL_TAG),
1044
                          *code, code->arguments_count()));
1045
  GDBJIT(AddCode(GDBJITInterface::CALL_NORMAL, *code));
1046
  return code;
1047
}
1048

    
1049

    
1050
Handle<Code> StubCompiler::CompileCallMegamorphic(Code::Flags flags) {
1051
  int argc = Code::ExtractArgumentsCountFromFlags(flags);
1052
  Code::Kind kind = Code::ExtractKindFromFlags(flags);
1053
  Code::ExtraICState extra_state = Code::ExtractExtraICStateFromFlags(flags);
1054
  if (kind == Code::CALL_IC) {
1055
    CallIC::GenerateMegamorphic(masm(), argc, extra_state);
1056
  } else {
1057
    KeyedCallIC::GenerateMegamorphic(masm(), argc);
1058
  }
1059
  Handle<Code> code = GetCodeWithFlags(flags, "CompileCallMegamorphic");
1060
  isolate()->counters()->call_megamorphic_stubs()->Increment();
1061
  PROFILE(isolate(),
1062
          CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_MEGAMORPHIC_TAG),
1063
                          *code, code->arguments_count()));
1064
  GDBJIT(AddCode(GDBJITInterface::CALL_MEGAMORPHIC, *code));
1065
  return code;
1066
}
1067

    
1068

    
1069
Handle<Code> StubCompiler::CompileCallArguments(Code::Flags flags) {
1070
  int argc = Code::ExtractArgumentsCountFromFlags(flags);
1071
  KeyedCallIC::GenerateNonStrictArguments(masm(), argc);
1072
  Handle<Code> code = GetCodeWithFlags(flags, "CompileCallArguments");
1073
  PROFILE(isolate(),
1074
          CodeCreateEvent(CALL_LOGGER_TAG(Code::ExtractKindFromFlags(flags),
1075
                                          CALL_MEGAMORPHIC_TAG),
1076
                          *code, code->arguments_count()));
1077
  GDBJIT(AddCode(GDBJITInterface::CALL_MEGAMORPHIC, *code));
1078
  return code;
1079
}
1080

    
1081

    
1082
Handle<Code> StubCompiler::CompileCallMiss(Code::Flags flags) {
1083
  int argc = Code::ExtractArgumentsCountFromFlags(flags);
1084
  Code::Kind kind = Code::ExtractKindFromFlags(flags);
1085
  Code::ExtraICState extra_state = Code::ExtractExtraICStateFromFlags(flags);
1086
  if (kind == Code::CALL_IC) {
1087
    CallIC::GenerateMiss(masm(), argc, extra_state);
1088
  } else {
1089
    KeyedCallIC::GenerateMiss(masm(), argc);
1090
  }
1091
  Handle<Code> code = GetCodeWithFlags(flags, "CompileCallMiss");
1092
  isolate()->counters()->call_megamorphic_stubs()->Increment();
1093
  PROFILE(isolate(),
1094
          CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_MISS_TAG),
1095
                          *code, code->arguments_count()));
1096
  GDBJIT(AddCode(GDBJITInterface::CALL_MISS, *code));
1097
  return code;
1098
}
1099

    
1100

    
1101
#ifdef ENABLE_DEBUGGER_SUPPORT
1102
Handle<Code> StubCompiler::CompileCallDebugBreak(Code::Flags flags) {
1103
  Debug::GenerateCallICDebugBreak(masm());
1104
  Handle<Code> code = GetCodeWithFlags(flags, "CompileCallDebugBreak");
1105
  PROFILE(isolate(),
1106
          CodeCreateEvent(CALL_LOGGER_TAG(Code::ExtractKindFromFlags(flags),
1107
                                          CALL_DEBUG_BREAK_TAG),
1108
                          *code, code->arguments_count()));
1109
  return code;
1110
}
1111

    
1112

    
1113
Handle<Code> StubCompiler::CompileCallDebugPrepareStepIn(Code::Flags flags) {
1114
  // Use the same code for the the step in preparations as we do for the
1115
  // miss case.
1116
  int argc = Code::ExtractArgumentsCountFromFlags(flags);
1117
  Code::Kind kind = Code::ExtractKindFromFlags(flags);
1118
  if (kind == Code::CALL_IC) {
1119
    // For the debugger extra ic state is irrelevant.
1120
    CallIC::GenerateMiss(masm(), argc, Code::kNoExtraICState);
1121
  } else {
1122
    KeyedCallIC::GenerateMiss(masm(), argc);
1123
  }
1124
  Handle<Code> code = GetCodeWithFlags(flags, "CompileCallDebugPrepareStepIn");
1125
  PROFILE(isolate(),
1126
          CodeCreateEvent(
1127
              CALL_LOGGER_TAG(kind, CALL_DEBUG_PREPARE_STEP_IN_TAG),
1128
              *code,
1129
              code->arguments_count()));
1130
  return code;
1131
}
1132
#endif  // ENABLE_DEBUGGER_SUPPORT
1133

    
1134
#undef CALL_LOGGER_TAG
1135

    
1136

    
1137
Handle<Code> StubCompiler::GetCodeWithFlags(Code::Flags flags,
1138
                                            const char* name) {
1139
  // Create code object in the heap.
1140
  CodeDesc desc;
1141
  masm_.GetCode(&desc);
1142
  Handle<Code> code = factory()->NewCode(desc, flags, masm_.CodeObject());
1143
#ifdef ENABLE_DISASSEMBLER
1144
  if (FLAG_print_code_stubs) code->Disassemble(name);
1145
#endif
1146
  return code;
1147
}
1148

    
1149

    
1150
Handle<Code> StubCompiler::GetCodeWithFlags(Code::Flags flags,
1151
                                            Handle<Name> name) {
1152
  return (FLAG_print_code_stubs && !name.is_null() && name->IsString())
1153
      ? GetCodeWithFlags(flags, *Handle<String>::cast(name)->ToCString())
1154
      : GetCodeWithFlags(flags, NULL);
1155
}
1156

    
1157

    
1158
void StubCompiler::LookupPostInterceptor(Handle<JSObject> holder,
1159
                                         Handle<Name> name,
1160
                                         LookupResult* lookup) {
1161
  holder->LocalLookupRealNamedProperty(*name, lookup);
1162
  if (lookup->IsFound()) return;
1163
  if (holder->GetPrototype()->IsNull()) return;
1164
  holder->GetPrototype()->Lookup(*name, lookup);
1165
}
1166

    
1167

    
1168
#define __ ACCESS_MASM(masm())
1169

    
1170

    
1171
Register LoadStubCompiler::HandlerFrontendHeader(
1172
    Handle<JSObject> object,
1173
    Register object_reg,
1174
    Handle<JSObject> holder,
1175
    Handle<Name> name,
1176
    Label* miss) {
1177
  return CheckPrototypes(object, object_reg, holder,
1178
                         scratch1(), scratch2(), scratch3(),
1179
                         name, miss, SKIP_RECEIVER);
1180
}
1181

    
1182

    
1183
// HandlerFrontend for store uses the name register. It has to be restored
1184
// before a miss.
1185
Register StoreStubCompiler::HandlerFrontendHeader(
1186
    Handle<JSObject> object,
1187
    Register object_reg,
1188
    Handle<JSObject> holder,
1189
    Handle<Name> name,
1190
    Label* miss) {
1191
  return CheckPrototypes(object, object_reg, holder,
1192
                         this->name(), scratch1(), scratch2(),
1193
                         name, miss, SKIP_RECEIVER);
1194
}
1195

    
1196

    
1197
Register BaseLoadStoreStubCompiler::HandlerFrontend(Handle<JSObject> object,
1198
                                                    Register object_reg,
1199
                                                    Handle<JSObject> holder,
1200
                                                    Handle<Name> name,
1201
                                                    Label* success) {
1202
  Label miss;
1203

    
1204
  Register reg = HandlerFrontendHeader(object, object_reg, holder, name, &miss);
1205

    
1206
  HandlerFrontendFooter(name, success, &miss);
1207
  return reg;
1208
}
1209

    
1210

    
1211
Handle<Code> LoadStubCompiler::CompileLoadField(
1212
    Handle<JSObject> object,
1213
    Handle<JSObject> holder,
1214
    Handle<Name> name,
1215
    PropertyIndex field,
1216
    Representation representation) {
1217
  Label miss;
1218

    
1219
  Register reg = HandlerFrontendHeader(object, receiver(), holder, name, &miss);
1220

    
1221
  GenerateLoadField(reg, holder, field, representation);
1222

    
1223
  __ bind(&miss);
1224
  TailCallBuiltin(masm(), MissBuiltin(kind()));
1225

    
1226
  // Return the generated code.
1227
  return GetCode(kind(), Code::FIELD, name);
1228
}
1229

    
1230

    
1231
Handle<Code> LoadStubCompiler::CompileLoadConstant(
1232
    Handle<JSObject> object,
1233
    Handle<JSObject> holder,
1234
    Handle<Name> name,
1235
    Handle<Object> value) {
1236
  Label success;
1237
  HandlerFrontend(object, receiver(), holder, name, &success);
1238
  __ bind(&success);
1239
  GenerateLoadConstant(value);
1240

    
1241
  // Return the generated code.
1242
  return GetCode(kind(), Code::CONSTANT, name);
1243
}
1244

    
1245

    
1246
Handle<Code> LoadStubCompiler::CompileLoadCallback(
1247
    Handle<JSObject> object,
1248
    Handle<JSObject> holder,
1249
    Handle<Name> name,
1250
    Handle<ExecutableAccessorInfo> callback) {
1251
  Label success;
1252

    
1253
  Register reg = CallbackHandlerFrontend(
1254
      object, receiver(), holder, name, &success, callback);
1255
  __ bind(&success);
1256
  GenerateLoadCallback(reg, callback);
1257

    
1258
  // Return the generated code.
1259
  return GetCode(kind(), Code::CALLBACKS, name);
1260
}
1261

    
1262

    
1263
Handle<Code> LoadStubCompiler::CompileLoadCallback(
1264
    Handle<JSObject> object,
1265
    Handle<JSObject> holder,
1266
    Handle<Name> name,
1267
    const CallOptimization& call_optimization) {
1268
  ASSERT(call_optimization.is_simple_api_call());
1269
  Label success;
1270

    
1271
  Handle<JSFunction> callback = call_optimization.constant_function();
1272
  CallbackHandlerFrontend(
1273
      object, receiver(), holder, name, &success, callback);
1274
  __ bind(&success);
1275
  GenerateLoadCallback(call_optimization);
1276

    
1277
  // Return the generated code.
1278
  return GetCode(kind(), Code::CALLBACKS, name);
1279
}
1280

    
1281

    
1282
Handle<Code> LoadStubCompiler::CompileLoadInterceptor(
1283
    Handle<JSObject> object,
1284
    Handle<JSObject> holder,
1285
    Handle<Name> name) {
1286
  Label success;
1287

    
1288
  LookupResult lookup(isolate());
1289
  LookupPostInterceptor(holder, name, &lookup);
1290

    
1291
  Register reg = HandlerFrontend(object, receiver(), holder, name, &success);
1292
  __ bind(&success);
1293
  // TODO(368): Compile in the whole chain: all the interceptors in
1294
  // prototypes and ultimate answer.
1295
  GenerateLoadInterceptor(reg, object, holder, &lookup, name);
1296

    
1297
  // Return the generated code.
1298
  return GetCode(kind(), Code::INTERCEPTOR, name);
1299
}
1300

    
1301

    
1302
void LoadStubCompiler::GenerateLoadPostInterceptor(
1303
    Register interceptor_reg,
1304
    Handle<JSObject> interceptor_holder,
1305
    Handle<Name> name,
1306
    LookupResult* lookup) {
1307
  Label success;
1308
  Handle<JSObject> holder(lookup->holder());
1309
  if (lookup->IsField()) {
1310
    PropertyIndex field = lookup->GetFieldIndex();
1311
    if (interceptor_holder.is_identical_to(holder)) {
1312
      GenerateLoadField(
1313
          interceptor_reg, holder, field, lookup->representation());
1314
    } else {
1315
      // We found FIELD property in prototype chain of interceptor's holder.
1316
      // Retrieve a field from field's holder.
1317
      Register reg = HandlerFrontend(
1318
          interceptor_holder, interceptor_reg, holder, name, &success);
1319
      __ bind(&success);
1320
      GenerateLoadField(
1321
          reg, holder, field, lookup->representation());
1322
    }
1323
  } else {
1324
    // We found CALLBACKS property in prototype chain of interceptor's
1325
    // holder.
1326
    ASSERT(lookup->type() == CALLBACKS);
1327
    Handle<ExecutableAccessorInfo> callback(
1328
        ExecutableAccessorInfo::cast(lookup->GetCallbackObject()));
1329
    ASSERT(callback->getter() != NULL);
1330

    
1331
    Register reg = CallbackHandlerFrontend(
1332
        interceptor_holder, interceptor_reg, holder, name, &success, callback);
1333
    __ bind(&success);
1334
    GenerateLoadCallback(reg, callback);
1335
  }
1336
}
1337

    
1338

    
1339
Handle<Code> BaseLoadStoreStubCompiler::CompileMonomorphicIC(
1340
    Handle<Map> receiver_map,
1341
    Handle<Code> handler,
1342
    Handle<Name> name) {
1343
  MapHandleList receiver_maps(1);
1344
  receiver_maps.Add(receiver_map);
1345
  CodeHandleList handlers(1);
1346
  handlers.Add(handler);
1347
  Code::StubType type = handler->type();
1348
  return CompilePolymorphicIC(&receiver_maps, &handlers, name, type, PROPERTY);
1349
}
1350

    
1351

    
1352
Handle<Code> LoadStubCompiler::CompileLoadViaGetter(
1353
    Handle<JSObject> object,
1354
    Handle<JSObject> holder,
1355
    Handle<Name> name,
1356
    Handle<JSFunction> getter) {
1357
  Label success;
1358
  HandlerFrontend(object, receiver(), holder, name, &success);
1359

    
1360
  __ bind(&success);
1361
  GenerateLoadViaGetter(masm(), receiver(), getter);
1362

    
1363
  // Return the generated code.
1364
  return GetCode(kind(), Code::CALLBACKS, name);
1365
}
1366

    
1367

    
1368
Handle<Code> StoreStubCompiler::CompileStoreTransition(
1369
    Handle<JSObject> object,
1370
    LookupResult* lookup,
1371
    Handle<Map> transition,
1372
    Handle<Name> name) {
1373
  Label miss, slow;
1374

    
1375
  // Ensure no transitions to deprecated maps are followed.
1376
  __ CheckMapDeprecated(transition, scratch1(), &miss);
1377

    
1378
  // Check that we are allowed to write this.
1379
  if (object->GetPrototype()->IsJSObject()) {
1380
    Handle<JSObject> holder;
1381
    // holder == object indicates that no property was found.
1382
    if (lookup->holder() != *object) {
1383
      holder = Handle<JSObject>(lookup->holder());
1384
    } else {
1385
      // Find the top object.
1386
      holder = object;
1387
      do {
1388
        holder = Handle<JSObject>(JSObject::cast(holder->GetPrototype()));
1389
      } while (holder->GetPrototype()->IsJSObject());
1390
    }
1391

    
1392
    Register holder_reg =
1393
        HandlerFrontendHeader(object, receiver(), holder, name, &miss);
1394

    
1395
    // If no property was found, and the holder (the last object in the
1396
    // prototype chain) is in slow mode, we need to do a negative lookup on the
1397
    // holder.
1398
    if (lookup->holder() == *object) {
1399
      GenerateNegativeHolderLookup(masm(), holder, holder_reg, name, &miss);
1400
    }
1401
  }
1402

    
1403
  GenerateStoreTransition(masm(),
1404
                          object,
1405
                          lookup,
1406
                          transition,
1407
                          name,
1408
                          receiver(), this->name(), value(),
1409
                          scratch1(), scratch2(), scratch3(),
1410
                          &miss,
1411
                          &slow);
1412

    
1413
  // Handle store cache miss.
1414
  GenerateRestoreName(masm(), &miss, name);
1415
  TailCallBuiltin(masm(), MissBuiltin(kind()));
1416

    
1417
  GenerateRestoreName(masm(), &slow, name);
1418
  TailCallBuiltin(masm(), SlowBuiltin(kind()));
1419

    
1420
  // Return the generated code.
1421
  return GetCode(kind(), Code::TRANSITION, name);
1422
}
1423

    
1424

    
1425
Handle<Code> StoreStubCompiler::CompileStoreField(Handle<JSObject> object,
1426
                                                  LookupResult* lookup,
1427
                                                  Handle<Name> name) {
1428
  Label miss;
1429

    
1430
  HandlerFrontendHeader(object, receiver(), object, name, &miss);
1431

    
1432
  // Generate store field code.
1433
  GenerateStoreField(masm(),
1434
                     object,
1435
                     lookup,
1436
                     receiver(), this->name(), value(), scratch1(), scratch2(),
1437
                     &miss);
1438

    
1439
  // Handle store cache miss.
1440
  __ bind(&miss);
1441
  TailCallBuiltin(masm(), MissBuiltin(kind()));
1442

    
1443
  // Return the generated code.
1444
  return GetCode(kind(), Code::FIELD, name);
1445
}
1446

    
1447

    
1448
Handle<Code> StoreStubCompiler::CompileStoreViaSetter(
1449
    Handle<JSObject> object,
1450
    Handle<JSObject> holder,
1451
    Handle<Name> name,
1452
    Handle<JSFunction> setter) {
1453
  Label success;
1454
  HandlerFrontend(object, receiver(), holder, name, &success);
1455

    
1456
  __ bind(&success);
1457
  GenerateStoreViaSetter(masm(), setter);
1458

    
1459
  return GetCode(kind(), Code::CALLBACKS, name);
1460
}
1461

    
1462

    
1463
Handle<Code> KeyedLoadStubCompiler::CompileLoadElement(
1464
    Handle<Map> receiver_map) {
1465
  ElementsKind elements_kind = receiver_map->elements_kind();
1466
  if (receiver_map->has_fast_elements() ||
1467
      receiver_map->has_external_array_elements()) {
1468
    Handle<Code> stub = KeyedLoadFastElementStub(
1469
        receiver_map->instance_type() == JS_ARRAY_TYPE,
1470
        elements_kind).GetCode(isolate());
1471
    __ DispatchMap(receiver(), scratch1(), receiver_map, stub, DO_SMI_CHECK);
1472
  } else {
1473
    Handle<Code> stub =
1474
        KeyedLoadDictionaryElementStub().GetCode(isolate());
1475
    __ DispatchMap(receiver(), scratch1(), receiver_map, stub, DO_SMI_CHECK);
1476
  }
1477

    
1478
  TailCallBuiltin(masm(), Builtins::kKeyedLoadIC_Miss);
1479

    
1480
  // Return the generated code.
1481
  return GetICCode(kind(), Code::NORMAL, factory()->empty_string());
1482
}
1483

    
1484

    
1485
Handle<Code> KeyedStoreStubCompiler::CompileStoreElement(
1486
    Handle<Map> receiver_map) {
1487
  ElementsKind elements_kind = receiver_map->elements_kind();
1488
  bool is_jsarray = receiver_map->instance_type() == JS_ARRAY_TYPE;
1489
  Handle<Code> stub;
1490
  if (receiver_map->has_fast_elements() ||
1491
      receiver_map->has_external_array_elements()) {
1492
    stub = KeyedStoreFastElementStub(
1493
        is_jsarray,
1494
        elements_kind,
1495
        store_mode_).GetCode(isolate());
1496
  } else {
1497
    stub = KeyedStoreElementStub(is_jsarray,
1498
                                 elements_kind,
1499
                                 store_mode_).GetCode(isolate());
1500
  }
1501

    
1502
  __ DispatchMap(receiver(), scratch1(), receiver_map, stub, DO_SMI_CHECK);
1503

    
1504
  TailCallBuiltin(masm(), Builtins::kKeyedStoreIC_Miss);
1505

    
1506
  // Return the generated code.
1507
  return GetICCode(kind(), Code::NORMAL, factory()->empty_string());
1508
}
1509

    
1510

    
1511
#undef __
1512

    
1513

    
1514
void StubCompiler::TailCallBuiltin(MacroAssembler* masm, Builtins::Name name) {
1515
  Handle<Code> code(masm->isolate()->builtins()->builtin(name));
1516
  GenerateTailCall(masm, code);
1517
}
1518

    
1519

    
1520
void BaseLoadStoreStubCompiler::JitEvent(Handle<Name> name, Handle<Code> code) {
1521
#ifdef ENABLE_GDB_JIT_INTERFACE
1522
  GDBJITInterface::CodeTag tag;
1523
  if (kind_ == Code::LOAD_IC) {
1524
    tag = GDBJITInterface::LOAD_IC;
1525
  } else if (kind_ == Code::KEYED_LOAD_IC) {
1526
    tag = GDBJITInterface::KEYED_LOAD_IC;
1527
  } else if (kind_ == Code::STORE_IC) {
1528
    tag = GDBJITInterface::STORE_IC;
1529
  } else {
1530
    tag = GDBJITInterface::KEYED_STORE_IC;
1531
  }
1532
  GDBJIT(AddCode(tag, *name, *code));
1533
#endif
1534
}
1535

    
1536

    
1537
void BaseLoadStoreStubCompiler::InitializeRegisters() {
1538
  if (kind_ == Code::LOAD_IC) {
1539
    registers_ = LoadStubCompiler::registers();
1540
  } else if (kind_ == Code::KEYED_LOAD_IC) {
1541
    registers_ = KeyedLoadStubCompiler::registers();
1542
  } else if (kind_ == Code::STORE_IC) {
1543
    registers_ = StoreStubCompiler::registers();
1544
  } else {
1545
    registers_ = KeyedStoreStubCompiler::registers();
1546
  }
1547
}
1548

    
1549

    
1550
Handle<Code> BaseLoadStoreStubCompiler::GetICCode(Code::Kind kind,
1551
                                                  Code::StubType type,
1552
                                                  Handle<Name> name,
1553
                                                  InlineCacheState state) {
1554
  Code::Flags flags = Code::ComputeFlags(kind, state, extra_state(), type);
1555
  Handle<Code> code = GetCodeWithFlags(flags, name);
1556
  PROFILE(isolate(), CodeCreateEvent(log_kind(code), *code, *name));
1557
  JitEvent(name, code);
1558
  return code;
1559
}
1560

    
1561

    
1562
Handle<Code> BaseLoadStoreStubCompiler::GetCode(Code::Kind kind,
1563
                                                Code::StubType type,
1564
                                                Handle<Name> name) {
1565
  ASSERT(type != Code::NORMAL);
1566
  Code::Flags flags = Code::ComputeFlags(
1567
      Code::HANDLER, MONOMORPHIC, extra_state(), type, kind);
1568
  Handle<Code> code = GetCodeWithFlags(flags, name);
1569
  PROFILE(isolate(), CodeCreateEvent(log_kind(code), *code, *name));
1570
  JitEvent(name, code);
1571
  return code;
1572
}
1573

    
1574

    
1575
void KeyedLoadStubCompiler::CompileElementHandlers(MapHandleList* receiver_maps,
1576
                                                   CodeHandleList* handlers) {
1577
  for (int i = 0; i < receiver_maps->length(); ++i) {
1578
    Handle<Map> receiver_map = receiver_maps->at(i);
1579
    Handle<Code> cached_stub;
1580

    
1581
    if ((receiver_map->instance_type() & kNotStringTag) == 0) {
1582
      cached_stub = isolate()->builtins()->KeyedLoadIC_String();
1583
    } else {
1584
      bool is_js_array = receiver_map->instance_type() == JS_ARRAY_TYPE;
1585
      ElementsKind elements_kind = receiver_map->elements_kind();
1586

    
1587
      if (IsFastElementsKind(elements_kind) ||
1588
          IsExternalArrayElementsKind(elements_kind)) {
1589
        cached_stub =
1590
            KeyedLoadFastElementStub(is_js_array,
1591
                                     elements_kind).GetCode(isolate());
1592
      } else {
1593
        ASSERT(elements_kind == DICTIONARY_ELEMENTS);
1594
        cached_stub = KeyedLoadDictionaryElementStub().GetCode(isolate());
1595
      }
1596
    }
1597

    
1598
    handlers->Add(cached_stub);
1599
  }
1600
}
1601

    
1602

    
1603
Handle<Code> KeyedStoreStubCompiler::CompileStoreElementPolymorphic(
1604
    MapHandleList* receiver_maps) {
1605
  // Collect MONOMORPHIC stubs for all |receiver_maps|.
1606
  CodeHandleList handlers(receiver_maps->length());
1607
  MapHandleList transitioned_maps(receiver_maps->length());
1608
  for (int i = 0; i < receiver_maps->length(); ++i) {
1609
    Handle<Map> receiver_map(receiver_maps->at(i));
1610
    Handle<Code> cached_stub;
1611
    Handle<Map> transitioned_map =
1612
        receiver_map->FindTransitionedMap(receiver_maps);
1613

    
1614
    // TODO(mvstanton): The code below is doing pessimistic elements
1615
    // transitions. I would like to stop doing that and rely on Allocation Site
1616
    // Tracking to do a better job of ensuring the data types are what they need
1617
    // to be. Not all the elements are in place yet, pessimistic elements
1618
    // transitions are still important for performance.
1619
    bool is_js_array = receiver_map->instance_type() == JS_ARRAY_TYPE;
1620
    ElementsKind elements_kind = receiver_map->elements_kind();
1621
    if (!transitioned_map.is_null()) {
1622
      cached_stub = ElementsTransitionAndStoreStub(
1623
          elements_kind,
1624
          transitioned_map->elements_kind(),
1625
          is_js_array,
1626
          store_mode_).GetCode(isolate());
1627
    } else {
1628
      if (receiver_map->has_fast_elements() ||
1629
          receiver_map->has_external_array_elements()) {
1630
        cached_stub = KeyedStoreFastElementStub(
1631
            is_js_array,
1632
            elements_kind,
1633
            store_mode_).GetCode(isolate());
1634
      } else {
1635
        cached_stub = KeyedStoreElementStub(
1636
            is_js_array,
1637
            elements_kind,
1638
            store_mode_).GetCode(isolate());
1639
      }
1640
    }
1641
    ASSERT(!cached_stub.is_null());
1642
    handlers.Add(cached_stub);
1643
    transitioned_maps.Add(transitioned_map);
1644
  }
1645
  Handle<Code> code =
1646
      CompileStorePolymorphic(receiver_maps, &handlers, &transitioned_maps);
1647
  isolate()->counters()->keyed_store_polymorphic_stubs()->Increment();
1648
  PROFILE(isolate(),
1649
          CodeCreateEvent(Logger::KEYED_STORE_POLYMORPHIC_IC_TAG, *code, 0));
1650
  return code;
1651
}
1652

    
1653

    
1654
void KeyedStoreStubCompiler::GenerateStoreDictionaryElement(
1655
    MacroAssembler* masm) {
1656
  KeyedStoreIC::GenerateSlow(masm);
1657
}
1658

    
1659

    
1660
CallStubCompiler::CallStubCompiler(Isolate* isolate,
1661
                                   int argc,
1662
                                   Code::Kind kind,
1663
                                   Code::ExtraICState extra_state,
1664
                                   InlineCacheHolderFlag cache_holder)
1665
    : StubCompiler(isolate),
1666
      arguments_(argc),
1667
      kind_(kind),
1668
      extra_state_(extra_state),
1669
      cache_holder_(cache_holder) {
1670
}
1671

    
1672

    
1673
bool CallStubCompiler::HasCustomCallGenerator(Handle<JSFunction> function) {
1674
  if (function->shared()->HasBuiltinFunctionId()) {
1675
    BuiltinFunctionId id = function->shared()->builtin_function_id();
1676
#define CALL_GENERATOR_CASE(name) if (id == k##name) return true;
1677
    CUSTOM_CALL_IC_GENERATORS(CALL_GENERATOR_CASE)
1678
#undef CALL_GENERATOR_CASE
1679
  }
1680

    
1681
  CallOptimization optimization(function);
1682
  return optimization.is_simple_api_call();
1683
}
1684

    
1685

    
1686
bool CallStubCompiler::CanBeCached(Handle<JSFunction> function) {
1687
  if (function->shared()->HasBuiltinFunctionId()) {
1688
    BuiltinFunctionId id = function->shared()->builtin_function_id();
1689
#define CALL_GENERATOR_CASE(name) if (id == k##name) return false;
1690
    SITE_SPECIFIC_CALL_GENERATORS(CALL_GENERATOR_CASE)
1691
#undef CALL_GENERATOR_CASE
1692
  }
1693

    
1694
  return true;
1695
}
1696

    
1697

    
1698
Handle<Code> CallStubCompiler::CompileCustomCall(
1699
    Handle<Object> object,
1700
    Handle<JSObject> holder,
1701
    Handle<Cell> cell,
1702
    Handle<JSFunction> function,
1703
    Handle<String> fname,
1704
    Code::StubType type) {
1705
  ASSERT(HasCustomCallGenerator(function));
1706

    
1707
  if (function->shared()->HasBuiltinFunctionId()) {
1708
    BuiltinFunctionId id = function->shared()->builtin_function_id();
1709
#define CALL_GENERATOR_CASE(name)                               \
1710
    if (id == k##name) {                                        \
1711
      return CallStubCompiler::Compile##name##Call(object,      \
1712
                                                   holder,      \
1713
                                                   cell,        \
1714
                                                   function,    \
1715
                                                   fname,       \
1716
                                                   type);       \
1717
    }
1718
    CUSTOM_CALL_IC_GENERATORS(CALL_GENERATOR_CASE)
1719
#undef CALL_GENERATOR_CASE
1720
  }
1721
  CallOptimization optimization(function);
1722
  ASSERT(optimization.is_simple_api_call());
1723
  return CompileFastApiCall(optimization,
1724
                            object,
1725
                            holder,
1726
                            cell,
1727
                            function,
1728
                            fname);
1729
}
1730

    
1731

    
1732
Handle<Code> CallStubCompiler::GetCode(Code::StubType type,
1733
                                       Handle<Name> name) {
1734
  int argc = arguments_.immediate();
1735
  Code::Flags flags = Code::ComputeMonomorphicFlags(kind_,
1736
                                                    extra_state_,
1737
                                                    type,
1738
                                                    argc,
1739
                                                    cache_holder_);
1740
  return GetCodeWithFlags(flags, name);
1741
}
1742

    
1743

    
1744
Handle<Code> CallStubCompiler::GetCode(Handle<JSFunction> function) {
1745
  Handle<String> function_name;
1746
  if (function->shared()->name()->IsString()) {
1747
    function_name = Handle<String>(String::cast(function->shared()->name()));
1748
  }
1749
  return GetCode(Code::CONSTANT, function_name);
1750
}
1751

    
1752

    
1753
CallOptimization::CallOptimization(LookupResult* lookup) {
1754
  if (lookup->IsFound() &&
1755
      lookup->IsCacheable() &&
1756
      lookup->IsConstantFunction()) {
1757
    // We only optimize constant function calls.
1758
    Initialize(Handle<JSFunction>(lookup->GetConstantFunction()));
1759
  } else {
1760
    Initialize(Handle<JSFunction>::null());
1761
  }
1762
}
1763

    
1764

    
1765
CallOptimization::CallOptimization(Handle<JSFunction> function) {
1766
  Initialize(function);
1767
}
1768

    
1769

    
1770
int CallOptimization::GetPrototypeDepthOfExpectedType(
1771
    Handle<JSObject> object,
1772
    Handle<JSObject> holder) const {
1773
  ASSERT(is_simple_api_call());
1774
  if (expected_receiver_type_.is_null()) return 0;
1775
  int depth = 0;
1776
  while (!object.is_identical_to(holder)) {
1777
    if (object->IsInstanceOf(*expected_receiver_type_)) return depth;
1778
    object = Handle<JSObject>(JSObject::cast(object->GetPrototype()));
1779
    if (!object->map()->is_hidden_prototype()) return kInvalidProtoDepth;
1780
    ++depth;
1781
  }
1782
  if (holder->IsInstanceOf(*expected_receiver_type_)) return depth;
1783
  return kInvalidProtoDepth;
1784
}
1785

    
1786

    
1787
void CallOptimization::Initialize(Handle<JSFunction> function) {
1788
  constant_function_ = Handle<JSFunction>::null();
1789
  is_simple_api_call_ = false;
1790
  expected_receiver_type_ = Handle<FunctionTemplateInfo>::null();
1791
  api_call_info_ = Handle<CallHandlerInfo>::null();
1792

    
1793
  if (function.is_null() || !function->is_compiled()) return;
1794

    
1795
  constant_function_ = function;
1796
  AnalyzePossibleApiFunction(function);
1797
}
1798

    
1799

    
1800
void CallOptimization::AnalyzePossibleApiFunction(Handle<JSFunction> function) {
1801
  if (!function->shared()->IsApiFunction()) return;
1802
  Handle<FunctionTemplateInfo> info(function->shared()->get_api_func_data());
1803

    
1804
  // Require a C++ callback.
1805
  if (info->call_code()->IsUndefined()) return;
1806
  api_call_info_ =
1807
      Handle<CallHandlerInfo>(CallHandlerInfo::cast(info->call_code()));
1808

    
1809
  // Accept signatures that either have no restrictions at all or
1810
  // only have restrictions on the receiver.
1811
  if (!info->signature()->IsUndefined()) {
1812
    Handle<SignatureInfo> signature =
1813
        Handle<SignatureInfo>(SignatureInfo::cast(info->signature()));
1814
    if (!signature->args()->IsUndefined()) return;
1815
    if (!signature->receiver()->IsUndefined()) {
1816
      expected_receiver_type_ =
1817
          Handle<FunctionTemplateInfo>(
1818
              FunctionTemplateInfo::cast(signature->receiver()));
1819
    }
1820
  }
1821

    
1822
  is_simple_api_call_ = true;
1823
}
1824

    
1825

    
1826
} }  // namespace v8::internal