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
|