1// Copyright 2006-2009 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 "gdb-jit.h"
33#include "ic-inl.h"
34#include "stub-cache.h"
35#include "vm-state-inl.h"
36
37namespace v8 {
38namespace internal {
39
40// -----------------------------------------------------------------------
41// StubCache implementation.
42
43
44StubCache::StubCache(Isolate* isolate) : isolate_(isolate) {
45  ASSERT(isolate == Isolate::Current());
46  memset(primary_, 0, sizeof(primary_[0]) * StubCache::kPrimaryTableSize);
47  memset(secondary_, 0, sizeof(secondary_[0]) * StubCache::kSecondaryTableSize);
48}
49
50
51void StubCache::Initialize(bool create_heap_objects) {
52  ASSERT(IsPowerOf2(kPrimaryTableSize));
53  ASSERT(IsPowerOf2(kSecondaryTableSize));
54  if (create_heap_objects) {
55    HandleScope scope;
56    Clear();
57  }
58}
59
60
61Code* StubCache::Set(String* name, Map* map, Code* code) {
62  // Get the flags from the code.
63  Code::Flags flags = Code::RemoveTypeFromFlags(code->flags());
64
65  // Validate that the name does not move on scavenge, and that we
66  // can use identity checks instead of string equality checks.
67  ASSERT(!heap()->InNewSpace(name));
68  ASSERT(name->IsSymbol());
69
70  // The state bits are not important to the hash function because
71  // the stub cache only contains monomorphic stubs. Make sure that
72  // the bits are the least significant so they will be the ones
73  // masked out.
74  ASSERT(Code::ExtractICStateFromFlags(flags) == MONOMORPHIC);
75  ASSERT(Code::kFlagsICStateShift == 0);
76
77  // Make sure that the code type is not included in the hash.
78  ASSERT(Code::ExtractTypeFromFlags(flags) == 0);
79
80  // Compute the primary entry.
81  int primary_offset = PrimaryOffset(name, flags, map);
82  Entry* primary = entry(primary_, primary_offset);
83  Code* hit = primary->value;
84
85  // If the primary entry has useful data in it, we retire it to the
86  // secondary cache before overwriting it.
87  if (hit != isolate_->builtins()->builtin(Builtins::kIllegal)) {
88    Code::Flags primary_flags = Code::RemoveTypeFromFlags(hit->flags());
89    int secondary_offset =
90        SecondaryOffset(primary->key, primary_flags, primary_offset);
91    Entry* secondary = entry(secondary_, secondary_offset);
92    *secondary = *primary;
93  }
94
95  // Update primary cache.
96  primary->key = name;
97  primary->value = code;
98  return code;
99}
100
101
102MaybeObject* StubCache::ComputeLoadNonexistent(String* name,
103                                               JSObject* receiver) {
104  ASSERT(receiver->IsGlobalObject() || receiver->HasFastProperties());
105  // If no global objects are present in the prototype chain, the load
106  // nonexistent IC stub can be shared for all names for a given map
107  // and we use the empty string for the map cache in that case.  If
108  // there are global objects involved, we need to check global
109  // property cells in the stub and therefore the stub will be
110  // specific to the name.
111  String* cache_name = heap()->empty_string();
112  if (receiver->IsGlobalObject()) cache_name = name;
113  JSObject* last = receiver;
114  while (last->GetPrototype() != heap()->null_value()) {
115    last = JSObject::cast(last->GetPrototype());
116    if (last->IsGlobalObject()) cache_name = name;
117  }
118  // Compile the stub that is either shared for all names or
119  // name specific if there are global objects involved.
120  Code::Flags flags =
121      Code::ComputeMonomorphicFlags(Code::LOAD_IC, NONEXISTENT);
122  Object* code = receiver->map()->FindInCodeCache(cache_name, flags);
123  if (code->IsUndefined()) {
124    LoadStubCompiler compiler;
125    { MaybeObject* maybe_code =
126          compiler.CompileLoadNonexistent(cache_name, receiver, last);
127      if (!maybe_code->ToObject(&code)) return maybe_code;
128    }
129    PROFILE(isolate_,
130            CodeCreateEvent(Logger::LOAD_IC_TAG, Code::cast(code), cache_name));
131    GDBJIT(AddCode(GDBJITInterface::LOAD_IC, cache_name, Code::cast(code)));
132    Object* result;
133    { MaybeObject* maybe_result =
134          receiver->UpdateMapCodeCache(cache_name, Code::cast(code));
135      if (!maybe_result->ToObject(&result)) return maybe_result;
136    }
137  }
138  return code;
139}
140
141
142MaybeObject* StubCache::ComputeLoadField(String* name,
143                                         JSObject* receiver,
144                                         JSObject* holder,
145                                         int field_index) {
146  ASSERT(IC::GetCodeCacheForObject(receiver, holder) == OWN_MAP);
147  Code::Flags flags = Code::ComputeMonomorphicFlags(Code::LOAD_IC, FIELD);
148  Object* code = receiver->map()->FindInCodeCache(name, flags);
149  if (code->IsUndefined()) {
150    LoadStubCompiler compiler;
151    { MaybeObject* maybe_code =
152          compiler.CompileLoadField(receiver, holder, field_index, name);
153      if (!maybe_code->ToObject(&code)) return maybe_code;
154    }
155    PROFILE(isolate_,
156            CodeCreateEvent(Logger::LOAD_IC_TAG, Code::cast(code), name));
157    GDBJIT(AddCode(GDBJITInterface::LOAD_IC, name, Code::cast(code)));
158    Object* result;
159    { MaybeObject* maybe_result =
160          receiver->UpdateMapCodeCache(name, Code::cast(code));
161      if (!maybe_result->ToObject(&result)) return maybe_result;
162    }
163  }
164  return code;
165}
166
167
168MaybeObject* StubCache::ComputeLoadCallback(String* name,
169                                            JSObject* receiver,
170                                            JSObject* holder,
171                                            AccessorInfo* callback) {
172  ASSERT(v8::ToCData<Address>(callback->getter()) != 0);
173  ASSERT(IC::GetCodeCacheForObject(receiver, holder) == OWN_MAP);
174  Code::Flags flags = Code::ComputeMonomorphicFlags(Code::LOAD_IC, CALLBACKS);
175  Object* code = receiver->map()->FindInCodeCache(name, flags);
176  if (code->IsUndefined()) {
177    LoadStubCompiler compiler;
178    { MaybeObject* maybe_code =
179          compiler.CompileLoadCallback(name, receiver, holder, callback);
180      if (!maybe_code->ToObject(&code)) return maybe_code;
181    }
182    PROFILE(isolate_,
183            CodeCreateEvent(Logger::LOAD_IC_TAG, Code::cast(code), name));
184    GDBJIT(AddCode(GDBJITInterface::LOAD_IC, name, Code::cast(code)));
185    Object* result;
186    { MaybeObject* maybe_result =
187          receiver->UpdateMapCodeCache(name, Code::cast(code));
188      if (!maybe_result->ToObject(&result)) return maybe_result;
189    }
190  }
191  return code;
192}
193
194
195MaybeObject* StubCache::ComputeLoadConstant(String* name,
196                                            JSObject* receiver,
197                                            JSObject* holder,
198                                            Object* value) {
199  ASSERT(IC::GetCodeCacheForObject(receiver, holder) == OWN_MAP);
200  Code::Flags flags =
201      Code::ComputeMonomorphicFlags(Code::LOAD_IC, CONSTANT_FUNCTION);
202  Object* code = receiver->map()->FindInCodeCache(name, flags);
203  if (code->IsUndefined()) {
204    LoadStubCompiler compiler;
205    { MaybeObject* maybe_code =
206          compiler.CompileLoadConstant(receiver, holder, value, name);
207      if (!maybe_code->ToObject(&code)) return maybe_code;
208    }
209    PROFILE(isolate_,
210            CodeCreateEvent(Logger::LOAD_IC_TAG, Code::cast(code), name));
211    GDBJIT(AddCode(GDBJITInterface::LOAD_IC, name, Code::cast(code)));
212    Object* result;
213    { MaybeObject* maybe_result =
214          receiver->UpdateMapCodeCache(name, Code::cast(code));
215      if (!maybe_result->ToObject(&result)) return maybe_result;
216    }
217  }
218  return code;
219}
220
221
222MaybeObject* StubCache::ComputeLoadInterceptor(String* name,
223                                               JSObject* receiver,
224                                               JSObject* holder) {
225  ASSERT(IC::GetCodeCacheForObject(receiver, holder) == OWN_MAP);
226  Code::Flags flags = Code::ComputeMonomorphicFlags(Code::LOAD_IC, INTERCEPTOR);
227  Object* code = receiver->map()->FindInCodeCache(name, flags);
228  if (code->IsUndefined()) {
229    LoadStubCompiler compiler;
230    { MaybeObject* maybe_code =
231          compiler.CompileLoadInterceptor(receiver, holder, name);
232      if (!maybe_code->ToObject(&code)) return maybe_code;
233    }
234    PROFILE(isolate_,
235            CodeCreateEvent(Logger::LOAD_IC_TAG, Code::cast(code), name));
236    GDBJIT(AddCode(GDBJITInterface::LOAD_IC, name, Code::cast(code)));
237    Object* result;
238    { MaybeObject* maybe_result =
239          receiver->UpdateMapCodeCache(name, Code::cast(code));
240      if (!maybe_result->ToObject(&result)) return maybe_result;
241    }
242  }
243  return code;
244}
245
246
247MaybeObject* StubCache::ComputeLoadNormal() {
248  return isolate_->builtins()->builtin(Builtins::kLoadIC_Normal);
249}
250
251
252MaybeObject* StubCache::ComputeLoadGlobal(String* name,
253                                          JSObject* receiver,
254                                          GlobalObject* holder,
255                                          JSGlobalPropertyCell* cell,
256                                          bool is_dont_delete) {
257  ASSERT(IC::GetCodeCacheForObject(receiver, holder) == OWN_MAP);
258  Code::Flags flags = Code::ComputeMonomorphicFlags(Code::LOAD_IC, NORMAL);
259  Object* code = receiver->map()->FindInCodeCache(name, flags);
260  if (code->IsUndefined()) {
261    LoadStubCompiler compiler;
262    { MaybeObject* maybe_code = compiler.CompileLoadGlobal(receiver,
263                                                           holder,
264                                                           cell,
265                                                           name,
266                                                           is_dont_delete);
267      if (!maybe_code->ToObject(&code)) return maybe_code;
268    }
269    PROFILE(isolate_,
270            CodeCreateEvent(Logger::LOAD_IC_TAG, Code::cast(code), name));
271    GDBJIT(AddCode(GDBJITInterface::LOAD_IC, name, Code::cast(code)));
272    Object* result;
273    { MaybeObject* maybe_result =
274          receiver->UpdateMapCodeCache(name, Code::cast(code));
275      if (!maybe_result->ToObject(&result)) return maybe_result;
276    }
277  }
278  return code;
279}
280
281
282MaybeObject* StubCache::ComputeKeyedLoadField(String* name,
283                                              JSObject* receiver,
284                                              JSObject* holder,
285                                              int field_index) {
286  ASSERT(IC::GetCodeCacheForObject(receiver, holder) == OWN_MAP);
287  Code::Flags flags = Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, FIELD);
288  Object* code = receiver->map()->FindInCodeCache(name, flags);
289  if (code->IsUndefined()) {
290    KeyedLoadStubCompiler compiler;
291    { MaybeObject* maybe_code =
292          compiler.CompileLoadField(name, receiver, holder, field_index);
293      if (!maybe_code->ToObject(&code)) return maybe_code;
294    }
295    PROFILE(isolate_,
296            CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, Code::cast(code), name));
297    GDBJIT(AddCode(GDBJITInterface::KEYED_LOAD_IC, name, Code::cast(code)));
298    Object* result;
299    { MaybeObject* maybe_result =
300          receiver->UpdateMapCodeCache(name, Code::cast(code));
301      if (!maybe_result->ToObject(&result)) return maybe_result;
302    }
303  }
304  return code;
305}
306
307
308MaybeObject* StubCache::ComputeKeyedLoadConstant(String* name,
309                                                 JSObject* receiver,
310                                                 JSObject* holder,
311                                                 Object* value) {
312  ASSERT(IC::GetCodeCacheForObject(receiver, holder) == OWN_MAP);
313  Code::Flags flags =
314      Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, CONSTANT_FUNCTION);
315  Object* code = receiver->map()->FindInCodeCache(name, flags);
316  if (code->IsUndefined()) {
317    KeyedLoadStubCompiler compiler;
318    { MaybeObject* maybe_code =
319          compiler.CompileLoadConstant(name, receiver, holder, value);
320      if (!maybe_code->ToObject(&code)) return maybe_code;
321    }
322    PROFILE(isolate_,
323            CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, Code::cast(code), name));
324    GDBJIT(AddCode(GDBJITInterface::KEYED_LOAD_IC, name, Code::cast(code)));
325    Object* result;
326    { MaybeObject* maybe_result =
327          receiver->UpdateMapCodeCache(name, Code::cast(code));
328      if (!maybe_result->ToObject(&result)) return maybe_result;
329    }
330  }
331  return code;
332}
333
334
335MaybeObject* StubCache::ComputeKeyedLoadInterceptor(String* name,
336                                                    JSObject* receiver,
337                                                    JSObject* holder) {
338  ASSERT(IC::GetCodeCacheForObject(receiver, holder) == OWN_MAP);
339  Code::Flags flags =
340      Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, INTERCEPTOR);
341  Object* code = receiver->map()->FindInCodeCache(name, flags);
342  if (code->IsUndefined()) {
343    KeyedLoadStubCompiler compiler;
344    { MaybeObject* maybe_code =
345          compiler.CompileLoadInterceptor(receiver, holder, name);
346      if (!maybe_code->ToObject(&code)) return maybe_code;
347    }
348    PROFILE(isolate_,
349            CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, Code::cast(code), name));
350    GDBJIT(AddCode(GDBJITInterface::KEYED_LOAD_IC, name, Code::cast(code)));
351    Object* result;
352    { MaybeObject* maybe_result =
353          receiver->UpdateMapCodeCache(name, Code::cast(code));
354      if (!maybe_result->ToObject(&result)) return maybe_result;
355    }
356  }
357  return code;
358}
359
360
361MaybeObject* StubCache::ComputeKeyedLoadCallback(String* name,
362                                                 JSObject* receiver,
363                                                 JSObject* holder,
364                                                 AccessorInfo* callback) {
365  ASSERT(IC::GetCodeCacheForObject(receiver, holder) == OWN_MAP);
366  Code::Flags flags =
367      Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, CALLBACKS);
368  Object* code = receiver->map()->FindInCodeCache(name, flags);
369  if (code->IsUndefined()) {
370    KeyedLoadStubCompiler compiler;
371    { MaybeObject* maybe_code =
372          compiler.CompileLoadCallback(name, receiver, holder, callback);
373      if (!maybe_code->ToObject(&code)) return maybe_code;
374    }
375    PROFILE(isolate_,
376            CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, Code::cast(code), name));
377    GDBJIT(AddCode(GDBJITInterface::KEYED_LOAD_IC, name, Code::cast(code)));
378    Object* result;
379    { MaybeObject* maybe_result =
380          receiver->UpdateMapCodeCache(name, Code::cast(code));
381      if (!maybe_result->ToObject(&result)) return maybe_result;
382    }
383  }
384  return code;
385}
386
387
388
389MaybeObject* StubCache::ComputeKeyedLoadArrayLength(String* name,
390                                                    JSArray* receiver) {
391  Code::Flags flags =
392      Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, CALLBACKS);
393  ASSERT(receiver->IsJSObject());
394  Object* code = receiver->map()->FindInCodeCache(name, flags);
395  if (code->IsUndefined()) {
396    KeyedLoadStubCompiler compiler;
397    { MaybeObject* maybe_code = compiler.CompileLoadArrayLength(name);
398      if (!maybe_code->ToObject(&code)) return maybe_code;
399    }
400    PROFILE(isolate_,
401            CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, Code::cast(code), name));
402    GDBJIT(AddCode(GDBJITInterface::KEYED_LOAD_IC, name, Code::cast(code)));
403    Object* result;
404    { MaybeObject* maybe_result =
405          receiver->UpdateMapCodeCache(name, Code::cast(code));
406      if (!maybe_result->ToObject(&result)) return maybe_result;
407    }
408  }
409  return code;
410}
411
412
413MaybeObject* StubCache::ComputeKeyedLoadStringLength(String* name,
414                                                     String* receiver) {
415  Code::Flags flags =
416      Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, CALLBACKS);
417  Map* map = receiver->map();
418  Object* code = map->FindInCodeCache(name, flags);
419  if (code->IsUndefined()) {
420    KeyedLoadStubCompiler compiler;
421    { MaybeObject* maybe_code = compiler.CompileLoadStringLength(name);
422      if (!maybe_code->ToObject(&code)) return maybe_code;
423    }
424    PROFILE(isolate_,
425            CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, Code::cast(code), name));
426    GDBJIT(AddCode(GDBJITInterface::KEYED_LOAD_IC, name, Code::cast(code)));
427    Object* result;
428    { MaybeObject* maybe_result = map->UpdateCodeCache(name, Code::cast(code));
429      if (!maybe_result->ToObject(&result)) return maybe_result;
430    }
431  }
432  return code;
433}
434
435
436MaybeObject* StubCache::ComputeKeyedLoadFunctionPrototype(
437    String* name,
438    JSFunction* receiver) {
439  Code::Flags flags =
440      Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, CALLBACKS);
441  Object* code = receiver->map()->FindInCodeCache(name, flags);
442  if (code->IsUndefined()) {
443    KeyedLoadStubCompiler compiler;
444    { MaybeObject* maybe_code = compiler.CompileLoadFunctionPrototype(name);
445      if (!maybe_code->ToObject(&code)) return maybe_code;
446    }
447    PROFILE(isolate_,
448            CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, Code::cast(code), name));
449    GDBJIT(AddCode(GDBJITInterface::KEYED_LOAD_IC, name, Code::cast(code)));
450    Object* result;
451    { MaybeObject* maybe_result =
452          receiver->UpdateMapCodeCache(name, Code::cast(code));
453      if (!maybe_result->ToObject(&result)) return maybe_result;
454    }
455  }
456  return code;
457}
458
459
460MaybeObject* StubCache::ComputeKeyedLoadSpecialized(JSObject* receiver) {
461  // Using NORMAL as the PropertyType for array element loads is a misuse. The
462  // generated stub always accesses fast elements, not slow-mode fields, but
463  // some property type is required for the stub lookup. Note that overloading
464  // the NORMAL PropertyType is only safe as long as no stubs are generated for
465  // other keyed field loads. This is guaranteed to be the case since all field
466  // keyed loads that are not array elements go through a generic builtin stub.
467  Code::Flags flags =
468      Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, NORMAL);
469  String* name = heap()->KeyedLoadSpecialized_symbol();
470  Object* code = receiver->map()->FindInCodeCache(name, flags);
471  if (code->IsUndefined()) {
472    KeyedLoadStubCompiler compiler;
473    { MaybeObject* maybe_code = compiler.CompileLoadSpecialized(receiver);
474      if (!maybe_code->ToObject(&code)) return maybe_code;
475    }
476    PROFILE(isolate_,
477            CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, Code::cast(code), 0));
478    Object* result;
479    { MaybeObject* maybe_result =
480          receiver->UpdateMapCodeCache(name, Code::cast(code));
481      if (!maybe_result->ToObject(&result)) return maybe_result;
482    }
483  }
484  return code;
485}
486
487
488MaybeObject* StubCache::ComputeStoreField(String* name,
489                                          JSObject* receiver,
490                                          int field_index,
491                                          Map* transition,
492                                          StrictModeFlag strict_mode) {
493  PropertyType type = (transition == NULL) ? FIELD : MAP_TRANSITION;
494  Code::Flags flags = Code::ComputeMonomorphicFlags(
495      Code::STORE_IC, type, strict_mode);
496  Object* code = receiver->map()->FindInCodeCache(name, flags);
497  if (code->IsUndefined()) {
498    StoreStubCompiler compiler(strict_mode);
499    { MaybeObject* maybe_code =
500          compiler.CompileStoreField(receiver, field_index, transition, name);
501      if (!maybe_code->ToObject(&code)) return maybe_code;
502    }
503    PROFILE(isolate_,
504            CodeCreateEvent(Logger::STORE_IC_TAG, Code::cast(code), name));
505    GDBJIT(AddCode(GDBJITInterface::STORE_IC, name, Code::cast(code)));
506    Object* result;
507    { MaybeObject* maybe_result =
508          receiver->UpdateMapCodeCache(name, Code::cast(code));
509      if (!maybe_result->ToObject(&result)) return maybe_result;
510    }
511  }
512  return code;
513}
514
515
516MaybeObject* StubCache::ComputeKeyedStoreSpecialized(
517    JSObject* receiver,
518    StrictModeFlag strict_mode) {
519  Code::Flags flags =
520      Code::ComputeMonomorphicFlags(Code::KEYED_STORE_IC, NORMAL, strict_mode);
521  String* name = heap()->KeyedStoreSpecialized_symbol();
522  Object* code = receiver->map()->FindInCodeCache(name, flags);
523  if (code->IsUndefined()) {
524    KeyedStoreStubCompiler compiler(strict_mode);
525    { MaybeObject* maybe_code = compiler.CompileStoreSpecialized(receiver);
526      if (!maybe_code->ToObject(&code)) return maybe_code;
527    }
528    PROFILE(isolate_,
529            CodeCreateEvent(Logger::KEYED_STORE_IC_TAG, Code::cast(code), 0));
530    Object* result;
531    { MaybeObject* maybe_result =
532          receiver->UpdateMapCodeCache(name, Code::cast(code));
533      if (!maybe_result->ToObject(&result)) return maybe_result;
534    }
535  }
536  return code;
537}
538
539
540namespace {
541
542ExternalArrayType ElementsKindToExternalArrayType(JSObject::ElementsKind kind) {
543  switch (kind) {
544    case JSObject::EXTERNAL_BYTE_ELEMENTS:
545      return kExternalByteArray;
546    case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
547      return kExternalUnsignedByteArray;
548    case JSObject::EXTERNAL_SHORT_ELEMENTS:
549      return kExternalShortArray;
550    case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
551      return kExternalUnsignedShortArray;
552    case JSObject::EXTERNAL_INT_ELEMENTS:
553      return kExternalIntArray;
554    case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS:
555      return kExternalUnsignedIntArray;
556    case JSObject::EXTERNAL_FLOAT_ELEMENTS:
557      return kExternalFloatArray;
558    case JSObject::EXTERNAL_PIXEL_ELEMENTS:
559      return kExternalPixelArray;
560    default:
561      UNREACHABLE();
562      return static_cast<ExternalArrayType>(0);
563  }
564}
565
566String* ExternalArrayTypeToStubName(Heap* heap,
567                                    ExternalArrayType array_type,
568                                    bool is_store) {
569  if (is_store) {
570    switch (array_type) {
571      case kExternalByteArray:
572        return heap->KeyedStoreExternalByteArray_symbol();
573      case kExternalUnsignedByteArray:
574        return heap->KeyedStoreExternalUnsignedByteArray_symbol();
575      case kExternalShortArray:
576        return heap->KeyedStoreExternalShortArray_symbol();
577      case kExternalUnsignedShortArray:
578        return heap->KeyedStoreExternalUnsignedShortArray_symbol();
579      case kExternalIntArray:
580        return heap->KeyedStoreExternalIntArray_symbol();
581      case kExternalUnsignedIntArray:
582        return heap->KeyedStoreExternalUnsignedIntArray_symbol();
583      case kExternalFloatArray:
584        return heap->KeyedStoreExternalFloatArray_symbol();
585      case kExternalPixelArray:
586        return heap->KeyedStoreExternalPixelArray_symbol();
587      default:
588        UNREACHABLE();
589        return NULL;
590    }
591  } else {
592    switch (array_type) {
593      case kExternalByteArray:
594        return heap->KeyedLoadExternalByteArray_symbol();
595      case kExternalUnsignedByteArray:
596        return heap->KeyedLoadExternalUnsignedByteArray_symbol();
597      case kExternalShortArray:
598        return heap->KeyedLoadExternalShortArray_symbol();
599      case kExternalUnsignedShortArray:
600        return heap->KeyedLoadExternalUnsignedShortArray_symbol();
601      case kExternalIntArray:
602        return heap->KeyedLoadExternalIntArray_symbol();
603      case kExternalUnsignedIntArray:
604        return heap->KeyedLoadExternalUnsignedIntArray_symbol();
605      case kExternalFloatArray:
606        return heap->KeyedLoadExternalFloatArray_symbol();
607      case kExternalPixelArray:
608        return heap->KeyedLoadExternalPixelArray_symbol();
609      default:
610        UNREACHABLE();
611        return NULL;
612    }
613  }
614}
615
616}  // anonymous namespace
617
618
619MaybeObject* StubCache::ComputeKeyedLoadOrStoreExternalArray(
620    JSObject* receiver,
621    bool is_store,
622    StrictModeFlag strict_mode) {
623  Code::Flags flags =
624      Code::ComputeMonomorphicFlags(
625          is_store ? Code::KEYED_EXTERNAL_ARRAY_STORE_IC :
626                     Code::KEYED_EXTERNAL_ARRAY_LOAD_IC,
627          NORMAL,
628          strict_mode);
629  ExternalArrayType array_type =
630      ElementsKindToExternalArrayType(receiver->GetElementsKind());
631  String* name = ExternalArrayTypeToStubName(heap(), array_type, is_store);
632  Object* code = receiver->map()->FindInCodeCache(name, flags);
633  if (code->IsUndefined()) {
634    ExternalArrayStubCompiler compiler;
635    { MaybeObject* maybe_code =
636          is_store ?
637              compiler.CompileKeyedStoreStub(receiver, array_type, flags) :
638              compiler.CompileKeyedLoadStub(receiver, array_type, flags);
639      if (!maybe_code->ToObject(&code)) return maybe_code;
640    }
641    Code::cast(code)->set_external_array_type(array_type);
642    if (is_store) {
643      PROFILE(isolate_,
644          CodeCreateEvent(Logger::KEYED_EXTERNAL_ARRAY_STORE_IC_TAG,
645                          Code::cast(code), 0));
646    } else {
647      PROFILE(isolate_,
648          CodeCreateEvent(Logger::KEYED_EXTERNAL_ARRAY_LOAD_IC_TAG,
649                          Code::cast(code), 0));
650    }
651    Object* result;
652    { MaybeObject* maybe_result =
653          receiver->UpdateMapCodeCache(name, Code::cast(code));
654      if (!maybe_result->ToObject(&result)) return maybe_result;
655    }
656  }
657  return code;
658}
659
660
661MaybeObject* StubCache::ComputeStoreNormal(StrictModeFlag strict_mode) {
662  return isolate_->builtins()->builtin((strict_mode == kStrictMode)
663                            ? Builtins::kStoreIC_Normal_Strict
664                            : Builtins::kStoreIC_Normal);
665}
666
667
668MaybeObject* StubCache::ComputeStoreGlobal(String* name,
669                                           GlobalObject* receiver,
670                                           JSGlobalPropertyCell* cell,
671                                           StrictModeFlag strict_mode) {
672  Code::Flags flags = Code::ComputeMonomorphicFlags(
673      Code::STORE_IC, NORMAL, strict_mode);
674  Object* code = receiver->map()->FindInCodeCache(name, flags);
675  if (code->IsUndefined()) {
676    StoreStubCompiler compiler(strict_mode);
677    { MaybeObject* maybe_code =
678          compiler.CompileStoreGlobal(receiver, cell, name);
679      if (!maybe_code->ToObject(&code)) return maybe_code;
680    }
681    PROFILE(isolate_,
682            CodeCreateEvent(Logger::STORE_IC_TAG, Code::cast(code), name));
683    GDBJIT(AddCode(GDBJITInterface::STORE_IC, name, Code::cast(code)));
684    Object* result;
685    { MaybeObject* maybe_result =
686          receiver->UpdateMapCodeCache(name, Code::cast(code));
687      if (!maybe_result->ToObject(&result)) return maybe_result;
688    }
689  }
690  return code;
691}
692
693
694MaybeObject* StubCache::ComputeStoreCallback(
695    String* name,
696    JSObject* receiver,
697    AccessorInfo* callback,
698    StrictModeFlag strict_mode) {
699  ASSERT(v8::ToCData<Address>(callback->setter()) != 0);
700  Code::Flags flags = Code::ComputeMonomorphicFlags(
701      Code::STORE_IC, CALLBACKS, strict_mode);
702  Object* code = receiver->map()->FindInCodeCache(name, flags);
703  if (code->IsUndefined()) {
704    StoreStubCompiler compiler(strict_mode);
705    { MaybeObject* maybe_code =
706          compiler.CompileStoreCallback(receiver, callback, name);
707      if (!maybe_code->ToObject(&code)) return maybe_code;
708    }
709    PROFILE(isolate_,
710            CodeCreateEvent(Logger::STORE_IC_TAG, Code::cast(code), name));
711    GDBJIT(AddCode(GDBJITInterface::STORE_IC, name, Code::cast(code)));
712    Object* result;
713    { MaybeObject* maybe_result =
714          receiver->UpdateMapCodeCache(name, Code::cast(code));
715      if (!maybe_result->ToObject(&result)) return maybe_result;
716    }
717  }
718  return code;
719}
720
721
722MaybeObject* StubCache::ComputeStoreInterceptor(
723    String* name,
724    JSObject* receiver,
725    StrictModeFlag strict_mode) {
726  Code::Flags flags = Code::ComputeMonomorphicFlags(
727      Code::STORE_IC, INTERCEPTOR, strict_mode);
728  Object* code = receiver->map()->FindInCodeCache(name, flags);
729  if (code->IsUndefined()) {
730    StoreStubCompiler compiler(strict_mode);
731    { MaybeObject* maybe_code =
732          compiler.CompileStoreInterceptor(receiver, name);
733      if (!maybe_code->ToObject(&code)) return maybe_code;
734    }
735    PROFILE(isolate_,
736            CodeCreateEvent(Logger::STORE_IC_TAG, Code::cast(code), name));
737    GDBJIT(AddCode(GDBJITInterface::STORE_IC, name, Code::cast(code)));
738    Object* result;
739    { MaybeObject* maybe_result =
740          receiver->UpdateMapCodeCache(name, Code::cast(code));
741      if (!maybe_result->ToObject(&result)) return maybe_result;
742    }
743  }
744  return code;
745}
746
747
748MaybeObject* StubCache::ComputeKeyedStoreField(String* name,
749                                               JSObject* receiver,
750                                               int field_index,
751                                               Map* transition,
752                                               StrictModeFlag strict_mode) {
753  PropertyType type = (transition == NULL) ? FIELD : MAP_TRANSITION;
754  Code::Flags flags = Code::ComputeMonomorphicFlags(
755      Code::KEYED_STORE_IC, type, strict_mode);
756  Object* code = receiver->map()->FindInCodeCache(name, flags);
757  if (code->IsUndefined()) {
758    KeyedStoreStubCompiler compiler(strict_mode);
759    { MaybeObject* maybe_code =
760          compiler.CompileStoreField(receiver, field_index, transition, name);
761      if (!maybe_code->ToObject(&code)) return maybe_code;
762    }
763    PROFILE(isolate(),
764            CodeCreateEvent(Logger::KEYED_STORE_IC_TAG,
765                            Code::cast(code), name));
766    GDBJIT(AddCode(GDBJITInterface::KEYED_STORE_IC, name, Code::cast(code)));
767    Object* result;
768    { MaybeObject* maybe_result =
769          receiver->UpdateMapCodeCache(name, Code::cast(code));
770      if (!maybe_result->ToObject(&result)) return maybe_result;
771    }
772  }
773  return code;
774}
775
776#define CALL_LOGGER_TAG(kind, type) \
777    (kind == Code::CALL_IC ? Logger::type : Logger::KEYED_##type)
778
779MaybeObject* StubCache::ComputeCallConstant(int argc,
780                                            InLoopFlag in_loop,
781                                            Code::Kind kind,
782                                            Code::ExtraICState extra_ic_state,
783                                            String* name,
784                                            Object* object,
785                                            JSObject* holder,
786                                            JSFunction* function) {
787  // Compute the check type and the map.
788  InlineCacheHolderFlag cache_holder =
789      IC::GetCodeCacheForObject(object, holder);
790  JSObject* map_holder = IC::GetCodeCacheHolder(object, cache_holder);
791
792  // Compute check type based on receiver/holder.
793  CheckType check = RECEIVER_MAP_CHECK;
794  if (object->IsString()) {
795    check = STRING_CHECK;
796  } else if (object->IsNumber()) {
797    check = NUMBER_CHECK;
798  } else if (object->IsBoolean()) {
799    check = BOOLEAN_CHECK;
800  }
801
802  Code::Flags flags = Code::ComputeMonomorphicFlags(kind,
803                                                    CONSTANT_FUNCTION,
804                                                    extra_ic_state,
805                                                    cache_holder,
806                                                    in_loop,
807                                                    argc);
808  Object* code = map_holder->map()->FindInCodeCache(name, flags);
809  if (code->IsUndefined()) {
810    // If the function hasn't been compiled yet, we cannot do it now
811    // because it may cause GC. To avoid this issue, we return an
812    // internal error which will make sure we do not update any
813    // caches.
814    if (!function->is_compiled()) return Failure::InternalError();
815    // Compile the stub - only create stubs for fully compiled functions.
816    CallStubCompiler compiler(
817        argc, in_loop, kind, extra_ic_state, cache_holder);
818    { MaybeObject* maybe_code =
819          compiler.CompileCallConstant(object, holder, function, name, check);
820      if (!maybe_code->ToObject(&code)) return maybe_code;
821    }
822    Code::cast(code)->set_check_type(check);
823    ASSERT_EQ(flags, Code::cast(code)->flags());
824    PROFILE(isolate_,
825            CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_IC_TAG),
826                            Code::cast(code), name));
827    GDBJIT(AddCode(GDBJITInterface::CALL_IC, name, Code::cast(code)));
828    Object* result;
829    { MaybeObject* maybe_result =
830          map_holder->UpdateMapCodeCache(name, Code::cast(code));
831      if (!maybe_result->ToObject(&result)) return maybe_result;
832    }
833  }
834  return code;
835}
836
837
838MaybeObject* StubCache::ComputeCallField(int argc,
839                                         InLoopFlag in_loop,
840                                         Code::Kind kind,
841                                         String* name,
842                                         Object* object,
843                                         JSObject* holder,
844                                         int index) {
845  // Compute the check type and the map.
846  InlineCacheHolderFlag cache_holder =
847      IC::GetCodeCacheForObject(object, holder);
848  JSObject* map_holder = IC::GetCodeCacheHolder(object, cache_holder);
849
850  // TODO(1233596): We cannot do receiver map check for non-JS objects
851  // because they may be represented as immediates without a
852  // map. Instead, we check against the map in the holder.
853  if (object->IsNumber() || object->IsBoolean() || object->IsString()) {
854    object = holder;
855  }
856
857  Code::Flags flags = Code::ComputeMonomorphicFlags(kind,
858                                                    FIELD,
859                                                    Code::kNoExtraICState,
860                                                    cache_holder,
861                                                    in_loop,
862                                                    argc);
863  Object* code = map_holder->map()->FindInCodeCache(name, flags);
864  if (code->IsUndefined()) {
865    CallStubCompiler compiler(
866        argc, in_loop, kind, Code::kNoExtraICState, cache_holder);
867    { MaybeObject* maybe_code =
868          compiler.CompileCallField(JSObject::cast(object),
869                                    holder,
870                                    index,
871                                    name);
872      if (!maybe_code->ToObject(&code)) return maybe_code;
873    }
874    ASSERT_EQ(flags, Code::cast(code)->flags());
875    PROFILE(isolate_,
876            CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_IC_TAG),
877                            Code::cast(code), name));
878    GDBJIT(AddCode(GDBJITInterface::CALL_IC, name, Code::cast(code)));
879    Object* result;
880    { MaybeObject* maybe_result =
881          map_holder->UpdateMapCodeCache(name, Code::cast(code));
882      if (!maybe_result->ToObject(&result)) return maybe_result;
883    }
884  }
885  return code;
886}
887
888
889MaybeObject* StubCache::ComputeCallInterceptor(int argc,
890                                               Code::Kind kind,
891                                               String* name,
892                                               Object* object,
893                                               JSObject* holder) {
894  // Compute the check type and the map.
895  InlineCacheHolderFlag cache_holder =
896      IC::GetCodeCacheForObject(object, holder);
897  JSObject* map_holder = IC::GetCodeCacheHolder(object, cache_holder);
898
899  // TODO(1233596): We cannot do receiver map check for non-JS objects
900  // because they may be represented as immediates without a
901  // map. Instead, we check against the map in the holder.
902  if (object->IsNumber() || object->IsBoolean() || object->IsString()) {
903    object = holder;
904  }
905
906  Code::Flags flags = Code::ComputeMonomorphicFlags(kind,
907                                                    INTERCEPTOR,
908                                                    Code::kNoExtraICState,
909                                                    cache_holder,
910                                                    NOT_IN_LOOP,
911                                                    argc);
912  Object* code = map_holder->map()->FindInCodeCache(name, flags);
913  if (code->IsUndefined()) {
914    CallStubCompiler compiler(
915        argc, NOT_IN_LOOP, kind, Code::kNoExtraICState, cache_holder);
916    { MaybeObject* maybe_code =
917          compiler.CompileCallInterceptor(JSObject::cast(object), holder, name);
918      if (!maybe_code->ToObject(&code)) return maybe_code;
919    }
920    ASSERT_EQ(flags, Code::cast(code)->flags());
921    PROFILE(isolate(),
922            CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_IC_TAG),
923                            Code::cast(code), name));
924    GDBJIT(AddCode(GDBJITInterface::CALL_IC, name, Code::cast(code)));
925    Object* result;
926    { MaybeObject* maybe_result =
927          map_holder->UpdateMapCodeCache(name, Code::cast(code));
928      if (!maybe_result->ToObject(&result)) return maybe_result;
929    }
930  }
931  return code;
932}
933
934
935MaybeObject* StubCache::ComputeCallNormal(int argc,
936                                          InLoopFlag in_loop,
937                                          Code::Kind kind,
938                                          String* name,
939                                          JSObject* receiver) {
940  Object* code;
941  { MaybeObject* maybe_code = ComputeCallNormal(argc, in_loop, kind);
942    if (!maybe_code->ToObject(&code)) return maybe_code;
943  }
944  return code;
945}
946
947
948MaybeObject* StubCache::ComputeCallGlobal(int argc,
949                                          InLoopFlag in_loop,
950                                          Code::Kind kind,
951                                          String* name,
952                                          JSObject* receiver,
953                                          GlobalObject* holder,
954                                          JSGlobalPropertyCell* cell,
955                                          JSFunction* function) {
956  InlineCacheHolderFlag cache_holder =
957      IC::GetCodeCacheForObject(receiver, holder);
958  JSObject* map_holder = IC::GetCodeCacheHolder(receiver, cache_holder);
959  Code::Flags flags = Code::ComputeMonomorphicFlags(kind,
960                                                    NORMAL,
961                                                    Code::kNoExtraICState,
962                                                    cache_holder,
963                                                    in_loop,
964                                                    argc);
965  Object* code = map_holder->map()->FindInCodeCache(name, flags);
966  if (code->IsUndefined()) {
967    // If the function hasn't been compiled yet, we cannot do it now
968    // because it may cause GC. To avoid this issue, we return an
969    // internal error which will make sure we do not update any
970    // caches.
971    if (!function->is_compiled()) return Failure::InternalError();
972    CallStubCompiler compiler(
973        argc, in_loop, kind, Code::kNoExtraICState, cache_holder);
974    { MaybeObject* maybe_code =
975          compiler.CompileCallGlobal(receiver, holder, cell, function, name);
976      if (!maybe_code->ToObject(&code)) return maybe_code;
977    }
978    ASSERT_EQ(flags, Code::cast(code)->flags());
979    PROFILE(isolate(),
980            CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_IC_TAG),
981                            Code::cast(code), name));
982    GDBJIT(AddCode(GDBJITInterface::CALL_IC, name, Code::cast(code)));
983    Object* result;
984    { MaybeObject* maybe_result =
985          map_holder->UpdateMapCodeCache(name, Code::cast(code));
986      if (!maybe_result->ToObject(&result)) return maybe_result;
987    }
988  }
989  return code;
990}
991
992
993static Object* GetProbeValue(Isolate* isolate, Code::Flags flags) {
994  // Use raw_unchecked... so we don't get assert failures during GC.
995  NumberDictionary* dictionary =
996      isolate->heap()->raw_unchecked_non_monomorphic_cache();
997  int entry = dictionary->FindEntry(isolate, flags);
998  if (entry != -1) return dictionary->ValueAt(entry);
999  return isolate->heap()->raw_unchecked_undefined_value();
1000}
1001
1002
1003MUST_USE_RESULT static MaybeObject* ProbeCache(Isolate* isolate,
1004                                               Code::Flags flags) {
1005  Heap* heap = isolate->heap();
1006  Object* probe = GetProbeValue(isolate, flags);
1007  if (probe != heap->undefined_value()) return probe;
1008  // Seed the cache with an undefined value to make sure that any
1009  // generated code object can always be inserted into the cache
1010  // without causing  allocation failures.
1011  Object* result;
1012  { MaybeObject* maybe_result =
1013        heap->non_monomorphic_cache()->AtNumberPut(flags,
1014                                                   heap->undefined_value());
1015    if (!maybe_result->ToObject(&result)) return maybe_result;
1016  }
1017  heap->public_set_non_monomorphic_cache(NumberDictionary::cast(result));
1018  return probe;
1019}
1020
1021
1022static MaybeObject* FillCache(Isolate* isolate, MaybeObject* maybe_code) {
1023  Object* code;
1024  if (maybe_code->ToObject(&code)) {
1025    if (code->IsCode()) {
1026      Heap* heap = isolate->heap();
1027      int entry = heap->non_monomorphic_cache()->FindEntry(
1028          Code::cast(code)->flags());
1029      // The entry must be present see comment in ProbeCache.
1030      ASSERT(entry != -1);
1031      ASSERT(heap->non_monomorphic_cache()->ValueAt(entry) ==
1032             heap->undefined_value());
1033      heap->non_monomorphic_cache()->ValueAtPut(entry, code);
1034      CHECK(GetProbeValue(isolate, Code::cast(code)->flags()) == code);
1035    }
1036  }
1037  return maybe_code;
1038}
1039
1040
1041Code* StubCache::FindCallInitialize(int argc,
1042                                    InLoopFlag in_loop,
1043                                    Code::Kind kind) {
1044  Code::Flags flags = Code::ComputeFlags(kind,
1045                                         in_loop,
1046                                         UNINITIALIZED,
1047                                         Code::kNoExtraICState,
1048                                         NORMAL,
1049                                         argc);
1050  Object* result = ProbeCache(isolate(), flags)->ToObjectUnchecked();
1051  ASSERT(result != heap()->undefined_value());
1052  // This might be called during the marking phase of the collector
1053  // hence the unchecked cast.
1054  return reinterpret_cast<Code*>(result);
1055}
1056
1057
1058MaybeObject* StubCache::ComputeCallInitialize(int argc,
1059                                              InLoopFlag in_loop,
1060                                              Code::Kind kind) {
1061  Code::Flags flags = Code::ComputeFlags(kind,
1062                                         in_loop,
1063                                         UNINITIALIZED,
1064                                         Code::kNoExtraICState,
1065                                         NORMAL,
1066                                         argc);
1067  Object* probe;
1068  { MaybeObject* maybe_probe = ProbeCache(isolate_, flags);
1069    if (!maybe_probe->ToObject(&probe)) return maybe_probe;
1070  }
1071  if (!probe->IsUndefined()) return probe;
1072  StubCompiler compiler;
1073  return FillCache(isolate_, compiler.CompileCallInitialize(flags));
1074}
1075
1076
1077Handle<Code> StubCache::ComputeCallInitialize(int argc, InLoopFlag in_loop) {
1078  if (in_loop == IN_LOOP) {
1079    // Force the creation of the corresponding stub outside loops,
1080    // because it may be used when clearing the ICs later - it is
1081    // possible for a series of IC transitions to lose the in-loop
1082    // information, and the IC clearing code can't generate a stub
1083    // that it needs so we need to ensure it is generated already.
1084    ComputeCallInitialize(argc, NOT_IN_LOOP);
1085  }
1086  CALL_HEAP_FUNCTION(isolate_,
1087                     ComputeCallInitialize(argc, in_loop, Code::CALL_IC), Code);
1088}
1089
1090
1091Handle<Code> StubCache::ComputeKeyedCallInitialize(int argc,
1092                                                   InLoopFlag in_loop) {
1093  if (in_loop == IN_LOOP) {
1094    // Force the creation of the corresponding stub outside loops,
1095    // because it may be used when clearing the ICs later - it is
1096    // possible for a series of IC transitions to lose the in-loop
1097    // information, and the IC clearing code can't generate a stub
1098    // that it needs so we need to ensure it is generated already.
1099    ComputeKeyedCallInitialize(argc, NOT_IN_LOOP);
1100  }
1101  CALL_HEAP_FUNCTION(
1102      isolate_,
1103      ComputeCallInitialize(argc, in_loop, Code::KEYED_CALL_IC), Code);
1104}
1105
1106
1107MaybeObject* StubCache::ComputeCallPreMonomorphic(int argc,
1108                                                  InLoopFlag in_loop,
1109                                                  Code::Kind kind) {
1110  Code::Flags flags = Code::ComputeFlags(kind,
1111                                         in_loop,
1112                                         PREMONOMORPHIC,
1113                                         Code::kNoExtraICState,
1114                                         NORMAL,
1115                                         argc);
1116  Object* probe;
1117  { MaybeObject* maybe_probe = ProbeCache(isolate_, flags);
1118    if (!maybe_probe->ToObject(&probe)) return maybe_probe;
1119  }
1120  if (!probe->IsUndefined()) return probe;
1121  StubCompiler compiler;
1122  return FillCache(isolate_, compiler.CompileCallPreMonomorphic(flags));
1123}
1124
1125
1126MaybeObject* StubCache::ComputeCallNormal(int argc,
1127                                          InLoopFlag in_loop,
1128                                          Code::Kind kind) {
1129  Code::Flags flags = Code::ComputeFlags(kind,
1130                                         in_loop,
1131                                         MONOMORPHIC,
1132                                         Code::kNoExtraICState,
1133                                         NORMAL,
1134                                         argc);
1135  Object* probe;
1136  { MaybeObject* maybe_probe = ProbeCache(isolate_, flags);
1137    if (!maybe_probe->ToObject(&probe)) return maybe_probe;
1138  }
1139  if (!probe->IsUndefined()) return probe;
1140  StubCompiler compiler;
1141  return FillCache(isolate_, compiler.CompileCallNormal(flags));
1142}
1143
1144
1145MaybeObject* StubCache::ComputeCallMegamorphic(int argc,
1146                                               InLoopFlag in_loop,
1147                                               Code::Kind kind) {
1148  Code::Flags flags = Code::ComputeFlags(kind,
1149                                         in_loop,
1150                                         MEGAMORPHIC,
1151                                         Code::kNoExtraICState,
1152                                         NORMAL,
1153                                         argc);
1154  Object* probe;
1155  { MaybeObject* maybe_probe = ProbeCache(isolate_, flags);
1156    if (!maybe_probe->ToObject(&probe)) return maybe_probe;
1157  }
1158  if (!probe->IsUndefined()) return probe;
1159  StubCompiler compiler;
1160  return FillCache(isolate_, compiler.CompileCallMegamorphic(flags));
1161}
1162
1163
1164MaybeObject* StubCache::ComputeCallMiss(int argc, Code::Kind kind) {
1165  // MONOMORPHIC_PROTOTYPE_FAILURE state is used to make sure that miss stubs
1166  // and monomorphic stubs are not mixed up together in the stub cache.
1167  Code::Flags flags = Code::ComputeFlags(kind,
1168                                         NOT_IN_LOOP,
1169                                         MONOMORPHIC_PROTOTYPE_FAILURE,
1170                                         Code::kNoExtraICState,
1171                                         NORMAL,
1172                                         argc,
1173                                         OWN_MAP);
1174  Object* probe;
1175  { MaybeObject* maybe_probe = ProbeCache(isolate_, flags);
1176    if (!maybe_probe->ToObject(&probe)) return maybe_probe;
1177  }
1178  if (!probe->IsUndefined()) return probe;
1179  StubCompiler compiler;
1180  return FillCache(isolate_, compiler.CompileCallMiss(flags));
1181}
1182
1183
1184#ifdef ENABLE_DEBUGGER_SUPPORT
1185MaybeObject* StubCache::ComputeCallDebugBreak(int argc, Code::Kind kind) {
1186  Code::Flags flags = Code::ComputeFlags(kind,
1187                                         NOT_IN_LOOP,
1188                                         DEBUG_BREAK,
1189                                         Code::kNoExtraICState,
1190                                         NORMAL,
1191                                         argc);
1192  Object* probe;
1193  { MaybeObject* maybe_probe = ProbeCache(isolate_, flags);
1194    if (!maybe_probe->ToObject(&probe)) return maybe_probe;
1195  }
1196  if (!probe->IsUndefined()) return probe;
1197  StubCompiler compiler;
1198  return FillCache(isolate_, compiler.CompileCallDebugBreak(flags));
1199}
1200
1201
1202MaybeObject* StubCache::ComputeCallDebugPrepareStepIn(int argc,
1203                                                      Code::Kind kind) {
1204  Code::Flags flags = Code::ComputeFlags(kind,
1205                                         NOT_IN_LOOP,
1206                                         DEBUG_PREPARE_STEP_IN,
1207                                         Code::kNoExtraICState,
1208                                         NORMAL,
1209                                         argc);
1210  Object* probe;
1211  { MaybeObject* maybe_probe = ProbeCache(isolate_, flags);
1212    if (!maybe_probe->ToObject(&probe)) return maybe_probe;
1213  }
1214  if (!probe->IsUndefined()) return probe;
1215  StubCompiler compiler;
1216  return FillCache(isolate_, compiler.CompileCallDebugPrepareStepIn(flags));
1217}
1218#endif
1219
1220
1221void StubCache::Clear() {
1222  for (int i = 0; i < kPrimaryTableSize; i++) {
1223    primary_[i].key = heap()->empty_string();
1224    primary_[i].value = isolate_->builtins()->builtin(
1225        Builtins::kIllegal);
1226  }
1227  for (int j = 0; j < kSecondaryTableSize; j++) {
1228    secondary_[j].key = heap()->empty_string();
1229    secondary_[j].value = isolate_->builtins()->builtin(
1230        Builtins::kIllegal);
1231  }
1232}
1233
1234
1235void StubCache::CollectMatchingMaps(ZoneMapList* types,
1236                                    String* name,
1237                                    Code::Flags flags) {
1238  for (int i = 0; i < kPrimaryTableSize; i++) {
1239    if (primary_[i].key == name) {
1240      Map* map = primary_[i].value->FindFirstMap();
1241      // Map can be NULL, if the stub is constant function call
1242      // with a primitive receiver.
1243      if (map == NULL) continue;
1244
1245      int offset = PrimaryOffset(name, flags, map);
1246      if (entry(primary_, offset) == &primary_[i]) {
1247        types->Add(Handle<Map>(map));
1248      }
1249    }
1250  }
1251
1252  for (int i = 0; i < kSecondaryTableSize; i++) {
1253    if (secondary_[i].key == name) {
1254      Map* map = secondary_[i].value->FindFirstMap();
1255      // Map can be NULL, if the stub is constant function call
1256      // with a primitive receiver.
1257      if (map == NULL) continue;
1258
1259      // Lookup in primary table and skip duplicates.
1260      int primary_offset = PrimaryOffset(name, flags, map);
1261      Entry* primary_entry = entry(primary_, primary_offset);
1262      if (primary_entry->key == name) {
1263        Map* primary_map = primary_entry->value->FindFirstMap();
1264        if (map == primary_map) continue;
1265      }
1266
1267      // Lookup in secondary table and add matches.
1268      int offset = SecondaryOffset(name, flags, primary_offset);
1269      if (entry(secondary_, offset) == &secondary_[i]) {
1270        types->Add(Handle<Map>(map));
1271      }
1272    }
1273  }
1274}
1275
1276
1277// ------------------------------------------------------------------------
1278// StubCompiler implementation.
1279
1280
1281RUNTIME_FUNCTION(MaybeObject*, LoadCallbackProperty) {
1282  ASSERT(args[0]->IsJSObject());
1283  ASSERT(args[1]->IsJSObject());
1284  AccessorInfo* callback = AccessorInfo::cast(args[3]);
1285  Address getter_address = v8::ToCData<Address>(callback->getter());
1286  v8::AccessorGetter fun = FUNCTION_CAST<v8::AccessorGetter>(getter_address);
1287  ASSERT(fun != NULL);
1288  v8::AccessorInfo info(&args[0]);
1289  HandleScope scope(isolate);
1290  v8::Handle<v8::Value> result;
1291  {
1292    // Leaving JavaScript.
1293    VMState state(isolate, EXTERNAL);
1294    ExternalCallbackScope call_scope(isolate, getter_address);
1295    result = fun(v8::Utils::ToLocal(args.at<String>(4)), info);
1296  }
1297  RETURN_IF_SCHEDULED_EXCEPTION(isolate);
1298  if (result.IsEmpty()) return HEAP->undefined_value();
1299  return *v8::Utils::OpenHandle(*result);
1300}
1301
1302
1303RUNTIME_FUNCTION(MaybeObject*, StoreCallbackProperty) {
1304  JSObject* recv = JSObject::cast(args[0]);
1305  AccessorInfo* callback = AccessorInfo::cast(args[1]);
1306  Address setter_address = v8::ToCData<Address>(callback->setter());
1307  v8::AccessorSetter fun = FUNCTION_CAST<v8::AccessorSetter>(setter_address);
1308  ASSERT(fun != NULL);
1309  Handle<String> name = args.at<String>(2);
1310  Handle<Object> value = args.at<Object>(3);
1311  HandleScope scope(isolate);
1312  LOG(isolate, ApiNamedPropertyAccess("store", recv, *name));
1313  CustomArguments custom_args(isolate, callback->data(), recv, recv);
1314  v8::AccessorInfo info(custom_args.end());
1315  {
1316    // Leaving JavaScript.
1317    VMState state(isolate, EXTERNAL);
1318    ExternalCallbackScope call_scope(isolate, setter_address);
1319    fun(v8::Utils::ToLocal(name), v8::Utils::ToLocal(value), info);
1320  }
1321  RETURN_IF_SCHEDULED_EXCEPTION(isolate);
1322  return *value;
1323}
1324
1325
1326static const int kAccessorInfoOffsetInInterceptorArgs = 2;
1327
1328
1329/**
1330 * Attempts to load a property with an interceptor (which must be present),
1331 * but doesn't search the prototype chain.
1332 *
1333 * Returns |Heap::no_interceptor_result_sentinel()| if interceptor doesn't
1334 * provide any value for the given name.
1335 */
1336RUNTIME_FUNCTION(MaybeObject*, LoadPropertyWithInterceptorOnly) {
1337  Handle<String> name_handle = args.at<String>(0);
1338  Handle<InterceptorInfo> interceptor_info = args.at<InterceptorInfo>(1);
1339  ASSERT(kAccessorInfoOffsetInInterceptorArgs == 2);
1340  ASSERT(args[2]->IsJSObject());  // Receiver.
1341  ASSERT(args[3]->IsJSObject());  // Holder.
1342  ASSERT(args.length() == 5);  // Last arg is data object.
1343
1344  Address getter_address = v8::ToCData<Address>(interceptor_info->getter());
1345  v8::NamedPropertyGetter getter =
1346      FUNCTION_CAST<v8::NamedPropertyGetter>(getter_address);
1347  ASSERT(getter != NULL);
1348
1349  {
1350    // Use the interceptor getter.
1351    v8::AccessorInfo info(args.arguments() -
1352                          kAccessorInfoOffsetInInterceptorArgs);
1353    HandleScope scope(isolate);
1354    v8::Handle<v8::Value> r;
1355    {
1356      // Leaving JavaScript.
1357      VMState state(isolate, EXTERNAL);
1358      r = getter(v8::Utils::ToLocal(name_handle), info);
1359    }
1360    RETURN_IF_SCHEDULED_EXCEPTION(isolate);
1361    if (!r.IsEmpty()) {
1362      return *v8::Utils::OpenHandle(*r);
1363    }
1364  }
1365
1366  return isolate->heap()->no_interceptor_result_sentinel();
1367}
1368
1369
1370static MaybeObject* ThrowReferenceError(String* name) {
1371  // If the load is non-contextual, just return the undefined result.
1372  // Note that both keyed and non-keyed loads may end up here, so we
1373  // can't use either LoadIC or KeyedLoadIC constructors.
1374  IC ic(IC::NO_EXTRA_FRAME, Isolate::Current());
1375  ASSERT(ic.target()->is_load_stub() || ic.target()->is_keyed_load_stub());
1376  if (!ic.SlowIsContextual()) return HEAP->undefined_value();
1377
1378  // Throw a reference error.
1379  HandleScope scope;
1380  Handle<String> name_handle(name);
1381  Handle<Object> error =
1382      FACTORY->NewReferenceError("not_defined",
1383                                  HandleVector(&name_handle, 1));
1384  return Isolate::Current()->Throw(*error);
1385}
1386
1387
1388static MaybeObject* LoadWithInterceptor(Arguments* args,
1389                                        PropertyAttributes* attrs) {
1390  Handle<String> name_handle = args->at<String>(0);
1391  Handle<InterceptorInfo> interceptor_info = args->at<InterceptorInfo>(1);
1392  ASSERT(kAccessorInfoOffsetInInterceptorArgs == 2);
1393  Handle<JSObject> receiver_handle = args->at<JSObject>(2);
1394  Handle<JSObject> holder_handle = args->at<JSObject>(3);
1395  ASSERT(args->length() == 5);  // Last arg is data object.
1396
1397  Isolate* isolate = receiver_handle->GetIsolate();
1398
1399  Address getter_address = v8::ToCData<Address>(interceptor_info->getter());
1400  v8::NamedPropertyGetter getter =
1401      FUNCTION_CAST<v8::NamedPropertyGetter>(getter_address);
1402  ASSERT(getter != NULL);
1403
1404  {
1405    // Use the interceptor getter.
1406    v8::AccessorInfo info(args->arguments() -
1407                          kAccessorInfoOffsetInInterceptorArgs);
1408    HandleScope scope(isolate);
1409    v8::Handle<v8::Value> r;
1410    {
1411      // Leaving JavaScript.
1412      VMState state(isolate, EXTERNAL);
1413      r = getter(v8::Utils::ToLocal(name_handle), info);
1414    }
1415    RETURN_IF_SCHEDULED_EXCEPTION(isolate);
1416    if (!r.IsEmpty()) {
1417      *attrs = NONE;
1418      return *v8::Utils::OpenHandle(*r);
1419    }
1420  }
1421
1422  MaybeObject* result = holder_handle->GetPropertyPostInterceptor(
1423      *receiver_handle,
1424      *name_handle,
1425      attrs);
1426  RETURN_IF_SCHEDULED_EXCEPTION(isolate);
1427  return result;
1428}
1429
1430
1431/**
1432 * Loads a property with an interceptor performing post interceptor
1433 * lookup if interceptor failed.
1434 */
1435RUNTIME_FUNCTION(MaybeObject*, LoadPropertyWithInterceptorForLoad) {
1436  PropertyAttributes attr = NONE;
1437  Object* result;
1438  { MaybeObject* maybe_result = LoadWithInterceptor(&args, &attr);
1439    if (!maybe_result->ToObject(&result)) return maybe_result;
1440  }
1441
1442  // If the property is present, return it.
1443  if (attr != ABSENT) return result;
1444  return ThrowReferenceError(String::cast(args[0]));
1445}
1446
1447
1448RUNTIME_FUNCTION(MaybeObject*, LoadPropertyWithInterceptorForCall) {
1449  PropertyAttributes attr;
1450  MaybeObject* result = LoadWithInterceptor(&args, &attr);
1451  RETURN_IF_SCHEDULED_EXCEPTION(isolate);
1452  // This is call IC. In this case, we simply return the undefined result which
1453  // will lead to an exception when trying to invoke the result as a
1454  // function.
1455  return result;
1456}
1457
1458
1459RUNTIME_FUNCTION(MaybeObject*, StoreInterceptorProperty) {
1460  ASSERT(args.length() == 4);
1461  JSObject* recv = JSObject::cast(args[0]);
1462  String* name = String::cast(args[1]);
1463  Object* value = args[2];
1464  StrictModeFlag strict_mode =
1465      static_cast<StrictModeFlag>(Smi::cast(args[3])->value());
1466  ASSERT(strict_mode == kStrictMode || strict_mode == kNonStrictMode);
1467  ASSERT(recv->HasNamedInterceptor());
1468  PropertyAttributes attr = NONE;
1469  MaybeObject* result = recv->SetPropertyWithInterceptor(
1470      name, value, attr, strict_mode);
1471  return result;
1472}
1473
1474
1475RUNTIME_FUNCTION(MaybeObject*, KeyedLoadPropertyWithInterceptor) {
1476  JSObject* receiver = JSObject::cast(args[0]);
1477  ASSERT(Smi::cast(args[1])->value() >= 0);
1478  uint32_t index = Smi::cast(args[1])->value();
1479  return receiver->GetElementWithInterceptor(receiver, index);
1480}
1481
1482
1483MaybeObject* StubCompiler::CompileCallInitialize(Code::Flags flags) {
1484  HandleScope scope(isolate());
1485  int argc = Code::ExtractArgumentsCountFromFlags(flags);
1486  Code::Kind kind = Code::ExtractKindFromFlags(flags);
1487  if (kind == Code::CALL_IC) {
1488    CallIC::GenerateInitialize(masm(), argc);
1489  } else {
1490    KeyedCallIC::GenerateInitialize(masm(), argc);
1491  }
1492  Object* result;
1493  { MaybeObject* maybe_result =
1494        GetCodeWithFlags(flags, "CompileCallInitialize");
1495    if (!maybe_result->ToObject(&result)) return maybe_result;
1496  }
1497  isolate()->counters()->call_initialize_stubs()->Increment();
1498  Code* code = Code::cast(result);
1499  USE(code);
1500  PROFILE(isolate(),
1501          CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_INITIALIZE_TAG),
1502                          code, code->arguments_count()));
1503  GDBJIT(AddCode(GDBJITInterface::CALL_INITIALIZE, Code::cast(code)));
1504  return result;
1505}
1506
1507
1508MaybeObject* StubCompiler::CompileCallPreMonomorphic(Code::Flags flags) {
1509  HandleScope scope(isolate());
1510  int argc = Code::ExtractArgumentsCountFromFlags(flags);
1511  // The code of the PreMonomorphic stub is the same as the code
1512  // of the Initialized stub.  They just differ on the code object flags.
1513  Code::Kind kind = Code::ExtractKindFromFlags(flags);
1514  if (kind == Code::CALL_IC) {
1515    CallIC::GenerateInitialize(masm(), argc);
1516  } else {
1517    KeyedCallIC::GenerateInitialize(masm(), argc);
1518  }
1519  Object* result;
1520  { MaybeObject* maybe_result =
1521        GetCodeWithFlags(flags, "CompileCallPreMonomorphic");
1522    if (!maybe_result->ToObject(&result)) return maybe_result;
1523  }
1524  isolate()->counters()->call_premonomorphic_stubs()->Increment();
1525  Code* code = Code::cast(result);
1526  USE(code);
1527  PROFILE(isolate(),
1528          CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_PRE_MONOMORPHIC_TAG),
1529                          code, code->arguments_count()));
1530  GDBJIT(AddCode(GDBJITInterface::CALL_PRE_MONOMORPHIC, Code::cast(code)));
1531  return result;
1532}
1533
1534
1535MaybeObject* StubCompiler::CompileCallNormal(Code::Flags flags) {
1536  HandleScope scope(isolate());
1537  int argc = Code::ExtractArgumentsCountFromFlags(flags);
1538  Code::Kind kind = Code::ExtractKindFromFlags(flags);
1539  if (kind == Code::CALL_IC) {
1540    CallIC::GenerateNormal(masm(), argc);
1541  } else {
1542    KeyedCallIC::GenerateNormal(masm(), argc);
1543  }
1544  Object* result;
1545  { MaybeObject* maybe_result = GetCodeWithFlags(flags, "CompileCallNormal");
1546    if (!maybe_result->ToObject(&result)) return maybe_result;
1547  }
1548  isolate()->counters()->call_normal_stubs()->Increment();
1549  Code* code = Code::cast(result);
1550  USE(code);
1551  PROFILE(isolate(),
1552          CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_NORMAL_TAG),
1553                          code, code->arguments_count()));
1554  GDBJIT(AddCode(GDBJITInterface::CALL_NORMAL, Code::cast(code)));
1555  return result;
1556}
1557
1558
1559MaybeObject* StubCompiler::CompileCallMegamorphic(Code::Flags flags) {
1560  HandleScope scope(isolate());
1561  int argc = Code::ExtractArgumentsCountFromFlags(flags);
1562  Code::Kind kind = Code::ExtractKindFromFlags(flags);
1563  if (kind == Code::CALL_IC) {
1564    CallIC::GenerateMegamorphic(masm(), argc);
1565  } else {
1566    KeyedCallIC::GenerateMegamorphic(masm(), argc);
1567  }
1568  Object* result;
1569  { MaybeObject* maybe_result =
1570        GetCodeWithFlags(flags, "CompileCallMegamorphic");
1571    if (!maybe_result->ToObject(&result)) return maybe_result;
1572  }
1573  isolate()->counters()->call_megamorphic_stubs()->Increment();
1574  Code* code = Code::cast(result);
1575  USE(code);
1576  PROFILE(isolate(),
1577          CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_MEGAMORPHIC_TAG),
1578                          code, code->arguments_count()));
1579  GDBJIT(AddCode(GDBJITInterface::CALL_MEGAMORPHIC, Code::cast(code)));
1580  return result;
1581}
1582
1583
1584MaybeObject* StubCompiler::CompileCallMiss(Code::Flags flags) {
1585  HandleScope scope(isolate());
1586  int argc = Code::ExtractArgumentsCountFromFlags(flags);
1587  Code::Kind kind = Code::ExtractKindFromFlags(flags);
1588  if (kind == Code::CALL_IC) {
1589    CallIC::GenerateMiss(masm(), argc);
1590  } else {
1591    KeyedCallIC::GenerateMiss(masm(), argc);
1592  }
1593  Object* result;
1594  { MaybeObject* maybe_result = GetCodeWithFlags(flags, "CompileCallMiss");
1595    if (!maybe_result->ToObject(&result)) return maybe_result;
1596  }
1597  isolate()->counters()->call_megamorphic_stubs()->Increment();
1598  Code* code = Code::cast(result);
1599  USE(code);
1600  PROFILE(isolate(),
1601          CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_MISS_TAG),
1602                          code, code->arguments_count()));
1603  GDBJIT(AddCode(GDBJITInterface::CALL_MISS, Code::cast(code)));
1604  return result;
1605}
1606
1607
1608#ifdef ENABLE_DEBUGGER_SUPPORT
1609MaybeObject* StubCompiler::CompileCallDebugBreak(Code::Flags flags) {
1610  HandleScope scope(isolate());
1611  Debug::GenerateCallICDebugBreak(masm());
1612  Object* result;
1613  { MaybeObject* maybe_result =
1614        GetCodeWithFlags(flags, "CompileCallDebugBreak");
1615    if (!maybe_result->ToObject(&result)) return maybe_result;
1616  }
1617  Code* code = Code::cast(result);
1618  USE(code);
1619  Code::Kind kind = Code::ExtractKindFromFlags(flags);
1620  USE(kind);
1621  PROFILE(isolate(),
1622          CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_DEBUG_BREAK_TAG),
1623                          code, code->arguments_count()));
1624  return result;
1625}
1626
1627
1628MaybeObject* StubCompiler::CompileCallDebugPrepareStepIn(Code::Flags flags) {
1629  HandleScope scope(isolate());
1630  // Use the same code for the the step in preparations as we do for
1631  // the miss case.
1632  int argc = Code::ExtractArgumentsCountFromFlags(flags);
1633  Code::Kind kind = Code::ExtractKindFromFlags(flags);
1634  if (kind == Code::CALL_IC) {
1635    CallIC::GenerateMiss(masm(), argc);
1636  } else {
1637    KeyedCallIC::GenerateMiss(masm(), argc);
1638  }
1639  Object* result;
1640  { MaybeObject* maybe_result =
1641        GetCodeWithFlags(flags, "CompileCallDebugPrepareStepIn");
1642    if (!maybe_result->ToObject(&result)) return maybe_result;
1643  }
1644  Code* code = Code::cast(result);
1645  USE(code);
1646  PROFILE(isolate(),
1647          CodeCreateEvent(
1648              CALL_LOGGER_TAG(kind, CALL_DEBUG_PREPARE_STEP_IN_TAG),
1649              code,
1650              code->arguments_count()));
1651  return result;
1652}
1653#endif
1654
1655#undef CALL_LOGGER_TAG
1656
1657MaybeObject* StubCompiler::GetCodeWithFlags(Code::Flags flags,
1658                                            const char* name) {
1659  // Check for allocation failures during stub compilation.
1660  if (failure_->IsFailure()) return failure_;
1661
1662  // Create code object in the heap.
1663  CodeDesc desc;
1664  masm_.GetCode(&desc);
1665  MaybeObject* result = heap()->CreateCode(desc, flags, masm_.CodeObject());
1666#ifdef ENABLE_DISASSEMBLER
1667  if (FLAG_print_code_stubs && !result->IsFailure()) {
1668    Code::cast(result->ToObjectUnchecked())->Disassemble(name);
1669  }
1670#endif
1671  return result;
1672}
1673
1674
1675MaybeObject* StubCompiler::GetCodeWithFlags(Code::Flags flags, String* name) {
1676  if (FLAG_print_code_stubs && (name != NULL)) {
1677    return GetCodeWithFlags(flags, *name->ToCString());
1678  }
1679  return GetCodeWithFlags(flags, reinterpret_cast<char*>(NULL));
1680}
1681
1682
1683void StubCompiler::LookupPostInterceptor(JSObject* holder,
1684                                         String* name,
1685                                         LookupResult* lookup) {
1686  holder->LocalLookupRealNamedProperty(name, lookup);
1687  if (!lookup->IsProperty()) {
1688    lookup->NotFound();
1689    Object* proto = holder->GetPrototype();
1690    if (!proto->IsNull()) {
1691      proto->Lookup(name, lookup);
1692    }
1693  }
1694}
1695
1696
1697
1698MaybeObject* LoadStubCompiler::GetCode(PropertyType type, String* name) {
1699  Code::Flags flags = Code::ComputeMonomorphicFlags(Code::LOAD_IC, type);
1700  MaybeObject* result = GetCodeWithFlags(flags, name);
1701  if (!result->IsFailure()) {
1702    PROFILE(isolate(),
1703            CodeCreateEvent(Logger::LOAD_IC_TAG,
1704                            Code::cast(result->ToObjectUnchecked()),
1705                            name));
1706    GDBJIT(AddCode(GDBJITInterface::LOAD_IC,
1707                   name,
1708                   Code::cast(result->ToObjectUnchecked())));
1709  }
1710  return result;
1711}
1712
1713
1714MaybeObject* KeyedLoadStubCompiler::GetCode(PropertyType type, String* name) {
1715  Code::Flags flags = Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, type);
1716  MaybeObject* result = GetCodeWithFlags(flags, name);
1717  if (!result->IsFailure()) {
1718    PROFILE(isolate(),
1719            CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG,
1720                            Code::cast(result->ToObjectUnchecked()),
1721                            name));
1722    GDBJIT(AddCode(GDBJITInterface::LOAD_IC,
1723                   name,
1724                   Code::cast(result->ToObjectUnchecked())));
1725  }
1726  return result;
1727}
1728
1729
1730MaybeObject* StoreStubCompiler::GetCode(PropertyType type, String* name) {
1731  Code::Flags flags = Code::ComputeMonomorphicFlags(
1732      Code::STORE_IC, type, strict_mode_);
1733  MaybeObject* result = GetCodeWithFlags(flags, name);
1734  if (!result->IsFailure()) {
1735    PROFILE(isolate(),
1736            CodeCreateEvent(Logger::STORE_IC_TAG,
1737                            Code::cast(result->ToObjectUnchecked()),
1738                            name));
1739    GDBJIT(AddCode(GDBJITInterface::STORE_IC,
1740                   name,
1741                   Code::cast(result->ToObjectUnchecked())));
1742  }
1743  return result;
1744}
1745
1746
1747MaybeObject* KeyedStoreStubCompiler::GetCode(PropertyType type, String* name) {
1748  Code::Flags flags = Code::ComputeMonomorphicFlags(
1749      Code::KEYED_STORE_IC, type, strict_mode_);
1750  MaybeObject* result = GetCodeWithFlags(flags, name);
1751  if (!result->IsFailure()) {
1752    PROFILE(isolate(),
1753            CodeCreateEvent(Logger::KEYED_STORE_IC_TAG,
1754                            Code::cast(result->ToObjectUnchecked()),
1755                            name));
1756    GDBJIT(AddCode(GDBJITInterface::KEYED_STORE_IC,
1757                   name,
1758                   Code::cast(result->ToObjectUnchecked())));
1759  }
1760  return result;
1761}
1762
1763
1764CallStubCompiler::CallStubCompiler(int argc,
1765                                   InLoopFlag in_loop,
1766                                   Code::Kind kind,
1767                                   Code::ExtraICState extra_ic_state,
1768                                   InlineCacheHolderFlag cache_holder)
1769    : arguments_(argc),
1770      in_loop_(in_loop),
1771      kind_(kind),
1772      extra_ic_state_(extra_ic_state),
1773      cache_holder_(cache_holder) {
1774}
1775
1776
1777bool CallStubCompiler::HasCustomCallGenerator(JSFunction* function) {
1778  SharedFunctionInfo* info = function->shared();
1779  if (info->HasBuiltinFunctionId()) {
1780    BuiltinFunctionId id = info->builtin_function_id();
1781#define CALL_GENERATOR_CASE(name) if (id == k##name) return true;
1782    CUSTOM_CALL_IC_GENERATORS(CALL_GENERATOR_CASE)
1783#undef CALL_GENERATOR_CASE
1784  }
1785  CallOptimization optimization(function);
1786  if (optimization.is_simple_api_call()) {
1787    return true;
1788  }
1789  return false;
1790}
1791
1792
1793MaybeObject* CallStubCompiler::CompileCustomCall(Object* object,
1794                                                 JSObject* holder,
1795                                                 JSGlobalPropertyCell* cell,
1796                                                 JSFunction* function,
1797                                                 String* fname) {
1798  ASSERT(HasCustomCallGenerator(function));
1799
1800  SharedFunctionInfo* info = function->shared();
1801  if (info->HasBuiltinFunctionId()) {
1802    BuiltinFunctionId id = info->builtin_function_id();
1803#define CALL_GENERATOR_CASE(name)                           \
1804    if (id == k##name) {                                    \
1805      return CallStubCompiler::Compile##name##Call(object,  \
1806                                                  holder,   \
1807                                                  cell,     \
1808                                                  function, \
1809                                                  fname);   \
1810    }
1811    CUSTOM_CALL_IC_GENERATORS(CALL_GENERATOR_CASE)
1812#undef CALL_GENERATOR_CASE
1813  }
1814  CallOptimization optimization(function);
1815  ASSERT(optimization.is_simple_api_call());
1816  return CompileFastApiCall(optimization,
1817                            object,
1818                            holder,
1819                            cell,
1820                            function,
1821                            fname);
1822}
1823
1824
1825MaybeObject* CallStubCompiler::GetCode(PropertyType type, String* name) {
1826  int argc = arguments_.immediate();
1827  Code::Flags flags = Code::ComputeMonomorphicFlags(kind_,
1828                                                    type,
1829                                                    extra_ic_state_,
1830                                                    cache_holder_,
1831                                                    in_loop_,
1832                                                    argc);
1833  return GetCodeWithFlags(flags, name);
1834}
1835
1836
1837MaybeObject* CallStubCompiler::GetCode(JSFunction* function) {
1838  String* function_name = NULL;
1839  if (function->shared()->name()->IsString()) {
1840    function_name = String::cast(function->shared()->name());
1841  }
1842  return GetCode(CONSTANT_FUNCTION, function_name);
1843}
1844
1845
1846MaybeObject* ConstructStubCompiler::GetCode() {
1847  Code::Flags flags = Code::ComputeFlags(Code::STUB);
1848  Object* result;
1849  { MaybeObject* maybe_result = GetCodeWithFlags(flags, "ConstructStub");
1850    if (!maybe_result->ToObject(&result)) return maybe_result;
1851  }
1852  Code* code = Code::cast(result);
1853  USE(code);
1854  PROFILE(isolate(), CodeCreateEvent(Logger::STUB_TAG, code, "ConstructStub"));
1855  GDBJIT(AddCode(GDBJITInterface::STUB, "ConstructStub", Code::cast(code)));
1856  return result;
1857}
1858
1859
1860CallOptimization::CallOptimization(LookupResult* lookup) {
1861  if (!lookup->IsProperty() || !lookup->IsCacheable() ||
1862      lookup->type() != CONSTANT_FUNCTION) {
1863    Initialize(NULL);
1864  } else {
1865    // We only optimize constant function calls.
1866    Initialize(lookup->GetConstantFunction());
1867  }
1868}
1869
1870CallOptimization::CallOptimization(JSFunction* function) {
1871  Initialize(function);
1872}
1873
1874
1875int CallOptimization::GetPrototypeDepthOfExpectedType(JSObject* object,
1876                                                      JSObject* holder) const {
1877  ASSERT(is_simple_api_call_);
1878  if (expected_receiver_type_ == NULL) return 0;
1879  int depth = 0;
1880  while (object != holder) {
1881    if (object->IsInstanceOf(expected_receiver_type_)) return depth;
1882    object = JSObject::cast(object->GetPrototype());
1883    ++depth;
1884  }
1885  if (holder->IsInstanceOf(expected_receiver_type_)) return depth;
1886  return kInvalidProtoDepth;
1887}
1888
1889
1890void CallOptimization::Initialize(JSFunction* function) {
1891  constant_function_ = NULL;
1892  is_simple_api_call_ = false;
1893  expected_receiver_type_ = NULL;
1894  api_call_info_ = NULL;
1895
1896  if (function == NULL || !function->is_compiled()) return;
1897
1898  constant_function_ = function;
1899  AnalyzePossibleApiFunction(function);
1900}
1901
1902
1903void CallOptimization::AnalyzePossibleApiFunction(JSFunction* function) {
1904  SharedFunctionInfo* sfi = function->shared();
1905  if (!sfi->IsApiFunction()) return;
1906  FunctionTemplateInfo* info = sfi->get_api_func_data();
1907
1908  // Require a C++ callback.
1909  if (info->call_code()->IsUndefined()) return;
1910  api_call_info_ = CallHandlerInfo::cast(info->call_code());
1911
1912  // Accept signatures that either have no restrictions at all or
1913  // only have restrictions on the receiver.
1914  if (!info->signature()->IsUndefined()) {
1915    SignatureInfo* signature = SignatureInfo::cast(info->signature());
1916    if (!signature->args()->IsUndefined()) return;
1917    if (!signature->receiver()->IsUndefined()) {
1918      expected_receiver_type_ =
1919          FunctionTemplateInfo::cast(signature->receiver());
1920    }
1921  }
1922
1923  is_simple_api_call_ = true;
1924}
1925
1926
1927MaybeObject* ExternalArrayStubCompiler::GetCode(Code::Flags flags) {
1928  Object* result;
1929  { MaybeObject* maybe_result = GetCodeWithFlags(flags, "ExternalArrayStub");
1930    if (!maybe_result->ToObject(&result)) return maybe_result;
1931  }
1932  Code* code = Code::cast(result);
1933  USE(code);
1934  PROFILE(isolate(),
1935          CodeCreateEvent(Logger::STUB_TAG, code, "ExternalArrayStub"));
1936  return result;
1937}
1938
1939
1940} }  // namespace v8::internal
1941