| OLD | NEW | 
|---|
| (Empty) |  | 
|  | 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 #include "src/builtins/builtins-utils.h" | 
|  | 7 | 
|  | 8 #include "src/string-builder.h" | 
|  | 9 | 
|  | 10 namespace v8 { | 
|  | 11 namespace internal { | 
|  | 12 | 
|  | 13 namespace { | 
|  | 14 | 
|  | 15 bool AllowDynamicFunction(Isolate* isolate, Handle<JSFunction> target, | 
|  | 16                           Handle<JSObject> target_global_proxy) { | 
|  | 17   if (FLAG_allow_unsafe_function_constructor) return true; | 
|  | 18   HandleScopeImplementer* impl = isolate->handle_scope_implementer(); | 
|  | 19   Handle<Context> responsible_context = impl->LastEnteredContext(); | 
|  | 20   if (responsible_context.is_null()) { | 
|  | 21     responsible_context = impl->MicrotaskContext(); | 
|  | 22     // TODO(jochen): Remove this. | 
|  | 23     if (responsible_context.is_null()) { | 
|  | 24       return true; | 
|  | 25     } | 
|  | 26   } | 
|  | 27   if (*responsible_context == target->context()) return true; | 
|  | 28   return isolate->MayAccess(responsible_context, target_global_proxy); | 
|  | 29 } | 
|  | 30 | 
|  | 31 // ES6 section 19.2.1.1.1 CreateDynamicFunction | 
|  | 32 MaybeHandle<Object> CreateDynamicFunction(Isolate* isolate, | 
|  | 33                                           BuiltinArguments args, | 
|  | 34                                           const char* token) { | 
|  | 35   // Compute number of arguments, ignoring the receiver. | 
|  | 36   DCHECK_LE(1, args.length()); | 
|  | 37   int const argc = args.length() - 1; | 
|  | 38 | 
|  | 39   Handle<JSFunction> target = args.target<JSFunction>(); | 
|  | 40   Handle<JSObject> target_global_proxy(target->global_proxy(), isolate); | 
|  | 41 | 
|  | 42   if (!AllowDynamicFunction(isolate, target, target_global_proxy)) { | 
|  | 43     isolate->CountUsage(v8::Isolate::kFunctionConstructorReturnedUndefined); | 
|  | 44     return isolate->factory()->undefined_value(); | 
|  | 45   } | 
|  | 46 | 
|  | 47   // Build the source string. | 
|  | 48   Handle<String> source; | 
|  | 49   { | 
|  | 50     IncrementalStringBuilder builder(isolate); | 
|  | 51     builder.AppendCharacter('('); | 
|  | 52     builder.AppendCString(token); | 
|  | 53     builder.AppendCharacter('('); | 
|  | 54     bool parenthesis_in_arg_string = false; | 
|  | 55     if (argc > 1) { | 
|  | 56       for (int i = 1; i < argc; ++i) { | 
|  | 57         if (i > 1) builder.AppendCharacter(','); | 
|  | 58         Handle<String> param; | 
|  | 59         ASSIGN_RETURN_ON_EXCEPTION( | 
|  | 60             isolate, param, Object::ToString(isolate, args.at<Object>(i)), | 
|  | 61             Object); | 
|  | 62         param = String::Flatten(param); | 
|  | 63         builder.AppendString(param); | 
|  | 64         // If the formal parameters string include ) - an illegal | 
|  | 65         // character - it may make the combined function expression | 
|  | 66         // compile. We avoid this problem by checking for this early on. | 
|  | 67         DisallowHeapAllocation no_gc;  // Ensure vectors stay valid. | 
|  | 68         String::FlatContent param_content = param->GetFlatContent(); | 
|  | 69         for (int i = 0, length = param->length(); i < length; ++i) { | 
|  | 70           if (param_content.Get(i) == ')') { | 
|  | 71             parenthesis_in_arg_string = true; | 
|  | 72             break; | 
|  | 73           } | 
|  | 74         } | 
|  | 75       } | 
|  | 76       // If the formal parameters include an unbalanced block comment, the | 
|  | 77       // function must be rejected. Since JavaScript does not allow nested | 
|  | 78       // comments we can include a trailing block comment to catch this. | 
|  | 79       builder.AppendCString("\n/**/"); | 
|  | 80     } | 
|  | 81     builder.AppendCString(") {\n"); | 
|  | 82     if (argc > 0) { | 
|  | 83       Handle<String> body; | 
|  | 84       ASSIGN_RETURN_ON_EXCEPTION( | 
|  | 85           isolate, body, Object::ToString(isolate, args.at<Object>(argc)), | 
|  | 86           Object); | 
|  | 87       builder.AppendString(body); | 
|  | 88     } | 
|  | 89     builder.AppendCString("\n})"); | 
|  | 90     ASSIGN_RETURN_ON_EXCEPTION(isolate, source, builder.Finish(), Object); | 
|  | 91 | 
|  | 92     // The SyntaxError must be thrown after all the (observable) ToString | 
|  | 93     // conversions are done. | 
|  | 94     if (parenthesis_in_arg_string) { | 
|  | 95       THROW_NEW_ERROR(isolate, | 
|  | 96                       NewSyntaxError(MessageTemplate::kParenthesisInArgString), | 
|  | 97                       Object); | 
|  | 98     } | 
|  | 99   } | 
|  | 100 | 
|  | 101   // Compile the string in the constructor and not a helper so that errors to | 
|  | 102   // come from here. | 
|  | 103   Handle<JSFunction> function; | 
|  | 104   { | 
|  | 105     ASSIGN_RETURN_ON_EXCEPTION( | 
|  | 106         isolate, function, | 
|  | 107         Builtins::CompileString(handle(target->native_context(), isolate), | 
|  | 108                                 source, ONLY_SINGLE_FUNCTION_LITERAL), | 
|  | 109         Object); | 
|  | 110     Handle<Object> result; | 
|  | 111     ASSIGN_RETURN_ON_EXCEPTION( | 
|  | 112         isolate, result, | 
|  | 113         Execution::Call(isolate, function, target_global_proxy, 0, nullptr), | 
|  | 114         Object); | 
|  | 115     function = Handle<JSFunction>::cast(result); | 
|  | 116     function->shared()->set_name_should_print_as_anonymous(true); | 
|  | 117   } | 
|  | 118 | 
|  | 119   // If new.target is equal to target then the function created | 
|  | 120   // is already correctly setup and nothing else should be done | 
|  | 121   // here. But if new.target is not equal to target then we are | 
|  | 122   // have a Function builtin subclassing case and therefore the | 
|  | 123   // function has wrong initial map. To fix that we create a new | 
|  | 124   // function object with correct initial map. | 
|  | 125   Handle<Object> unchecked_new_target = args.new_target(); | 
|  | 126   if (!unchecked_new_target->IsUndefined(isolate) && | 
|  | 127       !unchecked_new_target.is_identical_to(target)) { | 
|  | 128     Handle<JSReceiver> new_target = | 
|  | 129         Handle<JSReceiver>::cast(unchecked_new_target); | 
|  | 130     Handle<Map> initial_map; | 
|  | 131     ASSIGN_RETURN_ON_EXCEPTION( | 
|  | 132         isolate, initial_map, | 
|  | 133         JSFunction::GetDerivedMap(isolate, target, new_target), Object); | 
|  | 134 | 
|  | 135     Handle<SharedFunctionInfo> shared_info(function->shared(), isolate); | 
|  | 136     Handle<Map> map = Map::AsLanguageMode( | 
|  | 137         initial_map, shared_info->language_mode(), shared_info->kind()); | 
|  | 138 | 
|  | 139     Handle<Context> context(function->context(), isolate); | 
|  | 140     function = isolate->factory()->NewFunctionFromSharedFunctionInfo( | 
|  | 141         map, shared_info, context, NOT_TENURED); | 
|  | 142   } | 
|  | 143   return function; | 
|  | 144 } | 
|  | 145 | 
|  | 146 }  // namespace | 
|  | 147 | 
|  | 148 // ES6 section 19.2.1.1 Function ( p1, p2, ... , pn, body ) | 
|  | 149 BUILTIN(FunctionConstructor) { | 
|  | 150   HandleScope scope(isolate); | 
|  | 151   Handle<Object> result; | 
|  | 152   ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | 
|  | 153       isolate, result, CreateDynamicFunction(isolate, args, "function")); | 
|  | 154   return *result; | 
|  | 155 } | 
|  | 156 | 
|  | 157 // ES6 section 25.2.1.1 GeneratorFunction (p1, p2, ... , pn, body) | 
|  | 158 BUILTIN(GeneratorFunctionConstructor) { | 
|  | 159   HandleScope scope(isolate); | 
|  | 160   RETURN_RESULT_OR_FAILURE(isolate, | 
|  | 161                            CreateDynamicFunction(isolate, args, "function*")); | 
|  | 162 } | 
|  | 163 | 
|  | 164 BUILTIN(AsyncFunctionConstructor) { | 
|  | 165   HandleScope scope(isolate); | 
|  | 166   Handle<Object> maybe_func; | 
|  | 167   ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | 
|  | 168       isolate, maybe_func, | 
|  | 169       CreateDynamicFunction(isolate, args, "async function")); | 
|  | 170   if (!maybe_func->IsJSFunction()) return *maybe_func; | 
|  | 171 | 
|  | 172   // Do not lazily compute eval position for AsyncFunction, as they may not be | 
|  | 173   // determined after the function is resumed. | 
|  | 174   Handle<JSFunction> func = Handle<JSFunction>::cast(maybe_func); | 
|  | 175   Handle<Script> script = handle(Script::cast(func->shared()->script())); | 
|  | 176   int position = script->GetEvalPosition(); | 
|  | 177   USE(position); | 
|  | 178 | 
|  | 179   return *func; | 
|  | 180 } | 
|  | 181 | 
|  | 182 namespace { | 
|  | 183 | 
|  | 184 Object* DoFunctionBind(Isolate* isolate, BuiltinArguments args) { | 
|  | 185   HandleScope scope(isolate); | 
|  | 186   DCHECK_LE(1, args.length()); | 
|  | 187   if (!args.receiver()->IsCallable()) { | 
|  | 188     THROW_NEW_ERROR_RETURN_FAILURE( | 
|  | 189         isolate, NewTypeError(MessageTemplate::kFunctionBind)); | 
|  | 190   } | 
|  | 191 | 
|  | 192   // Allocate the bound function with the given {this_arg} and {args}. | 
|  | 193   Handle<JSReceiver> target = args.at<JSReceiver>(0); | 
|  | 194   Handle<Object> this_arg = isolate->factory()->undefined_value(); | 
|  | 195   ScopedVector<Handle<Object>> argv(std::max(0, args.length() - 2)); | 
|  | 196   if (args.length() > 1) { | 
|  | 197     this_arg = args.at<Object>(1); | 
|  | 198     for (int i = 2; i < args.length(); ++i) { | 
|  | 199       argv[i - 2] = args.at<Object>(i); | 
|  | 200     } | 
|  | 201   } | 
|  | 202   Handle<JSBoundFunction> function; | 
|  | 203   ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | 
|  | 204       isolate, function, | 
|  | 205       isolate->factory()->NewJSBoundFunction(target, this_arg, argv)); | 
|  | 206 | 
|  | 207   LookupIterator length_lookup(target, isolate->factory()->length_string(), | 
|  | 208                                target, LookupIterator::OWN); | 
|  | 209   // Setup the "length" property based on the "length" of the {target}. | 
|  | 210   // If the targets length is the default JSFunction accessor, we can keep the | 
|  | 211   // accessor that's installed by default on the JSBoundFunction. It lazily | 
|  | 212   // computes the value from the underlying internal length. | 
|  | 213   if (!target->IsJSFunction() || | 
|  | 214       length_lookup.state() != LookupIterator::ACCESSOR || | 
|  | 215       !length_lookup.GetAccessors()->IsAccessorInfo()) { | 
|  | 216     Handle<Object> length(Smi::FromInt(0), isolate); | 
|  | 217     Maybe<PropertyAttributes> attributes = | 
|  | 218         JSReceiver::GetPropertyAttributes(&length_lookup); | 
|  | 219     if (!attributes.IsJust()) return isolate->heap()->exception(); | 
|  | 220     if (attributes.FromJust() != ABSENT) { | 
|  | 221       Handle<Object> target_length; | 
|  | 222       ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, target_length, | 
|  | 223                                          Object::GetProperty(&length_lookup)); | 
|  | 224       if (target_length->IsNumber()) { | 
|  | 225         length = isolate->factory()->NewNumber(std::max( | 
|  | 226             0.0, DoubleToInteger(target_length->Number()) - argv.length())); | 
|  | 227       } | 
|  | 228     } | 
|  | 229     LookupIterator it(function, isolate->factory()->length_string(), function); | 
|  | 230     DCHECK_EQ(LookupIterator::ACCESSOR, it.state()); | 
|  | 231     RETURN_FAILURE_ON_EXCEPTION(isolate, | 
|  | 232                                 JSObject::DefineOwnPropertyIgnoreAttributes( | 
|  | 233                                     &it, length, it.property_attributes())); | 
|  | 234   } | 
|  | 235 | 
|  | 236   // Setup the "name" property based on the "name" of the {target}. | 
|  | 237   // If the targets name is the default JSFunction accessor, we can keep the | 
|  | 238   // accessor that's installed by default on the JSBoundFunction. It lazily | 
|  | 239   // computes the value from the underlying internal name. | 
|  | 240   LookupIterator name_lookup(target, isolate->factory()->name_string(), target, | 
|  | 241                              LookupIterator::OWN); | 
|  | 242   if (!target->IsJSFunction() || | 
|  | 243       name_lookup.state() != LookupIterator::ACCESSOR || | 
|  | 244       !name_lookup.GetAccessors()->IsAccessorInfo()) { | 
|  | 245     Handle<Object> target_name; | 
|  | 246     ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, target_name, | 
|  | 247                                        Object::GetProperty(&name_lookup)); | 
|  | 248     Handle<String> name; | 
|  | 249     if (target_name->IsString()) { | 
|  | 250       ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | 
|  | 251           isolate, name, | 
|  | 252           Name::ToFunctionName(Handle<String>::cast(target_name))); | 
|  | 253       ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | 
|  | 254           isolate, name, isolate->factory()->NewConsString( | 
|  | 255                              isolate->factory()->bound__string(), name)); | 
|  | 256     } else { | 
|  | 257       name = isolate->factory()->bound__string(); | 
|  | 258     } | 
|  | 259     LookupIterator it(function, isolate->factory()->name_string()); | 
|  | 260     DCHECK_EQ(LookupIterator::ACCESSOR, it.state()); | 
|  | 261     RETURN_FAILURE_ON_EXCEPTION(isolate, | 
|  | 262                                 JSObject::DefineOwnPropertyIgnoreAttributes( | 
|  | 263                                     &it, name, it.property_attributes())); | 
|  | 264   } | 
|  | 265   return *function; | 
|  | 266 } | 
|  | 267 | 
|  | 268 }  // namespace | 
|  | 269 | 
|  | 270 // ES6 section 19.2.3.2 Function.prototype.bind ( thisArg, ...args ) | 
|  | 271 BUILTIN(FunctionPrototypeBind) { return DoFunctionBind(isolate, args); } | 
|  | 272 | 
|  | 273 // TODO(verwaest): This is a temporary helper until the FastFunctionBind stub | 
|  | 274 // can tailcall to the builtin directly. | 
|  | 275 RUNTIME_FUNCTION(Runtime_FunctionBind) { | 
|  | 276   DCHECK_EQ(2, args.length()); | 
|  | 277   Arguments* incoming = reinterpret_cast<Arguments*>(args[0]); | 
|  | 278   // Rewrap the arguments as builtins arguments. | 
|  | 279   int argc = incoming->length() + BuiltinArguments::kNumExtraArgsWithReceiver; | 
|  | 280   BuiltinArguments caller_args(argc, incoming->arguments() + 1); | 
|  | 281   return DoFunctionBind(isolate, caller_args); | 
|  | 282 } | 
|  | 283 | 
|  | 284 // ES6 section 19.2.3.5 Function.prototype.toString ( ) | 
|  | 285 BUILTIN(FunctionPrototypeToString) { | 
|  | 286   HandleScope scope(isolate); | 
|  | 287   Handle<Object> receiver = args.receiver(); | 
|  | 288   if (receiver->IsJSBoundFunction()) { | 
|  | 289     return *JSBoundFunction::ToString(Handle<JSBoundFunction>::cast(receiver)); | 
|  | 290   } else if (receiver->IsJSFunction()) { | 
|  | 291     return *JSFunction::ToString(Handle<JSFunction>::cast(receiver)); | 
|  | 292   } | 
|  | 293   THROW_NEW_ERROR_RETURN_FAILURE( | 
|  | 294       isolate, NewTypeError(MessageTemplate::kNotGeneric, | 
|  | 295                             isolate->factory()->NewStringFromAsciiChecked( | 
|  | 296                                 "Function.prototype.toString"))); | 
|  | 297 } | 
|  | 298 | 
|  | 299 }  // namespace internal | 
|  | 300 }  // namespace v8 | 
| OLD | NEW | 
|---|