1 // Copyright 2014 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. 4 5 #include "src/v8.h" 6 7 #include "src/ic/call-optimization.h" 8 9 10 namespace v8 { 11 namespace internal { 12 CallOptimization(Handle<JSFunction> function)13CallOptimization::CallOptimization(Handle<JSFunction> function) { 14 Initialize(function); 15 } 16 17 LookupHolderOfExpectedType(Handle<Map> object_map,HolderLookup * holder_lookup) const18Handle<JSObject> CallOptimization::LookupHolderOfExpectedType( 19 Handle<Map> object_map, HolderLookup* holder_lookup) const { 20 DCHECK(is_simple_api_call()); 21 if (!object_map->IsJSObjectMap()) { 22 *holder_lookup = kHolderNotFound; 23 return Handle<JSObject>::null(); 24 } 25 if (expected_receiver_type_.is_null() || 26 expected_receiver_type_->IsTemplateFor(*object_map)) { 27 *holder_lookup = kHolderIsReceiver; 28 return Handle<JSObject>::null(); 29 } 30 while (true) { 31 if (!object_map->prototype()->IsJSObject()) break; 32 Handle<JSObject> prototype(JSObject::cast(object_map->prototype())); 33 if (!prototype->map()->is_hidden_prototype()) break; 34 object_map = handle(prototype->map()); 35 if (expected_receiver_type_->IsTemplateFor(*object_map)) { 36 *holder_lookup = kHolderFound; 37 return prototype; 38 } 39 } 40 *holder_lookup = kHolderNotFound; 41 return Handle<JSObject>::null(); 42 } 43 44 IsCompatibleReceiver(Handle<Object> receiver,Handle<JSObject> holder) const45bool CallOptimization::IsCompatibleReceiver(Handle<Object> receiver, 46 Handle<JSObject> holder) const { 47 DCHECK(is_simple_api_call()); 48 if (!receiver->IsJSObject()) return false; 49 Handle<Map> map(JSObject::cast(*receiver)->map()); 50 HolderLookup holder_lookup; 51 Handle<JSObject> api_holder = LookupHolderOfExpectedType(map, &holder_lookup); 52 switch (holder_lookup) { 53 case kHolderNotFound: 54 return false; 55 case kHolderIsReceiver: 56 return true; 57 case kHolderFound: 58 if (api_holder.is_identical_to(holder)) return true; 59 // Check if holder is in prototype chain of api_holder. 60 { 61 JSObject* object = *api_holder; 62 while (true) { 63 Object* prototype = object->map()->prototype(); 64 if (!prototype->IsJSObject()) return false; 65 if (prototype == *holder) return true; 66 object = JSObject::cast(prototype); 67 } 68 } 69 break; 70 } 71 UNREACHABLE(); 72 return false; 73 } 74 75 Initialize(Handle<JSFunction> function)76void CallOptimization::Initialize(Handle<JSFunction> function) { 77 constant_function_ = Handle<JSFunction>::null(); 78 is_simple_api_call_ = false; 79 expected_receiver_type_ = Handle<FunctionTemplateInfo>::null(); 80 api_call_info_ = Handle<CallHandlerInfo>::null(); 81 82 if (function.is_null() || !function->is_compiled()) return; 83 84 constant_function_ = function; 85 AnalyzePossibleApiFunction(function); 86 } 87 88 AnalyzePossibleApiFunction(Handle<JSFunction> function)89void CallOptimization::AnalyzePossibleApiFunction(Handle<JSFunction> function) { 90 if (!function->shared()->IsApiFunction()) return; 91 Handle<FunctionTemplateInfo> info(function->shared()->get_api_func_data()); 92 93 // Require a C++ callback. 94 if (info->call_code()->IsUndefined()) return; 95 api_call_info_ = 96 Handle<CallHandlerInfo>(CallHandlerInfo::cast(info->call_code())); 97 98 // Accept signatures that either have no restrictions at all or 99 // only have restrictions on the receiver. 100 if (!info->signature()->IsUndefined()) { 101 Handle<SignatureInfo> signature = 102 Handle<SignatureInfo>(SignatureInfo::cast(info->signature())); 103 if (!signature->args()->IsUndefined()) return; 104 if (!signature->receiver()->IsUndefined()) { 105 expected_receiver_type_ = Handle<FunctionTemplateInfo>( 106 FunctionTemplateInfo::cast(signature->receiver())); 107 } 108 } 109 110 is_simple_api_call_ = true; 111 } 112 } 113 } // namespace v8::internal 114