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