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(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(Handle<JSFunction>::cast(function));
     18   } else if (function->IsFunctionTemplateInfo()) {
     19     Initialize(Handle<FunctionTemplateInfo>::cast(function));
     20   }
     21 }
     22 
     23 
     24 Handle<JSObject> CallOptimization::LookupHolderOfExpectedType(
     25     Handle<Map> object_map, HolderLookup* holder_lookup,
     26     int* holder_depth_in_prototype_chain) const {
     27   DCHECK(is_simple_api_call());
     28   if (!object_map->IsJSObjectMap()) {
     29     *holder_lookup = kHolderNotFound;
     30     return Handle<JSObject>::null();
     31   }
     32   if (expected_receiver_type_.is_null() ||
     33       expected_receiver_type_->IsTemplateFor(*object_map)) {
     34     *holder_lookup = kHolderIsReceiver;
     35     return Handle<JSObject>::null();
     36   }
     37   for (int depth = 1; true; depth++) {
     38     if (!object_map->has_hidden_prototype()) break;
     39     Handle<JSObject> prototype(JSObject::cast(object_map->prototype()));
     40     object_map = handle(prototype->map());
     41     if (expected_receiver_type_->IsTemplateFor(*object_map)) {
     42       *holder_lookup = kHolderFound;
     43       if (holder_depth_in_prototype_chain != NULL) {
     44         *holder_depth_in_prototype_chain = depth;
     45       }
     46       return prototype;
     47     }
     48   }
     49   *holder_lookup = kHolderNotFound;
     50   return Handle<JSObject>::null();
     51 }
     52 
     53 
     54 bool CallOptimization::IsCompatibleReceiver(Handle<Object> receiver,
     55                                             Handle<JSObject> holder) const {
     56   DCHECK(is_simple_api_call());
     57   if (!receiver->IsHeapObject()) return false;
     58   Handle<Map> map(HeapObject::cast(*receiver)->map());
     59   return IsCompatibleReceiverMap(map, holder);
     60 }
     61 
     62 
     63 bool CallOptimization::IsCompatibleReceiverMap(Handle<Map> map,
     64                                                Handle<JSObject> holder) const {
     65   HolderLookup holder_lookup;
     66   Handle<JSObject> api_holder = LookupHolderOfExpectedType(map, &holder_lookup);
     67   switch (holder_lookup) {
     68     case kHolderNotFound:
     69       return false;
     70     case kHolderIsReceiver:
     71       return true;
     72     case kHolderFound:
     73       if (api_holder.is_identical_to(holder)) return true;
     74       // Check if holder is in prototype chain of api_holder.
     75       {
     76         JSObject* object = *api_holder;
     77         while (true) {
     78           Object* prototype = object->map()->prototype();
     79           if (!prototype->IsJSObject()) return false;
     80           if (prototype == *holder) return true;
     81           object = JSObject::cast(prototype);
     82         }
     83       }
     84       break;
     85   }
     86   UNREACHABLE();
     87   return false;
     88 }
     89 
     90 void CallOptimization::Initialize(
     91     Handle<FunctionTemplateInfo> function_template_info) {
     92   Isolate* isolate = function_template_info->GetIsolate();
     93   if (function_template_info->call_code()->IsUndefined(isolate)) return;
     94   api_call_info_ =
     95       handle(CallHandlerInfo::cast(function_template_info->call_code()));
     96 
     97   if (!function_template_info->signature()->IsUndefined(isolate)) {
     98     expected_receiver_type_ =
     99         handle(FunctionTemplateInfo::cast(function_template_info->signature()));
    100   }
    101   is_simple_api_call_ = true;
    102 }
    103 
    104 void CallOptimization::Initialize(Handle<JSFunction> function) {
    105   if (function.is_null() || !function->is_compiled()) return;
    106 
    107   constant_function_ = function;
    108   AnalyzePossibleApiFunction(function);
    109 }
    110 
    111 
    112 void CallOptimization::AnalyzePossibleApiFunction(Handle<JSFunction> function) {
    113   if (!function->shared()->IsApiFunction()) return;
    114   Isolate* isolate = function->GetIsolate();
    115   Handle<FunctionTemplateInfo> info(function->shared()->get_api_func_data(),
    116                                     isolate);
    117 
    118   // Require a C++ callback.
    119   if (info->call_code()->IsUndefined(isolate)) return;
    120   api_call_info_ = handle(CallHandlerInfo::cast(info->call_code()), isolate);
    121 
    122   if (!info->signature()->IsUndefined(isolate)) {
    123     expected_receiver_type_ =
    124         handle(FunctionTemplateInfo::cast(info->signature()), isolate);
    125   }
    126 
    127   is_simple_api_call_ = true;
    128 }
    129 }  // namespace internal
    130 }  // namespace v8
    131