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