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/v8.h"
6
7#include "src/ic/call-optimization.h"
8
9
10namespace v8 {
11namespace internal {
12
13CallOptimization::CallOptimization(Handle<JSFunction> function) {
14  Initialize(function);
15}
16
17
18Handle<JSObject> CallOptimization::LookupHolderOfExpectedType(
19    Handle<Map> object_map, HolderLookup* holder_lookup) const {
20  DCHECK(is_simple_api_call());
21  if (!object_map->IsJSObjectMap()) {
22    *holder_lookup = kHolderNotFound;
23    return Handle<JSObject>::null();
24  }
25  if (expected_receiver_type_.is_null() ||
26      expected_receiver_type_->IsTemplateFor(*object_map)) {
27    *holder_lookup = kHolderIsReceiver;
28    return Handle<JSObject>::null();
29  }
30  while (true) {
31    if (!object_map->prototype()->IsJSObject()) break;
32    Handle<JSObject> prototype(JSObject::cast(object_map->prototype()));
33    if (!prototype->map()->is_hidden_prototype()) break;
34    object_map = handle(prototype->map());
35    if (expected_receiver_type_->IsTemplateFor(*object_map)) {
36      *holder_lookup = kHolderFound;
37      return prototype;
38    }
39  }
40  *holder_lookup = kHolderNotFound;
41  return Handle<JSObject>::null();
42}
43
44
45bool CallOptimization::IsCompatibleReceiver(Handle<Object> receiver,
46                                            Handle<JSObject> holder) const {
47  DCHECK(is_simple_api_call());
48  if (!receiver->IsJSObject()) return false;
49  Handle<Map> map(JSObject::cast(*receiver)->map());
50  HolderLookup holder_lookup;
51  Handle<JSObject> api_holder = LookupHolderOfExpectedType(map, &holder_lookup);
52  switch (holder_lookup) {
53    case kHolderNotFound:
54      return false;
55    case kHolderIsReceiver:
56      return true;
57    case kHolderFound:
58      if (api_holder.is_identical_to(holder)) return true;
59      // Check if holder is in prototype chain of api_holder.
60      {
61        JSObject* object = *api_holder;
62        while (true) {
63          Object* prototype = object->map()->prototype();
64          if (!prototype->IsJSObject()) return false;
65          if (prototype == *holder) return true;
66          object = JSObject::cast(prototype);
67        }
68      }
69      break;
70  }
71  UNREACHABLE();
72  return false;
73}
74
75
76void CallOptimization::Initialize(Handle<JSFunction> function) {
77  constant_function_ = Handle<JSFunction>::null();
78  is_simple_api_call_ = false;
79  expected_receiver_type_ = Handle<FunctionTemplateInfo>::null();
80  api_call_info_ = Handle<CallHandlerInfo>::null();
81
82  if (function.is_null() || !function->is_compiled()) return;
83
84  constant_function_ = function;
85  AnalyzePossibleApiFunction(function);
86}
87
88
89void CallOptimization::AnalyzePossibleApiFunction(Handle<JSFunction> function) {
90  if (!function->shared()->IsApiFunction()) return;
91  Handle<FunctionTemplateInfo> info(function->shared()->get_api_func_data());
92
93  // Require a C++ callback.
94  if (info->call_code()->IsUndefined()) return;
95  api_call_info_ =
96      Handle<CallHandlerInfo>(CallHandlerInfo::cast(info->call_code()));
97
98  // Accept signatures that either have no restrictions at all or
99  // only have restrictions on the receiver.
100  if (!info->signature()->IsUndefined()) {
101    Handle<SignatureInfo> signature =
102        Handle<SignatureInfo>(SignatureInfo::cast(info->signature()));
103    if (!signature->args()->IsUndefined()) return;
104    if (!signature->receiver()->IsUndefined()) {
105      expected_receiver_type_ = Handle<FunctionTemplateInfo>(
106          FunctionTemplateInfo::cast(signature->receiver()));
107    }
108  }
109
110  is_simple_api_call_ = true;
111}
112}
113}  // namespace v8::internal
114