Home | History | Annotate | Download | only in ic
      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/ic/call-optimization.h"
      6 #include "src/objects-inl.h"
      7 
      8 namespace v8 {
      9 namespace internal {
     10 
     11 CallOptimization::CallOptimization(Isolate* isolate, Handle<Object> function) {
     12   constant_function_ = Handle<JSFunction>::null();
     13   is_simple_api_call_ = false;
     14   expected_receiver_type_ = Handle<FunctionTemplateInfo>::null();
     15   api_call_info_ = Handle<CallHandlerInfo>::null();
     16   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   JSFunction* constructor = JSFunction::cast(holder_map->GetConstructor());
     28   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   if (is_constant_call()) return false;
     35   return native_context != GetAccessorContext(holder_map);
     36 }
     37 
     38 Handle<JSObject> CallOptimization::LookupHolderOfExpectedType(
     39     Handle<Map> object_map, HolderLookup* holder_lookup) const {
     40   DCHECK(is_simple_api_call());
     41   if (!object_map->IsJSObjectMap()) {
     42     *holder_lookup = kHolderNotFound;
     43     return Handle<JSObject>::null();
     44   }
     45   if (expected_receiver_type_.is_null() ||
     46       expected_receiver_type_->IsTemplateFor(*object_map)) {
     47     *holder_lookup = kHolderIsReceiver;
     48     return Handle<JSObject>::null();
     49   }
     50   if (object_map->has_hidden_prototype()) {
     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     if (expected_receiver_type_->IsTemplateFor(*object_map)) {
     55       *holder_lookup = kHolderFound;
     56       return prototype;
     57     }
     58   }
     59   *holder_lookup = kHolderNotFound;
     60   return Handle<JSObject>::null();
     61 }
     62 
     63 
     64 bool CallOptimization::IsCompatibleReceiver(Handle<Object> receiver,
     65                                             Handle<JSObject> holder) const {
     66   DCHECK(is_simple_api_call());
     67   if (!receiver->IsHeapObject()) return false;
     68   Handle<Map> map(HeapObject::cast(*receiver)->map(), holder->GetIsolate());
     69   return IsCompatibleReceiverMap(map, holder);
     70 }
     71 
     72 
     73 bool CallOptimization::IsCompatibleReceiverMap(Handle<Map> map,
     74                                                Handle<JSObject> holder) const {
     75   HolderLookup holder_lookup;
     76   Handle<JSObject> api_holder = LookupHolderOfExpectedType(map, &holder_lookup);
     77   switch (holder_lookup) {
     78     case kHolderNotFound:
     79       return false;
     80     case kHolderIsReceiver:
     81       return true;
     82     case kHolderFound:
     83       if (api_holder.is_identical_to(holder)) return true;
     84       // Check if holder is in prototype chain of api_holder.
     85       {
     86         JSObject* object = *api_holder;
     87         while (true) {
     88           Object* prototype = object->map()->prototype();
     89           if (!prototype->IsJSObject()) return false;
     90           if (prototype == *holder) return true;
     91           object = JSObject::cast(prototype);
     92         }
     93       }
     94       break;
     95   }
     96   UNREACHABLE();
     97 }
     98 
     99 void CallOptimization::Initialize(
    100     Isolate* isolate, Handle<FunctionTemplateInfo> function_template_info) {
    101   if (function_template_info->call_code()->IsUndefined(isolate)) return;
    102   api_call_info_ = handle(
    103       CallHandlerInfo::cast(function_template_info->call_code()), isolate);
    104 
    105   if (!function_template_info->signature()->IsUndefined(isolate)) {
    106     expected_receiver_type_ =
    107         handle(FunctionTemplateInfo::cast(function_template_info->signature()),
    108                isolate);
    109   }
    110   is_simple_api_call_ = true;
    111 }
    112 
    113 void CallOptimization::Initialize(Isolate* isolate,
    114                                   Handle<JSFunction> function) {
    115   if (function.is_null() || !function->is_compiled()) return;
    116 
    117   constant_function_ = function;
    118   AnalyzePossibleApiFunction(isolate, function);
    119 }
    120 
    121 void CallOptimization::AnalyzePossibleApiFunction(Isolate* isolate,
    122                                                   Handle<JSFunction> function) {
    123   if (!function->shared()->IsApiFunction()) return;
    124   Handle<FunctionTemplateInfo> info(function->shared()->get_api_func_data(),
    125                                     isolate);
    126 
    127   // Require a C++ callback.
    128   if (info->call_code()->IsUndefined(isolate)) return;
    129   api_call_info_ = handle(CallHandlerInfo::cast(info->call_code()), isolate);
    130 
    131   if (!info->signature()->IsUndefined(isolate)) {
    132     expected_receiver_type_ =
    133         handle(FunctionTemplateInfo::cast(info->signature()), isolate);
    134   }
    135 
    136   is_simple_api_call_ = true;
    137 }
    138 }  // namespace internal
    139 }  // namespace v8
    140