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