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