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