• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
35 namespace v8 {
36 namespace internal {
37 
38 // -----------------------------------------------------------------------
39 // StubCache implementation.
40 
41 
42 StubCache::Entry StubCache::primary_[StubCache::kPrimaryTableSize];
43 StubCache::Entry StubCache::secondary_[StubCache::kSecondaryTableSize];
44 
Initialize(bool create_heap_objects)45 void StubCache::Initialize(bool create_heap_objects) {
46   ASSERT(IsPowerOf2(kPrimaryTableSize));
47   ASSERT(IsPowerOf2(kSecondaryTableSize));
48   if (create_heap_objects) {
49     HandleScope scope;
50     Clear();
51   }
52 }
53 
54 
Set(String * name,Map * map,Code * code)55 Code* StubCache::Set(String* name, Map* map, Code* code) {
56   // Get the flags from the code.
57   Code::Flags flags = Code::RemoveTypeFromFlags(code->flags());
58 
59   // Validate that the name does not move on scavenge, and that we
60   // can use identity checks instead of string equality checks.
61   ASSERT(!Heap::InNewSpace(name));
62   ASSERT(name->IsSymbol());
63 
64   // The state bits are not important to the hash function because
65   // the stub cache only contains monomorphic stubs. Make sure that
66   // the bits are the least significant so they will be the ones
67   // masked out.
68   ASSERT(Code::ExtractICStateFromFlags(flags) == MONOMORPHIC);
69   ASSERT(Code::kFlagsICStateShift == 0);
70 
71   // Make sure that the code type is not included in the hash.
72   ASSERT(Code::ExtractTypeFromFlags(flags) == 0);
73 
74   // Compute the primary entry.
75   int primary_offset = PrimaryOffset(name, flags, map);
76   Entry* primary = entry(primary_, primary_offset);
77   Code* hit = primary->value;
78 
79   // If the primary entry has useful data in it, we retire it to the
80   // secondary cache before overwriting it.
81   if (hit != Builtins::builtin(Builtins::Illegal)) {
82     Code::Flags primary_flags = Code::RemoveTypeFromFlags(hit->flags());
83     int secondary_offset =
84         SecondaryOffset(primary->key, primary_flags, primary_offset);
85     Entry* secondary = entry(secondary_, secondary_offset);
86     *secondary = *primary;
87   }
88 
89   // Update primary cache.
90   primary->key = name;
91   primary->value = code;
92   return code;
93 }
94 
95 
ComputeLoadField(String * name,JSObject * receiver,JSObject * holder,int field_index)96 Object* StubCache::ComputeLoadField(String* name,
97                                     JSObject* receiver,
98                                     JSObject* holder,
99                                     int field_index) {
100   Code::Flags flags = Code::ComputeMonomorphicFlags(Code::LOAD_IC, FIELD);
101   Object* code = receiver->map()->FindInCodeCache(name, flags);
102   if (code->IsUndefined()) {
103     LoadStubCompiler compiler;
104     code = compiler.CompileLoadField(receiver, holder, field_index, name);
105     if (code->IsFailure()) return code;
106     LOG(CodeCreateEvent(Logger::LOAD_IC_TAG, Code::cast(code), name));
107     Object* result = receiver->map()->UpdateCodeCache(name, Code::cast(code));
108     if (result->IsFailure()) return result;
109   }
110   return Set(name, receiver->map(), Code::cast(code));
111 }
112 
113 
ComputeLoadCallback(String * name,JSObject * receiver,JSObject * holder,AccessorInfo * callback)114 Object* StubCache::ComputeLoadCallback(String* name,
115                                        JSObject* receiver,
116                                        JSObject* holder,
117                                        AccessorInfo* callback) {
118   ASSERT(v8::ToCData<Address>(callback->getter()) != 0);
119   Code::Flags flags = Code::ComputeMonomorphicFlags(Code::LOAD_IC, CALLBACKS);
120   Object* code = receiver->map()->FindInCodeCache(name, flags);
121   if (code->IsUndefined()) {
122     LoadStubCompiler compiler;
123     code = compiler.CompileLoadCallback(name, receiver, holder, callback);
124     if (code->IsFailure()) return code;
125     LOG(CodeCreateEvent(Logger::LOAD_IC_TAG, Code::cast(code), name));
126     Object* result = receiver->map()->UpdateCodeCache(name, Code::cast(code));
127     if (result->IsFailure()) return result;
128   }
129   return Set(name, receiver->map(), Code::cast(code));
130 }
131 
132 
ComputeLoadConstant(String * name,JSObject * receiver,JSObject * holder,Object * value)133 Object* StubCache::ComputeLoadConstant(String* name,
134                                        JSObject* receiver,
135                                        JSObject* holder,
136                                        Object* value) {
137   Code::Flags flags =
138       Code::ComputeMonomorphicFlags(Code::LOAD_IC, CONSTANT_FUNCTION);
139   Object* code = receiver->map()->FindInCodeCache(name, flags);
140   if (code->IsUndefined()) {
141     LoadStubCompiler compiler;
142     code = compiler.CompileLoadConstant(receiver, holder, value, name);
143     if (code->IsFailure()) return code;
144     LOG(CodeCreateEvent(Logger::LOAD_IC_TAG, Code::cast(code), name));
145     Object* result = receiver->map()->UpdateCodeCache(name, Code::cast(code));
146     if (result->IsFailure()) return result;
147   }
148   return Set(name, receiver->map(), Code::cast(code));
149 }
150 
151 
ComputeLoadInterceptor(String * name,JSObject * receiver,JSObject * holder)152 Object* StubCache::ComputeLoadInterceptor(String* name,
153                                           JSObject* receiver,
154                                           JSObject* holder) {
155   Code::Flags flags = Code::ComputeMonomorphicFlags(Code::LOAD_IC, INTERCEPTOR);
156   Object* code = receiver->map()->FindInCodeCache(name, flags);
157   if (code->IsUndefined()) {
158     LoadStubCompiler compiler;
159     code = compiler.CompileLoadInterceptor(receiver, holder, name);
160     if (code->IsFailure()) return code;
161     LOG(CodeCreateEvent(Logger::LOAD_IC_TAG, Code::cast(code), name));
162     Object* result = receiver->map()->UpdateCodeCache(name, Code::cast(code));
163     if (result->IsFailure()) return result;
164   }
165   return Set(name, receiver->map(), Code::cast(code));
166 }
167 
168 
ComputeLoadNormal(String * name,JSObject * receiver)169 Object* StubCache::ComputeLoadNormal(String* name, JSObject* receiver) {
170   Code* code = Builtins::builtin(Builtins::LoadIC_Normal);
171   return Set(name, receiver->map(), code);
172 }
173 
174 
ComputeLoadGlobal(String * name,JSObject * receiver,GlobalObject * holder,JSGlobalPropertyCell * cell,bool is_dont_delete)175 Object* StubCache::ComputeLoadGlobal(String* name,
176                                      JSObject* receiver,
177                                      GlobalObject* holder,
178                                      JSGlobalPropertyCell* cell,
179                                      bool is_dont_delete) {
180   Code::Flags flags = Code::ComputeMonomorphicFlags(Code::LOAD_IC, NORMAL);
181   Object* code = receiver->map()->FindInCodeCache(name, flags);
182   if (code->IsUndefined()) {
183     LoadStubCompiler compiler;
184     code = compiler.CompileLoadGlobal(receiver,
185                                       holder,
186                                       cell,
187                                       name,
188                                       is_dont_delete);
189     if (code->IsFailure()) return code;
190     LOG(CodeCreateEvent(Logger::LOAD_IC_TAG, Code::cast(code), name));
191     Object* result = receiver->map()->UpdateCodeCache(name, Code::cast(code));
192     if (result->IsFailure()) return result;
193   }
194   return Set(name, receiver->map(), Code::cast(code));
195 }
196 
197 
ComputeKeyedLoadField(String * name,JSObject * receiver,JSObject * holder,int field_index)198 Object* StubCache::ComputeKeyedLoadField(String* name,
199                                          JSObject* receiver,
200                                          JSObject* holder,
201                                          int field_index) {
202   Code::Flags flags = Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, FIELD);
203   Object* code = receiver->map()->FindInCodeCache(name, flags);
204   if (code->IsUndefined()) {
205     KeyedLoadStubCompiler compiler;
206     code = compiler.CompileLoadField(name, receiver, holder, field_index);
207     if (code->IsFailure()) return code;
208     LOG(CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, Code::cast(code), name));
209     Object* result = receiver->map()->UpdateCodeCache(name, Code::cast(code));
210     if (result->IsFailure()) return result;
211   }
212   return code;
213 }
214 
215 
ComputeKeyedLoadConstant(String * name,JSObject * receiver,JSObject * holder,Object * value)216 Object* StubCache::ComputeKeyedLoadConstant(String* name,
217                                             JSObject* receiver,
218                                             JSObject* holder,
219                                             Object* value) {
220   Code::Flags flags =
221       Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, CONSTANT_FUNCTION);
222   Object* code = receiver->map()->FindInCodeCache(name, flags);
223   if (code->IsUndefined()) {
224     KeyedLoadStubCompiler compiler;
225     code = compiler.CompileLoadConstant(name, receiver, holder, value);
226     if (code->IsFailure()) return code;
227     LOG(CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, Code::cast(code), name));
228     Object* result = receiver->map()->UpdateCodeCache(name, Code::cast(code));
229     if (result->IsFailure()) return result;
230   }
231   return code;
232 }
233 
234 
ComputeKeyedLoadInterceptor(String * name,JSObject * receiver,JSObject * holder)235 Object* StubCache::ComputeKeyedLoadInterceptor(String* name,
236                                                JSObject* receiver,
237                                                JSObject* holder) {
238   Code::Flags flags =
239       Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, INTERCEPTOR);
240   Object* code = receiver->map()->FindInCodeCache(name, flags);
241   if (code->IsUndefined()) {
242     KeyedLoadStubCompiler compiler;
243     code = compiler.CompileLoadInterceptor(receiver, holder, name);
244     if (code->IsFailure()) return code;
245     LOG(CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, Code::cast(code), name));
246     Object* result = receiver->map()->UpdateCodeCache(name, Code::cast(code));
247     if (result->IsFailure()) return result;
248   }
249   return code;
250 }
251 
252 
ComputeKeyedLoadCallback(String * name,JSObject * receiver,JSObject * holder,AccessorInfo * callback)253 Object* StubCache::ComputeKeyedLoadCallback(String* name,
254                                             JSObject* receiver,
255                                             JSObject* holder,
256                                             AccessorInfo* callback) {
257   Code::Flags flags =
258       Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, CALLBACKS);
259   Object* code = receiver->map()->FindInCodeCache(name, flags);
260   if (code->IsUndefined()) {
261     KeyedLoadStubCompiler compiler;
262     code = compiler.CompileLoadCallback(name, receiver, holder, callback);
263     if (code->IsFailure()) return code;
264     LOG(CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, Code::cast(code), name));
265     Object* result = receiver->map()->UpdateCodeCache(name, Code::cast(code));
266     if (result->IsFailure()) return result;
267   }
268   return code;
269 }
270 
271 
272 
ComputeKeyedLoadArrayLength(String * name,JSArray * receiver)273 Object* StubCache::ComputeKeyedLoadArrayLength(String* name,
274                                                JSArray* receiver) {
275   Code::Flags flags =
276       Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, CALLBACKS);
277   Object* code = receiver->map()->FindInCodeCache(name, flags);
278   if (code->IsUndefined()) {
279     KeyedLoadStubCompiler compiler;
280     code = compiler.CompileLoadArrayLength(name);
281     if (code->IsFailure()) return code;
282     LOG(CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, Code::cast(code), name));
283     Object* result = receiver->map()->UpdateCodeCache(name, Code::cast(code));
284     if (result->IsFailure()) return result;
285   }
286   return code;
287 }
288 
289 
ComputeKeyedLoadStringLength(String * name,String * receiver)290 Object* StubCache::ComputeKeyedLoadStringLength(String* name,
291                                                 String* receiver) {
292   Code::Flags flags =
293       Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, CALLBACKS);
294   Object* code = receiver->map()->FindInCodeCache(name, flags);
295   if (code->IsUndefined()) {
296     KeyedLoadStubCompiler compiler;
297     code = compiler.CompileLoadStringLength(name);
298     if (code->IsFailure()) return code;
299     LOG(CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, Code::cast(code), name));
300     Object* result = receiver->map()->UpdateCodeCache(name, Code::cast(code));
301     if (result->IsFailure()) return result;
302   }
303   return code;
304 }
305 
306 
ComputeKeyedLoadFunctionPrototype(String * name,JSFunction * receiver)307 Object* StubCache::ComputeKeyedLoadFunctionPrototype(String* name,
308                                                      JSFunction* receiver) {
309   Code::Flags flags =
310       Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, CALLBACKS);
311   Object* code = receiver->map()->FindInCodeCache(name, flags);
312   if (code->IsUndefined()) {
313     KeyedLoadStubCompiler compiler;
314     code = compiler.CompileLoadFunctionPrototype(name);
315     if (code->IsFailure()) return code;
316     LOG(CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, Code::cast(code), name));
317     Object* result = receiver->map()->UpdateCodeCache(name, Code::cast(code));
318     if (result->IsFailure()) return result;
319   }
320   return code;
321 }
322 
323 
ComputeStoreField(String * name,JSObject * receiver,int field_index,Map * transition)324 Object* StubCache::ComputeStoreField(String* name,
325                                      JSObject* receiver,
326                                      int field_index,
327                                      Map* transition) {
328   PropertyType type = (transition == NULL) ? FIELD : MAP_TRANSITION;
329   Code::Flags flags = Code::ComputeMonomorphicFlags(Code::STORE_IC, type);
330   Object* code = receiver->map()->FindInCodeCache(name, flags);
331   if (code->IsUndefined()) {
332     StoreStubCompiler compiler;
333     code = compiler.CompileStoreField(receiver, field_index, transition, name);
334     if (code->IsFailure()) return code;
335     LOG(CodeCreateEvent(Logger::STORE_IC_TAG, Code::cast(code), name));
336     Object* result = receiver->map()->UpdateCodeCache(name, Code::cast(code));
337     if (result->IsFailure()) return result;
338   }
339   return Set(name, receiver->map(), Code::cast(code));
340 }
341 
342 
ComputeStoreGlobal(String * name,GlobalObject * receiver,JSGlobalPropertyCell * cell)343 Object* StubCache::ComputeStoreGlobal(String* name,
344                                       GlobalObject* receiver,
345                                       JSGlobalPropertyCell* cell) {
346   Code::Flags flags = Code::ComputeMonomorphicFlags(Code::STORE_IC, NORMAL);
347   Object* code = receiver->map()->FindInCodeCache(name, flags);
348   if (code->IsUndefined()) {
349     StoreStubCompiler compiler;
350     code = compiler.CompileStoreGlobal(receiver, cell, name);
351     if (code->IsFailure()) return code;
352     LOG(CodeCreateEvent(Logger::LOAD_IC_TAG, Code::cast(code), name));
353     Object* result = receiver->map()->UpdateCodeCache(name, Code::cast(code));
354     if (result->IsFailure()) return result;
355   }
356   return Set(name, receiver->map(), Code::cast(code));
357 }
358 
359 
ComputeStoreCallback(String * name,JSObject * receiver,AccessorInfo * callback)360 Object* StubCache::ComputeStoreCallback(String* name,
361                                         JSObject* receiver,
362                                         AccessorInfo* callback) {
363   ASSERT(v8::ToCData<Address>(callback->setter()) != 0);
364   Code::Flags flags = Code::ComputeMonomorphicFlags(Code::STORE_IC, CALLBACKS);
365   Object* code = receiver->map()->FindInCodeCache(name, flags);
366   if (code->IsUndefined()) {
367     StoreStubCompiler compiler;
368     code = compiler.CompileStoreCallback(receiver, callback, name);
369     if (code->IsFailure()) return code;
370     LOG(CodeCreateEvent(Logger::STORE_IC_TAG, Code::cast(code), name));
371     Object* result = receiver->map()->UpdateCodeCache(name, Code::cast(code));
372     if (result->IsFailure()) return result;
373   }
374   return Set(name, receiver->map(), Code::cast(code));
375 }
376 
377 
ComputeStoreInterceptor(String * name,JSObject * receiver)378 Object* StubCache::ComputeStoreInterceptor(String* name,
379                                            JSObject* receiver) {
380   Code::Flags flags =
381       Code::ComputeMonomorphicFlags(Code::STORE_IC, INTERCEPTOR);
382   Object* code = receiver->map()->FindInCodeCache(name, flags);
383   if (code->IsUndefined()) {
384     StoreStubCompiler compiler;
385     code = compiler.CompileStoreInterceptor(receiver, name);
386     if (code->IsFailure()) return code;
387     LOG(CodeCreateEvent(Logger::STORE_IC_TAG, Code::cast(code), name));
388     Object* result = receiver->map()->UpdateCodeCache(name, Code::cast(code));
389     if (result->IsFailure()) return result;
390   }
391   return Set(name, receiver->map(), Code::cast(code));
392 }
393 
394 
ComputeKeyedStoreField(String * name,JSObject * receiver,int field_index,Map * transition)395 Object* StubCache::ComputeKeyedStoreField(String* name, JSObject* receiver,
396                                           int field_index, Map* transition) {
397   PropertyType type = (transition == NULL) ? FIELD : MAP_TRANSITION;
398   Code::Flags flags = Code::ComputeMonomorphicFlags(Code::KEYED_STORE_IC, type);
399   Object* code = receiver->map()->FindInCodeCache(name, flags);
400   if (code->IsUndefined()) {
401     KeyedStoreStubCompiler compiler;
402     code = compiler.CompileStoreField(receiver, field_index, transition, name);
403     if (code->IsFailure()) return code;
404     LOG(CodeCreateEvent(Logger::KEYED_STORE_IC_TAG, Code::cast(code), name));
405     Object* result = receiver->map()->UpdateCodeCache(name, Code::cast(code));
406     if (result->IsFailure()) return result;
407   }
408   return code;
409 }
410 
411 
ComputeCallConstant(int argc,InLoopFlag in_loop,String * name,Object * object,JSObject * holder,JSFunction * function)412 Object* StubCache::ComputeCallConstant(int argc,
413                                        InLoopFlag in_loop,
414                                        String* name,
415                                        Object* object,
416                                        JSObject* holder,
417                                        JSFunction* function) {
418   // Compute the check type and the map.
419   Map* map = IC::GetCodeCacheMapForObject(object);
420 
421   // Compute check type based on receiver/holder.
422   StubCompiler::CheckType check = StubCompiler::RECEIVER_MAP_CHECK;
423   if (object->IsString()) {
424     check = StubCompiler::STRING_CHECK;
425   } else if (object->IsNumber()) {
426     check = StubCompiler::NUMBER_CHECK;
427   } else if (object->IsBoolean()) {
428     check = StubCompiler::BOOLEAN_CHECK;
429   }
430 
431   Code::Flags flags =
432       Code::ComputeMonomorphicFlags(Code::CALL_IC,
433                                     CONSTANT_FUNCTION,
434                                     in_loop,
435                                     argc);
436   Object* code = map->FindInCodeCache(name, flags);
437   if (code->IsUndefined()) {
438     if (object->IsJSObject()) {
439       Object* opt =
440           Top::LookupSpecialFunction(JSObject::cast(object), holder, function);
441       if (opt->IsJSFunction()) {
442         check = StubCompiler::JSARRAY_HAS_FAST_ELEMENTS_CHECK;
443         function = JSFunction::cast(opt);
444       }
445     }
446     // If the function hasn't been compiled yet, we cannot do it now
447     // because it may cause GC. To avoid this issue, we return an
448     // internal error which will make sure we do not update any
449     // caches.
450     if (!function->is_compiled()) return Failure::InternalError();
451     // Compile the stub - only create stubs for fully compiled functions.
452     CallStubCompiler compiler(argc, in_loop);
453     code = compiler.CompileCallConstant(object, holder, function, name, check);
454     if (code->IsFailure()) return code;
455     ASSERT_EQ(flags, Code::cast(code)->flags());
456     LOG(CodeCreateEvent(Logger::CALL_IC_TAG, Code::cast(code), name));
457     Object* result = map->UpdateCodeCache(name, Code::cast(code));
458     if (result->IsFailure()) return result;
459   }
460   return Set(name, map, Code::cast(code));
461 }
462 
463 
ComputeCallField(int argc,InLoopFlag in_loop,String * name,Object * object,JSObject * holder,int index)464 Object* StubCache::ComputeCallField(int argc,
465                                     InLoopFlag in_loop,
466                                     String* name,
467                                     Object* object,
468                                     JSObject* holder,
469                                     int index) {
470   // Compute the check type and the map.
471   Map* map = IC::GetCodeCacheMapForObject(object);
472 
473   // TODO(1233596): We cannot do receiver map check for non-JS objects
474   // because they may be represented as immediates without a
475   // map. Instead, we check against the map in the holder.
476   if (object->IsNumber() || object->IsBoolean() || object->IsString()) {
477     object = holder;
478   }
479 
480   Code::Flags flags = Code::ComputeMonomorphicFlags(Code::CALL_IC,
481                                                     FIELD,
482                                                     in_loop,
483                                                     argc);
484   Object* code = map->FindInCodeCache(name, flags);
485   if (code->IsUndefined()) {
486     CallStubCompiler compiler(argc, in_loop);
487     code = compiler.CompileCallField(JSObject::cast(object),
488                                      holder,
489                                      index,
490                                      name);
491     if (code->IsFailure()) return code;
492     ASSERT_EQ(flags, Code::cast(code)->flags());
493     LOG(CodeCreateEvent(Logger::CALL_IC_TAG, Code::cast(code), name));
494     Object* result = map->UpdateCodeCache(name, Code::cast(code));
495     if (result->IsFailure()) return result;
496   }
497   return Set(name, map, Code::cast(code));
498 }
499 
500 
ComputeCallInterceptor(int argc,String * name,Object * object,JSObject * holder)501 Object* StubCache::ComputeCallInterceptor(int argc,
502                                           String* name,
503                                           Object* object,
504                                           JSObject* holder) {
505   // Compute the check type and the map.
506   // If the object is a value, we use the prototype map for the cache.
507   Map* map = IC::GetCodeCacheMapForObject(object);
508 
509   // TODO(1233596): We cannot do receiver map check for non-JS objects
510   // because they may be represented as immediates without a
511   // map. Instead, we check against the map in the holder.
512   if (object->IsNumber() || object->IsBoolean() || object->IsString()) {
513     object = holder;
514   }
515 
516   Code::Flags flags =
517       Code::ComputeMonomorphicFlags(Code::CALL_IC,
518                                     INTERCEPTOR,
519                                     NOT_IN_LOOP,
520                                     argc);
521   Object* code = map->FindInCodeCache(name, flags);
522   if (code->IsUndefined()) {
523     CallStubCompiler compiler(argc, NOT_IN_LOOP);
524     code = compiler.CompileCallInterceptor(JSObject::cast(object),
525                                            holder,
526                                            name);
527     if (code->IsFailure()) return code;
528     ASSERT_EQ(flags, Code::cast(code)->flags());
529     LOG(CodeCreateEvent(Logger::CALL_IC_TAG, Code::cast(code), name));
530     Object* result = map->UpdateCodeCache(name, Code::cast(code));
531     if (result->IsFailure()) return result;
532   }
533   return Set(name, map, Code::cast(code));
534 }
535 
536 
ComputeCallNormal(int argc,InLoopFlag in_loop,String * name,JSObject * receiver)537 Object* StubCache::ComputeCallNormal(int argc,
538                                      InLoopFlag in_loop,
539                                      String* name,
540                                      JSObject* receiver) {
541   Object* code = ComputeCallNormal(argc, in_loop);
542   if (code->IsFailure()) return code;
543   return Set(name, receiver->map(), Code::cast(code));
544 }
545 
546 
ComputeCallGlobal(int argc,InLoopFlag in_loop,String * name,JSObject * receiver,GlobalObject * holder,JSGlobalPropertyCell * cell,JSFunction * function)547 Object* StubCache::ComputeCallGlobal(int argc,
548                                      InLoopFlag in_loop,
549                                      String* name,
550                                      JSObject* receiver,
551                                      GlobalObject* holder,
552                                      JSGlobalPropertyCell* cell,
553                                      JSFunction* function) {
554   Code::Flags flags =
555       Code::ComputeMonomorphicFlags(Code::CALL_IC, NORMAL, in_loop, argc);
556   Object* code = receiver->map()->FindInCodeCache(name, flags);
557   if (code->IsUndefined()) {
558     // If the function hasn't been compiled yet, we cannot do it now
559     // because it may cause GC. To avoid this issue, we return an
560     // internal error which will make sure we do not update any
561     // caches.
562     if (!function->is_compiled()) return Failure::InternalError();
563     CallStubCompiler compiler(argc, in_loop);
564     code = compiler.CompileCallGlobal(receiver, holder, cell, function, name);
565     if (code->IsFailure()) return code;
566     ASSERT_EQ(flags, Code::cast(code)->flags());
567     LOG(CodeCreateEvent(Logger::CALL_IC_TAG, Code::cast(code), name));
568     Object* result = receiver->map()->UpdateCodeCache(name, Code::cast(code));
569     if (result->IsFailure()) return result;
570   }
571   return Set(name, receiver->map(), Code::cast(code));
572 }
573 
574 
GetProbeValue(Code::Flags flags)575 static Object* GetProbeValue(Code::Flags flags) {
576   // Use raw_unchecked... so we don't get assert failures during GC.
577   NumberDictionary* dictionary = Heap::raw_unchecked_non_monomorphic_cache();
578   int entry = dictionary->FindEntry(flags);
579   if (entry != -1) return dictionary->ValueAt(entry);
580   return Heap::raw_unchecked_undefined_value();
581 }
582 
583 
ProbeCache(Code::Flags flags)584 static Object* ProbeCache(Code::Flags flags) {
585   Object* probe = GetProbeValue(flags);
586   if (probe != Heap::undefined_value()) return probe;
587   // Seed the cache with an undefined value to make sure that any
588   // generated code object can always be inserted into the cache
589   // without causing  allocation failures.
590   Object* result =
591       Heap::non_monomorphic_cache()->AtNumberPut(flags,
592                                                  Heap::undefined_value());
593   if (result->IsFailure()) return result;
594   Heap::public_set_non_monomorphic_cache(NumberDictionary::cast(result));
595   return probe;
596 }
597 
598 
FillCache(Object * code)599 static Object* FillCache(Object* code) {
600   if (code->IsCode()) {
601     int entry =
602         Heap::non_monomorphic_cache()->FindEntry(
603             Code::cast(code)->flags());
604     // The entry must be present see comment in ProbeCache.
605     ASSERT(entry != -1);
606     ASSERT(Heap::non_monomorphic_cache()->ValueAt(entry) ==
607            Heap::undefined_value());
608     Heap::non_monomorphic_cache()->ValueAtPut(entry, code);
609     CHECK(GetProbeValue(Code::cast(code)->flags()) == code);
610   }
611   return code;
612 }
613 
614 
FindCallInitialize(int argc,InLoopFlag in_loop)615 Code* StubCache::FindCallInitialize(int argc, InLoopFlag in_loop) {
616   Code::Flags flags =
617       Code::ComputeFlags(Code::CALL_IC, in_loop, UNINITIALIZED, NORMAL, argc);
618   Object* result = ProbeCache(flags);
619   ASSERT(!result->IsUndefined());
620   // This might be called during the marking phase of the collector
621   // hence the unchecked cast.
622   return reinterpret_cast<Code*>(result);
623 }
624 
625 
ComputeCallInitialize(int argc,InLoopFlag in_loop)626 Object* StubCache::ComputeCallInitialize(int argc, InLoopFlag in_loop) {
627   Code::Flags flags =
628       Code::ComputeFlags(Code::CALL_IC, in_loop, UNINITIALIZED, NORMAL, argc);
629   Object* probe = ProbeCache(flags);
630   if (!probe->IsUndefined()) return probe;
631   StubCompiler compiler;
632   return FillCache(compiler.CompileCallInitialize(flags));
633 }
634 
635 
ComputeCallPreMonomorphic(int argc,InLoopFlag in_loop)636 Object* StubCache::ComputeCallPreMonomorphic(int argc, InLoopFlag in_loop) {
637   Code::Flags flags =
638       Code::ComputeFlags(Code::CALL_IC, in_loop, PREMONOMORPHIC, NORMAL, argc);
639   Object* probe = ProbeCache(flags);
640   if (!probe->IsUndefined()) return probe;
641   StubCompiler compiler;
642   return FillCache(compiler.CompileCallPreMonomorphic(flags));
643 }
644 
645 
ComputeCallNormal(int argc,InLoopFlag in_loop)646 Object* StubCache::ComputeCallNormal(int argc, InLoopFlag in_loop) {
647   Code::Flags flags =
648       Code::ComputeFlags(Code::CALL_IC, in_loop, MONOMORPHIC, NORMAL, argc);
649   Object* probe = ProbeCache(flags);
650   if (!probe->IsUndefined()) return probe;
651   StubCompiler compiler;
652   return FillCache(compiler.CompileCallNormal(flags));
653 }
654 
655 
ComputeCallMegamorphic(int argc,InLoopFlag in_loop)656 Object* StubCache::ComputeCallMegamorphic(int argc, InLoopFlag in_loop) {
657   Code::Flags flags =
658       Code::ComputeFlags(Code::CALL_IC, in_loop, MEGAMORPHIC, NORMAL, argc);
659   Object* probe = ProbeCache(flags);
660   if (!probe->IsUndefined()) return probe;
661   StubCompiler compiler;
662   return FillCache(compiler.CompileCallMegamorphic(flags));
663 }
664 
665 
ComputeCallMiss(int argc)666 Object* StubCache::ComputeCallMiss(int argc) {
667   Code::Flags flags =
668       Code::ComputeFlags(Code::STUB, NOT_IN_LOOP, MEGAMORPHIC, NORMAL, argc);
669   Object* probe = ProbeCache(flags);
670   if (!probe->IsUndefined()) return probe;
671   StubCompiler compiler;
672   return FillCache(compiler.CompileCallMiss(flags));
673 }
674 
675 
676 #ifdef ENABLE_DEBUGGER_SUPPORT
ComputeCallDebugBreak(int argc)677 Object* StubCache::ComputeCallDebugBreak(int argc) {
678   Code::Flags flags =
679       Code::ComputeFlags(Code::CALL_IC, NOT_IN_LOOP, DEBUG_BREAK, NORMAL, argc);
680   Object* probe = ProbeCache(flags);
681   if (!probe->IsUndefined()) return probe;
682   StubCompiler compiler;
683   return FillCache(compiler.CompileCallDebugBreak(flags));
684 }
685 
686 
ComputeCallDebugPrepareStepIn(int argc)687 Object* StubCache::ComputeCallDebugPrepareStepIn(int argc) {
688   Code::Flags flags =
689       Code::ComputeFlags(Code::CALL_IC,
690                          NOT_IN_LOOP,
691                          DEBUG_PREPARE_STEP_IN,
692                          NORMAL,
693                          argc);
694   Object* probe = ProbeCache(flags);
695   if (!probe->IsUndefined()) return probe;
696   StubCompiler compiler;
697   return FillCache(compiler.CompileCallDebugPrepareStepIn(flags));
698 }
699 #endif
700 
701 
ComputeLazyCompile(int argc)702 Object* StubCache::ComputeLazyCompile(int argc) {
703   Code::Flags flags =
704       Code::ComputeFlags(Code::STUB, NOT_IN_LOOP, UNINITIALIZED, NORMAL, argc);
705   Object* probe = ProbeCache(flags);
706   if (!probe->IsUndefined()) return probe;
707   StubCompiler compiler;
708   Object* result = FillCache(compiler.CompileLazyCompile(flags));
709   if (result->IsCode()) {
710     Code* code = Code::cast(result);
711     USE(code);
712     LOG(CodeCreateEvent(Logger::LAZY_COMPILE_TAG,
713                         code, code->arguments_count()));
714   }
715   return result;
716 }
717 
718 
Clear()719 void StubCache::Clear() {
720   for (int i = 0; i < kPrimaryTableSize; i++) {
721     primary_[i].key = Heap::empty_string();
722     primary_[i].value = Builtins::builtin(Builtins::Illegal);
723   }
724   for (int j = 0; j < kSecondaryTableSize; j++) {
725     secondary_[j].key = Heap::empty_string();
726     secondary_[j].value = Builtins::builtin(Builtins::Illegal);
727   }
728 }
729 
730 
731 // ------------------------------------------------------------------------
732 // StubCompiler implementation.
733 
734 
735 // Support function for computing call IC miss stubs.
ComputeCallMiss(int argc)736 Handle<Code> ComputeCallMiss(int argc) {
737   CALL_HEAP_FUNCTION(StubCache::ComputeCallMiss(argc), Code);
738 }
739 
740 
741 
LoadCallbackProperty(Arguments args)742 Object* LoadCallbackProperty(Arguments args) {
743   ASSERT(args[0]->IsJSObject());
744   ASSERT(args[1]->IsJSObject());
745   AccessorInfo* callback = AccessorInfo::cast(args[2]);
746   Address getter_address = v8::ToCData<Address>(callback->getter());
747   v8::AccessorGetter fun = FUNCTION_CAST<v8::AccessorGetter>(getter_address);
748   ASSERT(fun != NULL);
749   CustomArguments custom_args(callback->data(),
750                               JSObject::cast(args[0]),
751                               JSObject::cast(args[1]));
752   v8::AccessorInfo info(custom_args.end());
753   HandleScope scope;
754   v8::Handle<v8::Value> result;
755   {
756     // Leaving JavaScript.
757     VMState state(EXTERNAL);
758 #ifdef ENABLE_LOGGING_AND_PROFILING
759     state.set_external_callback(getter_address);
760 #endif
761     result = fun(v8::Utils::ToLocal(args.at<String>(4)), info);
762   }
763   RETURN_IF_SCHEDULED_EXCEPTION();
764   if (result.IsEmpty()) return Heap::undefined_value();
765   return *v8::Utils::OpenHandle(*result);
766 }
767 
768 
StoreCallbackProperty(Arguments args)769 Object* StoreCallbackProperty(Arguments args) {
770   JSObject* recv = JSObject::cast(args[0]);
771   AccessorInfo* callback = AccessorInfo::cast(args[1]);
772   Address setter_address = v8::ToCData<Address>(callback->setter());
773   v8::AccessorSetter fun = FUNCTION_CAST<v8::AccessorSetter>(setter_address);
774   ASSERT(fun != NULL);
775   Handle<String> name = args.at<String>(2);
776   Handle<Object> value = args.at<Object>(3);
777   HandleScope scope;
778   LOG(ApiNamedPropertyAccess("store", recv, *name));
779   CustomArguments custom_args(callback->data(), recv, recv);
780   v8::AccessorInfo info(custom_args.end());
781   {
782     // Leaving JavaScript.
783     VMState state(EXTERNAL);
784 #ifdef ENABLE_LOGGING_AND_PROFILING
785     state.set_external_callback(setter_address);
786 #endif
787     fun(v8::Utils::ToLocal(name), v8::Utils::ToLocal(value), info);
788   }
789   RETURN_IF_SCHEDULED_EXCEPTION();
790   return *value;
791 }
792 
793 /**
794  * Attempts to load a property with an interceptor (which must be present),
795  * but doesn't search the prototype chain.
796  *
797  * Returns |Heap::no_interceptor_result_sentinel()| if interceptor doesn't
798  * provide any value for the given name.
799  */
LoadPropertyWithInterceptorOnly(Arguments args)800 Object* LoadPropertyWithInterceptorOnly(Arguments args) {
801   JSObject* receiver_handle = JSObject::cast(args[0]);
802   JSObject* holder_handle = JSObject::cast(args[1]);
803   Handle<String> name_handle = args.at<String>(2);
804   Handle<InterceptorInfo> interceptor_info = args.at<InterceptorInfo>(3);
805   Object* data_handle = args[4];
806 
807   Address getter_address = v8::ToCData<Address>(interceptor_info->getter());
808   v8::NamedPropertyGetter getter =
809       FUNCTION_CAST<v8::NamedPropertyGetter>(getter_address);
810   ASSERT(getter != NULL);
811 
812   {
813     // Use the interceptor getter.
814     CustomArguments args(data_handle, receiver_handle, holder_handle);
815     v8::AccessorInfo info(args.end());
816     HandleScope scope;
817     v8::Handle<v8::Value> r;
818     {
819       // Leaving JavaScript.
820       VMState state(EXTERNAL);
821       r = getter(v8::Utils::ToLocal(name_handle), info);
822     }
823     RETURN_IF_SCHEDULED_EXCEPTION();
824     if (!r.IsEmpty()) {
825       return *v8::Utils::OpenHandle(*r);
826     }
827   }
828 
829   return Heap::no_interceptor_result_sentinel();
830 }
831 
832 
ThrowReferenceError(String * name)833 static Object* ThrowReferenceError(String* name) {
834   // If the load is non-contextual, just return the undefined result.
835   // Note that both keyed and non-keyed loads may end up here, so we
836   // can't use either LoadIC or KeyedLoadIC constructors.
837   IC ic(IC::NO_EXTRA_FRAME);
838   ASSERT(ic.target()->is_load_stub() || ic.target()->is_keyed_load_stub());
839   if (!ic.SlowIsContextual()) return Heap::undefined_value();
840 
841   // Throw a reference error.
842   HandleScope scope;
843   Handle<String> name_handle(name);
844   Handle<Object> error =
845       Factory::NewReferenceError("not_defined",
846                                   HandleVector(&name_handle, 1));
847   return Top::Throw(*error);
848 }
849 
850 
LoadWithInterceptor(Arguments * args,PropertyAttributes * attrs)851 static Object* LoadWithInterceptor(Arguments* args,
852                                    PropertyAttributes* attrs) {
853   Handle<JSObject> receiver_handle = args->at<JSObject>(0);
854   Handle<JSObject> holder_handle = args->at<JSObject>(1);
855   Handle<String> name_handle = args->at<String>(2);
856   Handle<InterceptorInfo> interceptor_info = args->at<InterceptorInfo>(3);
857   Handle<Object> data_handle = args->at<Object>(4);
858 
859   Address getter_address = v8::ToCData<Address>(interceptor_info->getter());
860   v8::NamedPropertyGetter getter =
861       FUNCTION_CAST<v8::NamedPropertyGetter>(getter_address);
862   ASSERT(getter != NULL);
863 
864   {
865     // Use the interceptor getter.
866     CustomArguments args(*data_handle, *receiver_handle, *holder_handle);
867     v8::AccessorInfo info(args.end());
868     HandleScope scope;
869     v8::Handle<v8::Value> r;
870     {
871       // Leaving JavaScript.
872       VMState state(EXTERNAL);
873       r = getter(v8::Utils::ToLocal(name_handle), info);
874     }
875     RETURN_IF_SCHEDULED_EXCEPTION();
876     if (!r.IsEmpty()) {
877       *attrs = NONE;
878       return *v8::Utils::OpenHandle(*r);
879     }
880   }
881 
882   Object* result = holder_handle->GetPropertyPostInterceptor(
883       *receiver_handle,
884       *name_handle,
885       attrs);
886   RETURN_IF_SCHEDULED_EXCEPTION();
887   return result;
888 }
889 
890 
891 /**
892  * Loads a property with an interceptor performing post interceptor
893  * lookup if interceptor failed.
894  */
LoadPropertyWithInterceptorForLoad(Arguments args)895 Object* LoadPropertyWithInterceptorForLoad(Arguments args) {
896   PropertyAttributes attr = NONE;
897   Object* result = LoadWithInterceptor(&args, &attr);
898   if (result->IsFailure()) return result;
899 
900   // If the property is present, return it.
901   if (attr != ABSENT) return result;
902   return ThrowReferenceError(String::cast(args[2]));
903 }
904 
905 
LoadPropertyWithInterceptorForCall(Arguments args)906 Object* LoadPropertyWithInterceptorForCall(Arguments args) {
907   PropertyAttributes attr;
908   Object* result = LoadWithInterceptor(&args, &attr);
909   RETURN_IF_SCHEDULED_EXCEPTION();
910   // This is call IC. In this case, we simply return the undefined result which
911   // will lead to an exception when trying to invoke the result as a
912   // function.
913   return result;
914 }
915 
916 
StoreInterceptorProperty(Arguments args)917 Object* StoreInterceptorProperty(Arguments args) {
918   JSObject* recv = JSObject::cast(args[0]);
919   String* name = String::cast(args[1]);
920   Object* value = args[2];
921   ASSERT(recv->HasNamedInterceptor());
922   PropertyAttributes attr = NONE;
923   Object* result = recv->SetPropertyWithInterceptor(name, value, attr);
924   return result;
925 }
926 
927 
KeyedLoadPropertyWithInterceptor(Arguments args)928 Object* KeyedLoadPropertyWithInterceptor(Arguments args) {
929   JSObject* receiver = JSObject::cast(args[0]);
930   uint32_t index = Smi::cast(args[1])->value();
931   return receiver->GetElementWithInterceptor(receiver, index);
932 }
933 
934 
CompileCallInitialize(Code::Flags flags)935 Object* StubCompiler::CompileCallInitialize(Code::Flags flags) {
936   HandleScope scope;
937   int argc = Code::ExtractArgumentsCountFromFlags(flags);
938   CallIC::GenerateInitialize(masm(), argc);
939   Object* result = GetCodeWithFlags(flags, "CompileCallInitialize");
940   if (!result->IsFailure()) {
941     Counters::call_initialize_stubs.Increment();
942     Code* code = Code::cast(result);
943     USE(code);
944     LOG(CodeCreateEvent(Logger::CALL_INITIALIZE_TAG,
945                         code, code->arguments_count()));
946   }
947   return result;
948 }
949 
950 
CompileCallPreMonomorphic(Code::Flags flags)951 Object* StubCompiler::CompileCallPreMonomorphic(Code::Flags flags) {
952   HandleScope scope;
953   int argc = Code::ExtractArgumentsCountFromFlags(flags);
954   // The code of the PreMonomorphic stub is the same as the code
955   // of the Initialized stub.  They just differ on the code object flags.
956   CallIC::GenerateInitialize(masm(), argc);
957   Object* result = GetCodeWithFlags(flags, "CompileCallPreMonomorphic");
958   if (!result->IsFailure()) {
959     Counters::call_premonomorphic_stubs.Increment();
960     Code* code = Code::cast(result);
961     USE(code);
962     LOG(CodeCreateEvent(Logger::CALL_PRE_MONOMORPHIC_TAG,
963                         code, code->arguments_count()));
964   }
965   return result;
966 }
967 
968 
CompileCallNormal(Code::Flags flags)969 Object* StubCompiler::CompileCallNormal(Code::Flags flags) {
970   HandleScope scope;
971   int argc = Code::ExtractArgumentsCountFromFlags(flags);
972   CallIC::GenerateNormal(masm(), argc);
973   Object* result = GetCodeWithFlags(flags, "CompileCallNormal");
974   if (!result->IsFailure()) {
975     Counters::call_normal_stubs.Increment();
976     Code* code = Code::cast(result);
977     USE(code);
978     LOG(CodeCreateEvent(Logger::CALL_NORMAL_TAG,
979                         code, code->arguments_count()));
980   }
981   return result;
982 }
983 
984 
CompileCallMegamorphic(Code::Flags flags)985 Object* StubCompiler::CompileCallMegamorphic(Code::Flags flags) {
986   HandleScope scope;
987   int argc = Code::ExtractArgumentsCountFromFlags(flags);
988   CallIC::GenerateMegamorphic(masm(), argc);
989   Object* result = GetCodeWithFlags(flags, "CompileCallMegamorphic");
990   if (!result->IsFailure()) {
991     Counters::call_megamorphic_stubs.Increment();
992     Code* code = Code::cast(result);
993     USE(code);
994     LOG(CodeCreateEvent(Logger::CALL_MEGAMORPHIC_TAG,
995                         code, code->arguments_count()));
996   }
997   return result;
998 }
999 
1000 
CompileCallMiss(Code::Flags flags)1001 Object* StubCompiler::CompileCallMiss(Code::Flags flags) {
1002   HandleScope scope;
1003   int argc = Code::ExtractArgumentsCountFromFlags(flags);
1004   CallIC::GenerateMiss(masm(), argc);
1005   Object* result = GetCodeWithFlags(flags, "CompileCallMiss");
1006   if (!result->IsFailure()) {
1007     Counters::call_megamorphic_stubs.Increment();
1008     Code* code = Code::cast(result);
1009     USE(code);
1010     LOG(CodeCreateEvent(Logger::CALL_MISS_TAG, code, code->arguments_count()));
1011   }
1012   return result;
1013 }
1014 
1015 
1016 #ifdef ENABLE_DEBUGGER_SUPPORT
CompileCallDebugBreak(Code::Flags flags)1017 Object* StubCompiler::CompileCallDebugBreak(Code::Flags flags) {
1018   HandleScope scope;
1019   Debug::GenerateCallICDebugBreak(masm());
1020   Object* result = GetCodeWithFlags(flags, "CompileCallDebugBreak");
1021   if (!result->IsFailure()) {
1022     Code* code = Code::cast(result);
1023     USE(code);
1024     LOG(CodeCreateEvent(Logger::CALL_DEBUG_BREAK_TAG,
1025                         code, code->arguments_count()));
1026   }
1027   return result;
1028 }
1029 
1030 
CompileCallDebugPrepareStepIn(Code::Flags flags)1031 Object* StubCompiler::CompileCallDebugPrepareStepIn(Code::Flags flags) {
1032   HandleScope scope;
1033   // Use the same code for the the step in preparations as we do for
1034   // the miss case.
1035   int argc = Code::ExtractArgumentsCountFromFlags(flags);
1036   CallIC::GenerateMiss(masm(), argc);
1037   Object* result = GetCodeWithFlags(flags, "CompileCallDebugPrepareStepIn");
1038   if (!result->IsFailure()) {
1039     Code* code = Code::cast(result);
1040     USE(code);
1041     LOG(CodeCreateEvent(Logger::CALL_DEBUG_PREPARE_STEP_IN_TAG,
1042                         code, code->arguments_count()));
1043   }
1044   return result;
1045 }
1046 #endif
1047 
1048 
GetCodeWithFlags(Code::Flags flags,const char * name)1049 Object* StubCompiler::GetCodeWithFlags(Code::Flags flags, const char* name) {
1050   // Check for allocation failures during stub compilation.
1051   if (failure_->IsFailure()) return failure_;
1052 
1053   // Create code object in the heap.
1054   CodeDesc desc;
1055   masm_.GetCode(&desc);
1056   Object* result = Heap::CreateCode(desc, NULL, flags, masm_.CodeObject());
1057 #ifdef ENABLE_DISASSEMBLER
1058   if (FLAG_print_code_stubs && !result->IsFailure()) {
1059     Code::cast(result)->Disassemble(name);
1060   }
1061 #endif
1062   return result;
1063 }
1064 
1065 
GetCodeWithFlags(Code::Flags flags,String * name)1066 Object* StubCompiler::GetCodeWithFlags(Code::Flags flags, String* name) {
1067   if (FLAG_print_code_stubs && (name != NULL)) {
1068     return GetCodeWithFlags(flags, *name->ToCString());
1069   }
1070   return GetCodeWithFlags(flags, reinterpret_cast<char*>(NULL));
1071 }
1072 
1073 
LookupPostInterceptor(JSObject * holder,String * name,LookupResult * lookup)1074 void StubCompiler::LookupPostInterceptor(JSObject* holder,
1075                                          String* name,
1076                                          LookupResult* lookup) {
1077   holder->LocalLookupRealNamedProperty(name, lookup);
1078   if (!lookup->IsProperty()) {
1079     lookup->NotFound();
1080     Object* proto = holder->GetPrototype();
1081     if (proto != Heap::null_value()) {
1082       proto->Lookup(name, lookup);
1083     }
1084   }
1085 }
1086 
1087 
1088 
GetCode(PropertyType type,String * name)1089 Object* LoadStubCompiler::GetCode(PropertyType type, String* name) {
1090   Code::Flags flags = Code::ComputeMonomorphicFlags(Code::LOAD_IC, type);
1091   return GetCodeWithFlags(flags, name);
1092 }
1093 
1094 
GetCode(PropertyType type,String * name)1095 Object* KeyedLoadStubCompiler::GetCode(PropertyType type, String* name) {
1096   Code::Flags flags = Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, type);
1097   return GetCodeWithFlags(flags, name);
1098 }
1099 
1100 
GetCode(PropertyType type,String * name)1101 Object* StoreStubCompiler::GetCode(PropertyType type, String* name) {
1102   Code::Flags flags = Code::ComputeMonomorphicFlags(Code::STORE_IC, type);
1103   return GetCodeWithFlags(flags, name);
1104 }
1105 
1106 
GetCode(PropertyType type,String * name)1107 Object* KeyedStoreStubCompiler::GetCode(PropertyType type, String* name) {
1108   Code::Flags flags = Code::ComputeMonomorphicFlags(Code::KEYED_STORE_IC, type);
1109   return GetCodeWithFlags(flags, name);
1110 }
1111 
1112 
GetCode(PropertyType type,String * name)1113 Object* CallStubCompiler::GetCode(PropertyType type, String* name) {
1114   int argc = arguments_.immediate();
1115   Code::Flags flags = Code::ComputeMonomorphicFlags(Code::CALL_IC,
1116                                                     type,
1117                                                     in_loop_,
1118                                                     argc);
1119   return GetCodeWithFlags(flags, name);
1120 }
1121 
1122 
GetCode()1123 Object* ConstructStubCompiler::GetCode() {
1124   Code::Flags flags = Code::ComputeFlags(Code::STUB);
1125   Object* result = GetCodeWithFlags(flags, "ConstructStub");
1126   if (!result->IsFailure()) {
1127     Code* code = Code::cast(result);
1128     USE(code);
1129     LOG(CodeCreateEvent(Logger::STUB_TAG, code, "ConstructStub"));
1130   }
1131   return result;
1132 }
1133 
1134 
1135 } }  // namespace v8::internal
1136