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