Line data Source code
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 409222 : CallOptimization::CallOptimization(Handle<Object> function) {
12 : constant_function_ = Handle<JSFunction>::null();
13 409222 : is_simple_api_call_ = false;
14 : expected_receiver_type_ = Handle<FunctionTemplateInfo>::null();
15 : api_call_info_ = Handle<CallHandlerInfo>::null();
16 409222 : if (function->IsJSFunction()) {
17 399889 : Initialize(Handle<JSFunction>::cast(function));
18 9333 : } else if (function->IsFunctionTemplateInfo()) {
19 9278 : Initialize(Handle<FunctionTemplateInfo>::cast(function));
20 : }
21 409222 : }
22 :
23 :
24 21417 : 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 21417 : if (!object_map->IsJSObjectMap()) {
29 1 : *holder_lookup = kHolderNotFound;
30 : return Handle<JSObject>::null();
31 : }
32 21676 : if (expected_receiver_type_.is_null() ||
33 260 : expected_receiver_type_->IsTemplateFor(*object_map)) {
34 21358 : *holder_lookup = kHolderIsReceiver;
35 : return Handle<JSObject>::null();
36 : }
37 6 : for (int depth = 1; true; depth++) {
38 64 : if (!object_map->has_hidden_prototype()) break;
39 : Handle<JSObject> prototype(JSObject::cast(object_map->prototype()));
40 : object_map = handle(prototype->map());
41 46 : if (expected_receiver_type_->IsTemplateFor(*object_map)) {
42 40 : *holder_lookup = kHolderFound;
43 40 : if (holder_depth_in_prototype_chain != NULL) {
44 12 : *holder_depth_in_prototype_chain = depth;
45 : }
46 40 : return prototype;
47 : }
48 6 : }
49 18 : *holder_lookup = kHolderNotFound;
50 : return Handle<JSObject>::null();
51 : }
52 :
53 :
54 117 : bool CallOptimization::IsCompatibleReceiver(Handle<Object> receiver,
55 : Handle<JSObject> holder) const {
56 : DCHECK(is_simple_api_call());
57 117 : if (!receiver->IsHeapObject()) return false;
58 : Handle<Map> map(HeapObject::cast(*receiver)->map());
59 117 : return IsCompatibleReceiverMap(map, holder);
60 : }
61 :
62 :
63 812 : bool CallOptimization::IsCompatibleReceiverMap(Handle<Map> map,
64 : Handle<JSObject> holder) const {
65 : HolderLookup holder_lookup;
66 812 : Handle<JSObject> api_holder = LookupHolderOfExpectedType(map, &holder_lookup);
67 812 : switch (holder_lookup) {
68 : case kHolderNotFound:
69 : return false;
70 : case kHolderIsReceiver:
71 781 : return true;
72 : case kHolderFound:
73 18 : 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 12 : if (!prototype->IsJSObject()) return false;
80 12 : if (prototype == *holder) return true;
81 : object = JSObject::cast(prototype);
82 : }
83 : }
84 : break;
85 : }
86 0 : UNREACHABLE();
87 : return false;
88 : }
89 :
90 9278 : void CallOptimization::Initialize(
91 : Handle<FunctionTemplateInfo> function_template_info) {
92 : Isolate* isolate = function_template_info->GetIsolate();
93 18556 : if (function_template_info->call_code()->IsUndefined(isolate)) return;
94 : api_call_info_ =
95 9276 : handle(CallHandlerInfo::cast(function_template_info->call_code()));
96 :
97 9276 : if (!function_template_info->signature()->IsUndefined(isolate)) {
98 : expected_receiver_type_ =
99 132 : handle(FunctionTemplateInfo::cast(function_template_info->signature()));
100 : }
101 9276 : is_simple_api_call_ = true;
102 : }
103 :
104 399889 : void CallOptimization::Initialize(Handle<JSFunction> function) {
105 1199667 : if (function.is_null() || !function->is_compiled()) return;
106 :
107 316819 : constant_function_ = function;
108 316819 : AnalyzePossibleApiFunction(function);
109 : }
110 :
111 :
112 316819 : void CallOptimization::AnalyzePossibleApiFunction(Handle<JSFunction> function) {
113 316819 : 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 12182 : if (info->call_code()->IsUndefined(isolate)) return;
120 12150 : api_call_info_ = handle(CallHandlerInfo::cast(info->call_code()), isolate);
121 :
122 12150 : if (!info->signature()->IsUndefined(isolate)) {
123 : expected_receiver_type_ =
124 128 : handle(FunctionTemplateInfo::cast(info->signature()), isolate);
125 : }
126 :
127 12150 : is_simple_api_call_ = true;
128 : }
129 : } // namespace internal
130 : } // namespace v8
|