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 208760 : CallOptimization::CallOptimization(Isolate* isolate, Handle<Object> function) {
12 : constant_function_ = Handle<JSFunction>::null();
13 208760 : is_simple_api_call_ = false;
14 : expected_receiver_type_ = Handle<FunctionTemplateInfo>::null();
15 : api_call_info_ = Handle<CallHandlerInfo>::null();
16 208760 : if (function->IsJSFunction()) {
17 203305 : Initialize(isolate, Handle<JSFunction>::cast(function));
18 5455 : } else if (function->IsFunctionTemplateInfo()) {
19 2291 : Initialize(isolate, Handle<FunctionTemplateInfo>::cast(function));
20 : }
21 208761 : }
22 :
23 4112 : Context CallOptimization::GetAccessorContext(Map holder_map) const {
24 4112 : if (is_constant_call()) {
25 3509 : return constant_function_->context()->native_context();
26 : }
27 603 : JSFunction constructor = JSFunction::cast(holder_map->GetConstructor());
28 603 : return constructor->context()->native_context();
29 : }
30 :
31 172 : bool CallOptimization::IsCrossContextLazyAccessorPair(Context native_context,
32 : Map holder_map) const {
33 : DCHECK(native_context->IsNativeContext());
34 172 : if (is_constant_call()) return false;
35 344 : return native_context != GetAccessorContext(holder_map);
36 : }
37 :
38 9792 : Handle<JSObject> CallOptimization::LookupHolderOfExpectedType(
39 : Handle<Map> object_map, HolderLookup* holder_lookup) const {
40 : DCHECK(is_simple_api_call());
41 9792 : if (!object_map->IsJSObjectMap()) {
42 0 : *holder_lookup = kHolderNotFound;
43 : return Handle<JSObject>::null();
44 : }
45 29376 : if (expected_receiver_type_.is_null() ||
46 11458 : expected_receiver_type_->IsTemplateFor(*object_map)) {
47 9572 : *holder_lookup = kHolderIsReceiver;
48 : return Handle<JSObject>::null();
49 : }
50 220 : if (object_map->has_hidden_prototype()) {
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 31 : if (expected_receiver_type_->IsTemplateFor(*object_map)) {
55 31 : *holder_lookup = kHolderFound;
56 31 : return prototype;
57 : }
58 : }
59 189 : *holder_lookup = kHolderNotFound;
60 : return Handle<JSObject>::null();
61 : }
62 :
63 :
64 407 : bool CallOptimization::IsCompatibleReceiver(Handle<Object> receiver,
65 : Handle<JSObject> holder) const {
66 : DCHECK(is_simple_api_call());
67 407 : if (!receiver->IsHeapObject()) return false;
68 : Handle<Map> map(HeapObject::cast(*receiver)->map(), holder->GetIsolate());
69 407 : return IsCompatibleReceiverMap(map, holder);
70 : }
71 :
72 :
73 4057 : bool CallOptimization::IsCompatibleReceiverMap(Handle<Map> map,
74 : Handle<JSObject> holder) const {
75 : HolderLookup holder_lookup;
76 4057 : Handle<JSObject> api_holder = LookupHolderOfExpectedType(map, &holder_lookup);
77 4058 : switch (holder_lookup) {
78 : case kHolderNotFound:
79 : return false;
80 : case kHolderIsReceiver:
81 3942 : return true;
82 : case kHolderFound:
83 15 : if (api_holder.is_identical_to(holder)) return true;
84 : // Check if holder is in prototype chain of api_holder.
85 : {
86 : JSObject object = *api_holder;
87 : while (true) {
88 : Object prototype = object->map()->prototype();
89 10 : if (!prototype->IsJSObject()) return false;
90 10 : if (prototype == *holder) return true;
91 : object = JSObject::cast(prototype);
92 : }
93 : }
94 : break;
95 : }
96 0 : UNREACHABLE();
97 : }
98 :
99 2291 : void CallOptimization::Initialize(
100 : Isolate* isolate, Handle<FunctionTemplateInfo> function_template_info) {
101 2291 : if (function_template_info->call_code()->IsUndefined(isolate)) return;
102 : api_call_info_ = handle(
103 2291 : CallHandlerInfo::cast(function_template_info->call_code()), isolate);
104 :
105 2291 : if (!function_template_info->signature()->IsUndefined(isolate)) {
106 : expected_receiver_type_ =
107 : handle(FunctionTemplateInfo::cast(function_template_info->signature()),
108 571 : isolate);
109 : }
110 2291 : is_simple_api_call_ = true;
111 : }
112 :
113 203304 : void CallOptimization::Initialize(Isolate* isolate,
114 : Handle<JSFunction> function) {
115 406609 : if (function.is_null() || !function->is_compiled()) return;
116 :
117 194629 : constant_function_ = function;
118 194629 : AnalyzePossibleApiFunction(isolate, function);
119 : }
120 :
121 194629 : void CallOptimization::AnalyzePossibleApiFunction(Isolate* isolate,
122 : Handle<JSFunction> function) {
123 194629 : if (!function->shared()->IsApiFunction()) return;
124 : Handle<FunctionTemplateInfo> info(function->shared()->get_api_func_data(),
125 : isolate);
126 :
127 : // Require a C++ callback.
128 3592 : if (info->call_code()->IsUndefined(isolate)) return;
129 3573 : api_call_info_ = handle(CallHandlerInfo::cast(info->call_code()), isolate);
130 :
131 3573 : if (!info->signature()->IsUndefined(isolate)) {
132 : expected_receiver_type_ =
133 83 : handle(FunctionTemplateInfo::cast(info->signature()), isolate);
134 : }
135 :
136 3573 : is_simple_api_call_ = true;
137 : }
138 : } // namespace internal
139 121996 : } // namespace v8
|