call-optimization.cc 5.18 KB
Newer Older
1 2 3 4 5
// Copyright 2014 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "src/ic/call-optimization.h"
6
#include "src/objects/objects-inl.h"
7 8 9 10

namespace v8 {
namespace internal {

11 12
template <class IsolateT>
CallOptimization::CallOptimization(IsolateT* isolate, Handle<Object> function) {
13
  if (function->IsJSFunction()) {
14
    Initialize(isolate, Handle<JSFunction>::cast(function));
15
  } else if (function->IsFunctionTemplateInfo()) {
16
    Initialize(isolate, Handle<FunctionTemplateInfo>::cast(function));
17
  }
18 19
}

20 21 22 23 24 25
// Instantiations.
template CallOptimization::CallOptimization(Isolate* isolate,
                                            Handle<Object> function);
template CallOptimization::CallOptimization(LocalIsolate* isolate,
                                            Handle<Object> function);

26
Context CallOptimization::GetAccessorContext(Map holder_map) const {
27
  if (is_constant_call()) {
28
    return constant_function_->native_context();
29
  }
30
  JSFunction constructor = JSFunction::cast(holder_map.GetConstructor());
31
  return constructor.native_context();
32 33
}

34
bool CallOptimization::IsCrossContextLazyAccessorPair(Context native_context,
35
                                                      Map holder_map) const {
36
  DCHECK(native_context.IsNativeContext());
37 38 39 40
  if (is_constant_call()) return false;
  return native_context != GetAccessorContext(holder_map);
}

41
template <class IsolateT>
42
Handle<JSObject> CallOptimization::LookupHolderOfExpectedType(
43
    IsolateT* isolate, Handle<Map> object_map,
44
    HolderLookup* holder_lookup) const {
45 46 47 48 49 50 51 52 53 54
  DCHECK(is_simple_api_call());
  if (!object_map->IsJSObjectMap()) {
    *holder_lookup = kHolderNotFound;
    return Handle<JSObject>::null();
  }
  if (expected_receiver_type_.is_null() ||
      expected_receiver_type_->IsTemplateFor(*object_map)) {
    *holder_lookup = kHolderIsReceiver;
    return Handle<JSObject>::null();
  }
55
  if (object_map->IsJSGlobalProxyMap() && !object_map->prototype().IsNull()) {
56
    JSObject raw_prototype = JSObject::cast(object_map->prototype());
57 58
    Handle<JSObject> prototype(raw_prototype, isolate);
    object_map = handle(prototype->map(), isolate);
59 60 61 62 63 64 65 66 67
    if (expected_receiver_type_->IsTemplateFor(*object_map)) {
      *holder_lookup = kHolderFound;
      return prototype;
    }
  }
  *holder_lookup = kHolderNotFound;
  return Handle<JSObject>::null();
}

68 69 70 71 72 73 74 75
// Instantiations.
template Handle<JSObject> CallOptimization::LookupHolderOfExpectedType(
    Isolate* isolate, Handle<Map> object_map,
    HolderLookup* holder_lookup) const;
template Handle<JSObject> CallOptimization::LookupHolderOfExpectedType(
    LocalIsolate* isolate, Handle<Map> object_map,
    HolderLookup* holder_lookup) const;

76 77 78
bool CallOptimization::IsCompatibleReceiverMap(
    Handle<JSObject> api_holder, Handle<JSObject> holder,
    HolderLookup holder_lookup) const {
79 80 81 82 83 84 85 86 87 88
  DCHECK(is_simple_api_call());
  switch (holder_lookup) {
    case kHolderNotFound:
      return false;
    case kHolderIsReceiver:
      return true;
    case kHolderFound:
      if (api_holder.is_identical_to(holder)) return true;
      // Check if holder is in prototype chain of api_holder.
      {
89
        JSObject object = *api_holder;
90
        while (true) {
91 92
          Object prototype = object.map().prototype();
          if (!prototype.IsJSObject()) return false;
93 94 95 96 97 98 99 100
          if (prototype == *holder) return true;
          object = JSObject::cast(prototype);
        }
      }
  }
  UNREACHABLE();
}

101
template <class IsolateT>
102
void CallOptimization::Initialize(
103
    IsolateT* isolate, Handle<FunctionTemplateInfo> function_template_info) {
104 105 106
  HeapObject call_code = function_template_info->call_code(kAcquireLoad);
  if (call_code.IsUndefined(isolate)) return;
  api_call_info_ = handle(CallHandlerInfo::cast(call_code), isolate);
107

108 109
  HeapObject signature = function_template_info->signature();
  if (!signature.IsUndefined(isolate)) {
110
    expected_receiver_type_ =
111
        handle(FunctionTemplateInfo::cast(signature), isolate);
112 113
  }
  is_simple_api_call_ = true;
114
  accept_any_receiver_ = function_template_info->accept_any_receiver();
115
}
116

117 118
template <class IsolateT>
void CallOptimization::Initialize(IsolateT* isolate,
119
                                  Handle<JSFunction> function) {
120 121 122
  if (function.is_null() || !function->is_compiled()) return;

  constant_function_ = function;
123
  AnalyzePossibleApiFunction(isolate, function);
124 125
}

126 127
template <class IsolateT>
void CallOptimization::AnalyzePossibleApiFunction(IsolateT* isolate,
128
                                                  Handle<JSFunction> function) {
129 130
  if (!function->shared().IsApiFunction()) return;
  Handle<FunctionTemplateInfo> info(function->shared().get_api_func_data(),
131
                                    isolate);
132 133

  // Require a C++ callback.
134 135 136
  HeapObject call_code = info->call_code(kAcquireLoad);
  if (call_code.IsUndefined(isolate)) return;
  api_call_info_ = handle(CallHandlerInfo::cast(call_code), isolate);
137

138
  if (!info->signature().IsUndefined(isolate)) {
dcarney's avatar
dcarney committed
139
    expected_receiver_type_ =
140
        handle(FunctionTemplateInfo::cast(info->signature()), isolate);
141 142 143
  }

  is_simple_api_call_ = true;
144
  accept_any_receiver_ = info->accept_any_receiver();
145
}
146 147
}  // namespace internal
}  // namespace v8