LCOV - code coverage report
Current view: top level - src/builtins - builtins-api.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 83 85 97.6 %
Date: 2017-10-20 Functions: 10 15 66.7 %

          Line data    Source code
       1             : // Copyright 2016 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/builtins/builtins.h"
       6             : 
       7             : #include "src/api-arguments.h"
       8             : #include "src/api-natives.h"
       9             : #include "src/builtins/builtins-utils.h"
      10             : #include "src/counters.h"
      11             : #include "src/log.h"
      12             : #include "src/objects-inl.h"
      13             : #include "src/prototype.h"
      14             : #include "src/visitors.h"
      15             : 
      16             : namespace v8 {
      17             : namespace internal {
      18             : 
      19             : namespace {
      20             : 
      21             : // Returns the holder JSObject if the function can legally be called with this
      22             : // receiver.  Returns nullptr if the call is illegal.
      23             : // TODO(dcarney): CallOptimization duplicates this logic, merge.
      24    14120723 : JSObject* GetCompatibleReceiver(Isolate* isolate, FunctionTemplateInfo* info,
      25             :                                 JSObject* receiver) {
      26             :   Object* recv_type = info->signature();
      27             :   // No signature, return holder.
      28    14120724 :   if (!recv_type->IsFunctionTemplateInfo()) return receiver;
      29             :   FunctionTemplateInfo* signature = FunctionTemplateInfo::cast(recv_type);
      30             : 
      31             :   // Check the receiver. Fast path for receivers with no hidden prototypes.
      32        9053 :   if (signature->IsTemplateFor(receiver)) return receiver;
      33        6791 :   if (!receiver->map()->has_hidden_prototype()) return nullptr;
      34        6244 :   for (PrototypeIterator iter(isolate, receiver, kStartAtPrototype,
      35             :                               PrototypeIterator::END_AT_NON_HIDDEN);
      36          15 :        !iter.IsAtEnd(); iter.Advance()) {
      37        6229 :     JSObject* current = iter.GetCurrent<JSObject>();
      38        6229 :     if (signature->IsTemplateFor(current)) return current;
      39             :   }
      40          15 :   return nullptr;
      41             : }
      42             : 
      43             : template <bool is_construct>
      44    14429781 : MUST_USE_RESULT MaybeHandle<Object> HandleApiCallHelper(
      45    14427315 :     Isolate* isolate, Handle<HeapObject> function,
      46             :     Handle<HeapObject> new_target, Handle<FunctionTemplateInfo> fun_data,
      47             :     Handle<Object> receiver, BuiltinArguments args) {
      48             :   Handle<JSObject> js_receiver;
      49             :   JSObject* raw_holder;
      50             :   if (is_construct) {
      51             :     DCHECK(args.receiver()->IsTheHole(isolate));
      52      309049 :     if (fun_data->instance_template()->IsUndefined(isolate)) {
      53             :       v8::Local<ObjectTemplate> templ =
      54             :           ObjectTemplate::New(reinterpret_cast<v8::Isolate*>(isolate),
      55        5238 :                               ToApiHandle<v8::FunctionTemplate>(fun_data));
      56             :       fun_data->set_instance_template(*Utils::OpenHandle(*templ));
      57             :     }
      58             :     Handle<ObjectTemplateInfo> instance_template(
      59             :         ObjectTemplateInfo::cast(fun_data->instance_template()), isolate);
      60      618098 :     ASSIGN_RETURN_ON_EXCEPTION(
      61             :         isolate, js_receiver,
      62             :         ApiNatives::InstantiateObject(instance_template,
      63             :                                       Handle<JSReceiver>::cast(new_target)),
      64             :         Object);
      65      309049 :     args[0] = *js_receiver;
      66             :     DCHECK_EQ(*js_receiver, *args.receiver());
      67             : 
      68             :     raw_holder = *js_receiver;
      69             :   } else {
      70             :     DCHECK(receiver->IsJSReceiver());
      71             : 
      72    14120730 :     if (!receiver->IsJSObject()) {
      73             :       // This function cannot be called with the given receiver.  Abort!
      74           0 :       THROW_NEW_ERROR(
      75             :           isolate, NewTypeError(MessageTemplate::kIllegalInvocation), Object);
      76             :     }
      77             : 
      78             :     js_receiver = Handle<JSObject>::cast(receiver);
      79             : 
      80    14120849 :     if (!fun_data->accept_any_receiver() &&
      81             :         js_receiver->IsAccessCheckNeeded() &&
      82          57 :         !isolate->MayAccess(handle(isolate->context()), js_receiver)) {
      83           7 :       isolate->ReportFailedAccessCheck(js_receiver);
      84           7 :       RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
      85           2 :       return isolate->factory()->undefined_value();
      86             :     }
      87             : 
      88    14120723 :     raw_holder = GetCompatibleReceiver(isolate, *fun_data, *js_receiver);
      89             : 
      90    14120724 :     if (raw_holder == nullptr) {
      91             :       // This function cannot be called with the given receiver.  Abort!
      92        1154 :       THROW_NEW_ERROR(
      93             :           isolate, NewTypeError(MessageTemplate::kIllegalInvocation), Object);
      94             :     }
      95             :   }
      96             : 
      97             :   Object* raw_call_data = fun_data->call_code();
      98    14429196 :   if (!raw_call_data->IsUndefined(isolate)) {
      99             :     DCHECK(raw_call_data->IsCallHandlerInfo());
     100             :     CallHandlerInfo* call_data = CallHandlerInfo::cast(raw_call_data);
     101             :     Object* callback_obj = call_data->callback();
     102             :     v8::FunctionCallback callback =
     103             :         v8::ToCData<v8::FunctionCallback>(callback_obj);
     104             :     Object* data_obj = call_data->data();
     105             : 
     106    14427258 :     LOG(isolate, ApiObjectAccess("call", JSObject::cast(*js_receiver)));
     107             : 
     108             :     FunctionCallbackArguments custom(isolate, data_obj, *function, raw_holder,
     109             :                                      *new_target, &args[0] - 1,
     110    28547235 :                                      args.length() - 1);
     111             : 
     112    14427258 :     Handle<Object> result = custom.Call(callback);
     113             : 
     114    14427260 :     RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
     115    14403577 :     if (result.is_null()) {
     116         420 :       if (is_construct) return js_receiver;
     117     6853596 :       return isolate->factory()->undefined_value();
     118             :     }
     119             :     // Rebox the result.
     120             :     result->VerifyApiCallResultType();
     121      292221 :     if (!is_construct || result->IsJSReceiver())
     122     7549333 :       return handle(*result, isolate);
     123             :   }
     124             : 
     125        2166 :   return js_receiver;
     126             : }
     127             : 
     128             : }  // anonymous namespace
     129             : 
     130    43249361 : BUILTIN(HandleApiCall) {
     131             :   HandleScope scope(isolate);
     132             :   Handle<JSFunction> function = args.target();
     133    14416453 :   Handle<Object> receiver = args.receiver();
     134             :   Handle<HeapObject> new_target = args.new_target();
     135             :   Handle<FunctionTemplateInfo> fun_data(function->shared()->get_api_func_data(),
     136             :                                         isolate);
     137    14416454 :   if (new_target->IsJSReceiver()) {
     138      910170 :     RETURN_RESULT_OR_FAILURE(
     139             :         isolate, HandleApiCallHelper<true>(isolate, function, new_target,
     140             :                                            fun_data, receiver, args));
     141             :   } else {
     142    42315266 :     RETURN_RESULT_OR_FAILURE(
     143             :         isolate, HandleApiCallHelper<false>(isolate, function, new_target,
     144             :                                             fun_data, receiver, args));
     145             :   }
     146             : }
     147             : 
     148             : namespace {
     149             : 
     150       13327 : class RelocatableArguments : public BuiltinArguments, public Relocatable {
     151             :  public:
     152             :   RelocatableArguments(Isolate* isolate, int length, Object** arguments)
     153       13327 :       : BuiltinArguments(length, arguments), Relocatable(isolate) {}
     154             : 
     155          62 :   virtual inline void IterateInstance(RootVisitor* v) {
     156         124 :     if (length() == 0) return;
     157             :     v->VisitRootPointers(Root::kRelocatable, lowest_address(),
     158         186 :                          highest_address() + 1);
     159             :   }
     160             : 
     161             :  private:
     162             :   DISALLOW_COPY_AND_ASSIGN(RelocatableArguments);
     163             : };
     164             : 
     165             : }  // namespace
     166             : 
     167       13327 : MaybeHandle<Object> Builtins::InvokeApiFunction(Isolate* isolate,
     168             :                                                 bool is_construct,
     169             :                                                 Handle<HeapObject> function,
     170             :                                                 Handle<Object> receiver,
     171             :                                                 int argc, Handle<Object> args[],
     172             :                                                 Handle<HeapObject> new_target) {
     173             :   DCHECK(function->IsFunctionTemplateInfo() ||
     174             :          (function->IsJSFunction() &&
     175             :           JSFunction::cast(*function)->shared()->IsApiFunction()));
     176             : 
     177             :   // Do proper receiver conversion for non-strict mode api functions.
     178       25875 :   if (!is_construct && !receiver->IsJSReceiver()) {
     179         458 :     if (function->IsFunctionTemplateInfo() ||
     180             :         is_sloppy(JSFunction::cast(*function)->shared()->language_mode())) {
     181         494 :       ASSIGN_RETURN_ON_EXCEPTION(isolate, receiver,
     182             :                                  Object::ConvertReceiver(isolate, receiver),
     183             :                                  Object);
     184             :     }
     185             :   }
     186             : 
     187             :   Handle<FunctionTemplateInfo> fun_data =
     188             :       function->IsFunctionTemplateInfo()
     189             :           ? Handle<FunctionTemplateInfo>::cast(function)
     190             :           : handle(JSFunction::cast(*function)->shared()->get_api_func_data(),
     191       25453 :                    isolate);
     192             :   // Construct BuiltinArguments object:
     193             :   // new target, function, arguments reversed, receiver.
     194             :   const int kBufferSize = 32;
     195             :   Object* small_argv[kBufferSize];
     196             :   Object** argv;
     197       13327 :   const int frame_argc = argc + BuiltinArguments::kNumExtraArgsWithReceiver;
     198       13327 :   if (frame_argc <= kBufferSize) {
     199             :     argv = small_argv;
     200             :   } else {
     201           0 :     argv = new Object*[frame_argc];
     202             :   }
     203       13327 :   int cursor = frame_argc - 1;
     204       26654 :   argv[cursor--] = *receiver;
     205       14581 :   for (int i = 0; i < argc; ++i) {
     206        2508 :     argv[cursor--] = *args[i];
     207             :   }
     208             :   DCHECK_EQ(cursor, BuiltinArguments::kPaddingOffset);
     209       13327 :   argv[BuiltinArguments::kPaddingOffset] = isolate->heap()->the_hole_value();
     210       13327 :   argv[BuiltinArguments::kArgcOffset] = Smi::FromInt(frame_argc);
     211       13327 :   argv[BuiltinArguments::kTargetOffset] = *function;
     212       13327 :   argv[BuiltinArguments::kNewTargetOffset] = *new_target;
     213             :   MaybeHandle<Object> result;
     214             :   {
     215       13327 :     RelocatableArguments arguments(isolate, frame_argc, &argv[frame_argc - 1]);
     216       13327 :     if (is_construct) {
     217             :       result = HandleApiCallHelper<true>(isolate, function, new_target,
     218         779 :                                          fun_data, receiver, arguments);
     219             :     } else {
     220             :       result = HandleApiCallHelper<false>(isolate, function, new_target,
     221       12548 :                                           fun_data, receiver, arguments);
     222             :     }
     223             :   }
     224       13327 :   if (argv != small_argv) delete[] argv;
     225       13327 :   return result;
     226             : }
     227             : 
     228             : // Helper function to handle calls to non-function objects created through the
     229             : // API. The object can be called as either a constructor (using new) or just as
     230             : // a function (without new).
     231         324 : MUST_USE_RESULT static Object* HandleApiCallAsFunctionOrConstructor(
     232         324 :     Isolate* isolate, bool is_construct_call, BuiltinArguments args) {
     233             :   Handle<Object> receiver = args.receiver();
     234             : 
     235             :   // Get the object called.
     236             :   JSObject* obj = JSObject::cast(*receiver);
     237             : 
     238             :   // Set the new target.
     239             :   HeapObject* new_target;
     240         324 :   if (is_construct_call) {
     241             :     // TODO(adamk): This should be passed through in args instead of
     242             :     // being patched in here. We need to set a non-undefined value
     243             :     // for v8::FunctionCallbackInfo::IsConstructCall() to get the
     244             :     // right answer.
     245             :     new_target = obj;
     246             :   } else {
     247         234 :     new_target = isolate->heap()->undefined_value();
     248             :   }
     249             : 
     250             :   // Get the invocation callback from the function descriptor that was
     251             :   // used to create the called object.
     252             :   DCHECK(obj->map()->is_callable());
     253         324 :   JSFunction* constructor = JSFunction::cast(obj->map()->GetConstructor());
     254             :   // TODO(ishell): turn this back to a DCHECK.
     255         324 :   CHECK(constructor->shared()->IsApiFunction());
     256             :   Object* handler =
     257             :       constructor->shared()->get_api_func_data()->instance_call_handler();
     258             :   DCHECK(!handler->IsUndefined(isolate));
     259             :   // TODO(ishell): remove this debugging code.
     260         324 :   CHECK(handler->IsCallHandlerInfo());
     261             :   CallHandlerInfo* call_data = CallHandlerInfo::cast(handler);
     262             :   Object* callback_obj = call_data->callback();
     263             :   v8::FunctionCallback callback =
     264             :       v8::ToCData<v8::FunctionCallback>(callback_obj);
     265             : 
     266             :   // Get the data for the call and perform the callback.
     267             :   Object* result;
     268             :   {
     269             :     HandleScope scope(isolate);
     270         324 :     LOG(isolate, ApiObjectAccess("call non-function", obj));
     271             : 
     272             :     FunctionCallbackArguments custom(isolate, call_data->data(), constructor,
     273             :                                      obj, new_target, &args[0] - 1,
     274         324 :                                      args.length() - 1);
     275         324 :     Handle<Object> result_handle = custom.Call(callback);
     276         324 :     if (result_handle.is_null()) {
     277          24 :       result = isolate->heap()->undefined_value();
     278             :     } else {
     279             :       result = *result_handle;
     280             :     }
     281             :   }
     282             :   // Check for exceptions and return result.
     283         324 :   RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
     284             :   return result;
     285             : }
     286             : 
     287             : // Handle calls to non-function objects created through the API. This delegate
     288             : // function is used when the call is a normal function call.
     289         468 : BUILTIN(HandleApiCallAsFunction) {
     290         234 :   return HandleApiCallAsFunctionOrConstructor(isolate, false, args);
     291             : }
     292             : 
     293             : // Handle calls to non-function objects created through the API. This delegate
     294             : // function is used when the call is a construct call.
     295         180 : BUILTIN(HandleApiCallAsConstructor) {
     296          90 :   return HandleApiCallAsFunctionOrConstructor(isolate, true, args);
     297             : }
     298             : 
     299             : }  // namespace internal
     300             : }  // namespace v8

Generated by: LCOV version 1.10