v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
builtins-function.cc
Go to the documentation of this file.
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/api-inl.h"
13#include "src/objects/lookup.h"
16
17namespace v8 {
18namespace internal {
19
20namespace {
21
22// ES6 section 19.2.1.1.1 CreateDynamicFunction
23MaybeDirectHandle<Object> CreateDynamicFunction(Isolate* isolate,
24 BuiltinArguments args,
25 const char* token) {
26 // Compute number of arguments, ignoring the receiver.
27 DCHECK_LE(1, args.length());
28 int const argc = args.length() - 1;
29
30 DirectHandle<JSFunction> target = args.target();
31 DirectHandle<JSObject> target_global_proxy(target->global_proxy(), isolate);
32
33 if (!Builtins::AllowDynamicFunction(isolate, target, target_global_proxy)) {
35 // TODO(verwaest): We would like to throw using the calling context instead
36 // of the entered context but we don't currently have access to that.
37 HandleScopeImplementer* impl = isolate->handle_scope_implementer();
38 SaveAndSwitchContext save(isolate,
39 impl->LastEnteredContext()->native_context());
40 THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kNoAccess));
41 }
42
43 // Build the source string.
44 DirectHandle<String> source;
45 int parameters_end_pos = kNoSourcePosition;
46 {
47 IncrementalStringBuilder builder(isolate);
48 builder.AppendCharacter('(');
49 builder.AppendCString(token);
50 builder.AppendCStringLiteral(" anonymous(");
51 if (argc > 1) {
52 for (int i = 1; i < argc; ++i) {
53 if (i > 1) builder.AppendCharacter(',');
54 DirectHandle<String> param;
55 ASSIGN_RETURN_ON_EXCEPTION(isolate, param,
56 Object::ToString(isolate, args.at(i)));
57 param = String::Flatten(isolate, param);
58 builder.AppendString(param);
59 }
60 }
61 builder.AppendCharacter('\n');
62 parameters_end_pos = builder.Length();
63 builder.AppendCStringLiteral(") {\n");
64 if (argc > 0) {
65 DirectHandle<String> body;
66 ASSIGN_RETURN_ON_EXCEPTION(isolate, body,
67 Object::ToString(isolate, args.at(argc)));
68 builder.AppendString(body);
69 }
70 builder.AppendCStringLiteral("\n})");
71 ASSIGN_RETURN_ON_EXCEPTION(isolate, source, builder.Finish());
72 }
73
74 bool is_code_like = true;
75 for (int i = 0; i < argc; ++i) {
76 if (!Object::IsCodeLike(*args.at(i + 1), isolate)) {
77 is_code_like = false;
78 break;
79 }
80 }
81
82 // Compile the string in the constructor and not a helper so that errors to
83 // come from here.
84 DirectHandle<JSFunction> function;
85 {
87 isolate, function,
89 direct_handle(target->native_context(), isolate),
90 indirect_handle(source, isolate), parameters_end_pos,
91 is_code_like));
92 DirectHandle<Object> result;
94 isolate, result,
95 Execution::Call(isolate, function, target_global_proxy, {}));
96 function = Cast<JSFunction>(result);
97 function->shared()->set_name_should_print_as_anonymous(true);
98 }
99
100 // If new.target is equal to target then the function created
101 // is already correctly setup and nothing else should be done
102 // here. But if new.target is not equal to target then we are
103 // have a Function builtin subclassing case and therefore the
104 // function has wrong initial map. To fix that we create a new
105 // function object with correct initial map.
106 DirectHandle<Object> unchecked_new_target = args.new_target();
107 if (!IsUndefined(*unchecked_new_target, isolate) &&
108 !unchecked_new_target.is_identical_to(target)) {
109 DirectHandle<JSReceiver> new_target =
110 Cast<JSReceiver>(unchecked_new_target);
111 DirectHandle<Map> initial_map;
113 isolate, initial_map,
114 JSFunction::GetDerivedMap(isolate, target, new_target));
115
116 DirectHandle<SharedFunctionInfo> shared_info(function->shared(), isolate);
117 DirectHandle<Map> map =
118 Map::AsLanguageMode(isolate, initial_map, shared_info);
119
120 DirectHandle<Context> context(function->context(), isolate);
121 function = Factory::JSFunctionBuilder{isolate, shared_info, context}
122 .set_map(map)
123 .set_allocation_type(AllocationType::kYoung)
124 .Build();
125 }
126 return function;
127}
128
129} // namespace
130
131// ES6 section 19.2.1.1 Function ( p1, p2, ... , pn, body )
132BUILTIN(FunctionConstructor) {
133 HandleScope scope(isolate);
136 isolate, result, CreateDynamicFunction(isolate, args, "function"));
137 return *result;
138}
139
140// ES6 section 25.2.1.1 GeneratorFunction (p1, p2, ... , pn, body)
141BUILTIN(GeneratorFunctionConstructor) {
142 HandleScope scope(isolate);
144 CreateDynamicFunction(isolate, args, "function*"));
145}
146
147BUILTIN(AsyncFunctionConstructor) {
148 HandleScope scope(isolate);
149 DirectHandle<Object> maybe_func;
151 isolate, maybe_func,
152 CreateDynamicFunction(isolate, args, "async function"));
153 if (!IsJSFunction(*maybe_func)) return *maybe_func;
154
155 // Do not lazily compute eval position for AsyncFunction, as they may not be
156 // determined after the function is resumed.
157 auto func = Cast<JSFunction>(maybe_func);
158 DirectHandle<Script> script(Cast<Script>(func->shared()->script()), isolate);
159 int position = Script::GetEvalPosition(isolate, script);
160 USE(position);
161
162 return *func;
163}
164
165BUILTIN(AsyncGeneratorFunctionConstructor) {
166 HandleScope scope(isolate);
167 DirectHandle<Object> maybe_func;
169 isolate, maybe_func,
170 CreateDynamicFunction(isolate, args, "async function*"));
171 if (!IsJSFunction(*maybe_func)) return *maybe_func;
172
173 // Do not lazily compute eval position for AsyncFunction, as they may not be
174 // determined after the function is resumed.
175 auto func = Cast<JSFunction>(maybe_func);
176 DirectHandle<Script> script(Cast<Script>(func->shared()->script()), isolate);
177 int position = Script::GetEvalPosition(isolate, script);
178 USE(position);
179
180 return *func;
181}
182
183namespace {
184
185enum class ProtoSource {
187 kUseTargetPrototype,
188};
189
190Tagged<Object> DoFunctionBind(Isolate* isolate, BuiltinArguments args,
191 ProtoSource proto_source) {
192 HandleScope scope(isolate);
193 DCHECK_LE(1, args.length());
194 if (!IsCallable(*args.receiver())) {
196 isolate, NewTypeError(MessageTemplate::kFunctionBind));
197 }
198
199 // Allocate the bound function with the given {this_arg} and {args}.
200 DirectHandle<JSReceiver> target = args.at<JSReceiver>(0);
201 DirectHandle<JSAny> this_arg = isolate->factory()->undefined_value();
202 DirectHandleVector<Object> argv(isolate, std::max(0, args.length() - 2));
203 if (args.length() > 1) {
204 this_arg = args.at<JSAny>(1);
205 for (int i = 2; i < args.length(); ++i) {
206 argv[i - 2] = args.at(i);
207 }
208 }
209
210 DirectHandle<JSPrototype> proto;
211 if (proto_source == ProtoSource::kUseTargetPrototype) {
212 // Determine the prototype of the {target_function}.
214 isolate, proto, JSReceiver::GetPrototype(isolate, target));
215 } else if (proto_source == ProtoSource::kNormalFunction) {
216 DirectHandle<NativeContext> native_context(
217 isolate->global_object()->native_context(), isolate);
218 auto function_proto = native_context->function_prototype();
219 proto = direct_handle(function_proto, isolate);
220 } else {
221 UNREACHABLE();
222 }
223
224 DirectHandle<JSBoundFunction> function;
226 isolate, function,
227 isolate->factory()->NewJSBoundFunction(
228 target, this_arg, {argv.data(), argv.size()}, proto));
229 Maybe<bool> result =
231 isolate, function, target, isolate->factory()->bound__string(),
232 static_cast<int>(argv.size()));
233 if (result.IsNothing()) {
234 DCHECK(isolate->has_exception());
235 return ReadOnlyRoots(isolate).exception();
236 }
237 return *function;
238}
239
240} // namespace
241
242// ES6 section 19.2.3.2 Function.prototype.bind ( thisArg, ...args )
243BUILTIN(FunctionPrototypeBind) {
244 return DoFunctionBind(isolate, args, ProtoSource::kUseTargetPrototype);
245}
246
247#if V8_ENABLE_WEBASSEMBLY
248BUILTIN(WebAssemblyFunctionPrototypeBind) {
249 return DoFunctionBind(isolate, args, ProtoSource::kNormalFunction);
250}
251#endif // V8_ENABLE_WEBASSEMBLY
252
253// ES6 section 19.2.3.5 Function.prototype.toString ( )
254BUILTIN(FunctionPrototypeToString) {
255 HandleScope scope(isolate);
257 if (IsJSBoundFunction(*receiver)) {
259 }
260 if (IsJSFunction(*receiver)) {
262 }
263 // With the revised toString behavior, all callable objects are valid
264 // receivers for this method.
265 if (IsJSReceiver(*receiver) &&
266 Cast<JSReceiver>(*receiver)->map()->is_callable()) {
267 return ReadOnlyRoots(isolate).function_native_code_string();
268 }
270 isolate, NewTypeError(MessageTemplate::kNotGeneric,
271 isolate->factory()->NewStringFromAsciiChecked(
272 "Function.prototype.toString"),
273 isolate->factory()->Function_string()));
274}
275
276} // namespace internal
277} // namespace v8
#define BUILTIN(name)
@ kFunctionConstructorReturnedUndefined
Definition v8-isolate.h:504
static bool AllowDynamicFunction(Isolate *isolate, DirectHandle< JSFunction > target, DirectHandle< JSObject > target_global_proxy)
Definition builtins.cc:534
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< JSFunction > GetFunctionFromString(DirectHandle< NativeContext > context, Handle< i::Object > source, int parameters_end_pos, bool is_code_like)
Definition compiler.cc:3494
V8_EXPORT_PRIVATE static V8_WARN_UNUSED_RESULT MaybeHandle< Object > Call(Isolate *isolate, DirectHandle< Object > callable, DirectHandle< Object > receiver, base::Vector< const DirectHandle< Object > > args)
Definition execution.cc:523
static DirectHandle< String > ToString(DirectHandle< JSBoundFunction > function)
static Maybe< bool > CopyNameAndLength(Isolate *isolate, DirectHandle< JSFunctionOrBoundFunctionOrWrappedFunction > function, DirectHandle< JSReceiver > target, DirectHandle< String > prefix, int arg_count)
static V8_EXPORT_PRIVATE V8_WARN_UNUSED_RESULT MaybeHandle< Map > GetDerivedMap(Isolate *isolate, DirectHandle< JSFunction > constructor, DirectHandle< JSReceiver > new_target)
static DirectHandle< String > ToString(DirectHandle< JSFunction > function)
static MaybeDirectHandle< JSPrototype > GetPrototype(Isolate *isolate, DirectHandle< JSReceiver > receiver)
static DirectHandle< Map > AsLanguageMode(Isolate *isolate, DirectHandle< Map > initial_map, DirectHandle< SharedFunctionInfo > shared_info)
Definition map.cc:1734
static V8_WARN_UNUSED_RESULT HandleType< String >::MaybeType ToString(Isolate *isolate, HandleType< T > input)
static bool IsCodeLike(Tagged< Object > obj, Isolate *isolate)
Definition objects.cc:1860
static int GetEvalPosition(Isolate *isolate, DirectHandle< Script > script)
Definition objects.cc:4294
static V8_INLINE HandleType< String > Flatten(Isolate *isolate, HandleType< T > string, AllocationType allocation=AllocationType::kYoung)
#define ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, dst, call)
Definition isolate.h:284
#define ASSIGN_RETURN_ON_EXCEPTION(isolate, dst, call)
Definition isolate.h:291
#define THROW_NEW_ERROR(isolate, call)
Definition isolate.h:307
#define THROW_NEW_ERROR_RETURN_FAILURE(isolate, call)
Definition isolate.h:294
#define RETURN_RESULT_OR_FAILURE(isolate, call)
Definition isolate.h:264
base::Vector< const DirectHandle< Object > > args
Definition execution.cc:74
DirectHandle< Object > new_target
Definition execution.cc:75
Isolate * isolate
TNode< Context > context
TNode< Object > this_arg
TNode< Object > receiver
ZoneVector< RpoNumber > & result
int position
Definition liveedit.cc:290
InstructionOperand source
Union< Smi, HeapNumber, BigInt, String, Symbol, Boolean, Null, Undefined, JSReceiver > JSAny
Definition globals.h:1189
constexpr int kNoSourcePosition
Definition globals.h:850
V8_INLINE IndirectHandle< T > indirect_handle(DirectHandle< T > handle)
Definition handles.h:757
V8_INLINE DirectHandle< T > direct_handle(Tagged< T > object, Isolate *isolate)
kInterpreterTrampolineOffset script
!IsContextMap !IsContextMap native_context
Definition map-inl.h:877
Tagged< To > Cast(Tagged< From > value, const v8::SourceLocation &loc=INIT_SOURCE_LOCATION_IN_DEBUG)
Definition casting.h:150
auto impl(C *x) -> typename implement< C >::type *
Definition c-api.cc:243
#define DCHECK_LE(v1, v2)
Definition logging.h:490
#define DCHECK(condition)
Definition logging.h:482
#define USE(...)
Definition macros.h:293