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<JSFunction> function)11 CallOptimization::CallOptimization(Handle<JSFunction> function) {
12   Initialize(function);
13 }
14 
15 
LookupHolderOfExpectedType(Handle<Map> object_map,HolderLookup * holder_lookup,int * holder_depth_in_prototype_chain) const16 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 
IsCompatibleReceiver(Handle<Object> receiver,Handle<JSObject> holder) const47 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 
IsCompatibleReceiverMap(Handle<Map> map,Handle<JSObject> holder) const56 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 
Initialize(Handle<JSFunction> function)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 
AnalyzePossibleApiFunction(Handle<JSFunction> function)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