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