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
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.
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.
31 #include "arguments.h"
33 #include "code-stubs.h"
34 #include "cpu-profiler.h"
37 #include "stub-cache.h"
38 #include "type-info.h"
39 #include "vm-state-inl.h"
44 // -----------------------------------------------------------------------
45 // StubCache implementation.
48 StubCache::StubCache(Isolate* isolate)
49 : isolate_(isolate) { }
52 void StubCache::Initialize() {
53 ASSERT(IsPowerOf2(kPrimaryTableSize));
54 ASSERT(IsPowerOf2(kSecondaryTableSize));
59 Code* StubCache::Set(Name* name, Map* map, Code* code) {
60 // Get the flags from the code.
61 Code::Flags flags = Code::RemoveTypeFromFlags(code->flags());
63 // Validate that the name does not move on scavenge, and that we
64 // can use identity checks instead of structural equality checks.
65 ASSERT(!heap()->InNewSpace(name));
66 ASSERT(name->IsUniqueName());
68 // The state bits are not important to the hash function because
69 // the stub cache only contains monomorphic stubs. Make sure that
70 // the bits are the least significant so they will be the ones
72 ASSERT(Code::ExtractICStateFromFlags(flags) == MONOMORPHIC);
73 STATIC_ASSERT((Code::ICStateField::kMask & 1) == 1);
75 // Make sure that the code type is not included in the hash.
76 ASSERT(Code::ExtractTypeFromFlags(flags) == 0);
78 // Compute the primary entry.
79 int primary_offset = PrimaryOffset(name, flags, map);
80 Entry* primary = entry(primary_, primary_offset);
81 Code* old_code = primary->value;
83 // If the primary entry has useful data in it, we retire it to the
84 // secondary cache before overwriting it.
85 if (old_code != isolate_->builtins()->builtin(Builtins::kIllegal)) {
86 Map* old_map = primary->map;
87 Code::Flags old_flags = Code::RemoveTypeFromFlags(old_code->flags());
88 int seed = PrimaryOffset(primary->key, old_flags, old_map);
89 int secondary_offset = SecondaryOffset(primary->key, old_flags, seed);
90 Entry* secondary = entry(secondary_, secondary_offset);
91 *secondary = *primary;
94 // Update primary cache.
96 primary->value = code;
98 isolate()->counters()->megamorphic_stub_cache_updates()->Increment();
103 Handle<Code> StubCache::FindIC(Handle<Name> name,
104 Handle<Map> stub_holder,
106 ExtraICState extra_state,
107 InlineCacheHolderFlag cache_holder) {
108 Code::Flags flags = Code::ComputeMonomorphicFlags(
109 kind, extra_state, cache_holder);
110 Handle<Object> probe(stub_holder->FindInCodeCache(*name, flags), isolate_);
111 if (probe->IsCode()) return Handle<Code>::cast(probe);
112 return Handle<Code>::null();
116 Handle<Code> StubCache::FindHandler(Handle<Name> name,
117 Handle<Map> stub_holder,
119 InlineCacheHolderFlag cache_holder) {
120 Code::Flags flags = Code::ComputeMonomorphicFlags(
121 Code::HANDLER, kNoExtraICState, cache_holder, Code::NORMAL, kind);
123 Handle<Object> probe(stub_holder->FindInCodeCache(*name, flags), isolate_);
124 if (probe->IsCode()) return Handle<Code>::cast(probe);
125 return Handle<Code>::null();
129 Handle<Code> StubCache::ComputeMonomorphicIC(
131 Handle<HeapType> type,
132 Handle<Code> handler,
133 ExtraICState extra_ic_state) {
134 Code::Kind kind = handler->handler_kind();
135 InlineCacheHolderFlag flag = IC::GetCodeCacheFlag(*type);
137 Handle<Map> stub_holder;
139 // There are multiple string maps that all use the same prototype. That
140 // prototype cannot hold multiple handlers, one for each of the string maps,
141 // for a single name. Hence, turn off caching of the IC.
142 bool can_be_cached = !type->Is(HeapType::String());
144 stub_holder = IC::GetCodeCacheHolder(flag, *type, isolate());
145 ic = FindIC(name, stub_holder, kind, extra_ic_state, flag);
146 if (!ic.is_null()) return ic;
149 if (kind == Code::LOAD_IC) {
150 LoadStubCompiler ic_compiler(isolate(), extra_ic_state, flag);
151 ic = ic_compiler.CompileMonomorphicIC(type, handler, name);
152 } else if (kind == Code::KEYED_LOAD_IC) {
153 KeyedLoadStubCompiler ic_compiler(isolate(), extra_ic_state, flag);
154 ic = ic_compiler.CompileMonomorphicIC(type, handler, name);
155 } else if (kind == Code::STORE_IC) {
156 StoreStubCompiler ic_compiler(isolate(), extra_ic_state);
157 ic = ic_compiler.CompileMonomorphicIC(type, handler, name);
159 ASSERT(kind == Code::KEYED_STORE_IC);
160 ASSERT(STANDARD_STORE ==
161 KeyedStoreIC::GetKeyedAccessStoreMode(extra_ic_state));
162 KeyedStoreStubCompiler ic_compiler(isolate(), extra_ic_state);
163 ic = ic_compiler.CompileMonomorphicIC(type, handler, name);
166 if (can_be_cached) Map::UpdateCodeCache(stub_holder, name, ic);
171 Handle<Code> StubCache::ComputeLoadNonexistent(Handle<Name> name,
172 Handle<HeapType> type) {
173 InlineCacheHolderFlag flag = IC::GetCodeCacheFlag(*type);
174 Handle<Map> stub_holder = IC::GetCodeCacheHolder(flag, *type, isolate());
175 // If no dictionary mode objects are present in the prototype chain, the load
176 // nonexistent IC stub can be shared for all names for a given map and we use
177 // the empty string for the map cache in that case. If there are dictionary
178 // mode objects involved, we need to do negative lookups in the stub and
179 // therefore the stub will be specific to the name.
180 Handle<Map> current_map = stub_holder;
181 Handle<Name> cache_name = current_map->is_dictionary_map()
182 ? name : Handle<Name>::cast(isolate()->factory()->empty_string());
183 Handle<Object> next(current_map->prototype(), isolate());
184 Handle<JSObject> last = Handle<JSObject>::null();
185 while (!next->IsNull()) {
186 last = Handle<JSObject>::cast(next);
187 next = handle(current_map->prototype(), isolate());
188 current_map = handle(Handle<HeapObject>::cast(next)->map());
189 if (current_map->is_dictionary_map()) cache_name = name;
192 // Compile the stub that is either shared for all names or
193 // name specific if there are global objects involved.
194 Handle<Code> handler = FindHandler(
195 cache_name, stub_holder, Code::LOAD_IC, flag);
196 if (!handler.is_null()) return handler;
198 LoadStubCompiler compiler(isolate_, kNoExtraICState, flag);
199 handler = compiler.CompileLoadNonexistent(type, last, cache_name);
200 Map::UpdateCodeCache(stub_holder, cache_name, handler);
205 Handle<Code> StubCache::ComputeKeyedLoadElement(Handle<Map> receiver_map) {
206 Code::Flags flags = Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC);
208 isolate()->factory()->KeyedLoadElementMonomorphic_string();
210 Handle<Object> probe(receiver_map->FindInCodeCache(*name, flags), isolate_);
211 if (probe->IsCode()) return Handle<Code>::cast(probe);
213 KeyedLoadStubCompiler compiler(isolate());
214 Handle<Code> code = compiler.CompileLoadElement(receiver_map);
216 Map::UpdateCodeCache(receiver_map, name, code);
221 Handle<Code> StubCache::ComputeKeyedStoreElement(
222 Handle<Map> receiver_map,
223 StrictModeFlag strict_mode,
224 KeyedAccessStoreMode store_mode) {
225 ExtraICState extra_state =
226 KeyedStoreIC::ComputeExtraICState(strict_mode, store_mode);
227 Code::Flags flags = Code::ComputeMonomorphicFlags(
228 Code::KEYED_STORE_IC, extra_state);
230 ASSERT(store_mode == STANDARD_STORE ||
231 store_mode == STORE_AND_GROW_NO_TRANSITION ||
232 store_mode == STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS ||
233 store_mode == STORE_NO_TRANSITION_HANDLE_COW);
235 Handle<String> name =
236 isolate()->factory()->KeyedStoreElementMonomorphic_string();
237 Handle<Object> probe(receiver_map->FindInCodeCache(*name, flags), isolate_);
238 if (probe->IsCode()) return Handle<Code>::cast(probe);
240 KeyedStoreStubCompiler compiler(isolate(), extra_state);
241 Handle<Code> code = compiler.CompileStoreElement(receiver_map);
243 Map::UpdateCodeCache(receiver_map, name, code);
244 ASSERT(KeyedStoreIC::GetKeyedAccessStoreMode(code->extra_ic_state())
250 #define CALL_LOGGER_TAG(kind, type) (Logger::KEYED_##type)
252 static void FillCache(Isolate* isolate, Handle<Code> code) {
253 Handle<UnseededNumberDictionary> dictionary =
254 UnseededNumberDictionary::Set(isolate->factory()->non_monomorphic_cache(),
257 isolate->heap()->public_set_non_monomorphic_cache(*dictionary);
261 Code* StubCache::FindPreMonomorphicIC(Code::Kind kind, ExtraICState state) {
262 Code::Flags flags = Code::ComputeFlags(kind, PREMONOMORPHIC, state);
263 UnseededNumberDictionary* dictionary =
264 isolate()->heap()->non_monomorphic_cache();
265 int entry = dictionary->FindEntry(isolate(), flags);
267 Object* code = dictionary->ValueAt(entry);
268 // This might be called during the marking phase of the collector
269 // hence the unchecked cast.
270 return reinterpret_cast<Code*>(code);
274 Handle<Code> StubCache::ComputeLoad(InlineCacheState ic_state,
275 ExtraICState extra_state) {
276 Code::Flags flags = Code::ComputeFlags(Code::LOAD_IC, ic_state, extra_state);
277 Handle<UnseededNumberDictionary> cache =
278 isolate_->factory()->non_monomorphic_cache();
279 int entry = cache->FindEntry(isolate_, flags);
280 if (entry != -1) return Handle<Code>(Code::cast(cache->ValueAt(entry)));
282 StubCompiler compiler(isolate_);
284 if (ic_state == UNINITIALIZED) {
285 code = compiler.CompileLoadInitialize(flags);
286 } else if (ic_state == PREMONOMORPHIC) {
287 code = compiler.CompileLoadPreMonomorphic(flags);
288 } else if (ic_state == MEGAMORPHIC) {
289 code = compiler.CompileLoadMegamorphic(flags);
293 FillCache(isolate_, code);
298 Handle<Code> StubCache::ComputeStore(InlineCacheState ic_state,
299 ExtraICState extra_state) {
300 Code::Flags flags = Code::ComputeFlags(Code::STORE_IC, ic_state, extra_state);
301 Handle<UnseededNumberDictionary> cache =
302 isolate_->factory()->non_monomorphic_cache();
303 int entry = cache->FindEntry(isolate_, flags);
304 if (entry != -1) return Handle<Code>(Code::cast(cache->ValueAt(entry)));
306 StubCompiler compiler(isolate_);
308 if (ic_state == UNINITIALIZED) {
309 code = compiler.CompileStoreInitialize(flags);
310 } else if (ic_state == PREMONOMORPHIC) {
311 code = compiler.CompileStorePreMonomorphic(flags);
312 } else if (ic_state == GENERIC) {
313 code = compiler.CompileStoreGeneric(flags);
314 } else if (ic_state == MEGAMORPHIC) {
315 code = compiler.CompileStoreMegamorphic(flags);
320 FillCache(isolate_, code);
325 Handle<Code> StubCache::ComputeCompareNil(Handle<Map> receiver_map,
326 CompareNilICStub& stub) {
327 Handle<String> name(isolate_->heap()->empty_string());
328 if (!receiver_map->is_shared()) {
329 Handle<Code> cached_ic = FindIC(name, receiver_map, Code::COMPARE_NIL_IC,
330 stub.GetExtraICState());
331 if (!cached_ic.is_null()) return cached_ic;
334 Handle<Code> ic = stub.GetCodeCopyFromTemplate(isolate_);
335 ic->ReplaceNthObject(1, isolate_->heap()->meta_map(), *receiver_map);
337 if (!receiver_map->is_shared()) {
338 Map::UpdateCodeCache(receiver_map, name, ic);
345 // TODO(verwaest): Change this method so it takes in a TypeHandleList.
346 Handle<Code> StubCache::ComputeLoadElementPolymorphic(
347 MapHandleList* receiver_maps) {
348 Code::Flags flags = Code::ComputeFlags(Code::KEYED_LOAD_IC, POLYMORPHIC);
349 Handle<PolymorphicCodeCache> cache =
350 isolate_->factory()->polymorphic_code_cache();
351 Handle<Object> probe = cache->Lookup(receiver_maps, flags);
352 if (probe->IsCode()) return Handle<Code>::cast(probe);
354 TypeHandleList types(receiver_maps->length());
355 for (int i = 0; i < receiver_maps->length(); i++) {
356 types.Add(HeapType::Class(receiver_maps->at(i), isolate()));
358 CodeHandleList handlers(receiver_maps->length());
359 KeyedLoadStubCompiler compiler(isolate_);
360 compiler.CompileElementHandlers(receiver_maps, &handlers);
361 Handle<Code> code = compiler.CompilePolymorphicIC(
362 &types, &handlers, factory()->empty_string(), Code::NORMAL, ELEMENT);
364 isolate()->counters()->keyed_load_polymorphic_stubs()->Increment();
366 PolymorphicCodeCache::Update(cache, receiver_maps, flags, code);
371 Handle<Code> StubCache::ComputePolymorphicIC(
372 TypeHandleList* types,
373 CodeHandleList* handlers,
374 int number_of_valid_types,
376 ExtraICState extra_ic_state) {
378 Handle<Code> handler = handlers->at(0);
379 Code::Kind kind = handler->handler_kind();
380 Code::StubType type = number_of_valid_types == 1 ? handler->type()
382 if (kind == Code::LOAD_IC) {
383 LoadStubCompiler ic_compiler(isolate_, extra_ic_state);
384 return ic_compiler.CompilePolymorphicIC(
385 types, handlers, name, type, PROPERTY);
387 ASSERT(kind == Code::STORE_IC);
388 StoreStubCompiler ic_compiler(isolate_, extra_ic_state);
389 return ic_compiler.CompilePolymorphicIC(
390 types, handlers, name, type, PROPERTY);
395 Handle<Code> StubCache::ComputeStoreElementPolymorphic(
396 MapHandleList* receiver_maps,
397 KeyedAccessStoreMode store_mode,
398 StrictModeFlag strict_mode) {
399 ASSERT(store_mode == STANDARD_STORE ||
400 store_mode == STORE_AND_GROW_NO_TRANSITION ||
401 store_mode == STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS ||
402 store_mode == STORE_NO_TRANSITION_HANDLE_COW);
403 Handle<PolymorphicCodeCache> cache =
404 isolate_->factory()->polymorphic_code_cache();
405 ExtraICState extra_state = KeyedStoreIC::ComputeExtraICState(
406 strict_mode, store_mode);
408 Code::ComputeFlags(Code::KEYED_STORE_IC, POLYMORPHIC, extra_state);
409 Handle<Object> probe = cache->Lookup(receiver_maps, flags);
410 if (probe->IsCode()) return Handle<Code>::cast(probe);
412 KeyedStoreStubCompiler compiler(isolate_, extra_state);
413 Handle<Code> code = compiler.CompileStoreElementPolymorphic(receiver_maps);
414 PolymorphicCodeCache::Update(cache, receiver_maps, flags, code);
419 void StubCache::Clear() {
420 Code* empty = isolate_->builtins()->builtin(Builtins::kIllegal);
421 for (int i = 0; i < kPrimaryTableSize; i++) {
422 primary_[i].key = heap()->empty_string();
423 primary_[i].map = NULL;
424 primary_[i].value = empty;
426 for (int j = 0; j < kSecondaryTableSize; j++) {
427 secondary_[j].key = heap()->empty_string();
428 secondary_[j].map = NULL;
429 secondary_[j].value = empty;
434 void StubCache::CollectMatchingMaps(SmallMapList* types,
437 Handle<Context> native_context,
439 for (int i = 0; i < kPrimaryTableSize; i++) {
440 if (primary_[i].key == *name) {
441 Map* map = primary_[i].map;
442 // Map can be NULL, if the stub is constant function call
443 // with a primitive receiver.
444 if (map == NULL) continue;
446 int offset = PrimaryOffset(*name, flags, map);
447 if (entry(primary_, offset) == &primary_[i] &&
448 !TypeFeedbackOracle::CanRetainOtherContext(map, *native_context)) {
449 types->AddMapIfMissing(Handle<Map>(map), zone);
454 for (int i = 0; i < kSecondaryTableSize; i++) {
455 if (secondary_[i].key == *name) {
456 Map* map = secondary_[i].map;
457 // Map can be NULL, if the stub is constant function call
458 // with a primitive receiver.
459 if (map == NULL) continue;
461 // Lookup in primary table and skip duplicates.
462 int primary_offset = PrimaryOffset(*name, flags, map);
464 // Lookup in secondary table and add matches.
465 int offset = SecondaryOffset(*name, flags, primary_offset);
466 if (entry(secondary_, offset) == &secondary_[i] &&
467 !TypeFeedbackOracle::CanRetainOtherContext(map, *native_context)) {
468 types->AddMapIfMissing(Handle<Map>(map), zone);
475 // ------------------------------------------------------------------------
476 // StubCompiler implementation.
479 RUNTIME_FUNCTION(MaybeObject*, StoreCallbackProperty) {
480 JSObject* receiver = JSObject::cast(args[0]);
481 JSObject* holder = JSObject::cast(args[1]);
482 ExecutableAccessorInfo* callback = ExecutableAccessorInfo::cast(args[2]);
483 Address setter_address = v8::ToCData<Address>(callback->setter());
484 v8::AccessorSetterCallback fun =
485 FUNCTION_CAST<v8::AccessorSetterCallback>(setter_address);
487 ASSERT(callback->IsCompatibleReceiver(receiver));
488 Handle<Name> name = args.at<Name>(3);
489 Handle<Object> value = args.at<Object>(4);
490 HandleScope scope(isolate);
492 // TODO(rossberg): Support symbols in the API.
493 if (name->IsSymbol()) return *value;
494 Handle<String> str = Handle<String>::cast(name);
496 LOG(isolate, ApiNamedPropertyAccess("store", receiver, *name));
497 PropertyCallbackArguments
498 custom_args(isolate, callback->data(), receiver, holder);
499 custom_args.Call(fun, v8::Utils::ToLocal(str), v8::Utils::ToLocal(value));
500 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
506 * Attempts to load a property with an interceptor (which must be present),
507 * but doesn't search the prototype chain.
509 * Returns |Heap::no_interceptor_result_sentinel()| if interceptor doesn't
510 * provide any value for the given name.
512 RUNTIME_FUNCTION(MaybeObject*, LoadPropertyWithInterceptorOnly) {
513 ASSERT(args.length() == StubCache::kInterceptorArgsLength);
514 Handle<Name> name_handle =
515 args.at<Name>(StubCache::kInterceptorArgsNameIndex);
516 Handle<InterceptorInfo> interceptor_info =
517 args.at<InterceptorInfo>(StubCache::kInterceptorArgsInfoIndex);
519 // TODO(rossberg): Support symbols in the API.
520 if (name_handle->IsSymbol())
521 return isolate->heap()->no_interceptor_result_sentinel();
522 Handle<String> name = Handle<String>::cast(name_handle);
524 Address getter_address = v8::ToCData<Address>(interceptor_info->getter());
525 v8::NamedPropertyGetterCallback getter =
526 FUNCTION_CAST<v8::NamedPropertyGetterCallback>(getter_address);
527 ASSERT(getter != NULL);
529 Handle<JSObject> receiver =
530 args.at<JSObject>(StubCache::kInterceptorArgsThisIndex);
531 Handle<JSObject> holder =
532 args.at<JSObject>(StubCache::kInterceptorArgsHolderIndex);
533 PropertyCallbackArguments callback_args(
534 isolate, interceptor_info->data(), *receiver, *holder);
536 // Use the interceptor getter.
537 HandleScope scope(isolate);
538 v8::Handle<v8::Value> r =
539 callback_args.Call(getter, v8::Utils::ToLocal(name));
540 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
542 Handle<Object> result = v8::Utils::OpenHandle(*r);
543 result->VerifyApiCallResultType();
544 return *v8::Utils::OpenHandle(*r);
548 return isolate->heap()->no_interceptor_result_sentinel();
552 static MaybeObject* ThrowReferenceError(Isolate* isolate, Name* name) {
553 // If the load is non-contextual, just return the undefined result.
554 // Note that both keyed and non-keyed loads may end up here.
555 HandleScope scope(isolate);
556 LoadIC ic(IC::NO_EXTRA_FRAME, isolate);
557 if (ic.contextual_mode() != CONTEXTUAL) {
558 return isolate->heap()->undefined_value();
561 // Throw a reference error.
562 Handle<Name> name_handle(name);
563 Handle<Object> error =
564 isolate->factory()->NewReferenceError("not_defined",
565 HandleVector(&name_handle, 1));
566 return isolate->Throw(*error);
570 static Handle<Object> LoadWithInterceptor(Arguments* args,
571 PropertyAttributes* attrs) {
572 ASSERT(args->length() == StubCache::kInterceptorArgsLength);
573 Handle<Name> name_handle =
574 args->at<Name>(StubCache::kInterceptorArgsNameIndex);
575 Handle<InterceptorInfo> interceptor_info =
576 args->at<InterceptorInfo>(StubCache::kInterceptorArgsInfoIndex);
577 Handle<JSObject> receiver_handle =
578 args->at<JSObject>(StubCache::kInterceptorArgsThisIndex);
579 Handle<JSObject> holder_handle =
580 args->at<JSObject>(StubCache::kInterceptorArgsHolderIndex);
582 Isolate* isolate = receiver_handle->GetIsolate();
584 // TODO(rossberg): Support symbols in the API.
585 if (name_handle->IsSymbol()) {
586 return JSObject::GetPropertyPostInterceptor(
587 holder_handle, receiver_handle, name_handle, attrs);
589 Handle<String> name = Handle<String>::cast(name_handle);
591 Address getter_address = v8::ToCData<Address>(interceptor_info->getter());
592 v8::NamedPropertyGetterCallback getter =
593 FUNCTION_CAST<v8::NamedPropertyGetterCallback>(getter_address);
594 ASSERT(getter != NULL);
596 PropertyCallbackArguments callback_args(isolate,
597 interceptor_info->data(),
601 HandleScope scope(isolate);
602 // Use the interceptor getter.
603 v8::Handle<v8::Value> r =
604 callback_args.Call(getter, v8::Utils::ToLocal(name));
605 RETURN_HANDLE_IF_SCHEDULED_EXCEPTION(isolate, Object);
608 Handle<Object> result = v8::Utils::OpenHandle(*r);
609 result->VerifyApiCallResultType();
610 return scope.CloseAndEscape(result);
614 Handle<Object> result = JSObject::GetPropertyPostInterceptor(
615 holder_handle, receiver_handle, name_handle, attrs);
621 * Loads a property with an interceptor performing post interceptor
622 * lookup if interceptor failed.
624 RUNTIME_FUNCTION(MaybeObject*, LoadPropertyWithInterceptorForLoad) {
625 PropertyAttributes attr = NONE;
626 HandleScope scope(isolate);
627 Handle<Object> result = LoadWithInterceptor(&args, &attr);
628 RETURN_IF_EMPTY_HANDLE(isolate, result);
630 // If the property is present, return it.
631 if (attr != ABSENT) return *result;
632 return ThrowReferenceError(isolate, Name::cast(args[0]));
636 RUNTIME_FUNCTION(MaybeObject*, LoadPropertyWithInterceptorForCall) {
637 PropertyAttributes attr;
638 HandleScope scope(isolate);
639 Handle<Object> result = LoadWithInterceptor(&args, &attr);
640 RETURN_IF_EMPTY_HANDLE(isolate, result);
641 // This is call IC. In this case, we simply return the undefined result which
642 // will lead to an exception when trying to invoke the result as a
648 RUNTIME_FUNCTION(MaybeObject*, StoreInterceptorProperty) {
649 HandleScope scope(isolate);
650 ASSERT(args.length() == 3);
651 StoreIC ic(IC::NO_EXTRA_FRAME, isolate);
652 Handle<JSObject> receiver = args.at<JSObject>(0);
653 Handle<Name> name = args.at<Name>(1);
654 Handle<Object> value = args.at<Object>(2);
655 ASSERT(receiver->HasNamedInterceptor());
656 PropertyAttributes attr = NONE;
657 Handle<Object> result = JSObject::SetPropertyWithInterceptor(
658 receiver, name, value, attr, ic.strict_mode());
659 RETURN_IF_EMPTY_HANDLE(isolate, result);
664 RUNTIME_FUNCTION(MaybeObject*, KeyedLoadPropertyWithInterceptor) {
665 JSObject* receiver = JSObject::cast(args[0]);
666 ASSERT(args.smi_at(1) >= 0);
667 uint32_t index = args.smi_at(1);
668 return receiver->GetElementWithInterceptor(receiver, index);
672 Handle<Code> StubCompiler::CompileLoadInitialize(Code::Flags flags) {
673 LoadIC::GenerateInitialize(masm());
674 Handle<Code> code = GetCodeWithFlags(flags, "CompileLoadInitialize");
676 CodeCreateEvent(Logger::LOAD_INITIALIZE_TAG, *code, 0));
677 GDBJIT(AddCode(GDBJITInterface::LOAD_IC, *code));
682 Handle<Code> StubCompiler::CompileLoadPreMonomorphic(Code::Flags flags) {
683 LoadIC::GeneratePreMonomorphic(masm());
684 Handle<Code> code = GetCodeWithFlags(flags, "CompileLoadPreMonomorphic");
686 CodeCreateEvent(Logger::LOAD_PREMONOMORPHIC_TAG, *code, 0));
687 GDBJIT(AddCode(GDBJITInterface::LOAD_IC, *code));
692 Handle<Code> StubCompiler::CompileLoadMegamorphic(Code::Flags flags) {
693 ExtraICState extra_state = Code::ExtractExtraICStateFromFlags(flags);
694 ContextualMode mode = LoadIC::GetContextualMode(extra_state);
695 LoadIC::GenerateMegamorphic(masm(), mode);
696 Handle<Code> code = GetCodeWithFlags(flags, "CompileLoadMegamorphic");
698 CodeCreateEvent(Logger::LOAD_MEGAMORPHIC_TAG, *code, 0));
699 GDBJIT(AddCode(GDBJITInterface::LOAD_IC, *code));
704 Handle<Code> StubCompiler::CompileStoreInitialize(Code::Flags flags) {
705 StoreIC::GenerateInitialize(masm());
706 Handle<Code> code = GetCodeWithFlags(flags, "CompileStoreInitialize");
708 CodeCreateEvent(Logger::STORE_INITIALIZE_TAG, *code, 0));
709 GDBJIT(AddCode(GDBJITInterface::STORE_IC, *code));
714 Handle<Code> StubCompiler::CompileStorePreMonomorphic(Code::Flags flags) {
715 StoreIC::GeneratePreMonomorphic(masm());
716 Handle<Code> code = GetCodeWithFlags(flags, "CompileStorePreMonomorphic");
718 CodeCreateEvent(Logger::STORE_PREMONOMORPHIC_TAG, *code, 0));
719 GDBJIT(AddCode(GDBJITInterface::STORE_IC, *code));
724 Handle<Code> StubCompiler::CompileStoreGeneric(Code::Flags flags) {
725 ExtraICState extra_state = Code::ExtractExtraICStateFromFlags(flags);
726 StrictModeFlag strict_mode = StoreIC::GetStrictMode(extra_state);
727 StoreIC::GenerateRuntimeSetProperty(masm(), strict_mode);
728 Handle<Code> code = GetCodeWithFlags(flags, "CompileStoreGeneric");
730 CodeCreateEvent(Logger::STORE_GENERIC_TAG, *code, 0));
731 GDBJIT(AddCode(GDBJITInterface::STORE_IC, *code));
736 Handle<Code> StubCompiler::CompileStoreMegamorphic(Code::Flags flags) {
737 ExtraICState extra_state = Code::ExtractExtraICStateFromFlags(flags);
738 StoreIC::GenerateMegamorphic(masm(), extra_state);
739 Handle<Code> code = GetCodeWithFlags(flags, "CompileStoreMegamorphic");
741 CodeCreateEvent(Logger::STORE_MEGAMORPHIC_TAG, *code, 0));
742 GDBJIT(AddCode(GDBJITInterface::STORE_IC, *code));
747 #undef CALL_LOGGER_TAG
750 Handle<Code> StubCompiler::GetCodeWithFlags(Code::Flags flags,
752 // Create code object in the heap.
754 masm_.GetCode(&desc);
755 Handle<Code> code = factory()->NewCode(desc, flags, masm_.CodeObject());
756 if (code->has_major_key()) {
757 code->set_major_key(CodeStub::NoCache);
759 #ifdef ENABLE_DISASSEMBLER
760 if (FLAG_print_code_stubs) code->Disassemble(name);
766 Handle<Code> StubCompiler::GetCodeWithFlags(Code::Flags flags,
768 return (FLAG_print_code_stubs && !name.is_null() && name->IsString())
769 ? GetCodeWithFlags(flags, Handle<String>::cast(name)->ToCString().get())
770 : GetCodeWithFlags(flags, NULL);
774 void StubCompiler::LookupPostInterceptor(Handle<JSObject> holder,
776 LookupResult* lookup) {
777 holder->LocalLookupRealNamedProperty(*name, lookup);
778 if (lookup->IsFound()) return;
779 if (holder->GetPrototype()->IsNull()) return;
780 holder->GetPrototype()->Lookup(*name, lookup);
784 #define __ ACCESS_MASM(masm())
787 Register LoadStubCompiler::HandlerFrontendHeader(
788 Handle<HeapType> type,
790 Handle<JSObject> holder,
793 PrototypeCheckType check_type = CHECK_ALL_MAPS;
794 int function_index = -1;
795 if (type->Is(HeapType::String())) {
796 function_index = Context::STRING_FUNCTION_INDEX;
797 } else if (type->Is(HeapType::Symbol())) {
798 function_index = Context::SYMBOL_FUNCTION_INDEX;
799 } else if (type->Is(HeapType::Number())) {
800 function_index = Context::NUMBER_FUNCTION_INDEX;
801 } else if (type->Is(HeapType::Float32x4())) {
802 function_index = Context::FLOAT32x4_FUNCTION_INDEX;
803 } else if (type->Is(HeapType::Int32x4())) {
804 function_index = Context::INT32x4_FUNCTION_INDEX;
805 } else if (type->Is(HeapType::Boolean())) {
806 // Booleans use the generic oddball map, so an additional check is needed to
807 // ensure the receiver is really a boolean.
808 GenerateBooleanCheck(object_reg, miss);
809 function_index = Context::BOOLEAN_FUNCTION_INDEX;
811 check_type = SKIP_RECEIVER;
814 if (check_type == CHECK_ALL_MAPS) {
815 GenerateDirectLoadGlobalFunctionPrototype(
816 masm(), function_index, scratch1(), miss);
817 Object* function = isolate()->native_context()->get(function_index);
818 Object* prototype = JSFunction::cast(function)->instance_prototype();
819 type = IC::CurrentTypeOf(handle(prototype, isolate()), isolate());
820 object_reg = scratch1();
823 // Check that the maps starting from the prototype haven't changed.
824 return CheckPrototypes(
825 type, object_reg, holder, scratch1(), scratch2(), scratch3(),
826 name, miss, check_type);
830 // HandlerFrontend for store uses the name register. It has to be restored
832 Register StoreStubCompiler::HandlerFrontendHeader(
833 Handle<HeapType> type,
835 Handle<JSObject> holder,
838 return CheckPrototypes(type, object_reg, holder, this->name(),
839 scratch1(), scratch2(), name, miss, SKIP_RECEIVER);
843 bool BaseLoadStoreStubCompiler::IncludesNumberType(TypeHandleList* types) {
844 for (int i = 0; i < types->length(); ++i) {
845 if (types->at(i)->Is(HeapType::Number())) return true;
851 Register BaseLoadStoreStubCompiler::HandlerFrontend(Handle<HeapType> type,
853 Handle<JSObject> holder,
857 Register reg = HandlerFrontendHeader(type, object_reg, holder, name, &miss);
859 HandlerFrontendFooter(name, &miss);
865 void LoadStubCompiler::NonexistentHandlerFrontend(Handle<HeapType> type,
866 Handle<JSObject> last,
871 Handle<Map> last_map;
872 if (last.is_null()) {
874 last_map = IC::TypeToMap(*type, isolate());
875 // If |type| has null as its prototype, |last| is Handle<JSObject>::null().
876 ASSERT(last_map->prototype() == isolate()->heap()->null_value());
878 holder = HandlerFrontendHeader(type, receiver(), last, name, &miss);
879 last_map = handle(last->map());
882 if (last_map->is_dictionary_map() &&
883 !last_map->IsJSGlobalObjectMap() &&
884 !last_map->IsJSGlobalProxyMap()) {
885 if (!name->IsUniqueName()) {
886 ASSERT(name->IsString());
887 name = factory()->InternalizeString(Handle<String>::cast(name));
889 ASSERT(last.is_null() ||
890 last->property_dictionary()->FindEntry(*name) ==
891 NameDictionary::kNotFound);
892 GenerateDictionaryNegativeLookup(masm(), &miss, holder, name,
893 scratch2(), scratch3());
896 // If the last object in the prototype chain is a global object,
897 // check that the global property cell is empty.
898 if (last_map->IsJSGlobalObjectMap()) {
899 Handle<JSGlobalObject> global = last.is_null()
900 ? Handle<JSGlobalObject>::cast(type->AsConstant())
901 : Handle<JSGlobalObject>::cast(last);
902 GenerateCheckPropertyCell(masm(), global, name, scratch2(), &miss);
905 HandlerFrontendFooter(name, &miss);
909 Handle<Code> LoadStubCompiler::CompileLoadField(
910 Handle<HeapType> type,
911 Handle<JSObject> holder,
914 Representation representation) {
915 Register reg = HandlerFrontend(type, receiver(), holder, name);
916 GenerateLoadField(reg, holder, field, representation);
918 // Return the generated code.
919 return GetCode(kind(), Code::FAST, name);
923 Handle<Code> LoadStubCompiler::CompileLoadConstant(
924 Handle<HeapType> type,
925 Handle<JSObject> holder,
927 Handle<Object> value) {
928 HandlerFrontend(type, receiver(), holder, name);
929 GenerateLoadConstant(value);
931 // Return the generated code.
932 return GetCode(kind(), Code::FAST, name);
936 Handle<Code> LoadStubCompiler::CompileLoadCallback(
937 Handle<HeapType> type,
938 Handle<JSObject> holder,
940 Handle<ExecutableAccessorInfo> callback) {
941 Register reg = CallbackHandlerFrontend(
942 type, receiver(), holder, name, callback);
943 GenerateLoadCallback(reg, callback);
945 // Return the generated code.
946 return GetCode(kind(), Code::FAST, name);
950 Handle<Code> LoadStubCompiler::CompileLoadCallback(
951 Handle<HeapType> type,
952 Handle<JSObject> holder,
954 const CallOptimization& call_optimization) {
955 ASSERT(call_optimization.is_simple_api_call());
956 Handle<JSFunction> callback = call_optimization.constant_function();
957 CallbackHandlerFrontend(type, receiver(), holder, name, callback);
958 GenerateLoadCallback(call_optimization, IC::TypeToMap(*type, isolate()));
960 // Return the generated code.
961 return GetCode(kind(), Code::FAST, name);
965 Handle<Code> LoadStubCompiler::CompileLoadInterceptor(
966 Handle<HeapType> type,
967 Handle<JSObject> holder,
969 LookupResult lookup(isolate());
970 LookupPostInterceptor(holder, name, &lookup);
972 Register reg = HandlerFrontend(type, receiver(), holder, name);
973 // TODO(368): Compile in the whole chain: all the interceptors in
974 // prototypes and ultimate answer.
975 GenerateLoadInterceptor(reg, type, holder, &lookup, name);
977 // Return the generated code.
978 return GetCode(kind(), Code::FAST, name);
982 void LoadStubCompiler::GenerateLoadPostInterceptor(
983 Register interceptor_reg,
984 Handle<JSObject> interceptor_holder,
986 LookupResult* lookup) {
987 Handle<JSObject> holder(lookup->holder());
988 if (lookup->IsField()) {
989 PropertyIndex field = lookup->GetFieldIndex();
990 if (interceptor_holder.is_identical_to(holder)) {
992 interceptor_reg, holder, field, lookup->representation());
994 // We found FIELD property in prototype chain of interceptor's holder.
995 // Retrieve a field from field's holder.
996 Register reg = HandlerFrontend(
997 IC::CurrentTypeOf(interceptor_holder, isolate()),
998 interceptor_reg, holder, name);
1000 reg, holder, field, lookup->representation());
1003 // We found CALLBACKS property in prototype chain of interceptor's
1005 ASSERT(lookup->type() == CALLBACKS);
1006 Handle<ExecutableAccessorInfo> callback(
1007 ExecutableAccessorInfo::cast(lookup->GetCallbackObject()));
1008 ASSERT(callback->getter() != NULL);
1010 Register reg = CallbackHandlerFrontend(
1011 IC::CurrentTypeOf(interceptor_holder, isolate()),
1012 interceptor_reg, holder, name, callback);
1013 GenerateLoadCallback(reg, callback);
1018 Handle<Code> BaseLoadStoreStubCompiler::CompileMonomorphicIC(
1019 Handle<HeapType> type,
1020 Handle<Code> handler,
1021 Handle<Name> name) {
1022 TypeHandleList types(1);
1023 CodeHandleList handlers(1);
1025 handlers.Add(handler);
1026 Code::StubType stub_type = handler->type();
1027 return CompilePolymorphicIC(&types, &handlers, name, stub_type, PROPERTY);
1031 Handle<Code> LoadStubCompiler::CompileLoadViaGetter(
1032 Handle<HeapType> type,
1033 Handle<JSObject> holder,
1035 Handle<JSFunction> getter) {
1036 HandlerFrontend(type, receiver(), holder, name);
1037 GenerateLoadViaGetter(masm(), type, receiver(), getter);
1039 // Return the generated code.
1040 return GetCode(kind(), Code::FAST, name);
1044 Handle<Code> StoreStubCompiler::CompileStoreTransition(
1045 Handle<JSObject> object,
1046 LookupResult* lookup,
1047 Handle<Map> transition,
1048 Handle<Name> name) {
1051 // Ensure no transitions to deprecated maps are followed.
1052 __ CheckMapDeprecated(transition, scratch1(), &miss);
1054 // Check that we are allowed to write this.
1055 if (object->GetPrototype()->IsJSObject()) {
1056 Handle<JSObject> holder;
1057 // holder == object indicates that no property was found.
1058 if (lookup->holder() != *object) {
1059 holder = Handle<JSObject>(lookup->holder());
1061 // Find the top object.
1064 holder = Handle<JSObject>(JSObject::cast(holder->GetPrototype()));
1065 } while (holder->GetPrototype()->IsJSObject());
1068 Register holder_reg = HandlerFrontendHeader(
1069 IC::CurrentTypeOf(object, isolate()), receiver(), holder, name, &miss);
1071 // If no property was found, and the holder (the last object in the
1072 // prototype chain) is in slow mode, we need to do a negative lookup on the
1074 if (lookup->holder() == *object) {
1075 GenerateNegativeHolderLookup(masm(), holder, holder_reg, name, &miss);
1079 GenerateStoreTransition(masm(),
1084 receiver(), this->name(), value(),
1085 scratch1(), scratch2(), scratch3(),
1089 // Handle store cache miss.
1090 GenerateRestoreName(masm(), &miss, name);
1091 TailCallBuiltin(masm(), MissBuiltin(kind()));
1093 GenerateRestoreName(masm(), &slow, name);
1094 TailCallBuiltin(masm(), SlowBuiltin(kind()));
1096 // Return the generated code.
1097 return GetCode(kind(), Code::FAST, name);
1101 Handle<Code> StoreStubCompiler::CompileStoreField(Handle<JSObject> object,
1102 LookupResult* lookup,
1103 Handle<Name> name) {
1106 HandlerFrontendHeader(IC::CurrentTypeOf(object, isolate()),
1107 receiver(), object, name, &miss);
1109 // Generate store field code.
1110 GenerateStoreField(masm(),
1113 receiver(), this->name(), value(), scratch1(), scratch2(),
1116 // Handle store cache miss.
1118 TailCallBuiltin(masm(), MissBuiltin(kind()));
1120 // Return the generated code.
1121 return GetCode(kind(), Code::FAST, name);
1125 Handle<Code> StoreStubCompiler::CompileStoreViaSetter(
1126 Handle<JSObject> object,
1127 Handle<JSObject> holder,
1129 Handle<JSFunction> setter) {
1130 Handle<HeapType> type = IC::CurrentTypeOf(object, isolate());
1131 HandlerFrontend(type, receiver(), holder, name);
1132 GenerateStoreViaSetter(masm(), type, setter);
1134 return GetCode(kind(), Code::FAST, name);
1138 Handle<Code> KeyedLoadStubCompiler::CompileLoadElement(
1139 Handle<Map> receiver_map) {
1140 ElementsKind elements_kind = receiver_map->elements_kind();
1141 if (receiver_map->has_fast_elements() ||
1142 receiver_map->has_external_array_elements() ||
1143 receiver_map->has_fixed_typed_array_elements()) {
1144 Handle<Code> stub = KeyedLoadFastElementStub(
1145 receiver_map->instance_type() == JS_ARRAY_TYPE,
1146 elements_kind).GetCode(isolate());
1147 __ DispatchMap(receiver(), scratch1(), receiver_map, stub, DO_SMI_CHECK);
1149 Handle<Code> stub = FLAG_compiled_keyed_dictionary_loads
1150 ? KeyedLoadDictionaryElementStub().GetCode(isolate())
1151 : KeyedLoadDictionaryElementPlatformStub().GetCode(isolate());
1152 __ DispatchMap(receiver(), scratch1(), receiver_map, stub, DO_SMI_CHECK);
1155 TailCallBuiltin(masm(), Builtins::kKeyedLoadIC_Miss);
1157 // Return the generated code.
1158 return GetICCode(kind(), Code::NORMAL, factory()->empty_string());
1162 Handle<Code> KeyedStoreStubCompiler::CompileStoreElement(
1163 Handle<Map> receiver_map) {
1164 ElementsKind elements_kind = receiver_map->elements_kind();
1165 bool is_jsarray = receiver_map->instance_type() == JS_ARRAY_TYPE;
1167 if (receiver_map->has_fast_elements() ||
1168 receiver_map->has_external_array_elements() ||
1169 receiver_map->has_fixed_typed_array_elements()) {
1170 stub = KeyedStoreFastElementStub(
1173 store_mode()).GetCode(isolate());
1175 stub = KeyedStoreElementStub(is_jsarray,
1177 store_mode()).GetCode(isolate());
1180 __ DispatchMap(receiver(), scratch1(), receiver_map, stub, DO_SMI_CHECK);
1182 TailCallBuiltin(masm(), Builtins::kKeyedStoreIC_Miss);
1184 // Return the generated code.
1185 return GetICCode(kind(), Code::NORMAL, factory()->empty_string());
1192 void StubCompiler::TailCallBuiltin(MacroAssembler* masm, Builtins::Name name) {
1193 Handle<Code> code(masm->isolate()->builtins()->builtin(name));
1194 GenerateTailCall(masm, code);
1198 void BaseLoadStoreStubCompiler::JitEvent(Handle<Name> name, Handle<Code> code) {
1199 #ifdef ENABLE_GDB_JIT_INTERFACE
1200 GDBJITInterface::CodeTag tag;
1201 if (kind_ == Code::LOAD_IC) {
1202 tag = GDBJITInterface::LOAD_IC;
1203 } else if (kind_ == Code::KEYED_LOAD_IC) {
1204 tag = GDBJITInterface::KEYED_LOAD_IC;
1205 } else if (kind_ == Code::STORE_IC) {
1206 tag = GDBJITInterface::STORE_IC;
1208 tag = GDBJITInterface::KEYED_STORE_IC;
1210 GDBJIT(AddCode(tag, *name, *code));
1215 void BaseLoadStoreStubCompiler::InitializeRegisters() {
1216 if (kind_ == Code::LOAD_IC) {
1217 registers_ = LoadStubCompiler::registers();
1218 } else if (kind_ == Code::KEYED_LOAD_IC) {
1219 registers_ = KeyedLoadStubCompiler::registers();
1220 } else if (kind_ == Code::STORE_IC) {
1221 registers_ = StoreStubCompiler::registers();
1223 registers_ = KeyedStoreStubCompiler::registers();
1228 Handle<Code> BaseLoadStoreStubCompiler::GetICCode(Code::Kind kind,
1229 Code::StubType type,
1231 InlineCacheState state) {
1232 Code::Flags flags = Code::ComputeFlags(kind, state, extra_state(), type);
1233 Handle<Code> code = GetCodeWithFlags(flags, name);
1234 PROFILE(isolate(), CodeCreateEvent(log_kind(code), *code, *name));
1235 JitEvent(name, code);
1240 Handle<Code> BaseLoadStoreStubCompiler::GetCode(Code::Kind kind,
1241 Code::StubType type,
1242 Handle<Name> name) {
1243 Code::Flags flags = Code::ComputeFlags(
1244 Code::HANDLER, MONOMORPHIC, extra_state(), type, kind, cache_holder_);
1245 Handle<Code> code = GetCodeWithFlags(flags, name);
1246 PROFILE(isolate(), CodeCreateEvent(log_kind(code), *code, *name));
1247 JitEvent(name, code);
1252 void KeyedLoadStubCompiler::CompileElementHandlers(MapHandleList* receiver_maps,
1253 CodeHandleList* handlers) {
1254 for (int i = 0; i < receiver_maps->length(); ++i) {
1255 Handle<Map> receiver_map = receiver_maps->at(i);
1256 Handle<Code> cached_stub;
1258 if ((receiver_map->instance_type() & kNotStringTag) == 0) {
1259 cached_stub = isolate()->builtins()->KeyedLoadIC_String();
1260 } else if (receiver_map->instance_type() < FIRST_JS_RECEIVER_TYPE) {
1261 cached_stub = isolate()->builtins()->KeyedLoadIC_Slow();
1263 bool is_js_array = receiver_map->instance_type() == JS_ARRAY_TYPE;
1264 ElementsKind elements_kind = receiver_map->elements_kind();
1266 if (IsFastElementsKind(elements_kind) ||
1267 IsExternalArrayElementsKind(elements_kind) ||
1268 IsFixedTypedArrayElementsKind(elements_kind)) {
1270 KeyedLoadFastElementStub(is_js_array,
1271 elements_kind).GetCode(isolate());
1273 ASSERT(elements_kind == DICTIONARY_ELEMENTS);
1274 cached_stub = KeyedLoadDictionaryElementStub().GetCode(isolate());
1278 handlers->Add(cached_stub);
1283 Handle<Code> KeyedStoreStubCompiler::CompileStoreElementPolymorphic(
1284 MapHandleList* receiver_maps) {
1285 // Collect MONOMORPHIC stubs for all |receiver_maps|.
1286 CodeHandleList handlers(receiver_maps->length());
1287 MapHandleList transitioned_maps(receiver_maps->length());
1288 for (int i = 0; i < receiver_maps->length(); ++i) {
1289 Handle<Map> receiver_map(receiver_maps->at(i));
1290 Handle<Code> cached_stub;
1291 Handle<Map> transitioned_map =
1292 receiver_map->FindTransitionedMap(receiver_maps);
1294 // TODO(mvstanton): The code below is doing pessimistic elements
1295 // transitions. I would like to stop doing that and rely on Allocation Site
1296 // Tracking to do a better job of ensuring the data types are what they need
1297 // to be. Not all the elements are in place yet, pessimistic elements
1298 // transitions are still important for performance.
1299 bool is_js_array = receiver_map->instance_type() == JS_ARRAY_TYPE;
1300 ElementsKind elements_kind = receiver_map->elements_kind();
1301 if (!transitioned_map.is_null()) {
1302 cached_stub = ElementsTransitionAndStoreStub(
1304 transitioned_map->elements_kind(),
1306 store_mode()).GetCode(isolate());
1307 } else if (receiver_map->instance_type() < FIRST_JS_RECEIVER_TYPE) {
1308 cached_stub = isolate()->builtins()->KeyedStoreIC_Slow();
1310 if (receiver_map->has_fast_elements() ||
1311 receiver_map->has_external_array_elements() ||
1312 receiver_map->has_fixed_typed_array_elements()) {
1313 cached_stub = KeyedStoreFastElementStub(
1316 store_mode()).GetCode(isolate());
1318 cached_stub = KeyedStoreElementStub(
1321 store_mode()).GetCode(isolate());
1324 ASSERT(!cached_stub.is_null());
1325 handlers.Add(cached_stub);
1326 transitioned_maps.Add(transitioned_map);
1329 CompileStorePolymorphic(receiver_maps, &handlers, &transitioned_maps);
1330 isolate()->counters()->keyed_store_polymorphic_stubs()->Increment();
1332 CodeCreateEvent(Logger::KEYED_STORE_POLYMORPHIC_IC_TAG, *code, 0));
1337 void KeyedStoreStubCompiler::GenerateStoreDictionaryElement(
1338 MacroAssembler* masm) {
1339 KeyedStoreIC::GenerateSlow(masm);
1343 CallOptimization::CallOptimization(LookupResult* lookup) {
1344 if (lookup->IsFound() &&
1345 lookup->IsCacheable() &&
1346 lookup->IsConstantFunction()) {
1347 // We only optimize constant function calls.
1348 Initialize(Handle<JSFunction>(lookup->GetConstantFunction()));
1350 Initialize(Handle<JSFunction>::null());
1355 CallOptimization::CallOptimization(Handle<JSFunction> function) {
1356 Initialize(function);
1360 Handle<JSObject> CallOptimization::LookupHolderOfExpectedType(
1361 Handle<Map> object_map,
1362 HolderLookup* holder_lookup) const {
1363 ASSERT(is_simple_api_call());
1364 if (!object_map->IsJSObjectMap()) {
1365 *holder_lookup = kHolderNotFound;
1366 return Handle<JSObject>::null();
1368 if (expected_receiver_type_.is_null() ||
1369 expected_receiver_type_->IsTemplateFor(*object_map)) {
1370 *holder_lookup = kHolderIsReceiver;
1371 return Handle<JSObject>::null();
1374 if (!object_map->prototype()->IsJSObject()) break;
1375 Handle<JSObject> prototype(JSObject::cast(object_map->prototype()));
1376 if (!prototype->map()->is_hidden_prototype()) break;
1377 object_map = handle(prototype->map());
1378 if (expected_receiver_type_->IsTemplateFor(*object_map)) {
1379 *holder_lookup = kHolderFound;
1383 *holder_lookup = kHolderNotFound;
1384 return Handle<JSObject>::null();
1388 bool CallOptimization::IsCompatibleReceiver(Handle<Object> receiver,
1389 Handle<JSObject> holder) const {
1390 ASSERT(is_simple_api_call());
1391 if (!receiver->IsJSObject()) return false;
1392 Handle<Map> map(JSObject::cast(*receiver)->map());
1393 HolderLookup holder_lookup;
1394 Handle<JSObject> api_holder =
1395 LookupHolderOfExpectedType(map, &holder_lookup);
1396 switch (holder_lookup) {
1397 case kHolderNotFound:
1399 case kHolderIsReceiver:
1402 if (api_holder.is_identical_to(holder)) return true;
1403 // Check if holder is in prototype chain of api_holder.
1405 JSObject* object = *api_holder;
1407 Object* prototype = object->map()->prototype();
1408 if (!prototype->IsJSObject()) return false;
1409 if (prototype == *holder) return true;
1410 object = JSObject::cast(prototype);
1420 void CallOptimization::Initialize(Handle<JSFunction> function) {
1421 constant_function_ = Handle<JSFunction>::null();
1422 is_simple_api_call_ = false;
1423 expected_receiver_type_ = Handle<FunctionTemplateInfo>::null();
1424 api_call_info_ = Handle<CallHandlerInfo>::null();
1426 if (function.is_null() || !function->is_compiled()) return;
1428 constant_function_ = function;
1429 AnalyzePossibleApiFunction(function);
1433 void CallOptimization::AnalyzePossibleApiFunction(Handle<JSFunction> function) {
1434 if (!function->shared()->IsApiFunction()) return;
1435 Handle<FunctionTemplateInfo> info(function->shared()->get_api_func_data());
1437 // Require a C++ callback.
1438 if (info->call_code()->IsUndefined()) return;
1440 Handle<CallHandlerInfo>(CallHandlerInfo::cast(info->call_code()));
1442 // Accept signatures that either have no restrictions at all or
1443 // only have restrictions on the receiver.
1444 if (!info->signature()->IsUndefined()) {
1445 Handle<SignatureInfo> signature =
1446 Handle<SignatureInfo>(SignatureInfo::cast(info->signature()));
1447 if (!signature->args()->IsUndefined()) return;
1448 if (!signature->receiver()->IsUndefined()) {
1449 expected_receiver_type_ =
1450 Handle<FunctionTemplateInfo>(
1451 FunctionTemplateInfo::cast(signature->receiver()));
1455 is_simple_api_call_ = true;
1459 } } // namespace v8::internal