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