blob: f7a1f6982fa74d53c8075bebf294901f660cfb2b [file] [log] [blame]
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001// 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
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005#include "src/ic/call-optimization.h"
6
7
8namespace v8 {
9namespace internal {
10
Ben Murdoch097c5b22016-05-18 11:27:45 +010011CallOptimization::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 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000021}
22
23
24Handle<JSObject> CallOptimization::LookupHolderOfExpectedType(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000025 Handle<Map> object_map, HolderLookup* holder_lookup,
26 int* holder_depth_in_prototype_chain) const {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000027 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 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000037 for (int depth = 1; true; depth++) {
Ben Murdoch097c5b22016-05-18 11:27:45 +010038 if (!object_map->has_hidden_prototype()) break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000039 Handle<JSObject> prototype(JSObject::cast(object_map->prototype()));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000040 object_map = handle(prototype->map());
41 if (expected_receiver_type_->IsTemplateFor(*object_map)) {
42 *holder_lookup = kHolderFound;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000043 if (holder_depth_in_prototype_chain != NULL) {
44 *holder_depth_in_prototype_chain = depth;
45 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000046 return prototype;
47 }
48 }
49 *holder_lookup = kHolderNotFound;
50 return Handle<JSObject>::null();
51}
52
53
54bool CallOptimization::IsCompatibleReceiver(Handle<Object> receiver,
55 Handle<JSObject> holder) const {
56 DCHECK(is_simple_api_call());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000057 if (!receiver->IsHeapObject()) return false;
58 Handle<Map> map(HeapObject::cast(*receiver)->map());
59 return IsCompatibleReceiverMap(map, holder);
60}
61
62
63bool CallOptimization::IsCompatibleReceiverMap(Handle<Map> map,
64 Handle<JSObject> holder) const {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000065 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
Ben Murdoch097c5b22016-05-18 11:27:45 +010090void CallOptimization::Initialize(
91 Handle<FunctionTemplateInfo> function_template_info) {
Ben Murdoch61f157c2016-09-16 13:49:30 +010092 Isolate* isolate = function_template_info->GetIsolate();
93 if (function_template_info->call_code()->IsUndefined(isolate)) return;
Ben Murdoch097c5b22016-05-18 11:27:45 +010094 api_call_info_ =
95 handle(CallHandlerInfo::cast(function_template_info->call_code()));
96
Ben Murdoch61f157c2016-09-16 13:49:30 +010097 if (!function_template_info->signature()->IsUndefined(isolate)) {
Ben Murdoch097c5b22016-05-18 11:27:45 +010098 expected_receiver_type_ =
99 handle(FunctionTemplateInfo::cast(function_template_info->signature()));
100 }
101 is_simple_api_call_ = true;
102}
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000103
104void CallOptimization::Initialize(Handle<JSFunction> function) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000105 if (function.is_null() || !function->is_compiled()) return;
106
107 constant_function_ = function;
108 AnalyzePossibleApiFunction(function);
109}
110
111
112void CallOptimization::AnalyzePossibleApiFunction(Handle<JSFunction> function) {
113 if (!function->shared()->IsApiFunction()) return;
Ben Murdoch61f157c2016-09-16 13:49:30 +0100114 Isolate* isolate = function->GetIsolate();
115 Handle<FunctionTemplateInfo> info(function->shared()->get_api_func_data(),
116 isolate);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000117
118 // Require a C++ callback.
Ben Murdoch61f157c2016-09-16 13:49:30 +0100119 if (info->call_code()->IsUndefined(isolate)) return;
120 api_call_info_ = handle(CallHandlerInfo::cast(info->call_code()), isolate);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000121
Ben Murdoch61f157c2016-09-16 13:49:30 +0100122 if (!info->signature()->IsUndefined(isolate)) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000123 expected_receiver_type_ =
Ben Murdoch61f157c2016-09-16 13:49:30 +0100124 handle(FunctionTemplateInfo::cast(info->signature()), isolate);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000125 }
126
127 is_simple_api_call_ = true;
128}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000129} // namespace internal
130} // namespace v8