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