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