• 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 
CallOptimization(Isolate * isolate,Handle<Object> function)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 
GetAccessorContext(Map holder_map) const23 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 
IsCrossContextLazyAccessorPair(Context native_context,Map holder_map) const31 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 
LookupHolderOfExpectedType(Handle<Map> object_map,HolderLookup * holder_lookup) const38 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->IsJSGlobalProxyMap() && !object_map->prototype().IsNull()) {
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 
IsCompatibleReceiver(Handle<Object> receiver,Handle<JSObject> holder) const63 bool CallOptimization::IsCompatibleReceiver(Handle<Object> receiver,
64                                             Handle<JSObject> holder) const {
65   DCHECK(is_simple_api_call());
66   if (!receiver->IsHeapObject()) return false;
67   Handle<Map> map(HeapObject::cast(*receiver).map(), holder->GetIsolate());
68   return IsCompatibleReceiverMap(map, holder);
69 }
70 
71 
IsCompatibleReceiverMap(Handle<Map> map,Handle<JSObject> holder) const72 bool CallOptimization::IsCompatibleReceiverMap(Handle<Map> map,
73                                                Handle<JSObject> holder) const {
74   HolderLookup holder_lookup;
75   Handle<JSObject> api_holder = LookupHolderOfExpectedType(map, &holder_lookup);
76   switch (holder_lookup) {
77     case kHolderNotFound:
78       return false;
79     case kHolderIsReceiver:
80       return true;
81     case kHolderFound:
82       if (api_holder.is_identical_to(holder)) return true;
83       // Check if holder is in prototype chain of api_holder.
84       {
85         JSObject object = *api_holder;
86         while (true) {
87           Object prototype = object.map().prototype();
88           if (!prototype.IsJSObject()) return false;
89           if (prototype == *holder) return true;
90           object = JSObject::cast(prototype);
91         }
92       }
93       break;
94   }
95   UNREACHABLE();
96 }
97 
Initialize(Isolate * isolate,Handle<FunctionTemplateInfo> function_template_info)98 void CallOptimization::Initialize(
99     Isolate* isolate, Handle<FunctionTemplateInfo> function_template_info) {
100   if (function_template_info->call_code(kAcquireLoad).IsUndefined(isolate))
101     return;
102   api_call_info_ = handle(
103       CallHandlerInfo::cast(function_template_info->call_code(kAcquireLoad)),
104       isolate);
105 
106   if (!function_template_info->signature().IsUndefined(isolate)) {
107     expected_receiver_type_ =
108         handle(FunctionTemplateInfo::cast(function_template_info->signature()),
109                isolate);
110   }
111   is_simple_api_call_ = true;
112 }
113 
Initialize(Isolate * isolate,Handle<JSFunction> function)114 void CallOptimization::Initialize(Isolate* isolate,
115                                   Handle<JSFunction> function) {
116   if (function.is_null() || !function->is_compiled()) return;
117 
118   constant_function_ = function;
119   AnalyzePossibleApiFunction(isolate, function);
120 }
121 
AnalyzePossibleApiFunction(Isolate * isolate,Handle<JSFunction> function)122 void CallOptimization::AnalyzePossibleApiFunction(Isolate* isolate,
123                                                   Handle<JSFunction> function) {
124   if (!function->shared().IsApiFunction()) return;
125   Handle<FunctionTemplateInfo> info(function->shared().get_api_func_data(),
126                                     isolate);
127 
128   // Require a C++ callback.
129   HeapObject call_code = info->call_code(kAcquireLoad);
130   if (call_code.IsUndefined(isolate)) return;
131   api_call_info_ = handle(CallHandlerInfo::cast(call_code), isolate);
132 
133   if (!info->signature().IsUndefined(isolate)) {
134     expected_receiver_type_ =
135         handle(FunctionTemplateInfo::cast(info->signature()), isolate);
136   }
137 
138   is_simple_api_call_ = true;
139 }
140 }  // namespace internal
141 }  // namespace v8
142