LCOV - code coverage report
Current view: top level - src/builtins - builtins-api.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 92 93 98.9 %
Date: 2019-03-21 Functions: 12 16 75.0 %

          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/api-arguments-inl.h"
       6             : #include "src/api-natives.h"
       7             : #include "src/builtins/builtins-utils-inl.h"
       8             : #include "src/builtins/builtins.h"
       9             : #include "src/counters.h"
      10             : #include "src/log.h"
      11             : #include "src/objects-inl.h"
      12             : #include "src/objects/templates.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     2381080 : JSReceiver GetCompatibleReceiver(Isolate* isolate, FunctionTemplateInfo info,
      25             :                                  JSReceiver receiver) {
      26             :   Object recv_type = info->signature();
      27             :   // No signature, return holder.
      28     2381080 :   if (!recv_type->IsFunctionTemplateInfo()) return receiver;
      29             :   // A Proxy cannot have been created from the signature template.
      30        3839 :   if (!receiver->IsJSObject()) return JSReceiver();
      31             : 
      32             :   JSObject js_obj_receiver = JSObject::cast(receiver);
      33        3839 :   FunctionTemplateInfo signature = FunctionTemplateInfo::cast(recv_type);
      34             : 
      35             :   // Check the receiver. Fast path for receivers with no hidden prototypes.
      36        3839 :   if (signature->IsTemplateFor(js_obj_receiver)) return receiver;
      37         621 :   if (!js_obj_receiver->map()->has_hidden_prototype()) return JSReceiver();
      38         109 :   for (PrototypeIterator iter(isolate, js_obj_receiver, kStartAtPrototype,
      39             :                               PrototypeIterator::END_AT_NON_HIDDEN);
      40          10 :        !iter.IsAtEnd(); iter.Advance()) {
      41             :     JSObject current = iter.GetCurrent<JSObject>();
      42          89 :     if (signature->IsTemplateFor(current)) return current;
      43             :   }
      44          10 :   return JSReceiver();
      45             : }
      46             : 
      47             : template <bool is_construct>
      48     2681738 : V8_WARN_UNUSED_RESULT MaybeHandle<Object> HandleApiCallHelper(
      49             :     Isolate* isolate, Handle<HeapObject> function,
      50             :     Handle<HeapObject> new_target, Handle<FunctionTemplateInfo> fun_data,
      51             :     Handle<Object> receiver, BuiltinArguments args) {
      52             :   Handle<JSReceiver> js_receiver;
      53             :   JSReceiver raw_holder;
      54             :   if (is_construct) {
      55             :     DCHECK(args.receiver()->IsTheHole(isolate));
      56      601327 :     if (fun_data->GetInstanceTemplate()->IsUndefined(isolate)) {
      57             :       v8::Local<ObjectTemplate> templ =
      58             :           ObjectTemplate::New(reinterpret_cast<v8::Isolate*>(isolate),
      59         351 :                               ToApiHandle<v8::FunctionTemplate>(fun_data));
      60         351 :       FunctionTemplateInfo::SetInstanceTemplate(isolate, fun_data,
      61             :                                                 Utils::OpenHandle(*templ));
      62             :     }
      63             :     Handle<ObjectTemplateInfo> instance_template(
      64      300665 :         ObjectTemplateInfo::cast(fun_data->GetInstanceTemplate()), isolate);
      65      601323 :     ASSIGN_RETURN_ON_EXCEPTION(
      66             :         isolate, js_receiver,
      67             :         ApiNatives::InstantiateObject(isolate, instance_template,
      68             :                                       Handle<JSReceiver>::cast(new_target)),
      69             :         Object);
      70             :     args.set_at(0, *js_receiver);
      71             :     DCHECK_EQ(*js_receiver, *args.receiver());
      72             : 
      73      300658 :     raw_holder = *js_receiver;
      74             :   } else {
      75             :     DCHECK(receiver->IsJSReceiver());
      76             :     js_receiver = Handle<JSReceiver>::cast(receiver);
      77             : 
      78     2381138 :     if (!fun_data->accept_any_receiver() &&
      79             :         js_receiver->IsAccessCheckNeeded()) {
      80             :       // Proxies never need access checks.
      81             :       DCHECK(js_receiver->IsJSObject());
      82          57 :       Handle<JSObject> js_obj_receiver = Handle<JSObject>::cast(js_receiver);
      83          57 :       if (!isolate->MayAccess(handle(isolate->context(), isolate),
      84             :                               js_obj_receiver)) {
      85           7 :         isolate->ReportFailedAccessCheck(js_obj_receiver);
      86           7 :         RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
      87           2 :         return isolate->factory()->undefined_value();
      88             :       }
      89             :     }
      90             : 
      91     2381069 :     raw_holder = GetCompatibleReceiver(isolate, *fun_data, *js_receiver);
      92             : 
      93     2381079 :     if (raw_holder.is_null()) {
      94             :       // This function cannot be called with the given receiver.  Abort!
      95        1084 :       THROW_NEW_ERROR(
      96             :           isolate, NewTypeError(MessageTemplate::kIllegalInvocation), Object);
      97             :     }
      98             :   }
      99             : 
     100             :   Object raw_call_data = fun_data->call_code();
     101     2681195 :   if (!raw_call_data->IsUndefined(isolate)) {
     102             :     DCHECK(raw_call_data->IsCallHandlerInfo());
     103             :     CallHandlerInfo call_data = CallHandlerInfo::cast(raw_call_data);
     104     2676186 :     Object data_obj = call_data->data();
     105             : 
     106             :     FunctionCallbackArguments custom(isolate, data_obj, *function, raw_holder,
     107             :                                      *new_target, args.address_of_arg_at(1),
     108     5352372 :                                      args.length() - 1);
     109     2676174 :     Handle<Object> result = custom.Call(call_data);
     110             : 
     111     2676183 :     RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
     112     2647305 :     if (result.is_null()) {
     113         721 :       if (is_construct) return js_receiver;
     114     1218653 :       return isolate->factory()->undefined_value();
     115             :     }
     116             :     // Rebox the result.
     117             :     result->VerifyApiCallResultType();
     118      275217 :     if (!is_construct || result->IsJSReceiver())
     119     1427654 :       return handle(*result, isolate);
     120             :   }
     121             : 
     122        5287 :   return js_receiver;
     123             : }
     124             : 
     125             : }  // anonymous namespace
     126             : 
     127    12852827 : BUILTIN(HandleApiCall) {
     128             :   HandleScope scope(isolate);
     129             :   Handle<JSFunction> function = args.target();
     130     2566558 :   Handle<Object> receiver = args.receiver();
     131             :   Handle<HeapObject> new_target = args.new_target();
     132             :   Handle<FunctionTemplateInfo> fun_data(function->shared()->get_api_func_data(),
     133             :                                         isolate);
     134     2566559 :   if (new_target->IsJSReceiver()) {
     135      619643 :     RETURN_RESULT_OR_FAILURE(
     136             :         isolate, HandleApiCallHelper<true>(isolate, function, new_target,
     137             :                                            fun_data, receiver, args));
     138             :   } else {
     139     4542472 :     RETURN_RESULT_OR_FAILURE(
     140             :         isolate, HandleApiCallHelper<false>(isolate, function, new_target,
     141             :                                             fun_data, receiver, args));
     142             :   }
     143             : }
     144             : 
     145             : namespace {
     146             : 
     147      230372 : class RelocatableArguments : public BuiltinArguments, public Relocatable {
     148             :  public:
     149             :   RelocatableArguments(Isolate* isolate, int length, Address* arguments)
     150      115185 :       : BuiltinArguments(length, arguments), Relocatable(isolate) {}
     151             : 
     152          66 :   inline void IterateInstance(RootVisitor* v) override {
     153          66 :     if (length() == 0) return;
     154             :     v->VisitRootPointers(Root::kRelocatable, nullptr, first_slot(),
     155         132 :                          last_slot() + 1);
     156             :   }
     157             : 
     158             :  private:
     159             :   DISALLOW_COPY_AND_ASSIGN(RelocatableArguments);
     160             : };
     161             : 
     162             : }  // namespace
     163             : 
     164      115395 : MaybeHandle<Object> Builtins::InvokeApiFunction(Isolate* isolate,
     165             :                                                 bool is_construct,
     166             :                                                 Handle<HeapObject> function,
     167             :                                                 Handle<Object> receiver,
     168             :                                                 int argc, Handle<Object> args[],
     169             :                                                 Handle<HeapObject> new_target) {
     170             :   RuntimeCallTimerScope timer(isolate,
     171      115395 :                               RuntimeCallCounterId::kInvokeApiFunction);
     172             :   DCHECK(function->IsFunctionTemplateInfo() ||
     173             :          (function->IsJSFunction() &&
     174             :           JSFunction::cast(*function)->shared()->IsApiFunction()));
     175             : 
     176             :   // Do proper receiver conversion for non-strict mode api functions.
     177      230018 :   if (!is_construct && !receiver->IsJSReceiver()) {
     178         228 :     if (function->IsFunctionTemplateInfo() ||
     179             :         is_sloppy(JSFunction::cast(*function)->shared()->language_mode())) {
     180         264 :       ASSIGN_RETURN_ON_EXCEPTION(isolate, receiver,
     181             :                                  Object::ConvertReceiver(isolate, receiver),
     182             :                                  Object);
     183             :     }
     184             :   }
     185             : 
     186      115395 :   if (function->IsFunctionTemplateInfo()) {
     187             :     Handle<FunctionTemplateInfo> info =
     188             :         Handle<FunctionTemplateInfo>::cast(function);
     189             :     // If we need to break at function entry, go the long way. Instantiate the
     190             :     // function, use the DebugBreakTrampoline, and call it through JS.
     191      102728 :     if (info->BreakAtEntry()) {
     192             :       DCHECK(!is_construct);
     193             :       DCHECK(new_target->IsUndefined(isolate));
     194             :       Handle<JSFunction> function;
     195         420 :       ASSIGN_RETURN_ON_EXCEPTION(isolate, function,
     196             :                                  ApiNatives::InstantiateFunction(
     197             :                                      info, MaybeHandle<v8::internal::Name>()),
     198             :                                  Object);
     199         210 :       Handle<Code> trampoline = BUILTIN_CODE(isolate, DebugBreakTrampoline);
     200         210 :       function->set_code(*trampoline);
     201         210 :       return Execution::Call(isolate, function, receiver, argc, args);
     202             :     }
     203             :   }
     204             : 
     205             :   Handle<FunctionTemplateInfo> fun_data =
     206             :       function->IsFunctionTemplateInfo()
     207             :           ? Handle<FunctionTemplateInfo>::cast(function)
     208             :           : handle(JSFunction::cast(*function)->shared()->get_api_func_data(),
     209      127854 :                    isolate);
     210             :   // Construct BuiltinArguments object:
     211             :   // new target, function, arguments reversed, receiver.
     212             :   const int kBufferSize = 32;
     213             :   Address small_argv[kBufferSize];
     214             :   Address* argv;
     215      115187 :   const int frame_argc = argc + BuiltinArguments::kNumExtraArgsWithReceiver;
     216      115187 :   if (frame_argc <= kBufferSize) {
     217             :     argv = small_argv;
     218             :   } else {
     219           0 :     argv = new Address[frame_argc];
     220             :   }
     221      115185 :   int cursor = frame_argc - 1;
     222      230370 :   argv[cursor--] = receiver->ptr();
     223      117379 :   for (int i = 0; i < argc; ++i) {
     224        2194 :     argv[cursor--] = args[i]->ptr();
     225             :   }
     226             :   DCHECK_EQ(cursor, BuiltinArguments::kPaddingOffset);
     227             :   argv[BuiltinArguments::kPaddingOffset] =
     228      115185 :       ReadOnlyRoots(isolate).the_hole_value()->ptr();
     229      115185 :   argv[BuiltinArguments::kArgcOffset] = Smi::FromInt(frame_argc)->ptr();
     230      115185 :   argv[BuiltinArguments::kTargetOffset] = function->ptr();
     231      115185 :   argv[BuiltinArguments::kNewTargetOffset] = new_target->ptr();
     232             :   MaybeHandle<Object> result;
     233             :   {
     234      115185 :     RelocatableArguments arguments(isolate, frame_argc, &argv[frame_argc - 1]);
     235      115185 :     if (is_construct) {
     236             :       result = HandleApiCallHelper<true>(isolate, function, new_target,
     237         773 :                                          fun_data, receiver, arguments);
     238             :     } else {
     239             :       result = HandleApiCallHelper<false>(isolate, function, new_target,
     240      114412 :                                           fun_data, receiver, arguments);
     241             :     }
     242             :   }
     243      115186 :   if (argv != small_argv) delete[] argv;
     244      115186 :   return result;
     245             : }
     246             : 
     247             : // Helper function to handle calls to non-function objects created through the
     248             : // API. The object can be called as either a constructor (using new) or just as
     249             : // a function (without new).
     250         232 : V8_WARN_UNUSED_RESULT static Object HandleApiCallAsFunctionOrConstructor(
     251             :     Isolate* isolate, bool is_construct_call, BuiltinArguments args) {
     252             :   Handle<Object> receiver = args.receiver();
     253             : 
     254             :   // Get the object called.
     255             :   JSObject obj = JSObject::cast(*receiver);
     256             : 
     257             :   // Set the new target.
     258             :   HeapObject new_target;
     259         232 :   if (is_construct_call) {
     260             :     // TODO(adamk): This should be passed through in args instead of
     261             :     // being patched in here. We need to set a non-undefined value
     262             :     // for v8::FunctionCallbackInfo::IsConstructCall() to get the
     263             :     // right answer.
     264          18 :     new_target = obj;
     265             :   } else {
     266         214 :     new_target = ReadOnlyRoots(isolate).undefined_value();
     267             :   }
     268             : 
     269             :   // Get the invocation callback from the function descriptor that was
     270             :   // used to create the called object.
     271             :   DCHECK(obj->map()->is_callable());
     272         232 :   JSFunction constructor = JSFunction::cast(obj->map()->GetConstructor());
     273             :   DCHECK(constructor->shared()->IsApiFunction());
     274             :   Object handler =
     275         232 :       constructor->shared()->get_api_func_data()->GetInstanceCallHandler();
     276             :   DCHECK(!handler->IsUndefined(isolate));
     277             :   CallHandlerInfo call_data = CallHandlerInfo::cast(handler);
     278             : 
     279             :   // Get the data for the call and perform the callback.
     280             :   Object result;
     281             :   {
     282             :     HandleScope scope(isolate);
     283         232 :     LOG(isolate, ApiObjectAccess("call non-function", obj));
     284             :     FunctionCallbackArguments custom(isolate, call_data->data(), constructor,
     285             :                                      obj, new_target, args.address_of_arg_at(1),
     286         464 :                                      args.length() - 1);
     287         232 :     Handle<Object> result_handle = custom.Call(call_data);
     288         232 :     if (result_handle.is_null()) {
     289             :       result = ReadOnlyRoots(isolate).undefined_value();
     290             :     } else {
     291             :       result = *result_handle;
     292             :     }
     293             :   }
     294             :   // Check for exceptions and return result.
     295         232 :   RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
     296         220 :   return result;
     297             : }
     298             : 
     299             : // Handle calls to non-function objects created through the API. This delegate
     300             : // function is used when the call is a normal function call.
     301         428 : BUILTIN(HandleApiCallAsFunction) {
     302         214 :   return HandleApiCallAsFunctionOrConstructor(isolate, false, args);
     303             : }
     304             : 
     305             : // Handle calls to non-function objects created through the API. This delegate
     306             : // function is used when the call is a construct call.
     307          36 : BUILTIN(HandleApiCallAsConstructor) {
     308          18 :   return HandleApiCallAsFunctionOrConstructor(isolate, true, args);
     309             : }
     310             : 
     311             : }  // namespace internal
     312      120216 : }  // namespace v8

Generated by: LCOV version 1.10