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