1 // Copyright 2012 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
8 #include "src/arguments.h"
10 #include "src/code-stubs.h"
11 #include "src/cpu-profiler.h"
12 #include "src/gdb-jit.h"
13 #include "src/ic-inl.h"
14 #include "src/stub-cache.h"
15 #include "src/type-info.h"
16 #include "src/vm-state-inl.h"
21 // -----------------------------------------------------------------------
22 // StubCache implementation.
25 StubCache::StubCache(Isolate* isolate)
26 : isolate_(isolate) { }
29 void StubCache::Initialize() {
30 DCHECK(IsPowerOf2(kPrimaryTableSize));
31 DCHECK(IsPowerOf2(kSecondaryTableSize));
36 static Code::Flags CommonStubCacheChecks(Name* name, Map* map,
38 flags = Code::RemoveTypeAndHolderFromFlags(flags);
40 // Validate that the name does not move on scavenge, and that we
41 // can use identity checks instead of structural equality checks.
42 DCHECK(!name->GetHeap()->InNewSpace(name));
43 DCHECK(name->IsUniqueName());
45 // The state bits are not important to the hash function because the stub
46 // cache only contains handlers. Make sure that the bits are the least
47 // significant so they will be the ones masked out.
48 DCHECK_EQ(Code::HANDLER, Code::ExtractKindFromFlags(flags));
49 STATIC_ASSERT((Code::ICStateField::kMask & 1) == 1);
51 // Make sure that the code type and cache holder are not included in the hash.
52 DCHECK(Code::ExtractTypeFromFlags(flags) == 0);
53 DCHECK(Code::ExtractCacheHolderFromFlags(flags) == 0);
59 Code* StubCache::Set(Name* name, Map* map, Code* code) {
60 Code::Flags flags = CommonStubCacheChecks(name, map, code->flags());
62 // Compute the primary entry.
63 int primary_offset = PrimaryOffset(name, flags, map);
64 Entry* primary = entry(primary_, primary_offset);
65 Code* old_code = primary->value;
67 // If the primary entry has useful data in it, we retire it to the
68 // secondary cache before overwriting it.
69 if (old_code != isolate_->builtins()->builtin(Builtins::kIllegal)) {
70 Map* old_map = primary->map;
71 Code::Flags old_flags =
72 Code::RemoveTypeAndHolderFromFlags(old_code->flags());
73 int seed = PrimaryOffset(primary->key, old_flags, old_map);
74 int secondary_offset = SecondaryOffset(primary->key, old_flags, seed);
75 Entry* secondary = entry(secondary_, secondary_offset);
76 *secondary = *primary;
79 // Update primary cache.
81 primary->value = code;
83 isolate()->counters()->megamorphic_stub_cache_updates()->Increment();
88 Code* StubCache::Get(Name* name, Map* map, Code::Flags flags) {
89 flags = CommonStubCacheChecks(name, map, flags);
90 int primary_offset = PrimaryOffset(name, flags, map);
91 Entry* primary = entry(primary_, primary_offset);
92 if (primary->key == name && primary->map == map) {
93 return primary->value;
95 int secondary_offset = SecondaryOffset(name, flags, primary_offset);
96 Entry* secondary = entry(secondary_, secondary_offset);
97 if (secondary->key == name && secondary->map == map) {
98 return secondary->value;
104 Handle<Code> PropertyICCompiler::Find(Handle<Name> name,
105 Handle<Map> stub_holder, Code::Kind kind,
106 ExtraICState extra_state,
107 CacheHolderFlag cache_holder) {
108 Code::Flags flags = Code::ComputeMonomorphicFlags(
109 kind, extra_state, cache_holder);
110 Object* probe = stub_holder->FindInCodeCache(*name, flags);
111 if (probe->IsCode()) return handle(Code::cast(probe));
112 return Handle<Code>::null();
116 Handle<Code> PropertyHandlerCompiler::Find(Handle<Name> name,
117 Handle<Map> stub_holder,
119 CacheHolderFlag cache_holder,
120 Code::StubType type) {
121 Code::Flags flags = Code::ComputeHandlerFlags(kind, type, cache_holder);
122 Object* probe = stub_holder->FindInCodeCache(*name, flags);
123 if (probe->IsCode()) return handle(Code::cast(probe));
124 return Handle<Code>::null();
128 Handle<Code> PropertyICCompiler::ComputeMonomorphic(
129 Code::Kind kind, Handle<Name> name, Handle<HeapType> type,
130 Handle<Code> handler, ExtraICState extra_ic_state) {
131 Isolate* isolate = name->GetIsolate();
132 if (handler.is_identical_to(isolate->builtins()->LoadIC_Normal()) ||
133 handler.is_identical_to(isolate->builtins()->StoreIC_Normal())) {
134 name = isolate->factory()->normal_ic_symbol();
137 CacheHolderFlag flag;
138 Handle<Map> stub_holder = IC::GetICCacheHolder(*type, isolate, &flag);
141 // There are multiple string maps that all use the same prototype. That
142 // prototype cannot hold multiple handlers, one for each of the string maps,
143 // for a single name. Hence, turn off caching of the IC.
144 bool can_be_cached = !type->Is(HeapType::String());
146 ic = Find(name, stub_holder, kind, extra_ic_state, flag);
147 if (!ic.is_null()) return ic;
151 if (kind == Code::KEYED_STORE_IC) {
152 DCHECK(STANDARD_STORE ==
153 KeyedStoreIC::GetKeyedAccessStoreMode(extra_ic_state));
157 PropertyICCompiler ic_compiler(isolate, kind, extra_ic_state, flag);
158 ic = ic_compiler.CompileMonomorphic(type, handler, name, PROPERTY);
160 if (can_be_cached) Map::UpdateCodeCache(stub_holder, name, ic);
165 Handle<Code> NamedLoadHandlerCompiler::ComputeLoadNonexistent(
166 Handle<Name> name, Handle<HeapType> type) {
167 Isolate* isolate = name->GetIsolate();
168 Handle<Map> receiver_map = IC::TypeToMap(*type, isolate);
169 if (receiver_map->prototype()->IsNull()) {
170 // TODO(jkummerow/verwaest): If there is no prototype and the property
171 // is nonexistent, introduce a builtin to handle this (fast properties
172 // -> return undefined, dictionary properties -> do negative lookup).
173 return Handle<Code>();
175 CacheHolderFlag flag;
176 Handle<Map> stub_holder_map =
177 IC::GetHandlerCacheHolder(*type, false, isolate, &flag);
179 // If no dictionary mode objects are present in the prototype chain, the load
180 // nonexistent IC stub can be shared for all names for a given map and we use
181 // the empty string for the map cache in that case. If there are dictionary
182 // mode objects involved, we need to do negative lookups in the stub and
183 // therefore the stub will be specific to the name.
184 Handle<Name> cache_name =
185 receiver_map->is_dictionary_map()
187 : Handle<Name>::cast(isolate->factory()->nonexistent_symbol());
188 Handle<Map> current_map = stub_holder_map;
189 Handle<JSObject> last(JSObject::cast(receiver_map->prototype()));
191 if (current_map->is_dictionary_map()) cache_name = name;
192 if (current_map->prototype()->IsNull()) break;
193 last = handle(JSObject::cast(current_map->prototype()));
194 current_map = handle(last->map());
196 // Compile the stub that is either shared for all names or
197 // name specific if there are global objects involved.
198 Handle<Code> handler = PropertyHandlerCompiler::Find(
199 cache_name, stub_holder_map, Code::LOAD_IC, flag, Code::FAST);
200 if (!handler.is_null()) return handler;
202 NamedLoadHandlerCompiler compiler(isolate, type, last, flag);
203 handler = compiler.CompileLoadNonexistent(cache_name);
204 Map::UpdateCodeCache(stub_holder_map, cache_name, handler);
209 Handle<Code> PropertyICCompiler::ComputeKeyedLoadMonomorphic(
210 Handle<Map> receiver_map) {
211 Isolate* isolate = receiver_map->GetIsolate();
212 Code::Flags flags = Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC);
213 Handle<Name> name = isolate->factory()->KeyedLoadMonomorphic_string();
215 Handle<Object> probe(receiver_map->FindInCodeCache(*name, flags), isolate);
216 if (probe->IsCode()) return Handle<Code>::cast(probe);
218 ElementsKind elements_kind = receiver_map->elements_kind();
220 if (receiver_map->has_fast_elements() ||
221 receiver_map->has_external_array_elements() ||
222 receiver_map->has_fixed_typed_array_elements()) {
223 stub = LoadFastElementStub(isolate,
224 receiver_map->instance_type() == JS_ARRAY_TYPE,
225 elements_kind).GetCode();
227 stub = FLAG_compiled_keyed_dictionary_loads
228 ? LoadDictionaryElementStub(isolate).GetCode()
229 : LoadDictionaryElementPlatformStub(isolate).GetCode();
231 PropertyICCompiler compiler(isolate, Code::KEYED_LOAD_IC);
233 compiler.CompileMonomorphic(HeapType::Class(receiver_map, isolate), stub,
234 isolate->factory()->empty_string(), ELEMENT);
236 Map::UpdateCodeCache(receiver_map, name, code);
241 Handle<Code> PropertyICCompiler::ComputeKeyedStoreMonomorphic(
242 Handle<Map> receiver_map, StrictMode strict_mode,
243 KeyedAccessStoreMode store_mode) {
244 Isolate* isolate = receiver_map->GetIsolate();
245 ExtraICState extra_state =
246 KeyedStoreIC::ComputeExtraICState(strict_mode, store_mode);
248 Code::ComputeMonomorphicFlags(Code::KEYED_STORE_IC, extra_state);
250 DCHECK(store_mode == STANDARD_STORE ||
251 store_mode == STORE_AND_GROW_NO_TRANSITION ||
252 store_mode == STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS ||
253 store_mode == STORE_NO_TRANSITION_HANDLE_COW);
255 Handle<String> name = isolate->factory()->KeyedStoreMonomorphic_string();
256 Handle<Object> probe(receiver_map->FindInCodeCache(*name, flags), isolate);
257 if (probe->IsCode()) return Handle<Code>::cast(probe);
259 PropertyICCompiler compiler(isolate, Code::KEYED_STORE_IC, extra_state);
261 compiler.CompileKeyedStoreMonomorphic(receiver_map, store_mode);
263 Map::UpdateCodeCache(receiver_map, name, code);
264 DCHECK(KeyedStoreIC::GetKeyedAccessStoreMode(code->extra_ic_state())
270 #define CALL_LOGGER_TAG(kind, type) (Logger::KEYED_##type)
272 static void FillCache(Isolate* isolate, Handle<Code> code) {
273 Handle<UnseededNumberDictionary> dictionary =
274 UnseededNumberDictionary::Set(isolate->factory()->non_monomorphic_cache(),
277 isolate->heap()->public_set_non_monomorphic_cache(*dictionary);
281 Code* PropertyICCompiler::FindPreMonomorphic(Isolate* isolate, Code::Kind kind,
282 ExtraICState state) {
283 Code::Flags flags = Code::ComputeFlags(kind, PREMONOMORPHIC, state);
284 UnseededNumberDictionary* dictionary =
285 isolate->heap()->non_monomorphic_cache();
286 int entry = dictionary->FindEntry(isolate, flags);
288 Object* code = dictionary->ValueAt(entry);
289 // This might be called during the marking phase of the collector
290 // hence the unchecked cast.
291 return reinterpret_cast<Code*>(code);
295 Handle<Code> PropertyICCompiler::ComputeLoad(Isolate* isolate,
296 InlineCacheState ic_state,
297 ExtraICState extra_state) {
298 Code::Flags flags = Code::ComputeFlags(Code::LOAD_IC, ic_state, extra_state);
299 Handle<UnseededNumberDictionary> cache =
300 isolate->factory()->non_monomorphic_cache();
301 int entry = cache->FindEntry(isolate, flags);
302 if (entry != -1) return Handle<Code>(Code::cast(cache->ValueAt(entry)));
304 PropertyICCompiler compiler(isolate, Code::LOAD_IC);
306 if (ic_state == UNINITIALIZED) {
307 code = compiler.CompileLoadInitialize(flags);
308 } else if (ic_state == PREMONOMORPHIC) {
309 code = compiler.CompileLoadPreMonomorphic(flags);
310 } else if (ic_state == MEGAMORPHIC) {
311 code = compiler.CompileLoadMegamorphic(flags);
315 FillCache(isolate, code);
320 Handle<Code> PropertyICCompiler::ComputeStore(Isolate* isolate,
321 InlineCacheState ic_state,
322 ExtraICState extra_state) {
323 Code::Flags flags = Code::ComputeFlags(Code::STORE_IC, ic_state, extra_state);
324 Handle<UnseededNumberDictionary> cache =
325 isolate->factory()->non_monomorphic_cache();
326 int entry = cache->FindEntry(isolate, flags);
327 if (entry != -1) return Handle<Code>(Code::cast(cache->ValueAt(entry)));
329 PropertyICCompiler compiler(isolate, Code::STORE_IC);
331 if (ic_state == UNINITIALIZED) {
332 code = compiler.CompileStoreInitialize(flags);
333 } else if (ic_state == PREMONOMORPHIC) {
334 code = compiler.CompileStorePreMonomorphic(flags);
335 } else if (ic_state == GENERIC) {
336 code = compiler.CompileStoreGeneric(flags);
337 } else if (ic_state == MEGAMORPHIC) {
338 code = compiler.CompileStoreMegamorphic(flags);
343 FillCache(isolate, code);
348 Handle<Code> PropertyICCompiler::ComputeCompareNil(Handle<Map> receiver_map,
349 CompareNilICStub* stub) {
350 Isolate* isolate = receiver_map->GetIsolate();
351 Handle<String> name(isolate->heap()->empty_string());
352 if (!receiver_map->is_dictionary_map()) {
353 Handle<Code> cached_ic =
354 Find(name, receiver_map, Code::COMPARE_NIL_IC, stub->GetExtraICState());
355 if (!cached_ic.is_null()) return cached_ic;
358 Code::FindAndReplacePattern pattern;
359 pattern.Add(isolate->factory()->meta_map(), receiver_map);
360 Handle<Code> ic = stub->GetCodeCopy(pattern);
362 if (!receiver_map->is_dictionary_map()) {
363 Map::UpdateCodeCache(receiver_map, name, ic);
370 // TODO(verwaest): Change this method so it takes in a TypeHandleList.
371 Handle<Code> PropertyICCompiler::ComputeKeyedLoadPolymorphic(
372 MapHandleList* receiver_maps) {
373 Isolate* isolate = receiver_maps->at(0)->GetIsolate();
374 Code::Flags flags = Code::ComputeFlags(Code::KEYED_LOAD_IC, POLYMORPHIC);
375 Handle<PolymorphicCodeCache> cache =
376 isolate->factory()->polymorphic_code_cache();
377 Handle<Object> probe = cache->Lookup(receiver_maps, flags);
378 if (probe->IsCode()) return Handle<Code>::cast(probe);
380 TypeHandleList types(receiver_maps->length());
381 for (int i = 0; i < receiver_maps->length(); i++) {
382 types.Add(HeapType::Class(receiver_maps->at(i), isolate));
384 CodeHandleList handlers(receiver_maps->length());
385 ElementHandlerCompiler compiler(isolate);
386 compiler.CompileElementHandlers(receiver_maps, &handlers);
387 PropertyICCompiler ic_compiler(isolate, Code::KEYED_LOAD_IC);
388 Handle<Code> code = ic_compiler.CompilePolymorphic(
389 &types, &handlers, isolate->factory()->empty_string(), Code::NORMAL,
392 isolate->counters()->keyed_load_polymorphic_stubs()->Increment();
394 PolymorphicCodeCache::Update(cache, receiver_maps, flags, code);
399 Handle<Code> PropertyICCompiler::ComputePolymorphic(
400 Code::Kind kind, TypeHandleList* types, CodeHandleList* handlers,
401 int valid_types, Handle<Name> name, ExtraICState extra_ic_state) {
402 Handle<Code> handler = handlers->at(0);
403 Code::StubType type = valid_types == 1 ? handler->type() : Code::NORMAL;
404 DCHECK(kind == Code::LOAD_IC || kind == Code::STORE_IC);
405 PropertyICCompiler ic_compiler(name->GetIsolate(), kind, extra_ic_state);
406 return ic_compiler.CompilePolymorphic(types, handlers, name, type, PROPERTY);
410 Handle<Code> PropertyICCompiler::ComputeKeyedStorePolymorphic(
411 MapHandleList* receiver_maps, KeyedAccessStoreMode store_mode,
412 StrictMode strict_mode) {
413 Isolate* isolate = receiver_maps->at(0)->GetIsolate();
414 DCHECK(store_mode == STANDARD_STORE ||
415 store_mode == STORE_AND_GROW_NO_TRANSITION ||
416 store_mode == STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS ||
417 store_mode == STORE_NO_TRANSITION_HANDLE_COW);
418 Handle<PolymorphicCodeCache> cache =
419 isolate->factory()->polymorphic_code_cache();
420 ExtraICState extra_state = KeyedStoreIC::ComputeExtraICState(
421 strict_mode, store_mode);
423 Code::ComputeFlags(Code::KEYED_STORE_IC, POLYMORPHIC, extra_state);
424 Handle<Object> probe = cache->Lookup(receiver_maps, flags);
425 if (probe->IsCode()) return Handle<Code>::cast(probe);
427 PropertyICCompiler compiler(isolate, Code::KEYED_STORE_IC, extra_state);
429 compiler.CompileKeyedStorePolymorphic(receiver_maps, store_mode);
430 PolymorphicCodeCache::Update(cache, receiver_maps, flags, code);
435 void StubCache::Clear() {
436 Code* empty = isolate_->builtins()->builtin(Builtins::kIllegal);
437 for (int i = 0; i < kPrimaryTableSize; i++) {
438 primary_[i].key = isolate()->heap()->empty_string();
439 primary_[i].map = NULL;
440 primary_[i].value = empty;
442 for (int j = 0; j < kSecondaryTableSize; j++) {
443 secondary_[j].key = isolate()->heap()->empty_string();
444 secondary_[j].map = NULL;
445 secondary_[j].value = empty;
450 void StubCache::CollectMatchingMaps(SmallMapList* types,
453 Handle<Context> native_context,
455 for (int i = 0; i < kPrimaryTableSize; i++) {
456 if (primary_[i].key == *name) {
457 Map* map = primary_[i].map;
458 // Map can be NULL, if the stub is constant function call
459 // with a primitive receiver.
460 if (map == NULL) continue;
462 int offset = PrimaryOffset(*name, flags, map);
463 if (entry(primary_, offset) == &primary_[i] &&
464 !TypeFeedbackOracle::CanRetainOtherContext(map, *native_context)) {
465 types->AddMapIfMissing(Handle<Map>(map), zone);
470 for (int i = 0; i < kSecondaryTableSize; i++) {
471 if (secondary_[i].key == *name) {
472 Map* map = secondary_[i].map;
473 // Map can be NULL, if the stub is constant function call
474 // with a primitive receiver.
475 if (map == NULL) continue;
477 // Lookup in primary table and skip duplicates.
478 int primary_offset = PrimaryOffset(*name, flags, map);
480 // Lookup in secondary table and add matches.
481 int offset = SecondaryOffset(*name, flags, primary_offset);
482 if (entry(secondary_, offset) == &secondary_[i] &&
483 !TypeFeedbackOracle::CanRetainOtherContext(map, *native_context)) {
484 types->AddMapIfMissing(Handle<Map>(map), zone);
491 // ------------------------------------------------------------------------
492 // StubCompiler implementation.
495 RUNTIME_FUNCTION(StoreCallbackProperty) {
496 Handle<JSObject> receiver = args.at<JSObject>(0);
497 Handle<JSObject> holder = args.at<JSObject>(1);
498 Handle<ExecutableAccessorInfo> callback = args.at<ExecutableAccessorInfo>(2);
499 Handle<Name> name = args.at<Name>(3);
500 Handle<Object> value = args.at<Object>(4);
501 HandleScope scope(isolate);
503 DCHECK(callback->IsCompatibleReceiver(*receiver));
505 Address setter_address = v8::ToCData<Address>(callback->setter());
506 v8::AccessorSetterCallback fun =
507 FUNCTION_CAST<v8::AccessorSetterCallback>(setter_address);
510 // TODO(rossberg): Support symbols in the API.
511 if (name->IsSymbol()) return *value;
512 Handle<String> str = Handle<String>::cast(name);
514 LOG(isolate, ApiNamedPropertyAccess("store", *receiver, *name));
515 PropertyCallbackArguments custom_args(isolate, callback->data(), *receiver,
517 custom_args.Call(fun, v8::Utils::ToLocal(str), v8::Utils::ToLocal(value));
518 RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
524 * Attempts to load a property with an interceptor (which must be present),
525 * but doesn't search the prototype chain.
527 * Returns |Heap::no_interceptor_result_sentinel()| if interceptor doesn't
528 * provide any value for the given name.
530 RUNTIME_FUNCTION(LoadPropertyWithInterceptorOnly) {
531 DCHECK(args.length() == NamedLoadHandlerCompiler::kInterceptorArgsLength);
532 Handle<Name> name_handle =
533 args.at<Name>(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex);
534 Handle<InterceptorInfo> interceptor_info = args.at<InterceptorInfo>(
535 NamedLoadHandlerCompiler::kInterceptorArgsInfoIndex);
537 // TODO(rossberg): Support symbols in the API.
538 if (name_handle->IsSymbol())
539 return isolate->heap()->no_interceptor_result_sentinel();
540 Handle<String> name = Handle<String>::cast(name_handle);
542 Address getter_address = v8::ToCData<Address>(interceptor_info->getter());
543 v8::NamedPropertyGetterCallback getter =
544 FUNCTION_CAST<v8::NamedPropertyGetterCallback>(getter_address);
545 DCHECK(getter != NULL);
547 Handle<JSObject> receiver =
548 args.at<JSObject>(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex);
549 Handle<JSObject> holder =
550 args.at<JSObject>(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex);
551 PropertyCallbackArguments callback_args(
552 isolate, interceptor_info->data(), *receiver, *holder);
554 // Use the interceptor getter.
555 HandleScope scope(isolate);
556 v8::Handle<v8::Value> r =
557 callback_args.Call(getter, v8::Utils::ToLocal(name));
558 RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
560 Handle<Object> result = v8::Utils::OpenHandle(*r);
561 result->VerifyApiCallResultType();
562 return *v8::Utils::OpenHandle(*r);
566 return isolate->heap()->no_interceptor_result_sentinel();
570 static Object* ThrowReferenceError(Isolate* isolate, Name* name) {
571 // If the load is non-contextual, just return the undefined result.
572 // Note that both keyed and non-keyed loads may end up here.
573 HandleScope scope(isolate);
574 LoadIC ic(IC::NO_EXTRA_FRAME, isolate);
575 if (ic.contextual_mode() != CONTEXTUAL) {
576 return isolate->heap()->undefined_value();
579 // Throw a reference error.
580 Handle<Name> name_handle(name);
581 Handle<Object> error =
582 isolate->factory()->NewReferenceError("not_defined",
583 HandleVector(&name_handle, 1));
584 return isolate->Throw(*error);
589 * Loads a property with an interceptor performing post interceptor
590 * lookup if interceptor failed.
592 RUNTIME_FUNCTION(LoadPropertyWithInterceptor) {
593 HandleScope scope(isolate);
594 DCHECK(args.length() == NamedLoadHandlerCompiler::kInterceptorArgsLength);
596 args.at<Name>(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex);
597 Handle<JSObject> receiver =
598 args.at<JSObject>(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex);
599 Handle<JSObject> holder =
600 args.at<JSObject>(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex);
602 Handle<Object> result;
603 LookupIterator it(receiver, name, holder);
604 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
605 isolate, result, JSObject::GetProperty(&it));
607 if (it.IsFound()) return *result;
609 return ThrowReferenceError(isolate, Name::cast(args[0]));
613 RUNTIME_FUNCTION(StorePropertyWithInterceptor) {
614 HandleScope scope(isolate);
615 DCHECK(args.length() == 3);
616 StoreIC ic(IC::NO_EXTRA_FRAME, isolate);
617 Handle<JSObject> receiver = args.at<JSObject>(0);
618 Handle<Name> name = args.at<Name>(1);
619 Handle<Object> value = args.at<Object>(2);
621 if (receiver->IsJSGlobalProxy()) {
622 PrototypeIterator iter(isolate, receiver);
623 DCHECK(iter.IsAtEnd() ||
624 Handle<JSGlobalObject>::cast(PrototypeIterator::GetCurrent(iter))
625 ->HasNamedInterceptor());
627 DCHECK(receiver->HasNamedInterceptor());
630 Handle<Object> result;
631 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
633 JSObject::SetProperty(receiver, name, value, ic.strict_mode()));
638 RUNTIME_FUNCTION(LoadElementWithInterceptor) {
639 HandleScope scope(isolate);
640 Handle<JSObject> receiver = args.at<JSObject>(0);
641 DCHECK(args.smi_at(1) >= 0);
642 uint32_t index = args.smi_at(1);
643 Handle<Object> result;
644 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
646 JSObject::GetElementWithInterceptor(receiver, receiver, index));
651 Handle<Code> PropertyICCompiler::CompileLoadInitialize(Code::Flags flags) {
652 LoadIC::GenerateInitialize(masm());
653 Handle<Code> code = GetCodeWithFlags(flags, "CompileLoadInitialize");
655 CodeCreateEvent(Logger::LOAD_INITIALIZE_TAG, *code, 0));
660 Handle<Code> PropertyICCompiler::CompileLoadPreMonomorphic(Code::Flags flags) {
661 LoadIC::GeneratePreMonomorphic(masm());
662 Handle<Code> code = GetCodeWithFlags(flags, "CompileLoadPreMonomorphic");
664 CodeCreateEvent(Logger::LOAD_PREMONOMORPHIC_TAG, *code, 0));
669 Handle<Code> PropertyICCompiler::CompileLoadMegamorphic(Code::Flags flags) {
670 LoadIC::GenerateMegamorphic(masm());
671 Handle<Code> code = GetCodeWithFlags(flags, "CompileLoadMegamorphic");
673 CodeCreateEvent(Logger::LOAD_MEGAMORPHIC_TAG, *code, 0));
678 Handle<Code> PropertyICCompiler::CompileStoreInitialize(Code::Flags flags) {
679 StoreIC::GenerateInitialize(masm());
680 Handle<Code> code = GetCodeWithFlags(flags, "CompileStoreInitialize");
682 CodeCreateEvent(Logger::STORE_INITIALIZE_TAG, *code, 0));
687 Handle<Code> PropertyICCompiler::CompileStorePreMonomorphic(Code::Flags flags) {
688 StoreIC::GeneratePreMonomorphic(masm());
689 Handle<Code> code = GetCodeWithFlags(flags, "CompileStorePreMonomorphic");
691 CodeCreateEvent(Logger::STORE_PREMONOMORPHIC_TAG, *code, 0));
696 Handle<Code> PropertyICCompiler::CompileStoreGeneric(Code::Flags flags) {
697 ExtraICState extra_state = Code::ExtractExtraICStateFromFlags(flags);
698 StrictMode strict_mode = StoreIC::GetStrictMode(extra_state);
699 StoreIC::GenerateRuntimeSetProperty(masm(), strict_mode);
700 Handle<Code> code = GetCodeWithFlags(flags, "CompileStoreGeneric");
702 CodeCreateEvent(Logger::STORE_GENERIC_TAG, *code, 0));
707 Handle<Code> PropertyICCompiler::CompileStoreMegamorphic(Code::Flags flags) {
708 StoreIC::GenerateMegamorphic(masm());
709 Handle<Code> code = GetCodeWithFlags(flags, "CompileStoreMegamorphic");
711 CodeCreateEvent(Logger::STORE_MEGAMORPHIC_TAG, *code, 0));
716 #undef CALL_LOGGER_TAG
719 Handle<Code> PropertyAccessCompiler::GetCodeWithFlags(Code::Flags flags,
721 // Create code object in the heap.
723 masm()->GetCode(&desc);
724 Handle<Code> code = factory()->NewCode(desc, flags, masm()->CodeObject());
725 if (code->IsCodeStubOrIC()) code->set_stub_key(CodeStub::NoCacheKey());
726 #ifdef ENABLE_DISASSEMBLER
727 if (FLAG_print_code_stubs) {
729 code->Disassemble(name, os);
736 Handle<Code> PropertyAccessCompiler::GetCodeWithFlags(Code::Flags flags,
738 return (FLAG_print_code_stubs && !name.is_null() && name->IsString())
739 ? GetCodeWithFlags(flags, Handle<String>::cast(name)->ToCString().get())
740 : GetCodeWithFlags(flags, NULL);
744 #define __ ACCESS_MASM(masm())
747 Register NamedLoadHandlerCompiler::FrontendHeader(Register object_reg,
750 PrototypeCheckType check_type = CHECK_ALL_MAPS;
751 int function_index = -1;
752 if (type()->Is(HeapType::String())) {
753 function_index = Context::STRING_FUNCTION_INDEX;
754 } else if (type()->Is(HeapType::Symbol())) {
755 function_index = Context::SYMBOL_FUNCTION_INDEX;
756 } else if (type()->Is(HeapType::Number())) {
757 function_index = Context::NUMBER_FUNCTION_INDEX;
758 } else if (type()->Is(HeapType::Boolean())) {
759 function_index = Context::BOOLEAN_FUNCTION_INDEX;
761 check_type = SKIP_RECEIVER;
764 if (check_type == CHECK_ALL_MAPS) {
765 GenerateDirectLoadGlobalFunctionPrototype(
766 masm(), function_index, scratch1(), miss);
767 Object* function = isolate()->native_context()->get(function_index);
768 Object* prototype = JSFunction::cast(function)->instance_prototype();
769 set_type_for_object(handle(prototype, isolate()));
770 object_reg = scratch1();
773 // Check that the maps starting from the prototype haven't changed.
774 return CheckPrototypes(object_reg, scratch1(), scratch2(), scratch3(), name,
779 // Frontend for store uses the name register. It has to be restored before a
781 Register NamedStoreHandlerCompiler::FrontendHeader(Register object_reg,
784 return CheckPrototypes(object_reg, this->name(), scratch1(), scratch2(), name,
785 miss, SKIP_RECEIVER);
789 bool PropertyICCompiler::IncludesNumberType(TypeHandleList* types) {
790 for (int i = 0; i < types->length(); ++i) {
791 if (types->at(i)->Is(HeapType::Number())) return true;
797 Register PropertyHandlerCompiler::Frontend(Register object_reg,
800 Register reg = FrontendHeader(object_reg, name, &miss);
801 FrontendFooter(name, &miss);
806 void PropertyHandlerCompiler::NonexistentFrontendHeader(Handle<Name> name,
811 Handle<Map> last_map;
812 if (holder().is_null()) {
813 holder_reg = receiver();
814 last_map = IC::TypeToMap(*type(), isolate());
815 // If |type| has null as its prototype, |holder()| is
816 // Handle<JSObject>::null().
817 DCHECK(last_map->prototype() == isolate()->heap()->null_value());
819 holder_reg = FrontendHeader(receiver(), name, miss);
820 last_map = handle(holder()->map());
823 if (last_map->is_dictionary_map()) {
824 if (last_map->IsJSGlobalObjectMap()) {
825 Handle<JSGlobalObject> global =
827 ? Handle<JSGlobalObject>::cast(type()->AsConstant()->Value())
828 : Handle<JSGlobalObject>::cast(holder());
829 GenerateCheckPropertyCell(masm(), global, name, scratch1, miss);
831 if (!name->IsUniqueName()) {
832 DCHECK(name->IsString());
833 name = factory()->InternalizeString(Handle<String>::cast(name));
835 DCHECK(holder().is_null() ||
836 holder()->property_dictionary()->FindEntry(name) ==
837 NameDictionary::kNotFound);
838 GenerateDictionaryNegativeLookup(masm(), miss, holder_reg, name, scratch1,
845 Handle<Code> NamedLoadHandlerCompiler::CompileLoadField(Handle<Name> name,
847 Register reg = Frontend(receiver(), name);
848 __ Move(receiver(), reg);
849 LoadFieldStub stub(isolate(), field);
850 GenerateTailCall(masm(), stub.GetCode());
851 return GetCode(kind(), Code::FAST, name);
855 Handle<Code> NamedLoadHandlerCompiler::CompileLoadConstant(Handle<Name> name,
856 int constant_index) {
857 Register reg = Frontend(receiver(), name);
858 __ Move(receiver(), reg);
859 LoadConstantStub stub(isolate(), constant_index);
860 GenerateTailCall(masm(), stub.GetCode());
861 return GetCode(kind(), Code::FAST, name);
865 Handle<Code> NamedLoadHandlerCompiler::CompileLoadNonexistent(
868 NonexistentFrontendHeader(name, &miss, scratch2(), scratch3());
869 GenerateLoadConstant(isolate()->factory()->undefined_value());
870 FrontendFooter(name, &miss);
871 return GetCode(kind(), Code::FAST, name);
875 Handle<Code> NamedLoadHandlerCompiler::CompileLoadCallback(
876 Handle<Name> name, Handle<ExecutableAccessorInfo> callback) {
877 Register reg = Frontend(receiver(), name);
878 GenerateLoadCallback(reg, callback);
879 return GetCode(kind(), Code::FAST, name);
883 Handle<Code> NamedLoadHandlerCompiler::CompileLoadCallback(
884 Handle<Name> name, const CallOptimization& call_optimization) {
885 DCHECK(call_optimization.is_simple_api_call());
886 Frontend(receiver(), name);
887 Handle<Map> receiver_map = IC::TypeToMap(*type(), isolate());
889 masm(), call_optimization, receiver_map,
890 receiver(), scratch1(), false, 0, NULL);
891 return GetCode(kind(), Code::FAST, name);
895 Handle<Code> NamedLoadHandlerCompiler::CompileLoadInterceptor(
897 // Perform a lookup after the interceptor.
898 LookupResult lookup(isolate());
899 holder()->LookupOwnRealNamedProperty(name, &lookup);
900 if (!lookup.IsFound()) {
901 PrototypeIterator iter(holder()->GetIsolate(), holder());
902 if (!iter.IsAtEnd()) {
903 PrototypeIterator::GetCurrent(iter)->Lookup(name, &lookup);
907 Register reg = Frontend(receiver(), name);
908 // TODO(368): Compile in the whole chain: all the interceptors in
909 // prototypes and ultimate answer.
910 GenerateLoadInterceptor(reg, &lookup, name);
911 return GetCode(kind(), Code::FAST, name);
915 void NamedLoadHandlerCompiler::GenerateLoadPostInterceptor(
916 Register interceptor_reg, Handle<Name> name, LookupResult* lookup) {
917 Handle<JSObject> real_named_property_holder(lookup->holder());
919 set_type_for_object(holder());
920 set_holder(real_named_property_holder);
921 Register reg = Frontend(interceptor_reg, name);
923 if (lookup->IsField()) {
924 __ Move(receiver(), reg);
925 LoadFieldStub stub(isolate(), lookup->GetFieldIndex());
926 GenerateTailCall(masm(), stub.GetCode());
928 DCHECK(lookup->type() == CALLBACKS);
929 Handle<ExecutableAccessorInfo> callback(
930 ExecutableAccessorInfo::cast(lookup->GetCallbackObject()));
931 DCHECK(callback->getter() != NULL);
932 GenerateLoadCallback(reg, callback);
937 Handle<Code> PropertyICCompiler::CompileMonomorphic(Handle<HeapType> type,
938 Handle<Code> handler,
941 TypeHandleList types(1);
942 CodeHandleList handlers(1);
944 handlers.Add(handler);
945 Code::StubType stub_type = handler->type();
946 return CompilePolymorphic(&types, &handlers, name, stub_type, check);
950 Handle<Code> NamedLoadHandlerCompiler::CompileLoadViaGetter(
951 Handle<Name> name, Handle<JSFunction> getter) {
952 Frontend(receiver(), name);
953 GenerateLoadViaGetter(masm(), type(), receiver(), getter);
954 return GetCode(kind(), Code::FAST, name);
958 // TODO(verwaest): Cleanup. holder() is actually the receiver.
959 Handle<Code> NamedStoreHandlerCompiler::CompileStoreTransition(
960 Handle<Map> transition, Handle<Name> name) {
963 // Ensure no transitions to deprecated maps are followed.
964 __ CheckMapDeprecated(transition, scratch1(), &miss);
966 // Check that we are allowed to write this.
967 bool is_nonexistent = holder()->map() == transition->GetBackPointer();
968 if (is_nonexistent) {
969 // Find the top object.
970 Handle<JSObject> last;
971 PrototypeIterator iter(isolate(), holder());
972 while (!iter.IsAtEnd()) {
973 last = Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter));
976 if (!last.is_null()) set_holder(last);
977 NonexistentFrontendHeader(name, &miss, scratch1(), scratch2());
979 FrontendHeader(receiver(), name, &miss);
980 DCHECK(holder()->HasFastProperties());
983 GenerateStoreTransition(transition, name, receiver(), this->name(), value(),
984 scratch1(), scratch2(), scratch3(), &miss, &slow);
986 GenerateRestoreName(&miss, name);
987 TailCallBuiltin(masm(), MissBuiltin(kind()));
989 GenerateRestoreName(&slow, name);
990 TailCallBuiltin(masm(), SlowBuiltin(kind()));
991 return GetCode(kind(), Code::FAST, name);
995 Handle<Code> NamedStoreHandlerCompiler::CompileStoreField(LookupResult* lookup,
998 GenerateStoreField(lookup, value(), &miss);
1000 TailCallBuiltin(masm(), MissBuiltin(kind()));
1001 return GetCode(kind(), Code::FAST, name);
1005 Handle<Code> NamedStoreHandlerCompiler::CompileStoreViaSetter(
1006 Handle<JSObject> object, Handle<Name> name, Handle<JSFunction> setter) {
1007 Frontend(receiver(), name);
1008 GenerateStoreViaSetter(masm(), type(), receiver(), setter);
1010 return GetCode(kind(), Code::FAST, name);
1014 Handle<Code> NamedStoreHandlerCompiler::CompileStoreCallback(
1015 Handle<JSObject> object, Handle<Name> name,
1016 const CallOptimization& call_optimization) {
1017 Frontend(receiver(), name);
1018 Register values[] = { value() };
1019 GenerateFastApiCall(
1020 masm(), call_optimization, handle(object->map()),
1021 receiver(), scratch1(), true, 1, values);
1022 return GetCode(kind(), Code::FAST, name);
1026 Handle<Code> PropertyICCompiler::CompileKeyedStoreMonomorphic(
1027 Handle<Map> receiver_map, KeyedAccessStoreMode store_mode) {
1028 ElementsKind elements_kind = receiver_map->elements_kind();
1029 bool is_jsarray = receiver_map->instance_type() == JS_ARRAY_TYPE;
1031 if (receiver_map->has_fast_elements() ||
1032 receiver_map->has_external_array_elements() ||
1033 receiver_map->has_fixed_typed_array_elements()) {
1034 stub = StoreFastElementStub(isolate(), is_jsarray, elements_kind,
1035 store_mode).GetCode();
1037 stub = StoreElementStub(isolate(), is_jsarray, elements_kind, store_mode)
1041 __ DispatchMap(receiver(), scratch1(), receiver_map, stub, DO_SMI_CHECK);
1043 TailCallBuiltin(masm(), Builtins::kKeyedStoreIC_Miss);
1045 return GetCode(kind(), Code::NORMAL, factory()->empty_string());
1052 void PropertyAccessCompiler::TailCallBuiltin(MacroAssembler* masm,
1053 Builtins::Name name) {
1054 Handle<Code> code(masm->isolate()->builtins()->builtin(name));
1055 GenerateTailCall(masm, code);
1059 Register* PropertyAccessCompiler::GetCallingConvention(Code::Kind kind) {
1060 if (kind == Code::LOAD_IC || kind == Code::KEYED_LOAD_IC) {
1061 return load_calling_convention();
1063 DCHECK(kind == Code::STORE_IC || kind == Code::KEYED_STORE_IC);
1064 return store_calling_convention();
1068 Handle<Code> PropertyICCompiler::GetCode(Code::Kind kind, Code::StubType type,
1070 InlineCacheState state) {
1072 Code::ComputeFlags(kind, state, extra_ic_state_, type, cache_holder());
1073 Handle<Code> code = GetCodeWithFlags(flags, name);
1074 IC::RegisterWeakMapDependency(code);
1075 PROFILE(isolate(), CodeCreateEvent(log_kind(code), *code, *name));
1080 Handle<Code> PropertyHandlerCompiler::GetCode(Code::Kind kind,
1081 Code::StubType type,
1082 Handle<Name> name) {
1083 Code::Flags flags = Code::ComputeHandlerFlags(kind, type, cache_holder());
1084 Handle<Code> code = GetCodeWithFlags(flags, name);
1085 PROFILE(isolate(), CodeCreateEvent(Logger::STUB_TAG, *code, *name));
1090 void ElementHandlerCompiler::CompileElementHandlers(
1091 MapHandleList* receiver_maps, CodeHandleList* handlers) {
1092 for (int i = 0; i < receiver_maps->length(); ++i) {
1093 Handle<Map> receiver_map = receiver_maps->at(i);
1094 Handle<Code> cached_stub;
1096 if ((receiver_map->instance_type() & kNotStringTag) == 0) {
1097 cached_stub = isolate()->builtins()->KeyedLoadIC_String();
1098 } else if (receiver_map->instance_type() < FIRST_JS_RECEIVER_TYPE) {
1099 cached_stub = isolate()->builtins()->KeyedLoadIC_Slow();
1101 bool is_js_array = receiver_map->instance_type() == JS_ARRAY_TYPE;
1102 ElementsKind elements_kind = receiver_map->elements_kind();
1104 if (IsFastElementsKind(elements_kind) ||
1105 IsExternalArrayElementsKind(elements_kind) ||
1106 IsFixedTypedArrayElementsKind(elements_kind)) {
1107 cached_stub = LoadFastElementStub(isolate(), is_js_array, elements_kind)
1109 } else if (elements_kind == SLOPPY_ARGUMENTS_ELEMENTS) {
1110 cached_stub = isolate()->builtins()->KeyedLoadIC_SloppyArguments();
1112 DCHECK(elements_kind == DICTIONARY_ELEMENTS);
1113 cached_stub = LoadDictionaryElementStub(isolate()).GetCode();
1117 handlers->Add(cached_stub);
1122 Handle<Code> PropertyICCompiler::CompileKeyedStorePolymorphic(
1123 MapHandleList* receiver_maps, KeyedAccessStoreMode store_mode) {
1124 // Collect MONOMORPHIC stubs for all |receiver_maps|.
1125 CodeHandleList handlers(receiver_maps->length());
1126 MapHandleList transitioned_maps(receiver_maps->length());
1127 for (int i = 0; i < receiver_maps->length(); ++i) {
1128 Handle<Map> receiver_map(receiver_maps->at(i));
1129 Handle<Code> cached_stub;
1130 Handle<Map> transitioned_map =
1131 receiver_map->FindTransitionedMap(receiver_maps);
1133 // TODO(mvstanton): The code below is doing pessimistic elements
1134 // transitions. I would like to stop doing that and rely on Allocation Site
1135 // Tracking to do a better job of ensuring the data types are what they need
1136 // to be. Not all the elements are in place yet, pessimistic elements
1137 // transitions are still important for performance.
1138 bool is_js_array = receiver_map->instance_type() == JS_ARRAY_TYPE;
1139 ElementsKind elements_kind = receiver_map->elements_kind();
1140 if (!transitioned_map.is_null()) {
1142 ElementsTransitionAndStoreStub(isolate(), elements_kind,
1143 transitioned_map->elements_kind(),
1144 is_js_array, store_mode).GetCode();
1145 } else if (receiver_map->instance_type() < FIRST_JS_RECEIVER_TYPE) {
1146 cached_stub = isolate()->builtins()->KeyedStoreIC_Slow();
1148 if (receiver_map->has_fast_elements() ||
1149 receiver_map->has_external_array_elements() ||
1150 receiver_map->has_fixed_typed_array_elements()) {
1151 cached_stub = StoreFastElementStub(isolate(), is_js_array,
1152 elements_kind, store_mode).GetCode();
1154 cached_stub = StoreElementStub(isolate(), is_js_array, elements_kind,
1155 store_mode).GetCode();
1158 DCHECK(!cached_stub.is_null());
1159 handlers.Add(cached_stub);
1160 transitioned_maps.Add(transitioned_map);
1163 Handle<Code> code = CompileKeyedStorePolymorphic(receiver_maps, &handlers,
1164 &transitioned_maps);
1165 isolate()->counters()->keyed_store_polymorphic_stubs()->Increment();
1166 PROFILE(isolate(), CodeCreateEvent(log_kind(code), *code, 0));
1171 void ElementHandlerCompiler::GenerateStoreDictionaryElement(
1172 MacroAssembler* masm) {
1173 KeyedStoreIC::GenerateSlow(masm);
1177 CallOptimization::CallOptimization(LookupResult* lookup) {
1178 if (lookup->IsFound() &&
1179 lookup->IsCacheable() &&
1180 lookup->IsConstantFunction()) {
1181 // We only optimize constant function calls.
1182 Initialize(Handle<JSFunction>(lookup->GetConstantFunction()));
1184 Initialize(Handle<JSFunction>::null());
1189 CallOptimization::CallOptimization(Handle<JSFunction> function) {
1190 Initialize(function);
1194 Handle<JSObject> CallOptimization::LookupHolderOfExpectedType(
1195 Handle<Map> object_map,
1196 HolderLookup* holder_lookup) const {
1197 DCHECK(is_simple_api_call());
1198 if (!object_map->IsJSObjectMap()) {
1199 *holder_lookup = kHolderNotFound;
1200 return Handle<JSObject>::null();
1202 if (expected_receiver_type_.is_null() ||
1203 expected_receiver_type_->IsTemplateFor(*object_map)) {
1204 *holder_lookup = kHolderIsReceiver;
1205 return Handle<JSObject>::null();
1208 if (!object_map->prototype()->IsJSObject()) break;
1209 Handle<JSObject> prototype(JSObject::cast(object_map->prototype()));
1210 if (!prototype->map()->is_hidden_prototype()) break;
1211 object_map = handle(prototype->map());
1212 if (expected_receiver_type_->IsTemplateFor(*object_map)) {
1213 *holder_lookup = kHolderFound;
1217 *holder_lookup = kHolderNotFound;
1218 return Handle<JSObject>::null();
1222 bool CallOptimization::IsCompatibleReceiver(Handle<Object> receiver,
1223 Handle<JSObject> holder) const {
1224 DCHECK(is_simple_api_call());
1225 if (!receiver->IsJSObject()) return false;
1226 Handle<Map> map(JSObject::cast(*receiver)->map());
1227 HolderLookup holder_lookup;
1228 Handle<JSObject> api_holder =
1229 LookupHolderOfExpectedType(map, &holder_lookup);
1230 switch (holder_lookup) {
1231 case kHolderNotFound:
1233 case kHolderIsReceiver:
1236 if (api_holder.is_identical_to(holder)) return true;
1237 // Check if holder is in prototype chain of api_holder.
1239 JSObject* object = *api_holder;
1241 Object* prototype = object->map()->prototype();
1242 if (!prototype->IsJSObject()) return false;
1243 if (prototype == *holder) return true;
1244 object = JSObject::cast(prototype);
1254 void CallOptimization::Initialize(Handle<JSFunction> function) {
1255 constant_function_ = Handle<JSFunction>::null();
1256 is_simple_api_call_ = false;
1257 expected_receiver_type_ = Handle<FunctionTemplateInfo>::null();
1258 api_call_info_ = Handle<CallHandlerInfo>::null();
1260 if (function.is_null() || !function->is_compiled()) return;
1262 constant_function_ = function;
1263 AnalyzePossibleApiFunction(function);
1267 void CallOptimization::AnalyzePossibleApiFunction(Handle<JSFunction> function) {
1268 if (!function->shared()->IsApiFunction()) return;
1269 Handle<FunctionTemplateInfo> info(function->shared()->get_api_func_data());
1271 // Require a C++ callback.
1272 if (info->call_code()->IsUndefined()) return;
1274 Handle<CallHandlerInfo>(CallHandlerInfo::cast(info->call_code()));
1276 // Accept signatures that either have no restrictions at all or
1277 // only have restrictions on the receiver.
1278 if (!info->signature()->IsUndefined()) {
1279 Handle<SignatureInfo> signature =
1280 Handle<SignatureInfo>(SignatureInfo::cast(info->signature()));
1281 if (!signature->args()->IsUndefined()) return;
1282 if (!signature->receiver()->IsUndefined()) {
1283 expected_receiver_type_ =
1284 Handle<FunctionTemplateInfo>(
1285 FunctionTemplateInfo::cast(signature->receiver()));
1289 is_simple_api_call_ = true;
1293 } } // namespace v8::internal