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