call-optimization.cc 4.92 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
CallOptimization::CallOptimization(Isolate* isolate, Handle<Object> function) {
12 13 14 15 16
  constant_function_ = Handle<JSFunction>::null();
  is_simple_api_call_ = false;
  expected_receiver_type_ = Handle<FunctionTemplateInfo>::null();
  api_call_info_ = Handle<CallHandlerInfo>::null();
  if (function->IsJSFunction()) {
17
    Initialize(isolate, Handle<JSFunction>::cast(function));
18
  } else if (function->IsFunctionTemplateInfo()) {
19
    Initialize(isolate, Handle<FunctionTemplateInfo>::cast(function));
20
  }
21 22
}

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

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

38
Handle<JSObject> CallOptimization::LookupHolderOfExpectedType(
39
    Handle<Map> object_map, HolderLookup* holder_lookup) const {
40 41 42 43 44 45 46 47 48 49
  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();
  }
50
  if (object_map->IsJSGlobalProxyMap() && !object_map->prototype().IsNull()) {
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 55 56 57 58 59 60 61 62 63 64 65
    if (expected_receiver_type_->IsTemplateFor(*object_map)) {
      *holder_lookup = kHolderFound;
      return prototype;
    }
  }
  *holder_lookup = kHolderNotFound;
  return Handle<JSObject>::null();
}

bool CallOptimization::IsCompatibleReceiver(Handle<Object> receiver,
                                            Handle<JSObject> holder) const {
  DCHECK(is_simple_api_call());
66
  if (!receiver->IsHeapObject()) return false;
67
  Handle<Map> map(HeapObject::cast(*receiver).map(), holder->GetIsolate());
68
  return IsCompatibleReceiverMap(map, holder);
69 70 71
}


72 73
bool CallOptimization::IsCompatibleReceiverMap(Handle<Map> map,
                                               Handle<JSObject> holder) const {
74 75 76 77 78 79 80 81 82 83 84
  HolderLookup holder_lookup;
  Handle<JSObject> api_holder = LookupHolderOfExpectedType(map, &holder_lookup);
  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.
      {
85
        JSObject object = *api_holder;
86
        while (true) {
87 88
          Object prototype = object.map().prototype();
          if (!prototype.IsJSObject()) return false;
89 90 91 92 93 94 95 96 97
          if (prototype == *holder) return true;
          object = JSObject::cast(prototype);
        }
      }
      break;
  }
  UNREACHABLE();
}

98
void CallOptimization::Initialize(
99
    Isolate* isolate, Handle<FunctionTemplateInfo> function_template_info) {
100
  if (function_template_info->call_code().IsUndefined(isolate)) return;
101 102
  api_call_info_ = handle(
      CallHandlerInfo::cast(function_template_info->call_code()), isolate);
103

104
  if (!function_template_info->signature().IsUndefined(isolate)) {
105
    expected_receiver_type_ =
106 107
        handle(FunctionTemplateInfo::cast(function_template_info->signature()),
               isolate);
108 109 110
  }
  is_simple_api_call_ = true;
}
111

112 113
void CallOptimization::Initialize(Isolate* isolate,
                                  Handle<JSFunction> function) {
114 115 116
  if (function.is_null() || !function->is_compiled()) return;

  constant_function_ = function;
117
  AnalyzePossibleApiFunction(isolate, function);
118 119
}

120 121
void CallOptimization::AnalyzePossibleApiFunction(Isolate* isolate,
                                                  Handle<JSFunction> function) {
122 123
  if (!function->shared().IsApiFunction()) return;
  Handle<FunctionTemplateInfo> info(function->shared().get_api_func_data(),
124
                                    isolate);
125 126

  // Require a C++ callback.
127
  if (info->call_code().IsUndefined(isolate)) return;
128
  api_call_info_ = handle(CallHandlerInfo::cast(info->call_code()), isolate);
129

130
  if (!info->signature().IsUndefined(isolate)) {
dcarney's avatar
dcarney committed
131
    expected_receiver_type_ =
132
        handle(FunctionTemplateInfo::cast(info->signature()), isolate);
133 134 135 136
  }

  is_simple_api_call_ = true;
}
137 138
}  // namespace internal
}  // namespace v8