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