• Home
  • History
  • Annotate
  • 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  
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