• 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 "cpu-profiler.h"
35 #include "gdb-jit.h"
36 #include "ic-inl.h"
37 #include "stub-cache.h"
38 #include "vm-state-inl.h"
39 
40 namespace v8 {
41 namespace internal {
42 
43 // -----------------------------------------------------------------------
44 // StubCache implementation.
45 
46 
StubCache(Isolate * isolate)47 StubCache::StubCache(Isolate* isolate)
48     : isolate_(isolate) { }
49 
50 
Initialize()51 void StubCache::Initialize() {
52   ASSERT(IsPowerOf2(kPrimaryTableSize));
53   ASSERT(IsPowerOf2(kSecondaryTableSize));
54   Clear();
55 }
56 
57 
Set(Name * name,Map * map,Code * code)58 Code* StubCache::Set(Name* 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 structural equality checks.
64   ASSERT(!heap()->InNewSpace(name));
65   ASSERT(name->IsUniqueName());
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 
FindIC(Handle<Name> name,Handle<Map> stub_holder,Code::Kind kind,ExtraICState extra_state,InlineCacheHolderFlag cache_holder)102 Handle<Code> StubCache::FindIC(Handle<Name> name,
103                                Handle<Map> stub_holder,
104                                Code::Kind kind,
105                                ExtraICState extra_state,
106                                InlineCacheHolderFlag cache_holder) {
107   Code::Flags flags = Code::ComputeMonomorphicFlags(
108       kind, extra_state, cache_holder);
109   Handle<Object> probe(stub_holder->FindInCodeCache(*name, flags), isolate_);
110   if (probe->IsCode()) return Handle<Code>::cast(probe);
111   return Handle<Code>::null();
112 }
113 
114 
FindHandler(Handle<Name> name,Handle<Map> stub_holder,Code::Kind kind,InlineCacheHolderFlag cache_holder)115 Handle<Code> StubCache::FindHandler(Handle<Name> name,
116                                     Handle<Map> stub_holder,
117                                     Code::Kind kind,
118                                     InlineCacheHolderFlag cache_holder) {
119   Code::Flags flags = Code::ComputeMonomorphicFlags(
120       Code::HANDLER, kNoExtraICState, cache_holder, Code::NORMAL, kind);
121 
122   Handle<Object> probe(stub_holder->FindInCodeCache(*name, flags), isolate_);
123   if (probe->IsCode()) return Handle<Code>::cast(probe);
124   return Handle<Code>::null();
125 }
126 
127 
ComputeMonomorphicIC(Handle<Name> name,Handle<Type> type,Handle<Code> handler,ExtraICState extra_ic_state)128 Handle<Code> StubCache::ComputeMonomorphicIC(
129     Handle<Name> name,
130     Handle<Type> type,
131     Handle<Code> handler,
132     ExtraICState extra_ic_state) {
133   Code::Kind kind = handler->handler_kind();
134   InlineCacheHolderFlag flag = IC::GetCodeCacheFlag(*type);
135 
136   Handle<Map> stub_holder;
137   Handle<Code> ic;
138   // There are multiple string maps that all use the same prototype. That
139   // prototype cannot hold multiple handlers, one for each of the string maps,
140   // for a single name. Hence, turn off caching of the IC.
141   bool can_be_cached = !type->Is(Type::String());
142   if (can_be_cached) {
143     stub_holder = IC::GetCodeCacheHolder(flag, *type, isolate());
144     ic = FindIC(name, stub_holder, kind, extra_ic_state, flag);
145     if (!ic.is_null()) return ic;
146   }
147 
148   if (kind == Code::LOAD_IC) {
149     LoadStubCompiler ic_compiler(isolate(), flag);
150     ic = ic_compiler.CompileMonomorphicIC(type, handler, name);
151   } else if (kind == Code::KEYED_LOAD_IC) {
152     KeyedLoadStubCompiler ic_compiler(isolate(), flag);
153     ic = ic_compiler.CompileMonomorphicIC(type, handler, name);
154   } else if (kind == Code::STORE_IC) {
155     StoreStubCompiler ic_compiler(isolate(), extra_ic_state);
156     ic = ic_compiler.CompileMonomorphicIC(type, handler, name);
157   } else {
158     ASSERT(kind == Code::KEYED_STORE_IC);
159     ASSERT(STANDARD_STORE ==
160            KeyedStoreIC::GetKeyedAccessStoreMode(extra_ic_state));
161     KeyedStoreStubCompiler ic_compiler(isolate(), extra_ic_state);
162     ic = ic_compiler.CompileMonomorphicIC(type, handler, name);
163   }
164 
165   if (can_be_cached) Map::UpdateCodeCache(stub_holder, name, ic);
166   return ic;
167 }
168 
169 
ComputeLoadNonexistent(Handle<Name> name,Handle<Type> type)170 Handle<Code> StubCache::ComputeLoadNonexistent(Handle<Name> name,
171                                                Handle<Type> type) {
172   InlineCacheHolderFlag flag = IC::GetCodeCacheFlag(*type);
173   Handle<Map> stub_holder = IC::GetCodeCacheHolder(flag, *type, isolate());
174   // If no dictionary mode objects are present in the prototype chain, the load
175   // nonexistent IC stub can be shared for all names for a given map and we use
176   // the empty string for the map cache in that case. If there are dictionary
177   // mode objects involved, we need to do negative lookups in the stub and
178   // therefore the stub will be specific to the name.
179   Handle<Map> current_map = stub_holder;
180   Handle<Name> cache_name = current_map->is_dictionary_map()
181       ? name : Handle<Name>::cast(isolate()->factory()->empty_string());
182   Handle<Object> next(current_map->prototype(), isolate());
183   Handle<JSObject> last = Handle<JSObject>::null();
184   while (!next->IsNull()) {
185     last = Handle<JSObject>::cast(next);
186     next = handle(current_map->prototype(), isolate());
187     current_map = handle(Handle<HeapObject>::cast(next)->map());
188     if (current_map->is_dictionary_map()) cache_name = name;
189   }
190 
191   // Compile the stub that is either shared for all names or
192   // name specific if there are global objects involved.
193   Handle<Code> handler = FindHandler(
194       cache_name, stub_holder, Code::LOAD_IC, flag);
195   if (!handler.is_null()) return handler;
196 
197   LoadStubCompiler compiler(isolate_, flag);
198   handler = compiler.CompileLoadNonexistent(type, last, cache_name);
199   Map::UpdateCodeCache(stub_holder, cache_name, handler);
200   return handler;
201 }
202 
203 
ComputeKeyedLoadElement(Handle<Map> receiver_map)204 Handle<Code> StubCache::ComputeKeyedLoadElement(Handle<Map> receiver_map) {
205   Code::Flags flags = Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC);
206   Handle<Name> name =
207       isolate()->factory()->KeyedLoadElementMonomorphic_string();
208 
209   Handle<Object> probe(receiver_map->FindInCodeCache(*name, flags), isolate_);
210   if (probe->IsCode()) return Handle<Code>::cast(probe);
211 
212   KeyedLoadStubCompiler compiler(isolate());
213   Handle<Code> code = compiler.CompileLoadElement(receiver_map);
214 
215   Map::UpdateCodeCache(receiver_map, name, code);
216   return code;
217 }
218 
219 
ComputeKeyedStoreElement(Handle<Map> receiver_map,StrictModeFlag strict_mode,KeyedAccessStoreMode store_mode)220 Handle<Code> StubCache::ComputeKeyedStoreElement(
221     Handle<Map> receiver_map,
222     StrictModeFlag strict_mode,
223     KeyedAccessStoreMode store_mode) {
224   ExtraICState extra_state =
225       KeyedStoreIC::ComputeExtraICState(strict_mode, store_mode);
226   Code::Flags flags = Code::ComputeMonomorphicFlags(
227       Code::KEYED_STORE_IC, extra_state);
228 
229   ASSERT(store_mode == STANDARD_STORE ||
230          store_mode == STORE_AND_GROW_NO_TRANSITION ||
231          store_mode == STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS ||
232          store_mode == STORE_NO_TRANSITION_HANDLE_COW);
233 
234   Handle<String> name =
235       isolate()->factory()->KeyedStoreElementMonomorphic_string();
236   Handle<Object> probe(receiver_map->FindInCodeCache(*name, flags), isolate_);
237   if (probe->IsCode()) return Handle<Code>::cast(probe);
238 
239   KeyedStoreStubCompiler compiler(isolate(), extra_state);
240   Handle<Code> code = compiler.CompileStoreElement(receiver_map);
241 
242   Map::UpdateCodeCache(receiver_map, name, code);
243   ASSERT(KeyedStoreIC::GetKeyedAccessStoreMode(code->extra_ic_state())
244          == store_mode);
245   return code;
246 }
247 
248 
249 #define CALL_LOGGER_TAG(kind, type) \
250     (kind == Code::CALL_IC ? Logger::type : Logger::KEYED_##type)
251 
ComputeCallConstant(int argc,Code::Kind kind,ExtraICState extra_state,Handle<Name> name,Handle<Object> object,Handle<JSObject> holder,Handle<JSFunction> function)252 Handle<Code> StubCache::ComputeCallConstant(int argc,
253                                             Code::Kind kind,
254                                             ExtraICState extra_state,
255                                             Handle<Name> name,
256                                             Handle<Object> object,
257                                             Handle<JSObject> holder,
258                                             Handle<JSFunction> function) {
259   // Compute the check type and the map.
260   InlineCacheHolderFlag cache_holder = IC::GetCodeCacheForObject(*object);
261   Handle<HeapObject> stub_holder(IC::GetCodeCacheHolder(
262       isolate_, *object, cache_holder));
263 
264   // Compute check type based on receiver/holder.
265   CheckType check = RECEIVER_MAP_CHECK;
266   if (object->IsString()) {
267     check = STRING_CHECK;
268   } else if (object->IsSymbol()) {
269     check = SYMBOL_CHECK;
270   } else if (object->IsNumber()) {
271     check = NUMBER_CHECK;
272   } else if (object->IsBoolean()) {
273     check = BOOLEAN_CHECK;
274   }
275 
276   if (check != RECEIVER_MAP_CHECK &&
277       !function->IsBuiltin() &&
278       function->shared()->is_classic_mode()) {
279     // Calling non-strict non-builtins with a value as the receiver
280     // requires boxing.
281     return Handle<Code>::null();
282   }
283 
284   Code::Flags flags = Code::ComputeMonomorphicFlags(
285       kind, extra_state, cache_holder, Code::FAST, argc);
286   Handle<Object> probe(stub_holder->map()->FindInCodeCache(*name, flags),
287                        isolate_);
288   if (probe->IsCode()) return Handle<Code>::cast(probe);
289 
290   CallStubCompiler compiler(isolate_, argc, kind, extra_state, cache_holder);
291   Handle<Code> code =
292       compiler.CompileCallConstant(object, holder, name, check, function);
293   code->set_check_type(check);
294   ASSERT(flags == code->flags());
295   PROFILE(isolate_,
296           CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_IC_TAG), *code, *name));
297   GDBJIT(AddCode(GDBJITInterface::CALL_IC, *name, *code));
298 
299   if (CallStubCompiler::CanBeCached(function)) {
300     HeapObject::UpdateMapCodeCache(stub_holder, name, code);
301   }
302   return code;
303 }
304 
305 
ComputeCallField(int argc,Code::Kind kind,ExtraICState extra_state,Handle<Name> name,Handle<Object> object,Handle<JSObject> holder,PropertyIndex index)306 Handle<Code> StubCache::ComputeCallField(int argc,
307                                          Code::Kind kind,
308                                          ExtraICState extra_state,
309                                          Handle<Name> name,
310                                          Handle<Object> object,
311                                          Handle<JSObject> holder,
312                                          PropertyIndex index) {
313   // Compute the check type and the map.
314   InlineCacheHolderFlag cache_holder = IC::GetCodeCacheForObject(*object);
315   Handle<HeapObject> stub_holder(IC::GetCodeCacheHolder(
316       isolate_, *object, cache_holder));
317 
318   // TODO(1233596): We cannot do receiver map check for non-JS objects
319   // because they may be represented as immediates without a
320   // map. Instead, we check against the map in the holder.
321   if (object->IsNumber() || object->IsSymbol() ||
322       object->IsBoolean() || object->IsString()) {
323     object = holder;
324   }
325 
326   Code::Flags flags = Code::ComputeMonomorphicFlags(
327       kind, extra_state, cache_holder, Code::FAST, argc);
328   Handle<Object> probe(stub_holder->map()->FindInCodeCache(*name, flags),
329                        isolate_);
330   if (probe->IsCode()) return Handle<Code>::cast(probe);
331 
332   CallStubCompiler compiler(isolate_, argc, kind, extra_state, cache_holder);
333   Handle<Code> code =
334       compiler.CompileCallField(Handle<JSObject>::cast(object),
335                                 holder, index, name);
336   ASSERT(flags == code->flags());
337   PROFILE(isolate_,
338           CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_IC_TAG), *code, *name));
339   GDBJIT(AddCode(GDBJITInterface::CALL_IC, *name, *code));
340   HeapObject::UpdateMapCodeCache(stub_holder, name, code);
341   return code;
342 }
343 
344 
ComputeCallInterceptor(int argc,Code::Kind kind,ExtraICState extra_state,Handle<Name> name,Handle<Object> object,Handle<JSObject> holder)345 Handle<Code> StubCache::ComputeCallInterceptor(int argc,
346                                                Code::Kind kind,
347                                                ExtraICState extra_state,
348                                                Handle<Name> name,
349                                                Handle<Object> object,
350                                                Handle<JSObject> holder) {
351   // Compute the check type and the map.
352   InlineCacheHolderFlag cache_holder = IC::GetCodeCacheForObject(*object);
353   Handle<HeapObject> stub_holder(IC::GetCodeCacheHolder(
354       isolate_, *object, cache_holder));
355 
356   // TODO(1233596): We cannot do receiver map check for non-JS objects
357   // because they may be represented as immediates without a
358   // map. Instead, we check against the map in the holder.
359   if (object->IsNumber() || object->IsSymbol() ||
360       object->IsBoolean() || object->IsString()) {
361     object = holder;
362   }
363 
364   Code::Flags flags = Code::ComputeMonomorphicFlags(
365       kind, extra_state, cache_holder, Code::FAST, argc);
366   Handle<Object> probe(stub_holder->map()->FindInCodeCache(*name, flags),
367                        isolate_);
368   if (probe->IsCode()) return Handle<Code>::cast(probe);
369 
370   CallStubCompiler compiler(isolate(), argc, kind, extra_state, cache_holder);
371   Handle<Code> code =
372       compiler.CompileCallInterceptor(Handle<JSObject>::cast(object),
373                                       holder, name);
374   ASSERT(flags == code->flags());
375   PROFILE(isolate(),
376           CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_IC_TAG), *code, *name));
377   GDBJIT(AddCode(GDBJITInterface::CALL_IC, *name, *code));
378   HeapObject::UpdateMapCodeCache(stub_holder, name, code);
379   return code;
380 }
381 
382 
ComputeCallGlobal(int argc,Code::Kind kind,ExtraICState extra_state,Handle<Name> name,Handle<JSObject> receiver,Handle<GlobalObject> holder,Handle<PropertyCell> cell,Handle<JSFunction> function)383 Handle<Code> StubCache::ComputeCallGlobal(int argc,
384                                           Code::Kind kind,
385                                           ExtraICState extra_state,
386                                           Handle<Name> name,
387                                           Handle<JSObject> receiver,
388                                           Handle<GlobalObject> holder,
389                                           Handle<PropertyCell> cell,
390                                           Handle<JSFunction> function) {
391   Code::Flags flags = Code::ComputeMonomorphicFlags(
392       kind, extra_state, OWN_MAP, Code::NORMAL, argc);
393   Handle<Object> probe(receiver->map()->FindInCodeCache(*name, flags),
394                        isolate_);
395   if (probe->IsCode()) return Handle<Code>::cast(probe);
396 
397   CallStubCompiler compiler(isolate(), argc, kind, extra_state);
398   Handle<Code> code =
399       compiler.CompileCallGlobal(receiver, holder, cell, function, name);
400   ASSERT(flags == code->flags());
401   PROFILE(isolate(),
402           CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_IC_TAG), *code, *name));
403   GDBJIT(AddCode(GDBJITInterface::CALL_IC, *name, *code));
404   if (CallStubCompiler::CanBeCached(function)) {
405     HeapObject::UpdateMapCodeCache(receiver, name, code);
406   }
407   return code;
408 }
409 
410 
FillCache(Isolate * isolate,Handle<Code> code)411 static void FillCache(Isolate* isolate, Handle<Code> code) {
412   Handle<UnseededNumberDictionary> dictionary =
413       UnseededNumberDictionary::Set(isolate->factory()->non_monomorphic_cache(),
414                                     code->flags(),
415                                     code);
416   isolate->heap()->public_set_non_monomorphic_cache(*dictionary);
417 }
418 
419 
FindCallInitialize(int argc,RelocInfo::Mode mode,Code::Kind kind)420 Code* StubCache::FindCallInitialize(int argc,
421                                     RelocInfo::Mode mode,
422                                     Code::Kind kind) {
423   ExtraICState extra_state =
424       CallICBase::StringStubState::encode(DEFAULT_STRING_STUB) |
425       CallICBase::Contextual::encode(mode == RelocInfo::CODE_TARGET_CONTEXT
426                                          ? CONTEXTUAL : NOT_CONTEXTUAL);
427   Code::Flags flags =
428       Code::ComputeFlags(kind, UNINITIALIZED, extra_state, Code::NORMAL, argc);
429   UnseededNumberDictionary* dictionary =
430       isolate()->heap()->non_monomorphic_cache();
431   int entry = dictionary->FindEntry(isolate(), flags);
432   ASSERT(entry != -1);
433   Object* code = dictionary->ValueAt(entry);
434   // This might be called during the marking phase of the collector
435   // hence the unchecked cast.
436   return reinterpret_cast<Code*>(code);
437 }
438 
439 
ComputeCallInitialize(int argc,RelocInfo::Mode mode,Code::Kind kind)440 Handle<Code> StubCache::ComputeCallInitialize(int argc,
441                                               RelocInfo::Mode mode,
442                                               Code::Kind kind) {
443   ExtraICState extra_state =
444       CallICBase::StringStubState::encode(DEFAULT_STRING_STUB) |
445       CallICBase::Contextual::encode(mode == RelocInfo::CODE_TARGET_CONTEXT
446                                          ? CONTEXTUAL : NOT_CONTEXTUAL);
447   Code::Flags flags =
448       Code::ComputeFlags(kind, UNINITIALIZED, extra_state, Code::NORMAL, argc);
449   Handle<UnseededNumberDictionary> cache =
450       isolate_->factory()->non_monomorphic_cache();
451   int entry = cache->FindEntry(isolate_, flags);
452   if (entry != -1) return Handle<Code>(Code::cast(cache->ValueAt(entry)));
453 
454   StubCompiler compiler(isolate_);
455   Handle<Code> code = compiler.CompileCallInitialize(flags);
456   FillCache(isolate_, code);
457   return code;
458 }
459 
460 
ComputeCallInitialize(int argc,RelocInfo::Mode mode)461 Handle<Code> StubCache::ComputeCallInitialize(int argc, RelocInfo::Mode mode) {
462   return ComputeCallInitialize(argc, mode, Code::CALL_IC);
463 }
464 
465 
ComputeKeyedCallInitialize(int argc)466 Handle<Code> StubCache::ComputeKeyedCallInitialize(int argc) {
467   return ComputeCallInitialize(argc, RelocInfo::CODE_TARGET,
468                                Code::KEYED_CALL_IC);
469 }
470 
471 
ComputeCallPreMonomorphic(int argc,Code::Kind kind,ExtraICState extra_state)472 Handle<Code> StubCache::ComputeCallPreMonomorphic(
473     int argc,
474     Code::Kind kind,
475     ExtraICState extra_state) {
476   Code::Flags flags =
477       Code::ComputeFlags(kind, PREMONOMORPHIC, extra_state, Code::NORMAL, argc);
478   Handle<UnseededNumberDictionary> cache =
479       isolate_->factory()->non_monomorphic_cache();
480   int entry = cache->FindEntry(isolate_, flags);
481   if (entry != -1) return Handle<Code>(Code::cast(cache->ValueAt(entry)));
482 
483   StubCompiler compiler(isolate_);
484   Handle<Code> code = compiler.CompileCallPreMonomorphic(flags);
485   FillCache(isolate_, code);
486   return code;
487 }
488 
489 
ComputeCallNormal(int argc,Code::Kind kind,ExtraICState extra_state)490 Handle<Code> StubCache::ComputeCallNormal(int argc,
491                                           Code::Kind kind,
492                                           ExtraICState extra_state) {
493   Code::Flags flags =
494       Code::ComputeFlags(kind, MONOMORPHIC, extra_state, Code::NORMAL, argc);
495   Handle<UnseededNumberDictionary> cache =
496       isolate_->factory()->non_monomorphic_cache();
497   int entry = cache->FindEntry(isolate_, flags);
498   if (entry != -1) return Handle<Code>(Code::cast(cache->ValueAt(entry)));
499 
500   StubCompiler compiler(isolate_);
501   Handle<Code> code = compiler.CompileCallNormal(flags);
502   FillCache(isolate_, code);
503   return code;
504 }
505 
506 
ComputeCallArguments(int argc)507 Handle<Code> StubCache::ComputeCallArguments(int argc) {
508   Code::Flags flags =
509       Code::ComputeFlags(Code::KEYED_CALL_IC, MEGAMORPHIC,
510                          kNoExtraICState, Code::NORMAL, argc);
511   Handle<UnseededNumberDictionary> cache =
512       isolate_->factory()->non_monomorphic_cache();
513   int entry = cache->FindEntry(isolate_, flags);
514   if (entry != -1) return Handle<Code>(Code::cast(cache->ValueAt(entry)));
515 
516   StubCompiler compiler(isolate_);
517   Handle<Code> code = compiler.CompileCallArguments(flags);
518   FillCache(isolate_, code);
519   return code;
520 }
521 
522 
ComputeCallMegamorphic(int argc,Code::Kind kind,ExtraICState extra_state)523 Handle<Code> StubCache::ComputeCallMegamorphic(
524     int argc,
525     Code::Kind kind,
526     ExtraICState extra_state) {
527   Code::Flags flags =
528       Code::ComputeFlags(kind, MEGAMORPHIC, extra_state,
529                          Code::NORMAL, argc);
530   Handle<UnseededNumberDictionary> cache =
531       isolate_->factory()->non_monomorphic_cache();
532   int entry = cache->FindEntry(isolate_, flags);
533   if (entry != -1) return Handle<Code>(Code::cast(cache->ValueAt(entry)));
534 
535   StubCompiler compiler(isolate_);
536   Handle<Code> code = compiler.CompileCallMegamorphic(flags);
537   FillCache(isolate_, code);
538   return code;
539 }
540 
541 
ComputeCallMiss(int argc,Code::Kind kind,ExtraICState extra_state)542 Handle<Code> StubCache::ComputeCallMiss(int argc,
543                                         Code::Kind kind,
544                                         ExtraICState extra_state) {
545   // MONOMORPHIC_PROTOTYPE_FAILURE state is used to make sure that miss stubs
546   // and monomorphic stubs are not mixed up together in the stub cache.
547   Code::Flags flags =
548       Code::ComputeFlags(kind, MONOMORPHIC_PROTOTYPE_FAILURE, extra_state,
549                          Code::NORMAL, argc, OWN_MAP);
550   Handle<UnseededNumberDictionary> cache =
551       isolate_->factory()->non_monomorphic_cache();
552   int entry = cache->FindEntry(isolate_, flags);
553   if (entry != -1) return Handle<Code>(Code::cast(cache->ValueAt(entry)));
554 
555   StubCompiler compiler(isolate_);
556   Handle<Code> code = compiler.CompileCallMiss(flags);
557   FillCache(isolate_, code);
558   return code;
559 }
560 
561 
ComputeCompareNil(Handle<Map> receiver_map,CompareNilICStub & stub)562 Handle<Code> StubCache::ComputeCompareNil(Handle<Map> receiver_map,
563                                           CompareNilICStub& stub) {
564   Handle<String> name(isolate_->heap()->empty_string());
565   if (!receiver_map->is_shared()) {
566     Handle<Code> cached_ic = FindIC(name, receiver_map, Code::COMPARE_NIL_IC,
567                                     stub.GetExtraICState());
568     if (!cached_ic.is_null()) return cached_ic;
569   }
570 
571   Handle<Code> ic = stub.GetCodeCopyFromTemplate(isolate_);
572   ic->ReplaceNthObject(1, isolate_->heap()->meta_map(), *receiver_map);
573 
574   if (!receiver_map->is_shared()) {
575     Map::UpdateCodeCache(receiver_map, name, ic);
576   }
577 
578   return ic;
579 }
580 
581 
582 // TODO(verwaest): Change this method so it takes in a TypeHandleList.
ComputeLoadElementPolymorphic(MapHandleList * receiver_maps)583 Handle<Code> StubCache::ComputeLoadElementPolymorphic(
584     MapHandleList* receiver_maps) {
585   Code::Flags flags = Code::ComputeFlags(Code::KEYED_LOAD_IC, POLYMORPHIC);
586   Handle<PolymorphicCodeCache> cache =
587       isolate_->factory()->polymorphic_code_cache();
588   Handle<Object> probe = cache->Lookup(receiver_maps, flags);
589   if (probe->IsCode()) return Handle<Code>::cast(probe);
590 
591   TypeHandleList types(receiver_maps->length());
592   for (int i = 0; i < receiver_maps->length(); i++) {
593     types.Add(handle(Type::Class(receiver_maps->at(i)), isolate()));
594   }
595   CodeHandleList handlers(receiver_maps->length());
596   KeyedLoadStubCompiler compiler(isolate_);
597   compiler.CompileElementHandlers(receiver_maps, &handlers);
598   Handle<Code> code = compiler.CompilePolymorphicIC(
599       &types, &handlers, factory()->empty_string(), Code::NORMAL, ELEMENT);
600 
601   isolate()->counters()->keyed_load_polymorphic_stubs()->Increment();
602 
603   PolymorphicCodeCache::Update(cache, receiver_maps, flags, code);
604   return code;
605 }
606 
607 
ComputePolymorphicIC(TypeHandleList * types,CodeHandleList * handlers,int number_of_valid_types,Handle<Name> name,ExtraICState extra_ic_state)608 Handle<Code> StubCache::ComputePolymorphicIC(
609     TypeHandleList* types,
610     CodeHandleList* handlers,
611     int number_of_valid_types,
612     Handle<Name> name,
613     ExtraICState extra_ic_state) {
614 
615   Handle<Code> handler = handlers->at(0);
616   Code::Kind kind = handler->handler_kind();
617   Code::StubType type = number_of_valid_types == 1 ? handler->type()
618                                                    : Code::NORMAL;
619   if (kind == Code::LOAD_IC) {
620     LoadStubCompiler ic_compiler(isolate_);
621     return ic_compiler.CompilePolymorphicIC(
622         types, handlers, name, type, PROPERTY);
623   } else {
624     ASSERT(kind == Code::STORE_IC);
625     StrictModeFlag strict_mode = StoreIC::GetStrictMode(extra_ic_state);
626     StoreStubCompiler ic_compiler(isolate_, strict_mode);
627     return ic_compiler.CompilePolymorphicIC(
628         types, handlers, name, type, PROPERTY);
629   }
630 }
631 
632 
ComputeStoreElementPolymorphic(MapHandleList * receiver_maps,KeyedAccessStoreMode store_mode,StrictModeFlag strict_mode)633 Handle<Code> StubCache::ComputeStoreElementPolymorphic(
634     MapHandleList* receiver_maps,
635     KeyedAccessStoreMode store_mode,
636     StrictModeFlag strict_mode) {
637   ASSERT(store_mode == STANDARD_STORE ||
638          store_mode == STORE_AND_GROW_NO_TRANSITION ||
639          store_mode == STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS ||
640          store_mode == STORE_NO_TRANSITION_HANDLE_COW);
641   Handle<PolymorphicCodeCache> cache =
642       isolate_->factory()->polymorphic_code_cache();
643   ExtraICState extra_state = KeyedStoreIC::ComputeExtraICState(
644       strict_mode, store_mode);
645   Code::Flags flags =
646       Code::ComputeFlags(Code::KEYED_STORE_IC, POLYMORPHIC, extra_state);
647   Handle<Object> probe = cache->Lookup(receiver_maps, flags);
648   if (probe->IsCode()) return Handle<Code>::cast(probe);
649 
650   KeyedStoreStubCompiler compiler(isolate_, extra_state);
651   Handle<Code> code = compiler.CompileStoreElementPolymorphic(receiver_maps);
652   PolymorphicCodeCache::Update(cache, receiver_maps, flags, code);
653   return code;
654 }
655 
656 
657 #ifdef ENABLE_DEBUGGER_SUPPORT
ComputeCallDebugBreak(int argc,Code::Kind kind)658 Handle<Code> StubCache::ComputeCallDebugBreak(int argc,
659                                               Code::Kind kind) {
660   // Extra IC state is irrelevant for debug break ICs. They jump to
661   // the actual call ic to carry out the work.
662   Code::Flags flags =
663       Code::ComputeFlags(kind, DEBUG_STUB, DEBUG_BREAK,
664                          Code::NORMAL, argc);
665   Handle<UnseededNumberDictionary> cache =
666       isolate_->factory()->non_monomorphic_cache();
667   int entry = cache->FindEntry(isolate_, flags);
668   if (entry != -1) return Handle<Code>(Code::cast(cache->ValueAt(entry)));
669 
670   StubCompiler compiler(isolate_);
671   Handle<Code> code = compiler.CompileCallDebugBreak(flags);
672   FillCache(isolate_, code);
673   return code;
674 }
675 
676 
ComputeCallDebugPrepareStepIn(int argc,Code::Kind kind)677 Handle<Code> StubCache::ComputeCallDebugPrepareStepIn(int argc,
678                                                       Code::Kind kind) {
679   // Extra IC state is irrelevant for debug break ICs. They jump to
680   // the actual call ic to carry out the work.
681   Code::Flags flags =
682       Code::ComputeFlags(kind, DEBUG_STUB, DEBUG_PREPARE_STEP_IN,
683                          Code::NORMAL, argc);
684   Handle<UnseededNumberDictionary> cache =
685       isolate_->factory()->non_monomorphic_cache();
686   int entry = cache->FindEntry(isolate_, flags);
687   if (entry != -1) return Handle<Code>(Code::cast(cache->ValueAt(entry)));
688 
689   StubCompiler compiler(isolate_);
690   Handle<Code> code = compiler.CompileCallDebugPrepareStepIn(flags);
691   FillCache(isolate_, code);
692   return code;
693 }
694 #endif
695 
696 
Clear()697 void StubCache::Clear() {
698   Code* empty = isolate_->builtins()->builtin(Builtins::kIllegal);
699   for (int i = 0; i < kPrimaryTableSize; i++) {
700     primary_[i].key = heap()->empty_string();
701     primary_[i].map = NULL;
702     primary_[i].value = empty;
703   }
704   for (int j = 0; j < kSecondaryTableSize; j++) {
705     secondary_[j].key = heap()->empty_string();
706     secondary_[j].map = NULL;
707     secondary_[j].value = empty;
708   }
709 }
710 
711 
CollectMatchingMaps(SmallMapList * types,Handle<Name> name,Code::Flags flags,Handle<Context> native_context,Zone * zone)712 void StubCache::CollectMatchingMaps(SmallMapList* types,
713                                     Handle<Name> name,
714                                     Code::Flags flags,
715                                     Handle<Context> native_context,
716                                     Zone* zone) {
717   for (int i = 0; i < kPrimaryTableSize; i++) {
718     if (primary_[i].key == *name) {
719       Map* map = primary_[i].map;
720       // Map can be NULL, if the stub is constant function call
721       // with a primitive receiver.
722       if (map == NULL) continue;
723 
724       int offset = PrimaryOffset(*name, flags, map);
725       if (entry(primary_, offset) == &primary_[i] &&
726           !TypeFeedbackOracle::CanRetainOtherContext(map, *native_context)) {
727         types->AddMapIfMissing(Handle<Map>(map), zone);
728       }
729     }
730   }
731 
732   for (int i = 0; i < kSecondaryTableSize; i++) {
733     if (secondary_[i].key == *name) {
734       Map* map = secondary_[i].map;
735       // Map can be NULL, if the stub is constant function call
736       // with a primitive receiver.
737       if (map == NULL) continue;
738 
739       // Lookup in primary table and skip duplicates.
740       int primary_offset = PrimaryOffset(*name, flags, map);
741 
742       // Lookup in secondary table and add matches.
743       int offset = SecondaryOffset(*name, flags, primary_offset);
744       if (entry(secondary_, offset) == &secondary_[i] &&
745           !TypeFeedbackOracle::CanRetainOtherContext(map, *native_context)) {
746         types->AddMapIfMissing(Handle<Map>(map), zone);
747       }
748     }
749   }
750 }
751 
752 
753 // ------------------------------------------------------------------------
754 // StubCompiler implementation.
755 
756 
RUNTIME_FUNCTION(MaybeObject *,StoreCallbackProperty)757 RUNTIME_FUNCTION(MaybeObject*, StoreCallbackProperty) {
758   JSObject* recv = JSObject::cast(args[0]);
759   ExecutableAccessorInfo* callback = ExecutableAccessorInfo::cast(args[1]);
760   Address setter_address = v8::ToCData<Address>(callback->setter());
761   v8::AccessorSetterCallback fun =
762       FUNCTION_CAST<v8::AccessorSetterCallback>(setter_address);
763   ASSERT(fun != NULL);
764   ASSERT(callback->IsCompatibleReceiver(recv));
765   Handle<Name> name = args.at<Name>(2);
766   Handle<Object> value = args.at<Object>(3);
767   HandleScope scope(isolate);
768 
769   // TODO(rossberg): Support symbols in the API.
770   if (name->IsSymbol()) return *value;
771   Handle<String> str = Handle<String>::cast(name);
772 
773   LOG(isolate, ApiNamedPropertyAccess("store", recv, *name));
774   PropertyCallbackArguments
775       custom_args(isolate, callback->data(), recv, recv);
776   custom_args.Call(fun, v8::Utils::ToLocal(str), v8::Utils::ToLocal(value));
777   RETURN_IF_SCHEDULED_EXCEPTION(isolate);
778   return *value;
779 }
780 
781 
782 /**
783  * Attempts to load a property with an interceptor (which must be present),
784  * but doesn't search the prototype chain.
785  *
786  * Returns |Heap::no_interceptor_result_sentinel()| if interceptor doesn't
787  * provide any value for the given name.
788  */
RUNTIME_FUNCTION(MaybeObject *,LoadPropertyWithInterceptorOnly)789 RUNTIME_FUNCTION(MaybeObject*, LoadPropertyWithInterceptorOnly) {
790   ASSERT(args.length() == StubCache::kInterceptorArgsLength);
791   Handle<Name> name_handle =
792       args.at<Name>(StubCache::kInterceptorArgsNameIndex);
793   Handle<InterceptorInfo> interceptor_info =
794       args.at<InterceptorInfo>(StubCache::kInterceptorArgsInfoIndex);
795 
796   // TODO(rossberg): Support symbols in the API.
797   if (name_handle->IsSymbol())
798     return isolate->heap()->no_interceptor_result_sentinel();
799   Handle<String> name = Handle<String>::cast(name_handle);
800 
801   Address getter_address = v8::ToCData<Address>(interceptor_info->getter());
802   v8::NamedPropertyGetterCallback getter =
803       FUNCTION_CAST<v8::NamedPropertyGetterCallback>(getter_address);
804   ASSERT(getter != NULL);
805 
806   Handle<JSObject> receiver =
807       args.at<JSObject>(StubCache::kInterceptorArgsThisIndex);
808   Handle<JSObject> holder =
809       args.at<JSObject>(StubCache::kInterceptorArgsHolderIndex);
810   PropertyCallbackArguments callback_args(
811       isolate, interceptor_info->data(), *receiver, *holder);
812   {
813     // Use the interceptor getter.
814     HandleScope scope(isolate);
815     v8::Handle<v8::Value> r =
816         callback_args.Call(getter, v8::Utils::ToLocal(name));
817     RETURN_IF_SCHEDULED_EXCEPTION(isolate);
818     if (!r.IsEmpty()) {
819       Handle<Object> result = v8::Utils::OpenHandle(*r);
820       result->VerifyApiCallResultType();
821       return *v8::Utils::OpenHandle(*r);
822     }
823   }
824 
825   return isolate->heap()->no_interceptor_result_sentinel();
826 }
827 
828 
ThrowReferenceError(Isolate * isolate,Name * name)829 static MaybeObject* ThrowReferenceError(Isolate* isolate, Name* name) {
830   // If the load is non-contextual, just return the undefined result.
831   // Note that both keyed and non-keyed loads may end up here, so we
832   // can't use either LoadIC or KeyedLoadIC constructors.
833   HandleScope scope(isolate);
834   IC ic(IC::NO_EXTRA_FRAME, isolate);
835   ASSERT(ic.IsLoadStub());
836   if (!ic.SlowIsUndeclaredGlobal()) return isolate->heap()->undefined_value();
837 
838   // Throw a reference error.
839   Handle<Name> name_handle(name);
840   Handle<Object> error =
841       isolate->factory()->NewReferenceError("not_defined",
842                                             HandleVector(&name_handle, 1));
843   return isolate->Throw(*error);
844 }
845 
846 
LoadWithInterceptor(Arguments * args,PropertyAttributes * attrs)847 static Handle<Object> LoadWithInterceptor(Arguments* args,
848                                           PropertyAttributes* attrs) {
849   ASSERT(args->length() == StubCache::kInterceptorArgsLength);
850   Handle<Name> name_handle =
851       args->at<Name>(StubCache::kInterceptorArgsNameIndex);
852   Handle<InterceptorInfo> interceptor_info =
853       args->at<InterceptorInfo>(StubCache::kInterceptorArgsInfoIndex);
854   Handle<JSObject> receiver_handle =
855       args->at<JSObject>(StubCache::kInterceptorArgsThisIndex);
856   Handle<JSObject> holder_handle =
857       args->at<JSObject>(StubCache::kInterceptorArgsHolderIndex);
858 
859   Isolate* isolate = receiver_handle->GetIsolate();
860 
861   // TODO(rossberg): Support symbols in the API.
862   if (name_handle->IsSymbol()) {
863     return JSObject::GetPropertyPostInterceptor(
864         holder_handle, receiver_handle, name_handle, attrs);
865   }
866   Handle<String> name = Handle<String>::cast(name_handle);
867 
868   Address getter_address = v8::ToCData<Address>(interceptor_info->getter());
869   v8::NamedPropertyGetterCallback getter =
870       FUNCTION_CAST<v8::NamedPropertyGetterCallback>(getter_address);
871   ASSERT(getter != NULL);
872 
873   PropertyCallbackArguments callback_args(isolate,
874                                           interceptor_info->data(),
875                                           *receiver_handle,
876                                           *holder_handle);
877   {
878     HandleScope scope(isolate);
879     // Use the interceptor getter.
880     v8::Handle<v8::Value> r =
881         callback_args.Call(getter, v8::Utils::ToLocal(name));
882     RETURN_HANDLE_IF_SCHEDULED_EXCEPTION(isolate, Object);
883     if (!r.IsEmpty()) {
884       *attrs = NONE;
885       Handle<Object> result = v8::Utils::OpenHandle(*r);
886       result->VerifyApiCallResultType();
887       return scope.CloseAndEscape(result);
888     }
889   }
890 
891   Handle<Object> result = JSObject::GetPropertyPostInterceptor(
892       holder_handle, receiver_handle, name_handle, attrs);
893   return result;
894 }
895 
896 
897 /**
898  * Loads a property with an interceptor performing post interceptor
899  * lookup if interceptor failed.
900  */
RUNTIME_FUNCTION(MaybeObject *,LoadPropertyWithInterceptorForLoad)901 RUNTIME_FUNCTION(MaybeObject*, LoadPropertyWithInterceptorForLoad) {
902   PropertyAttributes attr = NONE;
903   HandleScope scope(isolate);
904   Handle<Object> result = LoadWithInterceptor(&args, &attr);
905   RETURN_IF_EMPTY_HANDLE(isolate, result);
906 
907   // If the property is present, return it.
908   if (attr != ABSENT) return *result;
909   return ThrowReferenceError(isolate, Name::cast(args[0]));
910 }
911 
912 
RUNTIME_FUNCTION(MaybeObject *,LoadPropertyWithInterceptorForCall)913 RUNTIME_FUNCTION(MaybeObject*, LoadPropertyWithInterceptorForCall) {
914   PropertyAttributes attr;
915   HandleScope scope(isolate);
916   Handle<Object> result = LoadWithInterceptor(&args, &attr);
917   RETURN_IF_EMPTY_HANDLE(isolate, result);
918   // This is call IC. In this case, we simply return the undefined result which
919   // will lead to an exception when trying to invoke the result as a
920   // function.
921   return *result;
922 }
923 
924 
RUNTIME_FUNCTION(MaybeObject *,StoreInterceptorProperty)925 RUNTIME_FUNCTION(MaybeObject*, StoreInterceptorProperty) {
926   HandleScope scope(isolate);
927   ASSERT(args.length() == 3);
928   StoreIC ic(IC::NO_EXTRA_FRAME, isolate);
929   Handle<JSObject> receiver = args.at<JSObject>(0);
930   Handle<Name> name = args.at<Name>(1);
931   Handle<Object> value = args.at<Object>(2);
932   ASSERT(receiver->HasNamedInterceptor());
933   PropertyAttributes attr = NONE;
934   Handle<Object> result = JSObject::SetPropertyWithInterceptor(
935       receiver, name, value, attr, ic.strict_mode());
936   RETURN_IF_EMPTY_HANDLE(isolate, result);
937   return *result;
938 }
939 
940 
RUNTIME_FUNCTION(MaybeObject *,KeyedLoadPropertyWithInterceptor)941 RUNTIME_FUNCTION(MaybeObject*, KeyedLoadPropertyWithInterceptor) {
942   JSObject* receiver = JSObject::cast(args[0]);
943   ASSERT(args.smi_at(1) >= 0);
944   uint32_t index = args.smi_at(1);
945   return receiver->GetElementWithInterceptor(receiver, index);
946 }
947 
948 
CompileCallInitialize(Code::Flags flags)949 Handle<Code> StubCompiler::CompileCallInitialize(Code::Flags flags) {
950   int argc = Code::ExtractArgumentsCountFromFlags(flags);
951   Code::Kind kind = Code::ExtractKindFromFlags(flags);
952   ExtraICState extra_state = Code::ExtractExtraICStateFromFlags(flags);
953   if (kind == Code::CALL_IC) {
954     CallIC::GenerateInitialize(masm(), argc, extra_state);
955   } else {
956     KeyedCallIC::GenerateInitialize(masm(), argc);
957   }
958   Handle<Code> code = GetCodeWithFlags(flags, "CompileCallInitialize");
959   isolate()->counters()->call_initialize_stubs()->Increment();
960   PROFILE(isolate(),
961           CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_INITIALIZE_TAG),
962                           *code, code->arguments_count()));
963   GDBJIT(AddCode(GDBJITInterface::CALL_INITIALIZE, *code));
964   return code;
965 }
966 
967 
CompileCallPreMonomorphic(Code::Flags flags)968 Handle<Code> StubCompiler::CompileCallPreMonomorphic(Code::Flags flags) {
969   int argc = Code::ExtractArgumentsCountFromFlags(flags);
970   // The code of the PreMonomorphic stub is the same as the code
971   // of the Initialized stub.  They just differ on the code object flags.
972   Code::Kind kind = Code::ExtractKindFromFlags(flags);
973   ExtraICState extra_state = Code::ExtractExtraICStateFromFlags(flags);
974   if (kind == Code::CALL_IC) {
975     CallIC::GenerateInitialize(masm(), argc, extra_state);
976   } else {
977     KeyedCallIC::GenerateInitialize(masm(), argc);
978   }
979   Handle<Code> code = GetCodeWithFlags(flags, "CompileCallPreMonomorphic");
980   isolate()->counters()->call_premonomorphic_stubs()->Increment();
981   PROFILE(isolate(),
982           CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_PRE_MONOMORPHIC_TAG),
983                           *code, code->arguments_count()));
984   GDBJIT(AddCode(GDBJITInterface::CALL_PRE_MONOMORPHIC, *code));
985   return code;
986 }
987 
988 
CompileCallNormal(Code::Flags flags)989 Handle<Code> StubCompiler::CompileCallNormal(Code::Flags flags) {
990   int argc = Code::ExtractArgumentsCountFromFlags(flags);
991   Code::Kind kind = Code::ExtractKindFromFlags(flags);
992   if (kind == Code::CALL_IC) {
993     // Call normal is always with a explict receiver.
994     ASSERT(!CallIC::Contextual::decode(
995         Code::ExtractExtraICStateFromFlags(flags)));
996     CallIC::GenerateNormal(masm(), argc);
997   } else {
998     KeyedCallIC::GenerateNormal(masm(), argc);
999   }
1000   Handle<Code> code = GetCodeWithFlags(flags, "CompileCallNormal");
1001   isolate()->counters()->call_normal_stubs()->Increment();
1002   PROFILE(isolate(),
1003           CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_NORMAL_TAG),
1004                           *code, code->arguments_count()));
1005   GDBJIT(AddCode(GDBJITInterface::CALL_NORMAL, *code));
1006   return code;
1007 }
1008 
1009 
CompileCallMegamorphic(Code::Flags flags)1010 Handle<Code> StubCompiler::CompileCallMegamorphic(Code::Flags flags) {
1011   int argc = Code::ExtractArgumentsCountFromFlags(flags);
1012   Code::Kind kind = Code::ExtractKindFromFlags(flags);
1013   ExtraICState extra_state = Code::ExtractExtraICStateFromFlags(flags);
1014   if (kind == Code::CALL_IC) {
1015     CallIC::GenerateMegamorphic(masm(), argc, extra_state);
1016   } else {
1017     KeyedCallIC::GenerateMegamorphic(masm(), argc);
1018   }
1019   Handle<Code> code = GetCodeWithFlags(flags, "CompileCallMegamorphic");
1020   isolate()->counters()->call_megamorphic_stubs()->Increment();
1021   PROFILE(isolate(),
1022           CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_MEGAMORPHIC_TAG),
1023                           *code, code->arguments_count()));
1024   GDBJIT(AddCode(GDBJITInterface::CALL_MEGAMORPHIC, *code));
1025   return code;
1026 }
1027 
1028 
CompileCallArguments(Code::Flags flags)1029 Handle<Code> StubCompiler::CompileCallArguments(Code::Flags flags) {
1030   int argc = Code::ExtractArgumentsCountFromFlags(flags);
1031   KeyedCallIC::GenerateNonStrictArguments(masm(), argc);
1032   Handle<Code> code = GetCodeWithFlags(flags, "CompileCallArguments");
1033   PROFILE(isolate(),
1034           CodeCreateEvent(CALL_LOGGER_TAG(Code::ExtractKindFromFlags(flags),
1035                                           CALL_MEGAMORPHIC_TAG),
1036                           *code, code->arguments_count()));
1037   GDBJIT(AddCode(GDBJITInterface::CALL_MEGAMORPHIC, *code));
1038   return code;
1039 }
1040 
1041 
CompileCallMiss(Code::Flags flags)1042 Handle<Code> StubCompiler::CompileCallMiss(Code::Flags flags) {
1043   int argc = Code::ExtractArgumentsCountFromFlags(flags);
1044   Code::Kind kind = Code::ExtractKindFromFlags(flags);
1045   ExtraICState extra_state = Code::ExtractExtraICStateFromFlags(flags);
1046   if (kind == Code::CALL_IC) {
1047     CallIC::GenerateMiss(masm(), argc, extra_state);
1048   } else {
1049     KeyedCallIC::GenerateMiss(masm(), argc);
1050   }
1051   Handle<Code> code = GetCodeWithFlags(flags, "CompileCallMiss");
1052   isolate()->counters()->call_megamorphic_stubs()->Increment();
1053   PROFILE(isolate(),
1054           CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_MISS_TAG),
1055                           *code, code->arguments_count()));
1056   GDBJIT(AddCode(GDBJITInterface::CALL_MISS, *code));
1057   return code;
1058 }
1059 
1060 
1061 #ifdef ENABLE_DEBUGGER_SUPPORT
CompileCallDebugBreak(Code::Flags flags)1062 Handle<Code> StubCompiler::CompileCallDebugBreak(Code::Flags flags) {
1063   Debug::GenerateCallICDebugBreak(masm());
1064   Handle<Code> code = GetCodeWithFlags(flags, "CompileCallDebugBreak");
1065   PROFILE(isolate(),
1066           CodeCreateEvent(CALL_LOGGER_TAG(Code::ExtractKindFromFlags(flags),
1067                                           CALL_DEBUG_BREAK_TAG),
1068                           *code, code->arguments_count()));
1069   return code;
1070 }
1071 
1072 
CompileCallDebugPrepareStepIn(Code::Flags flags)1073 Handle<Code> StubCompiler::CompileCallDebugPrepareStepIn(Code::Flags flags) {
1074   // Use the same code for the the step in preparations as we do for the
1075   // miss case.
1076   int argc = Code::ExtractArgumentsCountFromFlags(flags);
1077   Code::Kind kind = Code::ExtractKindFromFlags(flags);
1078   if (kind == Code::CALL_IC) {
1079     // For the debugger extra ic state is irrelevant.
1080     CallIC::GenerateMiss(masm(), argc, kNoExtraICState);
1081   } else {
1082     KeyedCallIC::GenerateMiss(masm(), argc);
1083   }
1084   Handle<Code> code = GetCodeWithFlags(flags, "CompileCallDebugPrepareStepIn");
1085   PROFILE(isolate(),
1086           CodeCreateEvent(
1087               CALL_LOGGER_TAG(kind, CALL_DEBUG_PREPARE_STEP_IN_TAG),
1088               *code,
1089               code->arguments_count()));
1090   return code;
1091 }
1092 #endif  // ENABLE_DEBUGGER_SUPPORT
1093 
1094 #undef CALL_LOGGER_TAG
1095 
1096 
GetCodeWithFlags(Code::Flags flags,const char * name)1097 Handle<Code> StubCompiler::GetCodeWithFlags(Code::Flags flags,
1098                                             const char* name) {
1099   // Create code object in the heap.
1100   CodeDesc desc;
1101   masm_.GetCode(&desc);
1102   Handle<Code> code = factory()->NewCode(desc, flags, masm_.CodeObject());
1103   if (code->has_major_key()) {
1104     code->set_major_key(CodeStub::NoCache);
1105   }
1106 #ifdef ENABLE_DISASSEMBLER
1107   if (FLAG_print_code_stubs) code->Disassemble(name);
1108 #endif
1109   return code;
1110 }
1111 
1112 
GetCodeWithFlags(Code::Flags flags,Handle<Name> name)1113 Handle<Code> StubCompiler::GetCodeWithFlags(Code::Flags flags,
1114                                             Handle<Name> name) {
1115   return (FLAG_print_code_stubs && !name.is_null() && name->IsString())
1116       ? GetCodeWithFlags(flags, *Handle<String>::cast(name)->ToCString())
1117       : GetCodeWithFlags(flags, NULL);
1118 }
1119 
1120 
LookupPostInterceptor(Handle<JSObject> holder,Handle<Name> name,LookupResult * lookup)1121 void StubCompiler::LookupPostInterceptor(Handle<JSObject> holder,
1122                                          Handle<Name> name,
1123                                          LookupResult* lookup) {
1124   holder->LocalLookupRealNamedProperty(*name, lookup);
1125   if (lookup->IsFound()) return;
1126   if (holder->GetPrototype()->IsNull()) return;
1127   holder->GetPrototype()->Lookup(*name, lookup);
1128 }
1129 
1130 
1131 #define __ ACCESS_MASM(masm())
1132 
1133 
call_kind()1134 CallKind CallStubCompiler::call_kind() {
1135   return CallICBase::Contextual::decode(extra_state())
1136       ? CALL_AS_FUNCTION
1137       : CALL_AS_METHOD;
1138 }
1139 
1140 
HandlerFrontendFooter(Label * miss)1141 void CallStubCompiler::HandlerFrontendFooter(Label* miss) {
1142   __ bind(miss);
1143   GenerateMissBranch();
1144 }
1145 
1146 
GenerateJumpFunctionIgnoreReceiver(Handle<JSFunction> function)1147 void CallStubCompiler::GenerateJumpFunctionIgnoreReceiver(
1148     Handle<JSFunction> function) {
1149   ParameterCount expected(function);
1150   __ InvokeFunction(function, expected, arguments(),
1151                     JUMP_FUNCTION, NullCallWrapper(), call_kind());
1152 }
1153 
1154 
GenerateJumpFunction(Handle<Object> object,Handle<JSFunction> function)1155 void CallStubCompiler::GenerateJumpFunction(Handle<Object> object,
1156                                             Handle<JSFunction> function) {
1157   PatchGlobalProxy(object);
1158   GenerateJumpFunctionIgnoreReceiver(function);
1159 }
1160 
1161 
GenerateJumpFunction(Handle<Object> object,Register actual_closure,Handle<JSFunction> function)1162 void CallStubCompiler::GenerateJumpFunction(Handle<Object> object,
1163                                             Register actual_closure,
1164                                             Handle<JSFunction> function) {
1165   PatchGlobalProxy(object);
1166   ParameterCount expected(function);
1167   __ InvokeFunction(actual_closure, expected, arguments(),
1168                     JUMP_FUNCTION, NullCallWrapper(), call_kind());
1169 }
1170 
1171 
CompileCallConstant(Handle<Object> object,Handle<JSObject> holder,Handle<Name> name,CheckType check,Handle<JSFunction> function)1172 Handle<Code> CallStubCompiler::CompileCallConstant(
1173     Handle<Object> object,
1174     Handle<JSObject> holder,
1175     Handle<Name> name,
1176     CheckType check,
1177     Handle<JSFunction> function) {
1178   if (HasCustomCallGenerator(function)) {
1179     Handle<Code> code = CompileCustomCall(object, holder,
1180                                           Handle<Cell>::null(),
1181                                           function, Handle<String>::cast(name),
1182                                           Code::FAST);
1183     // A null handle means bail out to the regular compiler code below.
1184     if (!code.is_null()) return code;
1185   }
1186 
1187   Label miss;
1188   HandlerFrontendHeader(object, holder, name, check, &miss);
1189   GenerateJumpFunction(object, function);
1190   HandlerFrontendFooter(&miss);
1191 
1192   // Return the generated code.
1193   return GetCode(function);
1194 }
1195 
1196 
HandlerFrontendHeader(Handle<Type> type,Register object_reg,Handle<JSObject> holder,Handle<Name> name,Label * miss)1197 Register LoadStubCompiler::HandlerFrontendHeader(
1198     Handle<Type> type,
1199     Register object_reg,
1200     Handle<JSObject> holder,
1201     Handle<Name> name,
1202     Label* miss) {
1203   PrototypeCheckType check_type = CHECK_ALL_MAPS;
1204   int function_index = -1;
1205   if (type->Is(Type::String())) {
1206     function_index = Context::STRING_FUNCTION_INDEX;
1207   } else if (type->Is(Type::Symbol())) {
1208     function_index = Context::SYMBOL_FUNCTION_INDEX;
1209   } else if (type->Is(Type::Number())) {
1210     function_index = Context::NUMBER_FUNCTION_INDEX;
1211   } else if (type->Is(Type::Boolean())) {
1212     // Booleans use the generic oddball map, so an additional check is needed to
1213     // ensure the receiver is really a boolean.
1214     GenerateBooleanCheck(object_reg, miss);
1215     function_index = Context::BOOLEAN_FUNCTION_INDEX;
1216   } else {
1217     check_type = SKIP_RECEIVER;
1218   }
1219 
1220   if (check_type == CHECK_ALL_MAPS) {
1221     GenerateDirectLoadGlobalFunctionPrototype(
1222         masm(), function_index, scratch1(), miss);
1223     Object* function = isolate()->native_context()->get(function_index);
1224     Object* prototype = JSFunction::cast(function)->instance_prototype();
1225     type = IC::CurrentTypeOf(handle(prototype, isolate()), isolate());
1226     object_reg = scratch1();
1227   }
1228 
1229   // Check that the maps starting from the prototype haven't changed.
1230   return CheckPrototypes(
1231       type, object_reg, holder, scratch1(), scratch2(), scratch3(),
1232       name, miss, check_type);
1233 }
1234 
1235 
1236 // HandlerFrontend for store uses the name register. It has to be restored
1237 // before a miss.
HandlerFrontendHeader(Handle<Type> type,Register object_reg,Handle<JSObject> holder,Handle<Name> name,Label * miss)1238 Register StoreStubCompiler::HandlerFrontendHeader(
1239     Handle<Type> type,
1240     Register object_reg,
1241     Handle<JSObject> holder,
1242     Handle<Name> name,
1243     Label* miss) {
1244   return CheckPrototypes(type, object_reg, holder, this->name(),
1245                          scratch1(), scratch2(), name, miss, SKIP_RECEIVER);
1246 }
1247 
1248 
IncludesNumberType(TypeHandleList * types)1249 bool BaseLoadStoreStubCompiler::IncludesNumberType(TypeHandleList* types) {
1250   for (int i = 0; i < types->length(); ++i) {
1251     if (types->at(i)->Is(Type::Number())) return true;
1252   }
1253   return false;
1254 }
1255 
1256 
HandlerFrontend(Handle<Type> type,Register object_reg,Handle<JSObject> holder,Handle<Name> name)1257 Register BaseLoadStoreStubCompiler::HandlerFrontend(Handle<Type> type,
1258                                                     Register object_reg,
1259                                                     Handle<JSObject> holder,
1260                                                     Handle<Name> name) {
1261   Label miss;
1262 
1263   Register reg = HandlerFrontendHeader(type, object_reg, holder, name, &miss);
1264 
1265   HandlerFrontendFooter(name, &miss);
1266 
1267   return reg;
1268 }
1269 
1270 
NonexistentHandlerFrontend(Handle<Type> type,Handle<JSObject> last,Handle<Name> name)1271 void LoadStubCompiler::NonexistentHandlerFrontend(Handle<Type> type,
1272                                                   Handle<JSObject> last,
1273                                                   Handle<Name> name) {
1274   Label miss;
1275 
1276   Register holder;
1277   Handle<Map> last_map;
1278   if (last.is_null()) {
1279     holder = receiver();
1280     last_map = IC::TypeToMap(*type, isolate());
1281     // If |type| has null as its prototype, |last| is Handle<JSObject>::null().
1282     ASSERT(last_map->prototype() == isolate()->heap()->null_value());
1283   } else {
1284     holder = HandlerFrontendHeader(type, receiver(), last, name, &miss);
1285     last_map = handle(last->map());
1286   }
1287 
1288   if (last_map->is_dictionary_map() &&
1289       !last_map->IsJSGlobalObjectMap() &&
1290       !last_map->IsJSGlobalProxyMap()) {
1291     if (!name->IsUniqueName()) {
1292       ASSERT(name->IsString());
1293       name = factory()->InternalizeString(Handle<String>::cast(name));
1294     }
1295     ASSERT(last.is_null() ||
1296            last->property_dictionary()->FindEntry(*name) ==
1297                NameDictionary::kNotFound);
1298     GenerateDictionaryNegativeLookup(masm(), &miss, holder, name,
1299                                      scratch2(), scratch3());
1300   }
1301 
1302   // If the last object in the prototype chain is a global object,
1303   // check that the global property cell is empty.
1304   if (last_map->IsJSGlobalObjectMap()) {
1305     Handle<JSGlobalObject> global = last.is_null()
1306         ? Handle<JSGlobalObject>::cast(type->AsConstant())
1307         : Handle<JSGlobalObject>::cast(last);
1308     GenerateCheckPropertyCell(masm(), global, name, scratch2(), &miss);
1309   }
1310 
1311   HandlerFrontendFooter(name, &miss);
1312 }
1313 
1314 
CompileLoadField(Handle<Type> type,Handle<JSObject> holder,Handle<Name> name,PropertyIndex field,Representation representation)1315 Handle<Code> LoadStubCompiler::CompileLoadField(
1316     Handle<Type> type,
1317     Handle<JSObject> holder,
1318     Handle<Name> name,
1319     PropertyIndex field,
1320     Representation representation) {
1321   Label miss;
1322 
1323   Register reg = HandlerFrontendHeader(type, receiver(), holder, name, &miss);
1324 
1325   GenerateLoadField(reg, holder, field, representation);
1326 
1327   __ bind(&miss);
1328   TailCallBuiltin(masm(), MissBuiltin(kind()));
1329 
1330   // Return the generated code.
1331   return GetCode(kind(), Code::FAST, name);
1332 }
1333 
1334 
CompileLoadConstant(Handle<Type> type,Handle<JSObject> holder,Handle<Name> name,Handle<Object> value)1335 Handle<Code> LoadStubCompiler::CompileLoadConstant(
1336     Handle<Type> type,
1337     Handle<JSObject> holder,
1338     Handle<Name> name,
1339     Handle<Object> value) {
1340   HandlerFrontend(type, receiver(), holder, name);
1341   GenerateLoadConstant(value);
1342 
1343   // Return the generated code.
1344   return GetCode(kind(), Code::FAST, name);
1345 }
1346 
1347 
CompileLoadCallback(Handle<Type> type,Handle<JSObject> holder,Handle<Name> name,Handle<ExecutableAccessorInfo> callback)1348 Handle<Code> LoadStubCompiler::CompileLoadCallback(
1349     Handle<Type> type,
1350     Handle<JSObject> holder,
1351     Handle<Name> name,
1352     Handle<ExecutableAccessorInfo> callback) {
1353   Register reg = CallbackHandlerFrontend(
1354       type, receiver(), holder, name, callback);
1355   GenerateLoadCallback(reg, callback);
1356 
1357   // Return the generated code.
1358   return GetCode(kind(), Code::FAST, name);
1359 }
1360 
1361 
CompileLoadCallback(Handle<Type> type,Handle<JSObject> holder,Handle<Name> name,const CallOptimization & call_optimization)1362 Handle<Code> LoadStubCompiler::CompileLoadCallback(
1363     Handle<Type> type,
1364     Handle<JSObject> holder,
1365     Handle<Name> name,
1366     const CallOptimization& call_optimization) {
1367   ASSERT(call_optimization.is_simple_api_call());
1368   Handle<JSFunction> callback = call_optimization.constant_function();
1369   CallbackHandlerFrontend(type, receiver(), holder, name, callback);
1370   GenerateLoadCallback(call_optimization);
1371 
1372   // Return the generated code.
1373   return GetCode(kind(), Code::FAST, name);
1374 }
1375 
1376 
CompileLoadInterceptor(Handle<Type> type,Handle<JSObject> holder,Handle<Name> name)1377 Handle<Code> LoadStubCompiler::CompileLoadInterceptor(
1378     Handle<Type> type,
1379     Handle<JSObject> holder,
1380     Handle<Name> name) {
1381   LookupResult lookup(isolate());
1382   LookupPostInterceptor(holder, name, &lookup);
1383 
1384   Register reg = HandlerFrontend(type, receiver(), holder, name);
1385   // TODO(368): Compile in the whole chain: all the interceptors in
1386   // prototypes and ultimate answer.
1387   GenerateLoadInterceptor(reg, type, holder, &lookup, name);
1388 
1389   // Return the generated code.
1390   return GetCode(kind(), Code::FAST, name);
1391 }
1392 
1393 
GenerateLoadPostInterceptor(Register interceptor_reg,Handle<JSObject> interceptor_holder,Handle<Name> name,LookupResult * lookup)1394 void LoadStubCompiler::GenerateLoadPostInterceptor(
1395     Register interceptor_reg,
1396     Handle<JSObject> interceptor_holder,
1397     Handle<Name> name,
1398     LookupResult* lookup) {
1399   Handle<JSObject> holder(lookup->holder());
1400   if (lookup->IsField()) {
1401     PropertyIndex field = lookup->GetFieldIndex();
1402     if (interceptor_holder.is_identical_to(holder)) {
1403       GenerateLoadField(
1404           interceptor_reg, holder, field, lookup->representation());
1405     } else {
1406       // We found FIELD property in prototype chain of interceptor's holder.
1407       // Retrieve a field from field's holder.
1408       Register reg = HandlerFrontend(
1409           IC::CurrentTypeOf(interceptor_holder, isolate()),
1410           interceptor_reg, holder, name);
1411       GenerateLoadField(
1412           reg, holder, field, lookup->representation());
1413     }
1414   } else {
1415     // We found CALLBACKS property in prototype chain of interceptor's
1416     // holder.
1417     ASSERT(lookup->type() == CALLBACKS);
1418     Handle<ExecutableAccessorInfo> callback(
1419         ExecutableAccessorInfo::cast(lookup->GetCallbackObject()));
1420     ASSERT(callback->getter() != NULL);
1421 
1422     Register reg = CallbackHandlerFrontend(
1423         IC::CurrentTypeOf(interceptor_holder, isolate()),
1424         interceptor_reg, holder, name, callback);
1425     GenerateLoadCallback(reg, callback);
1426   }
1427 }
1428 
1429 
CompileMonomorphicIC(Handle<Type> type,Handle<Code> handler,Handle<Name> name)1430 Handle<Code> BaseLoadStoreStubCompiler::CompileMonomorphicIC(
1431     Handle<Type> type,
1432     Handle<Code> handler,
1433     Handle<Name> name) {
1434   TypeHandleList types(1);
1435   CodeHandleList handlers(1);
1436   types.Add(type);
1437   handlers.Add(handler);
1438   Code::StubType stub_type = handler->type();
1439   return CompilePolymorphicIC(&types, &handlers, name, stub_type, PROPERTY);
1440 }
1441 
1442 
CompileLoadViaGetter(Handle<Type> type,Handle<JSObject> holder,Handle<Name> name,Handle<JSFunction> getter)1443 Handle<Code> LoadStubCompiler::CompileLoadViaGetter(
1444     Handle<Type> type,
1445     Handle<JSObject> holder,
1446     Handle<Name> name,
1447     Handle<JSFunction> getter) {
1448   HandlerFrontend(type, receiver(), holder, name);
1449   GenerateLoadViaGetter(masm(), receiver(), getter);
1450 
1451   // Return the generated code.
1452   return GetCode(kind(), Code::FAST, name);
1453 }
1454 
1455 
CompileStoreTransition(Handle<JSObject> object,LookupResult * lookup,Handle<Map> transition,Handle<Name> name)1456 Handle<Code> StoreStubCompiler::CompileStoreTransition(
1457     Handle<JSObject> object,
1458     LookupResult* lookup,
1459     Handle<Map> transition,
1460     Handle<Name> name) {
1461   Label miss, slow;
1462 
1463   // Ensure no transitions to deprecated maps are followed.
1464   __ CheckMapDeprecated(transition, scratch1(), &miss);
1465 
1466   // Check that we are allowed to write this.
1467   if (object->GetPrototype()->IsJSObject()) {
1468     Handle<JSObject> holder;
1469     // holder == object indicates that no property was found.
1470     if (lookup->holder() != *object) {
1471       holder = Handle<JSObject>(lookup->holder());
1472     } else {
1473       // Find the top object.
1474       holder = object;
1475       do {
1476         holder = Handle<JSObject>(JSObject::cast(holder->GetPrototype()));
1477       } while (holder->GetPrototype()->IsJSObject());
1478     }
1479 
1480     Register holder_reg = HandlerFrontendHeader(
1481         IC::CurrentTypeOf(object, isolate()), receiver(), holder, name, &miss);
1482 
1483     // If no property was found, and the holder (the last object in the
1484     // prototype chain) is in slow mode, we need to do a negative lookup on the
1485     // holder.
1486     if (lookup->holder() == *object) {
1487       GenerateNegativeHolderLookup(masm(), holder, holder_reg, name, &miss);
1488     }
1489   }
1490 
1491   GenerateStoreTransition(masm(),
1492                           object,
1493                           lookup,
1494                           transition,
1495                           name,
1496                           receiver(), this->name(), value(),
1497                           scratch1(), scratch2(), scratch3(),
1498                           &miss,
1499                           &slow);
1500 
1501   // Handle store cache miss.
1502   GenerateRestoreName(masm(), &miss, name);
1503   TailCallBuiltin(masm(), MissBuiltin(kind()));
1504 
1505   GenerateRestoreName(masm(), &slow, name);
1506   TailCallBuiltin(masm(), SlowBuiltin(kind()));
1507 
1508   // Return the generated code.
1509   return GetCode(kind(), Code::FAST, name);
1510 }
1511 
1512 
CompileStoreField(Handle<JSObject> object,LookupResult * lookup,Handle<Name> name)1513 Handle<Code> StoreStubCompiler::CompileStoreField(Handle<JSObject> object,
1514                                                   LookupResult* lookup,
1515                                                   Handle<Name> name) {
1516   Label miss;
1517 
1518   HandlerFrontendHeader(IC::CurrentTypeOf(object, isolate()),
1519                         receiver(), object, name, &miss);
1520 
1521   // Generate store field code.
1522   GenerateStoreField(masm(),
1523                      object,
1524                      lookup,
1525                      receiver(), this->name(), value(), scratch1(), scratch2(),
1526                      &miss);
1527 
1528   // Handle store cache miss.
1529   __ bind(&miss);
1530   TailCallBuiltin(masm(), MissBuiltin(kind()));
1531 
1532   // Return the generated code.
1533   return GetCode(kind(), Code::FAST, name);
1534 }
1535 
1536 
CompileStoreViaSetter(Handle<JSObject> object,Handle<JSObject> holder,Handle<Name> name,Handle<JSFunction> setter)1537 Handle<Code> StoreStubCompiler::CompileStoreViaSetter(
1538     Handle<JSObject> object,
1539     Handle<JSObject> holder,
1540     Handle<Name> name,
1541     Handle<JSFunction> setter) {
1542   HandlerFrontend(IC::CurrentTypeOf(object, isolate()),
1543                   receiver(), holder, name);
1544   GenerateStoreViaSetter(masm(), setter);
1545 
1546   return GetCode(kind(), Code::FAST, name);
1547 }
1548 
1549 
CompileLoadElement(Handle<Map> receiver_map)1550 Handle<Code> KeyedLoadStubCompiler::CompileLoadElement(
1551     Handle<Map> receiver_map) {
1552   ElementsKind elements_kind = receiver_map->elements_kind();
1553   if (receiver_map->has_fast_elements() ||
1554       receiver_map->has_external_array_elements()) {
1555     Handle<Code> stub = KeyedLoadFastElementStub(
1556         receiver_map->instance_type() == JS_ARRAY_TYPE,
1557         elements_kind).GetCode(isolate());
1558     __ DispatchMap(receiver(), scratch1(), receiver_map, stub, DO_SMI_CHECK);
1559   } else {
1560     Handle<Code> stub = FLAG_compiled_keyed_dictionary_loads
1561         ? KeyedLoadDictionaryElementStub().GetCode(isolate())
1562         : KeyedLoadDictionaryElementPlatformStub().GetCode(isolate());
1563     __ DispatchMap(receiver(), scratch1(), receiver_map, stub, DO_SMI_CHECK);
1564   }
1565 
1566   TailCallBuiltin(masm(), Builtins::kKeyedLoadIC_Miss);
1567 
1568   // Return the generated code.
1569   return GetICCode(kind(), Code::NORMAL, factory()->empty_string());
1570 }
1571 
1572 
CompileStoreElement(Handle<Map> receiver_map)1573 Handle<Code> KeyedStoreStubCompiler::CompileStoreElement(
1574     Handle<Map> receiver_map) {
1575   ElementsKind elements_kind = receiver_map->elements_kind();
1576   bool is_jsarray = receiver_map->instance_type() == JS_ARRAY_TYPE;
1577   Handle<Code> stub;
1578   if (receiver_map->has_fast_elements() ||
1579       receiver_map->has_external_array_elements()) {
1580     stub = KeyedStoreFastElementStub(
1581         is_jsarray,
1582         elements_kind,
1583         store_mode()).GetCode(isolate());
1584   } else {
1585     stub = KeyedStoreElementStub(is_jsarray,
1586                                  elements_kind,
1587                                  store_mode()).GetCode(isolate());
1588   }
1589 
1590   __ DispatchMap(receiver(), scratch1(), receiver_map, stub, DO_SMI_CHECK);
1591 
1592   TailCallBuiltin(masm(), Builtins::kKeyedStoreIC_Miss);
1593 
1594   // Return the generated code.
1595   return GetICCode(kind(), Code::NORMAL, factory()->empty_string());
1596 }
1597 
1598 
1599 #undef __
1600 
1601 
TailCallBuiltin(MacroAssembler * masm,Builtins::Name name)1602 void StubCompiler::TailCallBuiltin(MacroAssembler* masm, Builtins::Name name) {
1603   Handle<Code> code(masm->isolate()->builtins()->builtin(name));
1604   GenerateTailCall(masm, code);
1605 }
1606 
1607 
JitEvent(Handle<Name> name,Handle<Code> code)1608 void BaseLoadStoreStubCompiler::JitEvent(Handle<Name> name, Handle<Code> code) {
1609 #ifdef ENABLE_GDB_JIT_INTERFACE
1610   GDBJITInterface::CodeTag tag;
1611   if (kind_ == Code::LOAD_IC) {
1612     tag = GDBJITInterface::LOAD_IC;
1613   } else if (kind_ == Code::KEYED_LOAD_IC) {
1614     tag = GDBJITInterface::KEYED_LOAD_IC;
1615   } else if (kind_ == Code::STORE_IC) {
1616     tag = GDBJITInterface::STORE_IC;
1617   } else {
1618     tag = GDBJITInterface::KEYED_STORE_IC;
1619   }
1620   GDBJIT(AddCode(tag, *name, *code));
1621 #endif
1622 }
1623 
1624 
InitializeRegisters()1625 void BaseLoadStoreStubCompiler::InitializeRegisters() {
1626   if (kind_ == Code::LOAD_IC) {
1627     registers_ = LoadStubCompiler::registers();
1628   } else if (kind_ == Code::KEYED_LOAD_IC) {
1629     registers_ = KeyedLoadStubCompiler::registers();
1630   } else if (kind_ == Code::STORE_IC) {
1631     registers_ = StoreStubCompiler::registers();
1632   } else {
1633     registers_ = KeyedStoreStubCompiler::registers();
1634   }
1635 }
1636 
1637 
GetICCode(Code::Kind kind,Code::StubType type,Handle<Name> name,InlineCacheState state)1638 Handle<Code> BaseLoadStoreStubCompiler::GetICCode(Code::Kind kind,
1639                                                   Code::StubType type,
1640                                                   Handle<Name> name,
1641                                                   InlineCacheState state) {
1642   Code::Flags flags = Code::ComputeFlags(kind, state, extra_state(), type);
1643   Handle<Code> code = GetCodeWithFlags(flags, name);
1644   PROFILE(isolate(), CodeCreateEvent(log_kind(code), *code, *name));
1645   JitEvent(name, code);
1646   return code;
1647 }
1648 
1649 
GetCode(Code::Kind kind,Code::StubType type,Handle<Name> name)1650 Handle<Code> BaseLoadStoreStubCompiler::GetCode(Code::Kind kind,
1651                                                 Code::StubType type,
1652                                                 Handle<Name> name) {
1653   Code::Flags flags = Code::ComputeFlags(
1654       Code::HANDLER, MONOMORPHIC, extra_state(), type, kind, cache_holder_);
1655   Handle<Code> code = GetCodeWithFlags(flags, name);
1656   PROFILE(isolate(), CodeCreateEvent(log_kind(code), *code, *name));
1657   JitEvent(name, code);
1658   return code;
1659 }
1660 
1661 
CompileElementHandlers(MapHandleList * receiver_maps,CodeHandleList * handlers)1662 void KeyedLoadStubCompiler::CompileElementHandlers(MapHandleList* receiver_maps,
1663                                                    CodeHandleList* handlers) {
1664   for (int i = 0; i < receiver_maps->length(); ++i) {
1665     Handle<Map> receiver_map = receiver_maps->at(i);
1666     Handle<Code> cached_stub;
1667 
1668     if ((receiver_map->instance_type() & kNotStringTag) == 0) {
1669       cached_stub = isolate()->builtins()->KeyedLoadIC_String();
1670     } else if (receiver_map->instance_type() < FIRST_JS_RECEIVER_TYPE) {
1671       cached_stub = isolate()->builtins()->KeyedLoadIC_Slow();
1672     } else {
1673       bool is_js_array = receiver_map->instance_type() == JS_ARRAY_TYPE;
1674       ElementsKind elements_kind = receiver_map->elements_kind();
1675 
1676       if (IsFastElementsKind(elements_kind) ||
1677           IsExternalArrayElementsKind(elements_kind)) {
1678         cached_stub =
1679             KeyedLoadFastElementStub(is_js_array,
1680                                      elements_kind).GetCode(isolate());
1681       } else {
1682         ASSERT(elements_kind == DICTIONARY_ELEMENTS);
1683         cached_stub = KeyedLoadDictionaryElementStub().GetCode(isolate());
1684       }
1685     }
1686 
1687     handlers->Add(cached_stub);
1688   }
1689 }
1690 
1691 
CompileStoreElementPolymorphic(MapHandleList * receiver_maps)1692 Handle<Code> KeyedStoreStubCompiler::CompileStoreElementPolymorphic(
1693     MapHandleList* receiver_maps) {
1694   // Collect MONOMORPHIC stubs for all |receiver_maps|.
1695   CodeHandleList handlers(receiver_maps->length());
1696   MapHandleList transitioned_maps(receiver_maps->length());
1697   for (int i = 0; i < receiver_maps->length(); ++i) {
1698     Handle<Map> receiver_map(receiver_maps->at(i));
1699     Handle<Code> cached_stub;
1700     Handle<Map> transitioned_map =
1701         receiver_map->FindTransitionedMap(receiver_maps);
1702 
1703     // TODO(mvstanton): The code below is doing pessimistic elements
1704     // transitions. I would like to stop doing that and rely on Allocation Site
1705     // Tracking to do a better job of ensuring the data types are what they need
1706     // to be. Not all the elements are in place yet, pessimistic elements
1707     // transitions are still important for performance.
1708     bool is_js_array = receiver_map->instance_type() == JS_ARRAY_TYPE;
1709     ElementsKind elements_kind = receiver_map->elements_kind();
1710     if (!transitioned_map.is_null()) {
1711       cached_stub = ElementsTransitionAndStoreStub(
1712           elements_kind,
1713           transitioned_map->elements_kind(),
1714           is_js_array,
1715           store_mode()).GetCode(isolate());
1716     } else if (receiver_map->instance_type() < FIRST_JS_RECEIVER_TYPE) {
1717       cached_stub = isolate()->builtins()->KeyedStoreIC_Slow();
1718     } else {
1719       if (receiver_map->has_fast_elements() ||
1720           receiver_map->has_external_array_elements()) {
1721         cached_stub = KeyedStoreFastElementStub(
1722             is_js_array,
1723             elements_kind,
1724             store_mode()).GetCode(isolate());
1725       } else {
1726         cached_stub = KeyedStoreElementStub(
1727             is_js_array,
1728             elements_kind,
1729             store_mode()).GetCode(isolate());
1730       }
1731     }
1732     ASSERT(!cached_stub.is_null());
1733     handlers.Add(cached_stub);
1734     transitioned_maps.Add(transitioned_map);
1735   }
1736   Handle<Code> code =
1737       CompileStorePolymorphic(receiver_maps, &handlers, &transitioned_maps);
1738   isolate()->counters()->keyed_store_polymorphic_stubs()->Increment();
1739   PROFILE(isolate(),
1740           CodeCreateEvent(Logger::KEYED_STORE_POLYMORPHIC_IC_TAG, *code, 0));
1741   return code;
1742 }
1743 
1744 
GenerateStoreDictionaryElement(MacroAssembler * masm)1745 void KeyedStoreStubCompiler::GenerateStoreDictionaryElement(
1746     MacroAssembler* masm) {
1747   KeyedStoreIC::GenerateSlow(masm);
1748 }
1749 
1750 
CallStubCompiler(Isolate * isolate,int argc,Code::Kind kind,ExtraICState extra_state,InlineCacheHolderFlag cache_holder)1751 CallStubCompiler::CallStubCompiler(Isolate* isolate,
1752                                    int argc,
1753                                    Code::Kind kind,
1754                                    ExtraICState extra_state,
1755                                    InlineCacheHolderFlag cache_holder)
1756     : StubCompiler(isolate, extra_state),
1757       arguments_(argc),
1758       kind_(kind),
1759       cache_holder_(cache_holder) {
1760 }
1761 
1762 
HasCustomCallGenerator(Handle<JSFunction> function)1763 bool CallStubCompiler::HasCustomCallGenerator(Handle<JSFunction> function) {
1764   if (function->shared()->HasBuiltinFunctionId()) {
1765     BuiltinFunctionId id = function->shared()->builtin_function_id();
1766 #define CALL_GENERATOR_CASE(name) if (id == k##name) return true;
1767     CUSTOM_CALL_IC_GENERATORS(CALL_GENERATOR_CASE)
1768 #undef CALL_GENERATOR_CASE
1769   }
1770 
1771   CallOptimization optimization(function);
1772   return optimization.is_simple_api_call();
1773 }
1774 
1775 
CanBeCached(Handle<JSFunction> function)1776 bool CallStubCompiler::CanBeCached(Handle<JSFunction> function) {
1777   if (function->shared()->HasBuiltinFunctionId()) {
1778     BuiltinFunctionId id = function->shared()->builtin_function_id();
1779 #define CALL_GENERATOR_CASE(name) if (id == k##name) return false;
1780     SITE_SPECIFIC_CALL_GENERATORS(CALL_GENERATOR_CASE)
1781 #undef CALL_GENERATOR_CASE
1782   }
1783 
1784   return true;
1785 }
1786 
1787 
CompileCustomCall(Handle<Object> object,Handle<JSObject> holder,Handle<Cell> cell,Handle<JSFunction> function,Handle<String> fname,Code::StubType type)1788 Handle<Code> CallStubCompiler::CompileCustomCall(
1789     Handle<Object> object,
1790     Handle<JSObject> holder,
1791     Handle<Cell> cell,
1792     Handle<JSFunction> function,
1793     Handle<String> fname,
1794     Code::StubType type) {
1795   ASSERT(HasCustomCallGenerator(function));
1796 
1797   if (function->shared()->HasBuiltinFunctionId()) {
1798     BuiltinFunctionId id = function->shared()->builtin_function_id();
1799 #define CALL_GENERATOR_CASE(name)                               \
1800     if (id == k##name) {                                        \
1801       return CallStubCompiler::Compile##name##Call(object,      \
1802                                                    holder,      \
1803                                                    cell,        \
1804                                                    function,    \
1805                                                    fname,       \
1806                                                    type);       \
1807     }
1808     CUSTOM_CALL_IC_GENERATORS(CALL_GENERATOR_CASE)
1809 #undef CALL_GENERATOR_CASE
1810   }
1811   CallOptimization optimization(function);
1812   ASSERT(optimization.is_simple_api_call());
1813   return CompileFastApiCall(optimization,
1814                             object,
1815                             holder,
1816                             cell,
1817                             function,
1818                             fname);
1819 }
1820 
1821 
GetCode(Code::StubType type,Handle<Name> name)1822 Handle<Code> CallStubCompiler::GetCode(Code::StubType type,
1823                                        Handle<Name> name) {
1824   int argc = arguments_.immediate();
1825   Code::Flags flags = Code::ComputeMonomorphicFlags(
1826       kind_, extra_state(), cache_holder_, type, argc);
1827   return GetCodeWithFlags(flags, name);
1828 }
1829 
1830 
GetCode(Handle<JSFunction> function)1831 Handle<Code> CallStubCompiler::GetCode(Handle<JSFunction> function) {
1832   Handle<String> function_name;
1833   if (function->shared()->name()->IsString()) {
1834     function_name = Handle<String>(String::cast(function->shared()->name()));
1835   }
1836   return GetCode(Code::FAST, function_name);
1837 }
1838 
1839 
CallOptimization(LookupResult * lookup)1840 CallOptimization::CallOptimization(LookupResult* lookup) {
1841   if (lookup->IsFound() &&
1842       lookup->IsCacheable() &&
1843       lookup->IsConstantFunction()) {
1844     // We only optimize constant function calls.
1845     Initialize(Handle<JSFunction>(lookup->GetConstantFunction()));
1846   } else {
1847     Initialize(Handle<JSFunction>::null());
1848   }
1849 }
1850 
1851 
CallOptimization(Handle<JSFunction> function)1852 CallOptimization::CallOptimization(Handle<JSFunction> function) {
1853   Initialize(function);
1854 }
1855 
1856 
GetPrototypeDepthOfExpectedType(Handle<JSObject> object,Handle<JSObject> holder) const1857 int CallOptimization::GetPrototypeDepthOfExpectedType(
1858     Handle<JSObject> object,
1859     Handle<JSObject> holder) const {
1860   ASSERT(is_simple_api_call());
1861   if (expected_receiver_type_.is_null()) return 0;
1862   int depth = 0;
1863   while (!object.is_identical_to(holder)) {
1864     if (expected_receiver_type_->IsTemplateFor(object->map())) return depth;
1865     object = Handle<JSObject>(JSObject::cast(object->GetPrototype()));
1866     if (!object->map()->is_hidden_prototype()) return kInvalidProtoDepth;
1867     ++depth;
1868   }
1869   if (expected_receiver_type_->IsTemplateFor(holder->map())) return depth;
1870   return kInvalidProtoDepth;
1871 }
1872 
1873 
Initialize(Handle<JSFunction> function)1874 void CallOptimization::Initialize(Handle<JSFunction> function) {
1875   constant_function_ = Handle<JSFunction>::null();
1876   is_simple_api_call_ = false;
1877   expected_receiver_type_ = Handle<FunctionTemplateInfo>::null();
1878   api_call_info_ = Handle<CallHandlerInfo>::null();
1879 
1880   if (function.is_null() || !function->is_compiled()) return;
1881 
1882   constant_function_ = function;
1883   AnalyzePossibleApiFunction(function);
1884 }
1885 
1886 
AnalyzePossibleApiFunction(Handle<JSFunction> function)1887 void CallOptimization::AnalyzePossibleApiFunction(Handle<JSFunction> function) {
1888   if (!function->shared()->IsApiFunction()) return;
1889   Handle<FunctionTemplateInfo> info(function->shared()->get_api_func_data());
1890 
1891   // Require a C++ callback.
1892   if (info->call_code()->IsUndefined()) return;
1893   api_call_info_ =
1894       Handle<CallHandlerInfo>(CallHandlerInfo::cast(info->call_code()));
1895 
1896   // Accept signatures that either have no restrictions at all or
1897   // only have restrictions on the receiver.
1898   if (!info->signature()->IsUndefined()) {
1899     Handle<SignatureInfo> signature =
1900         Handle<SignatureInfo>(SignatureInfo::cast(info->signature()));
1901     if (!signature->args()->IsUndefined()) return;
1902     if (!signature->receiver()->IsUndefined()) {
1903       expected_receiver_type_ =
1904           Handle<FunctionTemplateInfo>(
1905               FunctionTemplateInfo::cast(signature->receiver()));
1906     }
1907   }
1908 
1909   is_simple_api_call_ = true;
1910 }
1911 
1912 
1913 } }  // namespace v8::internal
1914