LCOV - code coverage report
Current view: top level - src/builtins - builtins-function.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 82 82 100.0 %
Date: 2019-04-17 Functions: 14 20 70.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/builtins/builtins-utils-inl.h"
       6             : #include "src/builtins/builtins.h"
       7             : #include "src/code-factory.h"
       8             : #include "src/compiler.h"
       9             : #include "src/conversions.h"
      10             : #include "src/counters.h"
      11             : #include "src/lookup.h"
      12             : #include "src/objects-inl.h"
      13             : #include "src/objects/api-callbacks.h"
      14             : #include "src/string-builder-inl.h"
      15             : 
      16             : namespace v8 {
      17             : namespace internal {
      18             : 
      19             : namespace {
      20             : 
      21             : // ES6 section 19.2.1.1.1 CreateDynamicFunction
      22     1089076 : MaybeHandle<Object> CreateDynamicFunction(Isolate* isolate,
      23             :                                           BuiltinArguments args,
      24             :                                           const char* token) {
      25             :   // Compute number of arguments, ignoring the receiver.
      26             :   DCHECK_LE(1, args.length());
      27     1089076 :   int const argc = args.length() - 1;
      28             : 
      29             :   Handle<JSFunction> target = args.target();
      30             :   Handle<JSObject> target_global_proxy(target->global_proxy(), isolate);
      31             : 
      32     1089076 :   if (!Builtins::AllowDynamicFunction(isolate, target, target_global_proxy)) {
      33         180 :     isolate->CountUsage(v8::Isolate::kFunctionConstructorReturnedUndefined);
      34         180 :     return isolate->factory()->undefined_value();
      35             :   }
      36             : 
      37             :   // Build the source string.
      38             :   Handle<String> source;
      39             :   int parameters_end_pos = kNoSourcePosition;
      40             :   {
      41     1088896 :     IncrementalStringBuilder builder(isolate);
      42             :     builder.AppendCharacter('(');
      43             :     builder.AppendCString(token);
      44             :     builder.AppendCString(" anonymous(");
      45             :     bool parenthesis_in_arg_string = false;
      46     1088896 :     if (argc > 1) {
      47     3065950 :       for (int i = 1; i < argc; ++i) {
      48     1022740 :         if (i > 1) builder.AppendCharacter(',');
      49             :         Handle<String> param;
      50     2045480 :         ASSIGN_RETURN_ON_EXCEPTION(
      51             :             isolate, param, Object::ToString(isolate, args.at(i)), Object);
      52     1022740 :         param = String::Flatten(isolate, param);
      53     1022740 :         builder.AppendString(param);
      54             :       }
      55             :     }
      56             :     builder.AppendCharacter('\n');
      57     1088896 :     parameters_end_pos = builder.Length();
      58             :     builder.AppendCString(") {\n");
      59     1088896 :     if (argc > 0) {
      60             :       Handle<String> body;
      61     2169660 :       ASSIGN_RETURN_ON_EXCEPTION(
      62             :           isolate, body, Object::ToString(isolate, args.at(argc)), Object);
      63     1084830 :       builder.AppendString(body);
      64             :     }
      65             :     builder.AppendCString("\n})");
      66     2177792 :     ASSIGN_RETURN_ON_EXCEPTION(isolate, source, builder.Finish(), Object);
      67             : 
      68             :     // The SyntaxError must be thrown after all the (observable) ToString
      69             :     // conversions are done.
      70             :     if (parenthesis_in_arg_string) {
      71             :       THROW_NEW_ERROR(isolate,
      72             :                       NewSyntaxError(MessageTemplate::kParenthesisInArgString),
      73             :                       Object);
      74             :     }
      75             :   }
      76             : 
      77             :   // Compile the string in the constructor and not a helper so that errors to
      78             :   // come from here.
      79             :   Handle<JSFunction> function;
      80             :   {
      81     2177792 :     ASSIGN_RETURN_ON_EXCEPTION(
      82             :         isolate, function,
      83             :         Compiler::GetFunctionFromString(
      84             :             handle(target->native_context(), isolate), source,
      85             :             ONLY_SINGLE_FUNCTION_LITERAL, parameters_end_pos),
      86             :         Object);
      87             :     Handle<Object> result;
      88     2174290 :     ASSIGN_RETURN_ON_EXCEPTION(
      89             :         isolate, result,
      90             :         Execution::Call(isolate, function, target_global_proxy, 0, nullptr),
      91             :         Object);
      92             :     function = Handle<JSFunction>::cast(result);
      93     1085281 :     function->shared()->set_name_should_print_as_anonymous(true);
      94             :   }
      95             : 
      96             :   // If new.target is equal to target then the function created
      97             :   // is already correctly setup and nothing else should be done
      98             :   // here. But if new.target is not equal to target then we are
      99             :   // have a Function builtin subclassing case and therefore the
     100             :   // function has wrong initial map. To fix that we create a new
     101             :   // function object with correct initial map.
     102             :   Handle<Object> unchecked_new_target = args.new_target();
     103     1210416 :   if (!unchecked_new_target->IsUndefined(isolate) &&
     104             :       !unchecked_new_target.is_identical_to(target)) {
     105             :     Handle<JSReceiver> new_target =
     106         671 :         Handle<JSReceiver>::cast(unchecked_new_target);
     107             :     Handle<Map> initial_map;
     108        1342 :     ASSIGN_RETURN_ON_EXCEPTION(
     109             :         isolate, initial_map,
     110             :         JSFunction::GetDerivedMap(isolate, target, new_target), Object);
     111             : 
     112             :     Handle<SharedFunctionInfo> shared_info(function->shared(), isolate);
     113         671 :     Handle<Map> map = Map::AsLanguageMode(isolate, initial_map, shared_info);
     114             : 
     115             :     Handle<Context> context(function->context(), isolate);
     116             :     function = isolate->factory()->NewFunctionFromSharedFunctionInfo(
     117         671 :         map, shared_info, context, AllocationType::kYoung);
     118             :   }
     119     1085281 :   return function;
     120             : }
     121             : 
     122             : }  // namespace
     123             : 
     124             : // ES6 section 19.2.1.1 Function ( p1, p2, ... , pn, body )
     125     5426770 : BUILTIN(FunctionConstructor) {
     126             :   HandleScope scope(isolate);
     127             :   Handle<Object> result;
     128     2172293 :   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
     129             :       isolate, result, CreateDynamicFunction(isolate, args, "function"));
     130             :   return *result;
     131             : }
     132             : 
     133             : // ES6 section 25.2.1.1 GeneratorFunction (p1, p2, ... , pn, body)
     134        7485 : BUILTIN(GeneratorFunctionConstructor) {
     135             :   HandleScope scope(isolate);
     136        3996 :   RETURN_RESULT_OR_FAILURE(isolate,
     137             :                            CreateDynamicFunction(isolate, args, "function*"));
     138             : }
     139             : 
     140        7255 : BUILTIN(AsyncFunctionConstructor) {
     141             :   HandleScope scope(isolate);
     142             :   Handle<Object> maybe_func;
     143        3930 :   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
     144             :       isolate, maybe_func,
     145             :       CreateDynamicFunction(isolate, args, "async function"));
     146         423 :   if (!maybe_func->IsJSFunction()) return *maybe_func;
     147             : 
     148             :   // Do not lazily compute eval position for AsyncFunction, as they may not be
     149             :   // determined after the function is resumed.
     150             :   Handle<JSFunction> func = Handle<JSFunction>::cast(maybe_func);
     151             :   Handle<Script> script =
     152         846 :       handle(Script::cast(func->shared()->script()), isolate);
     153         423 :   int position = Script::GetEvalPosition(isolate, script);
     154             :   USE(position);
     155             : 
     156         423 :   return *func;
     157             : }
     158             : 
     159        3870 : BUILTIN(AsyncGeneratorFunctionConstructor) {
     160             :   HandleScope scope(isolate);
     161             :   Handle<Object> maybe_func;
     162        1548 :   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
     163             :       isolate, maybe_func,
     164             :       CreateDynamicFunction(isolate, args, "async function*"));
     165         774 :   if (!maybe_func->IsJSFunction()) return *maybe_func;
     166             : 
     167             :   // Do not lazily compute eval position for AsyncFunction, as they may not be
     168             :   // determined after the function is resumed.
     169             :   Handle<JSFunction> func = Handle<JSFunction>::cast(maybe_func);
     170             :   Handle<Script> script =
     171        1548 :       handle(Script::cast(func->shared()->script()), isolate);
     172         774 :   int position = Script::GetEvalPosition(isolate, script);
     173             :   USE(position);
     174             : 
     175         774 :   return *func;
     176             : }
     177             : 
     178             : namespace {
     179             : 
     180         555 : Object DoFunctionBind(Isolate* isolate, BuiltinArguments args) {
     181             :   HandleScope scope(isolate);
     182             :   DCHECK_LE(1, args.length());
     183         555 :   if (!args.receiver()->IsCallable()) {
     184          54 :     THROW_NEW_ERROR_RETURN_FAILURE(
     185             :         isolate, NewTypeError(MessageTemplate::kFunctionBind));
     186             :   }
     187             : 
     188             :   // Allocate the bound function with the given {this_arg} and {args}.
     189             :   Handle<JSReceiver> target = args.at<JSReceiver>(0);
     190             :   Handle<Object> this_arg = isolate->factory()->undefined_value();
     191        1584 :   ScopedVector<Handle<Object>> argv(std::max(0, args.length() - 2));
     192         528 :   if (args.length() > 1) {
     193         348 :     this_arg = args.at(1);
     194        1086 :     for (int i = 2; i < args.length(); ++i) {
     195         738 :       argv[i - 2] = args.at(i);
     196             :     }
     197             :   }
     198             :   Handle<JSBoundFunction> function;
     199        1056 :   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
     200             :       isolate, function,
     201             :       isolate->factory()->NewJSBoundFunction(target, this_arg, argv));
     202             : 
     203             :   LookupIterator length_lookup(target, isolate->factory()->length_string(),
     204             :                                target, LookupIterator::OWN);
     205             :   // Setup the "length" property based on the "length" of the {target}.
     206             :   // If the targets length is the default JSFunction accessor, we can keep the
     207             :   // accessor that's installed by default on the JSBoundFunction. It lazily
     208             :   // computes the value from the underlying internal length.
     209         885 :   if (!target->IsJSFunction() ||
     210         876 :       length_lookup.state() != LookupIterator::ACCESSOR ||
     211         348 :       !length_lookup.GetAccessors()->IsAccessorInfo()) {
     212             :     Handle<Object> length(Smi::kZero, isolate);
     213             :     Maybe<PropertyAttributes> attributes =
     214         180 :         JSReceiver::GetPropertyAttributes(&length_lookup);
     215         180 :     if (attributes.IsNothing()) return ReadOnlyRoots(isolate).exception();
     216         180 :     if (attributes.FromJust() != ABSENT) {
     217             :       Handle<Object> target_length;
     218         342 :       ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, target_length,
     219             :                                          Object::GetProperty(&length_lookup));
     220         171 :       if (target_length->IsNumber()) {
     221             :         length = isolate->factory()->NewNumber(std::max(
     222         324 :             0.0, DoubleToInteger(target_length->Number()) - argv.length()));
     223             :       }
     224             :     }
     225             :     LookupIterator it(function, isolate->factory()->length_string(), function);
     226             :     DCHECK_EQ(LookupIterator::ACCESSOR, it.state());
     227         360 :     RETURN_FAILURE_ON_EXCEPTION(isolate,
     228             :                                 JSObject::DefineOwnPropertyIgnoreAttributes(
     229             :                                     &it, length, it.property_attributes()));
     230             :   }
     231             : 
     232             :   // Setup the "name" property based on the "name" of the {target}.
     233             :   // If the target's name is the default JSFunction accessor, we can keep the
     234             :   // accessor that's installed by default on the JSBoundFunction. It lazily
     235             :   // computes the value from the underlying internal name.
     236             :   LookupIterator name_lookup(target, isolate->factory()->name_string(), target);
     237         885 :   if (!target->IsJSFunction() ||
     238         348 :       name_lookup.state() != LookupIterator::ACCESSOR ||
     239        1215 :       !name_lookup.GetAccessors()->IsAccessorInfo() ||
     240         339 :       (name_lookup.IsFound() && !name_lookup.HolderIsReceiver())) {
     241             :     Handle<Object> target_name;
     242         450 :     ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, target_name,
     243             :                                        Object::GetProperty(&name_lookup));
     244             :     Handle<String> name;
     245         225 :     if (target_name->IsString()) {
     246         342 :       ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
     247             :           isolate, name,
     248             :           Name::ToFunctionName(isolate, Handle<String>::cast(target_name)));
     249         342 :       ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
     250             :           isolate, name, isolate->factory()->NewConsString(
     251             :                              isolate->factory()->bound__string(), name));
     252             :     } else {
     253             :       name = isolate->factory()->bound__string();
     254             :     }
     255         225 :     LookupIterator it(isolate, function, isolate->factory()->name_string());
     256             :     DCHECK_EQ(LookupIterator::ACCESSOR, it.state());
     257         450 :     RETURN_FAILURE_ON_EXCEPTION(isolate,
     258             :                                 JSObject::DefineOwnPropertyIgnoreAttributes(
     259             :                                     &it, name, it.property_attributes()));
     260             :   }
     261         528 :   return *function;
     262             : }
     263             : 
     264             : }  // namespace
     265             : 
     266             : // ES6 section 19.2.3.2 Function.prototype.bind ( thisArg, ...args )
     267        1665 : BUILTIN(FunctionPrototypeBind) { return DoFunctionBind(isolate, args); }
     268             : 
     269             : // ES6 section 19.2.3.5 Function.prototype.toString ( )
     270     9459525 : BUILTIN(FunctionPrototypeToString) {
     271             :   HandleScope scope(isolate);
     272             :   Handle<Object> receiver = args.receiver();
     273     1891905 :   if (receiver->IsJSBoundFunction()) {
     274         120 :     return *JSBoundFunction::ToString(Handle<JSBoundFunction>::cast(receiver));
     275             :   }
     276     1891845 :   if (receiver->IsJSFunction()) {
     277     3783168 :     return *JSFunction::ToString(Handle<JSFunction>::cast(receiver));
     278             :   }
     279             :   // With the revised toString behavior, all callable objects are valid
     280             :   // receivers for this method.
     281         351 :   if (receiver->IsJSReceiver() &&
     282             :       JSReceiver::cast(*receiver)->map()->is_callable()) {
     283          81 :     return ReadOnlyRoots(isolate).function_native_code_string();
     284             :   }
     285         540 :   THROW_NEW_ERROR_RETURN_FAILURE(
     286             :       isolate, NewTypeError(MessageTemplate::kNotGeneric,
     287             :                             isolate->factory()->NewStringFromAsciiChecked(
     288             :                                 "Function.prototype.toString"),
     289             :                             isolate->factory()->Function_string()));
     290             : }
     291             : 
     292             : }  // namespace internal
     293      121996 : }  // namespace v8

Generated by: LCOV version 1.10