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 374792 : CallOptimization::CallOptimization(Handle<Object> function) {
12 : constant_function_ = Handle<JSFunction>::null();
13 374792 : is_simple_api_call_ = false;
14 : expected_receiver_type_ = Handle<FunctionTemplateInfo>::null();
15 : api_call_info_ = Handle<CallHandlerInfo>::null();
16 374792 : if (function->IsJSFunction()) {
17 360541 : Initialize(Handle<JSFunction>::cast(function));
18 14251 : } else if (function->IsFunctionTemplateInfo()) {
19 12116 : Initialize(Handle<FunctionTemplateInfo>::cast(function));
20 : }
21 374792 : }
22 :
23 18906 : Handle<JSObject> CallOptimization::LookupHolderOfExpectedType(
24 : Handle<Map> object_map, HolderLookup* holder_lookup) const {
25 : DCHECK(is_simple_api_call());
26 18906 : if (!object_map->IsJSObjectMap()) {
27 0 : *holder_lookup = kHolderNotFound;
28 : return Handle<JSObject>::null();
29 : }
30 19548 : if (expected_receiver_type_.is_null() ||
31 642 : expected_receiver_type_->IsTemplateFor(*object_map)) {
32 18690 : *holder_lookup = kHolderIsReceiver;
33 : return Handle<JSObject>::null();
34 : }
35 216 : if (object_map->has_hidden_prototype()) {
36 : Handle<JSObject> prototype(JSObject::cast(object_map->prototype()));
37 : object_map = handle(prototype->map());
38 35 : if (expected_receiver_type_->IsTemplateFor(*object_map)) {
39 32 : *holder_lookup = kHolderFound;
40 32 : return prototype;
41 : }
42 : }
43 184 : *holder_lookup = kHolderNotFound;
44 : return Handle<JSObject>::null();
45 : }
46 :
47 :
48 322 : bool CallOptimization::IsCompatibleReceiver(Handle<Object> receiver,
49 : Handle<JSObject> holder) const {
50 : DCHECK(is_simple_api_call());
51 322 : if (!receiver->IsHeapObject()) return false;
52 : Handle<Map> map(HeapObject::cast(*receiver)->map());
53 322 : return IsCompatibleReceiverMap(map, holder);
54 : }
55 :
56 :
57 3903 : bool CallOptimization::IsCompatibleReceiverMap(Handle<Map> map,
58 : Handle<JSObject> holder) const {
59 : HolderLookup holder_lookup;
60 3903 : Handle<JSObject> api_holder = LookupHolderOfExpectedType(map, &holder_lookup);
61 3903 : switch (holder_lookup) {
62 : case kHolderNotFound:
63 : return false;
64 : case kHolderIsReceiver:
65 3787 : return true;
66 : case kHolderFound:
67 15 : if (api_holder.is_identical_to(holder)) return true;
68 : // Check if holder is in prototype chain of api_holder.
69 : {
70 : JSObject* object = *api_holder;
71 : while (true) {
72 : Object* prototype = object->map()->prototype();
73 10 : if (!prototype->IsJSObject()) return false;
74 10 : if (prototype == *holder) return true;
75 : object = JSObject::cast(prototype);
76 : }
77 : }
78 : break;
79 : }
80 0 : UNREACHABLE();
81 : }
82 :
83 12116 : void CallOptimization::Initialize(
84 : Handle<FunctionTemplateInfo> function_template_info) {
85 : Isolate* isolate = function_template_info->GetIsolate();
86 24232 : if (function_template_info->call_code()->IsUndefined(isolate)) return;
87 : api_call_info_ =
88 12114 : handle(CallHandlerInfo::cast(function_template_info->call_code()));
89 :
90 12114 : if (!function_template_info->signature()->IsUndefined(isolate)) {
91 : expected_receiver_type_ =
92 529 : handle(FunctionTemplateInfo::cast(function_template_info->signature()));
93 : }
94 12114 : is_simple_api_call_ = true;
95 : }
96 :
97 360541 : void CallOptimization::Initialize(Handle<JSFunction> function) {
98 1081623 : if (function.is_null() || !function->is_compiled()) return;
99 :
100 349425 : constant_function_ = function;
101 349425 : AnalyzePossibleApiFunction(function);
102 : }
103 :
104 :
105 349425 : void CallOptimization::AnalyzePossibleApiFunction(Handle<JSFunction> function) {
106 349425 : if (!function->shared()->IsApiFunction()) return;
107 : Isolate* isolate = function->GetIsolate();
108 : Handle<FunctionTemplateInfo> info(function->shared()->get_api_func_data(),
109 : isolate);
110 :
111 : // Require a C++ callback.
112 6812 : if (info->call_code()->IsUndefined(isolate)) return;
113 6792 : api_call_info_ = handle(CallHandlerInfo::cast(info->call_code()), isolate);
114 :
115 6792 : if (!info->signature()->IsUndefined(isolate)) {
116 : expected_receiver_type_ =
117 113 : handle(FunctionTemplateInfo::cast(info->signature()), isolate);
118 : }
119 :
120 6792 : is_simple_api_call_ = true;
121 : }
122 : } // namespace internal
123 : } // namespace v8
|