Line data Source code
1 : // Copyright 2014 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/runtime/runtime-utils.h"
6 :
7 : #include <memory>
8 :
9 : #include "src/accessors.h"
10 : #include "src/arguments.h"
11 : #include "src/ast/scopes.h"
12 : #include "src/deoptimizer.h"
13 : #include "src/frames-inl.h"
14 : #include "src/isolate-inl.h"
15 : #include "src/messages.h"
16 :
17 : namespace v8 {
18 : namespace internal {
19 :
20 73702 : RUNTIME_FUNCTION(Runtime_ThrowConstAssignError) {
21 36851 : HandleScope scope(isolate);
22 73702 : THROW_NEW_ERROR_RETURN_FAILURE(isolate,
23 36851 : NewTypeError(MessageTemplate::kConstAssign));
24 : }
25 :
26 : namespace {
27 :
28 : enum class RedeclarationType { kSyntaxError = 0, kTypeError = 1 };
29 :
30 483 : Object* ThrowRedeclarationError(Isolate* isolate, Handle<String> name,
31 : RedeclarationType redeclaration_type) {
32 : HandleScope scope(isolate);
33 483 : if (redeclaration_type == RedeclarationType::kSyntaxError) {
34 846 : THROW_NEW_ERROR_RETURN_FAILURE(
35 : isolate, NewSyntaxError(MessageTemplate::kVarRedeclaration, name));
36 : } else {
37 120 : THROW_NEW_ERROR_RETURN_FAILURE(
38 : isolate, NewTypeError(MessageTemplate::kVarRedeclaration, name));
39 : }
40 : }
41 :
42 :
43 : // May throw a RedeclarationError.
44 2230969 : Object* DeclareGlobal(
45 : Isolate* isolate, Handle<JSGlobalObject> global, Handle<String> name,
46 : Handle<Object> value, PropertyAttributes attr, bool is_var,
47 : bool is_function_declaration, RedeclarationType redeclaration_type,
48 : Handle<FeedbackVector> feedback_vector = Handle<FeedbackVector>(),
49 : FeedbackSlot slot = FeedbackSlot::Invalid()) {
50 : Handle<ScriptContextTable> script_contexts(
51 : global->native_context()->script_context_table());
52 : ScriptContextTable::LookupResult lookup;
53 2231008 : if (ScriptContextTable::Lookup(script_contexts, name, &lookup) &&
54 39 : IsLexicalVariableMode(lookup.mode)) {
55 : // ES#sec-globaldeclarationinstantiation 6.a:
56 : // If envRec.HasLexicalDeclaration(name) is true, throw a SyntaxError
57 : // exception.
58 : return ThrowRedeclarationError(isolate, name,
59 39 : RedeclarationType::kSyntaxError);
60 : }
61 :
62 : // Do the lookup own properties only, see ES5 erratum.
63 : LookupIterator::Configuration lookup_config(
64 : LookupIterator::Configuration::OWN_SKIP_INTERCEPTOR);
65 2230930 : if (is_function_declaration) {
66 : // For function declarations, use the interceptor on the declaration. For
67 : // non-functions, use it only on initialization.
68 : lookup_config = LookupIterator::Configuration::OWN;
69 : }
70 2230930 : LookupIterator it(global, name, global, lookup_config);
71 2230930 : Maybe<PropertyAttributes> maybe = JSReceiver::GetPropertyAttributes(&it);
72 2230930 : if (!maybe.IsJust()) return isolate->heap()->exception();
73 :
74 2230930 : if (it.IsFound()) {
75 : PropertyAttributes old_attributes = maybe.FromJust();
76 : // The name was declared before; check for conflicting re-declarations.
77 :
78 : // Skip var re-declarations.
79 261732 : if (is_var) return isolate->heap()->undefined_value();
80 :
81 : DCHECK(is_function_declaration);
82 38220 : if ((old_attributes & DONT_DELETE) != 0) {
83 : // Only allow reconfiguring globals to functions in user code (no
84 : // natives, which are marked as read-only).
85 : DCHECK((attr & READ_ONLY) == 0);
86 :
87 : // Check whether we can reconfigure the existing property into a
88 : // function.
89 68262 : if (old_attributes & READ_ONLY || old_attributes & DONT_ENUM ||
90 34090 : (it.state() == LookupIterator::ACCESSOR)) {
91 : // ECMA-262 section 15.1.11 GlobalDeclarationInstantiation 5.d:
92 : // If hasRestrictedGlobal is true, throw a SyntaxError exception.
93 : // ECMA-262 section 18.2.1.3 EvalDeclarationInstantiation 8.a.iv.1.b:
94 : // If fnDefinable is false, throw a TypeError exception.
95 89 : return ThrowRedeclarationError(isolate, name, redeclaration_type);
96 : }
97 : // If the existing property is not configurable, keep its attributes. Do
98 : attr = old_attributes;
99 : }
100 :
101 : // If the current state is ACCESSOR, this could mean it's an AccessorInfo
102 : // type property. We are not allowed to call into such setters during global
103 : // function declaration since this would break e.g., onload. Meaning
104 : // 'function onload() {}' would invalidly register that function as the
105 : // onload callback. To avoid this situation, we first delete the property
106 : // before readding it as a regular data property below.
107 38131 : if (it.state() == LookupIterator::ACCESSOR) it.Delete();
108 : }
109 :
110 2007329 : if (is_function_declaration) {
111 411196 : it.Restart();
112 : }
113 :
114 : // Define or redefine own property.
115 4014658 : RETURN_FAILURE_ON_EXCEPTION(
116 : isolate, JSObject::DefineOwnPropertyIgnoreAttributes(&it, value, attr));
117 :
118 4009267 : if (!feedback_vector.is_null() &&
119 2001952 : it.state() != LookupIterator::State::INTERCEPTOR) {
120 : DCHECK_EQ(*global, *it.GetHolder<Object>());
121 : // Preinitialize the feedback slot if the global object does not have
122 : // named interceptor or the interceptor is not masking.
123 2002259 : if (!global->HasNamedInterceptor() ||
124 314 : global->GetNamedInterceptor()->non_masking()) {
125 : LoadGlobalICNexus nexus(feedback_vector, slot);
126 2001631 : nexus.ConfigurePropertyCellMode(it.GetPropertyCell());
127 : }
128 : }
129 2007315 : return isolate->heap()->undefined_value();
130 : }
131 :
132 349044 : Object* DeclareGlobals(Isolate* isolate, Handle<FixedArray> declarations,
133 : int flags, Handle<FeedbackVector> feedback_vector) {
134 : HandleScope scope(isolate);
135 174522 : Handle<JSGlobalObject> global(isolate->global_object());
136 : Handle<Context> context(isolate->context());
137 :
138 : // Traverse the name/value pairs and set the properties.
139 : int length = declarations->length();
140 14777043 : FOR_WITH_HANDLE_SCOPE(isolate, int, i = 0, i, i < length, i += 4, {
141 : Handle<String> name(String::cast(declarations->get(i)), isolate);
142 : FeedbackSlot slot(Smi::cast(declarations->get(i + 1))->value());
143 : Handle<Object> possibly_literal_slot(declarations->get(i + 2), isolate);
144 : Handle<Object> initial_value(declarations->get(i + 3), isolate);
145 :
146 : bool is_var = initial_value->IsUndefined(isolate);
147 : bool is_function = initial_value->IsSharedFunctionInfo();
148 : DCHECK_EQ(1, BoolToInt(is_var) + BoolToInt(is_function));
149 :
150 : Handle<Object> value;
151 : if (is_function) {
152 : DCHECK(possibly_literal_slot->IsSmi());
153 : // Copy the function and update its context. Use it as value.
154 : Handle<SharedFunctionInfo> shared =
155 : Handle<SharedFunctionInfo>::cast(initial_value);
156 : FeedbackSlot literals_slot(Smi::cast(*possibly_literal_slot)->value());
157 : Handle<Cell> literals(Cell::cast(feedback_vector->Get(literals_slot)),
158 : isolate);
159 : Handle<JSFunction> function =
160 : isolate->factory()->NewFunctionFromSharedFunctionInfo(
161 : shared, context, literals, TENURED);
162 : value = function;
163 : } else {
164 : value = isolate->factory()->undefined_value();
165 : }
166 :
167 : // Compute the property attributes. According to ECMA-262,
168 : // the property must be non-configurable except in eval.
169 : bool is_native = DeclareGlobalsNativeFlag::decode(flags);
170 : bool is_eval = DeclareGlobalsEvalFlag::decode(flags);
171 : int attr = NONE;
172 : if (is_function && is_native) attr |= READ_ONLY;
173 : if (!is_eval) attr |= DONT_DELETE;
174 :
175 : // ES#sec-globaldeclarationinstantiation 5.d:
176 : // If hasRestrictedGlobal is true, throw a SyntaxError exception.
177 : Object* result = DeclareGlobal(
178 : isolate, global, name, value, static_cast<PropertyAttributes>(attr),
179 : is_var, is_function, RedeclarationType::kSyntaxError, feedback_vector,
180 : slot);
181 : if (isolate->has_pending_exception()) return result;
182 : });
183 :
184 174454 : return isolate->heap()->undefined_value();
185 : }
186 :
187 : } // namespace
188 :
189 115004 : RUNTIME_FUNCTION(Runtime_DeclareGlobals) {
190 57502 : HandleScope scope(isolate);
191 : DCHECK_EQ(3, args.length());
192 :
193 115004 : CONVERT_ARG_HANDLE_CHECKED(FixedArray, declarations, 0);
194 115004 : CONVERT_SMI_ARG_CHECKED(flags, 1);
195 115004 : CONVERT_ARG_HANDLE_CHECKED(FeedbackVector, feedback_vector, 2);
196 :
197 57502 : return DeclareGlobals(isolate, declarations, flags, feedback_vector);
198 : }
199 :
200 : // TODO(ishell): merge this with Runtime::kDeclareGlobals once interpreter
201 : // is able to pass feedback vector.
202 234040 : RUNTIME_FUNCTION(Runtime_DeclareGlobalsForInterpreter) {
203 117020 : HandleScope scope(isolate);
204 : DCHECK_EQ(3, args.length());
205 :
206 234040 : CONVERT_ARG_HANDLE_CHECKED(FixedArray, declarations, 0);
207 234040 : CONVERT_SMI_ARG_CHECKED(flags, 1);
208 234040 : CONVERT_ARG_HANDLE_CHECKED(JSFunction, closure, 2);
209 :
210 117020 : Handle<FeedbackVector> feedback_vector(closure->feedback_vector(), isolate);
211 117020 : return DeclareGlobals(isolate, declarations, flags, feedback_vector);
212 : }
213 :
214 407148 : RUNTIME_FUNCTION(Runtime_InitializeVarGlobal) {
215 203574 : HandleScope scope(isolate);
216 : DCHECK_EQ(3, args.length());
217 407148 : CONVERT_ARG_HANDLE_CHECKED(String, name, 0);
218 407148 : CONVERT_LANGUAGE_MODE_ARG_CHECKED(language_mode, 1);
219 203574 : CONVERT_ARG_HANDLE_CHECKED(Object, value, 2);
220 :
221 203574 : Handle<JSGlobalObject> global(isolate->global_object());
222 407148 : RETURN_RESULT_OR_FAILURE(
223 203574 : isolate, Object::SetProperty(global, name, value, language_mode));
224 : }
225 :
226 : namespace {
227 :
228 504173 : Object* DeclareEvalHelper(Isolate* isolate, Handle<String> name,
229 : Handle<Object> value) {
230 : // Declarations are always made in a function, native, eval, or script
231 : // context, or a declaration block scope. Since this is called from eval, the
232 : // context passed is the context of the caller, which may be some nested
233 : // context and not the declaration context.
234 : Handle<Context> context_arg(isolate->context(), isolate);
235 504173 : Handle<Context> context(context_arg->declaration_context(), isolate);
236 :
237 : DCHECK(context->IsFunctionContext() || context->IsNativeContext() ||
238 : context->IsScriptContext() || context->IsEvalContext() ||
239 : (context->IsBlockContext() && context->has_extension()));
240 :
241 : bool is_function = value->IsJSFunction();
242 504173 : bool is_var = !is_function;
243 : DCHECK(!is_var || value->IsUndefined(isolate));
244 :
245 : int index;
246 : PropertyAttributes attributes;
247 : InitializationFlag init_flag;
248 : VariableMode mode;
249 :
250 : // Check for a conflict with a lexically scoped variable
251 : context_arg->Lookup(name, LEXICAL_TEST, &index, &attributes, &init_flag,
252 504173 : &mode);
253 704342 : if (attributes != ABSENT && IsLexicalVariableMode(mode)) {
254 : // ES#sec-evaldeclarationinstantiation 5.a.i.1:
255 : // If varEnvRec.HasLexicalDeclaration(name) is true, throw a SyntaxError
256 : // exception.
257 : // ES#sec-evaldeclarationinstantiation 5.d.ii.2.a.i:
258 : // Throw a SyntaxError exception.
259 : return ThrowRedeclarationError(isolate, name,
260 244 : RedeclarationType::kSyntaxError);
261 : }
262 :
263 : Handle<Object> holder = context->Lookup(name, DONT_FOLLOW_CHAINS, &index,
264 503929 : &attributes, &init_flag, &mode);
265 : DCHECK(!isolate->has_pending_exception());
266 :
267 : Handle<JSObject> object;
268 :
269 703840 : if (attributes != ABSENT && holder->IsJSGlobalObject()) {
270 : // ES#sec-evaldeclarationinstantiation 8.a.iv.1.b:
271 : // If fnDefinable is false, throw a TypeError exception.
272 : return DeclareGlobal(isolate, Handle<JSGlobalObject>::cast(holder), name,
273 : value, NONE, is_var, is_function,
274 193181 : RedeclarationType::kTypeError);
275 : }
276 310748 : if (context_arg->extension()->IsJSGlobalObject()) {
277 : Handle<JSGlobalObject> global(
278 : JSGlobalObject::cast(context_arg->extension()), isolate);
279 : return DeclareGlobal(isolate, global, name, value, NONE, is_var,
280 1479 : is_function, RedeclarationType::kTypeError);
281 309269 : } else if (context->IsScriptContext()) {
282 : DCHECK(context->global_object()->IsJSGlobalObject());
283 : Handle<JSGlobalObject> global(
284 85 : JSGlobalObject::cast(context->global_object()), isolate);
285 : return DeclareGlobal(isolate, global, name, value, NONE, is_var,
286 85 : is_function, RedeclarationType::kTypeError);
287 : }
288 :
289 309184 : if (attributes != ABSENT) {
290 : DCHECK_EQ(NONE, attributes);
291 :
292 : // Skip var re-declarations.
293 6730 : if (is_var) return isolate->heap()->undefined_value();
294 :
295 : DCHECK(is_function);
296 881 : if (index != Context::kNotFound) {
297 : DCHECK(holder.is_identical_to(context));
298 164 : context->set(index, *value);
299 164 : return isolate->heap()->undefined_value();
300 : }
301 :
302 : object = Handle<JSObject>::cast(holder);
303 :
304 302454 : } else if (context->has_extension()) {
305 : // Sloppy varblock contexts might not have an extension object yet,
306 : // in which case their extension is a ScopeInfo.
307 269662 : if (context->extension()->IsScopeInfo()) {
308 : DCHECK(context->IsBlockContext());
309 : object = isolate->factory()->NewJSObject(
310 1358 : isolate->context_extension_function());
311 : Handle<HeapObject> extension = isolate->factory()->NewContextExtension(
312 2716 : handle(context->scope_info()), object);
313 : context->set_extension(*extension);
314 : } else {
315 268304 : object = handle(context->extension_object(), isolate);
316 : }
317 : DCHECK(object->IsJSContextExtensionObject() || object->IsJSGlobalObject());
318 : } else {
319 : // Sloppy eval will never have an extension object, as vars are hoisted out,
320 : // and lets are known statically.
321 : DCHECK(context->IsFunctionContext());
322 : object =
323 32792 : isolate->factory()->NewJSObject(isolate->context_extension_function());
324 : context->set_extension(*object);
325 : }
326 :
327 606342 : RETURN_FAILURE_ON_EXCEPTION(isolate, JSObject::SetOwnPropertyIgnoreAttributes(
328 : object, name, value, NONE));
329 :
330 303171 : return isolate->heap()->undefined_value();
331 : }
332 :
333 : } // namespace
334 :
335 31680 : RUNTIME_FUNCTION(Runtime_DeclareEvalFunction) {
336 15840 : HandleScope scope(isolate);
337 : DCHECK_EQ(2, args.length());
338 31680 : CONVERT_ARG_HANDLE_CHECKED(String, name, 0);
339 15840 : CONVERT_ARG_HANDLE_CHECKED(Object, value, 1);
340 15840 : return DeclareEvalHelper(isolate, name, value);
341 : }
342 :
343 976666 : RUNTIME_FUNCTION(Runtime_DeclareEvalVar) {
344 488333 : HandleScope scope(isolate);
345 : DCHECK_EQ(1, args.length());
346 976666 : CONVERT_ARG_HANDLE_CHECKED(String, name, 0);
347 : return DeclareEvalHelper(isolate, name,
348 976666 : isolate->factory()->undefined_value());
349 : }
350 :
351 : namespace {
352 :
353 : // Find the arguments of the JavaScript function invocation that called
354 : // into C++ code. Collect these in a newly allocated array of handles.
355 106 : std::unique_ptr<Handle<Object>[]> GetCallerArguments(Isolate* isolate,
356 : int* total_argc) {
357 : // Find frame containing arguments passed to the caller.
358 106 : JavaScriptFrameIterator it(isolate);
359 : JavaScriptFrame* frame = it.frame();
360 : List<SharedFunctionInfo*> functions(2);
361 106 : frame->GetFunctions(&functions);
362 106 : if (functions.length() > 1) {
363 0 : int inlined_jsframe_index = functions.length() - 1;
364 0 : TranslatedState translated_values(frame);
365 0 : translated_values.Prepare(false, frame->fp());
366 :
367 0 : int argument_count = 0;
368 : TranslatedFrame* translated_frame =
369 : translated_values.GetArgumentsInfoFromJSFrameIndex(
370 0 : inlined_jsframe_index, &argument_count);
371 : TranslatedFrame::iterator iter = translated_frame->begin();
372 :
373 : // Skip the function.
374 : iter++;
375 :
376 : // Skip the receiver.
377 : iter++;
378 0 : argument_count--;
379 :
380 0 : *total_argc = argument_count;
381 : std::unique_ptr<Handle<Object>[]> param_data(
382 0 : NewArray<Handle<Object>>(*total_argc));
383 : bool should_deoptimize = false;
384 0 : for (int i = 0; i < argument_count; i++) {
385 : // If we materialize any object, we should deoptimize the frame because we
386 : // might alias an object that was eliminated by escape analysis.
387 0 : should_deoptimize = should_deoptimize || iter->IsMaterializedObject();
388 0 : Handle<Object> value = iter->GetValue();
389 0 : param_data[i] = value;
390 : iter++;
391 : }
392 :
393 0 : if (should_deoptimize) {
394 0 : translated_values.StoreMaterializedValuesAndDeopt(frame);
395 : }
396 :
397 : return param_data;
398 : } else {
399 106 : it.AdvanceToArgumentsFrame();
400 : frame = it.frame();
401 106 : int args_count = frame->ComputeParametersCount();
402 :
403 106 : *total_argc = args_count;
404 : std::unique_ptr<Handle<Object>[]> param_data(
405 106 : NewArray<Handle<Object>>(*total_argc));
406 2654501 : for (int i = 0; i < args_count; i++) {
407 2654395 : Handle<Object> val = Handle<Object>(frame->GetParameter(i), isolate);
408 5308790 : param_data[i] = val;
409 : }
410 : return param_data;
411 : }
412 : }
413 :
414 : template <typename T>
415 163 : Handle<JSObject> NewSloppyArguments(Isolate* isolate, Handle<JSFunction> callee,
416 : T parameters, int argument_count) {
417 91 : CHECK(!IsDerivedConstructor(callee->shared()->kind()));
418 : DCHECK(callee->shared()->has_simple_parameters());
419 : Handle<JSObject> result =
420 91 : isolate->factory()->NewArgumentsObject(callee, argument_count);
421 :
422 : // Allocate the elements if needed.
423 : int parameter_count = callee->shared()->internal_formal_parameter_count();
424 91 : if (argument_count > 0) {
425 84 : if (parameter_count > 0) {
426 : int mapped_count = Min(argument_count, parameter_count);
427 : Handle<FixedArray> parameter_map =
428 72 : isolate->factory()->NewFixedArray(mapped_count + 2, NOT_TENURED);
429 144 : parameter_map->set_map(isolate->heap()->sloppy_arguments_elements_map());
430 144 : result->set_map(isolate->native_context()->fast_aliased_arguments_map());
431 72 : result->set_elements(*parameter_map);
432 :
433 : // Store the context and the arguments array at the beginning of the
434 : // parameter map.
435 : Handle<Context> context(isolate->context());
436 : Handle<FixedArray> arguments =
437 72 : isolate->factory()->NewFixedArray(argument_count, NOT_TENURED);
438 72 : parameter_map->set(0, *context);
439 72 : parameter_map->set(1, *arguments);
440 :
441 : // Loop over the actual parameters backwards.
442 72 : int index = argument_count - 1;
443 173 : while (index >= mapped_count) {
444 : // These go directly in the arguments array and have no
445 : // corresponding slot in the parameter map.
446 29 : arguments->set(index, parameters[index]);
447 29 : --index;
448 : }
449 :
450 : Handle<ScopeInfo> scope_info(callee->shared()->scope_info());
451 230 : while (index >= 0) {
452 : // Detect duplicate names to the right in the parameter list.
453 158 : Handle<String> name(scope_info->ParameterName(index));
454 158 : int context_local_count = scope_info->ContextLocalCount();
455 : bool duplicate = false;
456 165 : for (int j = index + 1; j < parameter_count; ++j) {
457 186 : if (scope_info->ParameterName(j) == *name) {
458 : duplicate = true;
459 : break;
460 : }
461 : }
462 :
463 158 : if (duplicate) {
464 : // This goes directly in the arguments array with a hole in the
465 : // parameter map.
466 86 : arguments->set(index, parameters[index]);
467 172 : parameter_map->set_the_hole(index + 2);
468 : } else {
469 : // The context index goes in the parameter map with a hole in the
470 : // arguments array.
471 : int context_index = -1;
472 7 : for (int j = 0; j < context_local_count; ++j) {
473 158 : if (scope_info->ContextLocalName(j) == *name) {
474 : context_index = j;
475 : break;
476 : }
477 : }
478 :
479 : DCHECK(context_index >= 0);
480 72 : arguments->set_the_hole(index);
481 : parameter_map->set(
482 : index + 2,
483 72 : Smi::FromInt(Context::MIN_CONTEXT_SLOTS + context_index));
484 : }
485 :
486 158 : --index;
487 : }
488 : } else {
489 : // If there is no aliasing, the arguments object elements are not
490 : // special in any way.
491 : Handle<FixedArray> elements =
492 12 : isolate->factory()->NewFixedArray(argument_count, NOT_TENURED);
493 12 : result->set_elements(*elements);
494 786444 : for (int i = 0; i < argument_count; ++i) {
495 1572864 : elements->set(i, parameters[i]);
496 : }
497 : }
498 : }
499 91 : return result;
500 : }
501 :
502 :
503 : class HandleArguments BASE_EMBEDDED {
504 : public:
505 79 : explicit HandleArguments(Handle<Object>* array) : array_(array) {}
506 115 : Object* operator[](int index) { return *array_[index]; }
507 :
508 : private:
509 : Handle<Object>* array_;
510 : };
511 :
512 :
513 : class ParameterArguments BASE_EMBEDDED {
514 : public:
515 12 : explicit ParameterArguments(Object** parameters) : parameters_(parameters) {}
516 786432 : Object*& operator[](int index) { return *(parameters_ - index - 1); }
517 :
518 : private:
519 : Object** parameters_;
520 : };
521 :
522 : } // namespace
523 :
524 :
525 158 : RUNTIME_FUNCTION(Runtime_NewSloppyArguments_Generic) {
526 79 : HandleScope scope(isolate);
527 : DCHECK_EQ(1, args.length());
528 158 : CONVERT_ARG_HANDLE_CHECKED(JSFunction, callee, 0);
529 : // This generic runtime function can also be used when the caller has been
530 : // inlined, we use the slow but accurate {GetCallerArguments}.
531 79 : int argument_count = 0;
532 : std::unique_ptr<Handle<Object>[]> arguments =
533 158 : GetCallerArguments(isolate, &argument_count);
534 79 : HandleArguments argument_getter(arguments.get());
535 237 : return *NewSloppyArguments(isolate, callee, argument_getter, argument_count);
536 : }
537 :
538 :
539 28 : RUNTIME_FUNCTION(Runtime_NewStrictArguments) {
540 14 : HandleScope scope(isolate);
541 : DCHECK_EQ(1, args.length());
542 28 : CONVERT_ARG_HANDLE_CHECKED(JSFunction, callee, 0);
543 : // This generic runtime function can also be used when the caller has been
544 : // inlined, we use the slow but accurate {GetCallerArguments}.
545 14 : int argument_count = 0;
546 : std::unique_ptr<Handle<Object>[]> arguments =
547 28 : GetCallerArguments(isolate, &argument_count);
548 : Handle<JSObject> result =
549 14 : isolate->factory()->NewArgumentsObject(callee, argument_count);
550 14 : if (argument_count) {
551 : Handle<FixedArray> array =
552 14 : isolate->factory()->NewUninitializedFixedArray(argument_count);
553 : DisallowHeapAllocation no_gc;
554 14 : WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
555 1376256 : for (int i = 0; i < argument_count; i++) {
556 2752512 : array->set(i, *arguments[i], mode);
557 : }
558 14 : result->set_elements(*array);
559 : }
560 14 : return *result;
561 : }
562 :
563 :
564 26 : RUNTIME_FUNCTION(Runtime_NewRestParameter) {
565 13 : HandleScope scope(isolate);
566 : DCHECK_EQ(1, args.length());
567 26 : CONVERT_ARG_HANDLE_CHECKED(JSFunction, callee, 0)
568 13 : int start_index = callee->shared()->internal_formal_parameter_count();
569 : // This generic runtime function can also be used when the caller has been
570 : // inlined, we use the slow but accurate {GetCallerArguments}.
571 13 : int argument_count = 0;
572 : std::unique_ptr<Handle<Object>[]> arguments =
573 26 : GetCallerArguments(isolate, &argument_count);
574 13 : int num_elements = std::max(0, argument_count - start_index);
575 : Handle<JSObject> result =
576 : isolate->factory()->NewJSArray(FAST_ELEMENTS, num_elements, num_elements,
577 13 : DONT_INITIALIZE_ARRAY_ELEMENTS);
578 : {
579 : DisallowHeapAllocation no_gc;
580 13 : FixedArray* elements = FixedArray::cast(result->elements());
581 13 : WriteBarrierMode mode = elements->GetWriteBarrierMode(no_gc);
582 1277952 : for (int i = 0; i < num_elements; i++) {
583 2555904 : elements->set(i, *arguments[i + start_index], mode);
584 : }
585 : }
586 13 : return *result;
587 : }
588 :
589 :
590 24 : RUNTIME_FUNCTION(Runtime_NewSloppyArguments) {
591 12 : HandleScope scope(isolate);
592 : DCHECK_EQ(1, args.length());
593 24 : CONVERT_ARG_HANDLE_CHECKED(JSFunction, callee, 0);
594 24 : StackFrameIterator iterator(isolate);
595 :
596 : // Stub/interpreter handler frame
597 12 : iterator.Advance();
598 : DCHECK(iterator.frame()->type() == StackFrame::STUB);
599 :
600 : // Function frame
601 12 : iterator.Advance();
602 12 : JavaScriptFrame* function_frame = JavaScriptFrame::cast(iterator.frame());
603 : DCHECK(function_frame->is_java_script());
604 12 : int argc = function_frame->GetArgumentsLength();
605 12 : Address fp = function_frame->fp();
606 12 : if (function_frame->has_adapted_arguments()) {
607 12 : iterator.Advance();
608 12 : fp = iterator.frame()->fp();
609 : }
610 :
611 : Object** parameters = reinterpret_cast<Object**>(
612 12 : fp + argc * kPointerSize + StandardFrameConstants::kCallerSPOffset);
613 12 : ParameterArguments argument_getter(parameters);
614 36 : return *NewSloppyArguments(isolate, callee, argument_getter, argc);
615 : }
616 :
617 8 : RUNTIME_FUNCTION(Runtime_NewArgumentsElements) {
618 4 : HandleScope scope(isolate);
619 : DCHECK_EQ(2, args.length());
620 4 : Object** frame = reinterpret_cast<Object**>(args[0]);
621 8 : CONVERT_SMI_ARG_CHECKED(length, 1);
622 : Handle<FixedArray> result =
623 4 : isolate->factory()->NewUninitializedFixedArray(length);
624 4 : int const offset = length + 1;
625 : DisallowHeapAllocation no_gc;
626 4 : WriteBarrierMode mode = result->GetWriteBarrierMode(no_gc);
627 360448 : for (int index = 0; index < length; ++index) {
628 720896 : result->set(index, frame[offset - index], mode);
629 : }
630 4 : return *result;
631 : }
632 :
633 10225512 : RUNTIME_FUNCTION(Runtime_NewClosure) {
634 3408505 : HandleScope scope(isolate);
635 : DCHECK_EQ(3, args.length());
636 6817010 : CONVERT_ARG_HANDLE_CHECKED(SharedFunctionInfo, shared, 0);
637 6817008 : CONVERT_ARG_HANDLE_CHECKED(FeedbackVector, vector, 1);
638 6817008 : CONVERT_SMI_ARG_CHECKED(index, 2);
639 3408504 : Handle<Context> context(isolate->context(), isolate);
640 3408500 : FeedbackSlot slot = FeedbackVector::ToSlot(index);
641 3408501 : Handle<Cell> vector_cell(Cell::cast(vector->Get(slot)), isolate);
642 : Handle<JSFunction> function =
643 : isolate->factory()->NewFunctionFromSharedFunctionInfo(
644 3408502 : shared, context, vector_cell, NOT_TENURED);
645 3408505 : return *function;
646 : }
647 :
648 :
649 14655408 : RUNTIME_FUNCTION(Runtime_NewClosure_Tenured) {
650 4885136 : HandleScope scope(isolate);
651 : DCHECK_EQ(3, args.length());
652 9770272 : CONVERT_ARG_HANDLE_CHECKED(SharedFunctionInfo, shared, 0);
653 9770272 : CONVERT_ARG_HANDLE_CHECKED(FeedbackVector, vector, 1);
654 9770272 : CONVERT_SMI_ARG_CHECKED(index, 2);
655 4885136 : Handle<Context> context(isolate->context(), isolate);
656 4885136 : FeedbackSlot slot = FeedbackVector::ToSlot(index);
657 4885136 : Handle<Cell> vector_cell(Cell::cast(vector->Get(slot)), isolate);
658 : // The caller ensures that we pretenure closures that are assigned
659 : // directly to properties.
660 : Handle<JSFunction> function =
661 : isolate->factory()->NewFunctionFromSharedFunctionInfo(
662 4885136 : shared, context, vector_cell, TENURED);
663 4885136 : return *function;
664 : }
665 :
666 11647 : static Object* FindNameClash(Handle<ScopeInfo> scope_info,
667 : Handle<JSGlobalObject> global_object,
668 : Handle<ScriptContextTable> script_context) {
669 : Isolate* isolate = scope_info->GetIsolate();
670 676240 : for (int var = 0; var < scope_info->ContextLocalCount(); var++) {
671 326584 : Handle<String> name(scope_info->ContextLocalName(var));
672 326584 : VariableMode mode = scope_info->ContextLocalMode(var);
673 : ScriptContextTable::LookupResult lookup;
674 326584 : if (ScriptContextTable::Lookup(script_context, name, &lookup)) {
675 57 : if (IsLexicalVariableMode(mode) || IsLexicalVariableMode(lookup.mode)) {
676 : // ES#sec-globaldeclarationinstantiation 5.b:
677 : // If envRec.HasLexicalDeclaration(name) is true, throw a SyntaxError
678 : // exception.
679 : return ThrowRedeclarationError(isolate, name,
680 168 : RedeclarationType::kSyntaxError);
681 : }
682 : }
683 :
684 326527 : if (IsLexicalVariableMode(mode)) {
685 : LookupIterator it(global_object, name, global_object,
686 326527 : LookupIterator::OWN_SKIP_INTERCEPTOR);
687 326527 : Maybe<PropertyAttributes> maybe = JSReceiver::GetPropertyAttributes(&it);
688 326581 : if (!maybe.IsJust()) return isolate->heap()->exception();
689 326527 : if ((maybe.FromJust() & DONT_DELETE) != 0) {
690 : // ES#sec-globaldeclarationinstantiation 5.a:
691 : // If envRec.HasVarDeclaration(name) is true, throw a SyntaxError
692 : // exception.
693 : // ES#sec-globaldeclarationinstantiation 5.d:
694 : // If hasRestrictedGlobal is true, throw a SyntaxError exception.
695 : return ThrowRedeclarationError(isolate, name,
696 54 : RedeclarationType::kSyntaxError);
697 : }
698 :
699 326473 : JSGlobalObject::InvalidatePropertyCell(global_object, name);
700 : }
701 : }
702 11536 : return isolate->heap()->undefined_value();
703 : }
704 :
705 :
706 23294 : RUNTIME_FUNCTION(Runtime_NewScriptContext) {
707 11647 : HandleScope scope(isolate);
708 : DCHECK_EQ(2, args.length());
709 :
710 23294 : CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
711 23294 : CONVERT_ARG_HANDLE_CHECKED(ScopeInfo, scope_info, 1);
712 11647 : Handle<JSGlobalObject> global_object(function->context()->global_object());
713 11647 : Handle<Context> native_context(global_object->native_context());
714 : Handle<ScriptContextTable> script_context_table(
715 11647 : native_context->script_context_table());
716 :
717 : Object* name_clash_result =
718 11647 : FindNameClash(scope_info, global_object, script_context_table);
719 11647 : if (isolate->has_pending_exception()) return name_clash_result;
720 :
721 : // Script contexts have a canonical empty function as their closure, not the
722 : // anonymous closure containing the global code. See
723 : // FullCodeGenerator::PushFunctionArgumentForContextAllocation.
724 11536 : Handle<JSFunction> closure(function->shared()->IsUserJavaScript()
725 : ? native_context->closure()
726 23072 : : *function);
727 : Handle<Context> result =
728 11536 : isolate->factory()->NewScriptContext(closure, scope_info);
729 :
730 : DCHECK(function->context() == isolate->context());
731 : DCHECK(*global_object == result->global_object());
732 :
733 : Handle<ScriptContextTable> new_script_context_table =
734 11536 : ScriptContextTable::Extend(script_context_table, result);
735 11536 : native_context->set_script_context_table(*new_script_context_table);
736 11647 : return *result;
737 : }
738 :
739 30 : RUNTIME_FUNCTION(Runtime_NewFunctionContext) {
740 15 : HandleScope scope(isolate);
741 : DCHECK_EQ(2, args.length());
742 :
743 30 : CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
744 30 : CONVERT_SMI_ARG_CHECKED(scope_type, 1);
745 :
746 : DCHECK(function->context() == isolate->context());
747 15 : int length = function->shared()->scope_info()->ContextLength();
748 : return *isolate->factory()->NewFunctionContext(
749 30 : length, function, static_cast<ScopeType>(scope_type));
750 : }
751 :
752 882039 : RUNTIME_FUNCTION(Runtime_PushWithContext) {
753 294013 : HandleScope scope(isolate);
754 : DCHECK_EQ(3, args.length());
755 588026 : CONVERT_ARG_HANDLE_CHECKED(JSReceiver, extension_object, 0);
756 588026 : CONVERT_ARG_HANDLE_CHECKED(ScopeInfo, scope_info, 1);
757 588026 : CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 2);
758 294013 : Handle<Context> current(isolate->context());
759 : Handle<Context> context = isolate->factory()->NewWithContext(
760 294013 : function, current, scope_info, extension_object);
761 294013 : isolate->set_context(*context);
762 294013 : return *context;
763 : }
764 :
765 3750 : RUNTIME_FUNCTION(Runtime_PushModuleContext) {
766 1875 : HandleScope scope(isolate);
767 : DCHECK_EQ(3, args.length());
768 3750 : CONVERT_ARG_HANDLE_CHECKED(Module, module, 0);
769 3750 : CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 1);
770 3750 : CONVERT_ARG_HANDLE_CHECKED(ScopeInfo, scope_info, 2);
771 : DCHECK(function->context() == isolate->context());
772 :
773 : Handle<Context> context =
774 1875 : isolate->factory()->NewModuleContext(module, function, scope_info);
775 1875 : isolate->set_context(*context);
776 1875 : return *context;
777 : }
778 :
779 2722320 : RUNTIME_FUNCTION(Runtime_PushCatchContext) {
780 907440 : HandleScope scope(isolate);
781 : DCHECK_EQ(4, args.length());
782 1814880 : CONVERT_ARG_HANDLE_CHECKED(String, name, 0);
783 907440 : CONVERT_ARG_HANDLE_CHECKED(Object, thrown_object, 1);
784 1814880 : CONVERT_ARG_HANDLE_CHECKED(ScopeInfo, scope_info, 2);
785 1814880 : CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 3);
786 907440 : Handle<Context> current(isolate->context());
787 : Handle<Context> context = isolate->factory()->NewCatchContext(
788 907440 : function, current, scope_info, name, thrown_object);
789 907440 : isolate->set_context(*context);
790 907440 : return *context;
791 : }
792 :
793 :
794 252216 : RUNTIME_FUNCTION(Runtime_PushBlockContext) {
795 84072 : HandleScope scope(isolate);
796 : DCHECK_EQ(2, args.length());
797 168144 : CONVERT_ARG_HANDLE_CHECKED(ScopeInfo, scope_info, 0);
798 168144 : CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 1);
799 84072 : Handle<Context> current(isolate->context());
800 : Handle<Context> context =
801 84072 : isolate->factory()->NewBlockContext(function, current, scope_info);
802 84072 : isolate->set_context(*context);
803 84072 : return *context;
804 : }
805 :
806 :
807 1224 : RUNTIME_FUNCTION(Runtime_DeleteLookupSlot) {
808 408 : HandleScope scope(isolate);
809 : DCHECK_EQ(1, args.length());
810 816 : CONVERT_ARG_HANDLE_CHECKED(String, name, 0);
811 :
812 : int index;
813 : PropertyAttributes attributes;
814 : InitializationFlag flag;
815 : VariableMode mode;
816 : Handle<Object> holder = isolate->context()->Lookup(
817 408 : name, FOLLOW_CHAINS, &index, &attributes, &flag, &mode);
818 :
819 : // If the slot was not found the result is true.
820 408 : if (holder.is_null()) {
821 : // In case of JSProxy, an exception might have been thrown.
822 66 : if (isolate->has_pending_exception()) return isolate->heap()->exception();
823 66 : return isolate->heap()->true_value();
824 : }
825 :
826 : // If the slot was found in a context, it should be DONT_DELETE.
827 342 : if (holder->IsContext()) {
828 90 : return isolate->heap()->false_value();
829 : }
830 :
831 : // The slot was found in a JSReceiver, either a context extension object,
832 : // the global object, or the subject of a with. Try to delete it
833 : // (respecting DONT_DELETE).
834 252 : Handle<JSReceiver> object = Handle<JSReceiver>::cast(holder);
835 252 : Maybe<bool> result = JSReceiver::DeleteProperty(object, name);
836 252 : MAYBE_RETURN(result, isolate->heap()->exception());
837 252 : return isolate->heap()->ToBoolean(result.FromJust());
838 : }
839 :
840 :
841 : namespace {
842 :
843 1971417 : MaybeHandle<Object> LoadLookupSlot(Handle<String> name,
844 : Object::ShouldThrow should_throw,
845 : Handle<Object>* receiver_return = nullptr) {
846 1971417 : Isolate* const isolate = name->GetIsolate();
847 :
848 : int index;
849 : PropertyAttributes attributes;
850 : InitializationFlag flag;
851 : VariableMode mode;
852 : Handle<Object> holder = isolate->context()->Lookup(
853 1971417 : name, FOLLOW_CHAINS, &index, &attributes, &flag, &mode);
854 1971417 : if (isolate->has_pending_exception()) return MaybeHandle<Object>();
855 :
856 1971368 : if (index != Context::kNotFound) {
857 : DCHECK(holder->IsContext());
858 : // If the "property" we were looking for is a local variable, the
859 : // receiver is the global object; see ECMA-262, 3rd., 10.1.6 and 10.2.3.
860 : Handle<Object> receiver = isolate->factory()->undefined_value();
861 : Handle<Object> value = handle(Context::cast(*holder)->get(index), isolate);
862 : // Check for uninitialized bindings.
863 506647 : if (flag == kNeedsInitialization && value->IsTheHole(isolate)) {
864 1682 : THROW_NEW_ERROR(isolate,
865 : NewReferenceError(MessageTemplate::kNotDefined, name),
866 : Object);
867 : }
868 : DCHECK(!value->IsTheHole(isolate));
869 469898 : if (receiver_return) *receiver_return = receiver;
870 : return value;
871 : }
872 :
873 : // Otherwise, if the slot was found the holder is a context extension
874 : // object, subject of a with, or a global object. We read the named
875 : // property from it.
876 1500629 : if (!holder.is_null()) {
877 : // No need to unhole the value here. This is taken care of by the
878 : // GetProperty function.
879 : Handle<Object> value;
880 2999954 : ASSIGN_RETURN_ON_EXCEPTION(
881 : isolate, value, Object::GetProperty(holder, name),
882 : Object);
883 1499932 : if (receiver_return) {
884 : *receiver_return =
885 18822 : (holder->IsJSGlobalObject() || holder->IsJSContextExtensionObject())
886 : ? Handle<Object>::cast(isolate->factory()->undefined_value())
887 551882 : : holder;
888 : }
889 : return value;
890 : }
891 :
892 652 : if (should_throw == Object::THROW_ON_ERROR) {
893 : // The property doesn't exist - throw exception.
894 1138 : THROW_NEW_ERROR(
895 : isolate, NewReferenceError(MessageTemplate::kNotDefined, name), Object);
896 : }
897 :
898 : // The property doesn't exist - return undefined.
899 83 : if (receiver_return) *receiver_return = isolate->factory()->undefined_value();
900 : return isolate->factory()->undefined_value();
901 : }
902 :
903 : } // namespace
904 :
905 :
906 3370038 : RUNTIME_FUNCTION(Runtime_LoadLookupSlot) {
907 1685019 : HandleScope scope(isolate);
908 : DCHECK_EQ(1, args.length());
909 3370038 : CONVERT_ARG_HANDLE_CHECKED(String, name, 0);
910 3370038 : RETURN_RESULT_OR_FAILURE(isolate,
911 1685019 : LoadLookupSlot(name, Object::THROW_ON_ERROR));
912 : }
913 :
914 :
915 1298 : RUNTIME_FUNCTION(Runtime_LoadLookupSlotInsideTypeof) {
916 649 : HandleScope scope(isolate);
917 : DCHECK_EQ(1, args.length());
918 1298 : CONVERT_ARG_HANDLE_CHECKED(String, name, 0);
919 1947 : RETURN_RESULT_OR_FAILURE(isolate, LoadLookupSlot(name, Object::DONT_THROW));
920 : }
921 :
922 :
923 285749 : RUNTIME_FUNCTION_RETURN_PAIR(Runtime_LoadLookupSlotForCall) {
924 285749 : HandleScope scope(isolate);
925 : DCHECK_EQ(1, args.length());
926 : DCHECK(args[0]->IsString());
927 285749 : Handle<String> name = args.at<String>(0);
928 : Handle<Object> value;
929 : Handle<Object> receiver;
930 571498 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(
931 : isolate, value, LoadLookupSlot(name, Object::THROW_ON_ERROR, &receiver),
932 : MakePair(isolate->heap()->exception(), nullptr));
933 285719 : return MakePair(*value, *receiver);
934 : }
935 :
936 :
937 : namespace {
938 :
939 3481439 : MaybeHandle<Object> StoreLookupSlot(Handle<String> name, Handle<Object> value,
940 : LanguageMode language_mode) {
941 3481439 : Isolate* const isolate = name->GetIsolate();
942 : Handle<Context> context(isolate->context(), isolate);
943 :
944 : int index;
945 : PropertyAttributes attributes;
946 : InitializationFlag flag;
947 : VariableMode mode;
948 : Handle<Object> holder =
949 3481439 : context->Lookup(name, FOLLOW_CHAINS, &index, &attributes, &flag, &mode);
950 3481439 : if (holder.is_null()) {
951 : // In case of JSProxy, an exception might have been thrown.
952 747 : if (isolate->has_pending_exception()) return MaybeHandle<Object>();
953 : }
954 :
955 : // The property was found in a context slot.
956 3481376 : if (index != Context::kNotFound) {
957 2342994 : if (flag == kNeedsInitialization &&
958 253 : Handle<Context>::cast(holder)->is_the_hole(isolate, index)) {
959 168 : THROW_NEW_ERROR(isolate,
960 : NewReferenceError(MessageTemplate::kNotDefined, name),
961 : Object);
962 : }
963 2342657 : if ((attributes & READ_ONLY) == 0) {
964 4685136 : Handle<Context>::cast(holder)->set(index, *value);
965 89 : } else if (is_strict(language_mode)) {
966 : // Setting read only property in strict mode.
967 30 : THROW_NEW_ERROR(isolate,
968 : NewTypeError(MessageTemplate::kStrictCannotAssign, name),
969 : Object);
970 : }
971 : return value;
972 : }
973 :
974 : // Slow case: The property is not in a context slot. It is either in a
975 : // context extension object, a property of the subject of a with, or a
976 : // property of the global object.
977 : Handle<JSReceiver> object;
978 1138635 : if (attributes != ABSENT) {
979 : // The property exists on the holder.
980 : object = Handle<JSReceiver>::cast(holder);
981 684 : } else if (is_strict(language_mode)) {
982 : // If absent in strict mode: throw.
983 84 : THROW_NEW_ERROR(
984 : isolate, NewReferenceError(MessageTemplate::kNotDefined, name), Object);
985 : } else {
986 : // If absent in sloppy mode: add the property to the global object.
987 642 : object = Handle<JSReceiver>(context->global_object());
988 : }
989 :
990 2277186 : ASSIGN_RETURN_ON_EXCEPTION(
991 : isolate, value, Object::SetProperty(object, name, value, language_mode),
992 : Object);
993 : return value;
994 : }
995 :
996 : } // namespace
997 :
998 :
999 6955368 : RUNTIME_FUNCTION(Runtime_StoreLookupSlot_Sloppy) {
1000 3477684 : HandleScope scope(isolate);
1001 : DCHECK_EQ(2, args.length());
1002 6955368 : CONVERT_ARG_HANDLE_CHECKED(String, name, 0);
1003 3477684 : CONVERT_ARG_HANDLE_CHECKED(Object, value, 1);
1004 10433052 : RETURN_RESULT_OR_FAILURE(isolate, StoreLookupSlot(name, value, SLOPPY));
1005 : }
1006 :
1007 :
1008 7510 : RUNTIME_FUNCTION(Runtime_StoreLookupSlot_Strict) {
1009 3755 : HandleScope scope(isolate);
1010 : DCHECK_EQ(2, args.length());
1011 7510 : CONVERT_ARG_HANDLE_CHECKED(String, name, 0);
1012 3755 : CONVERT_ARG_HANDLE_CHECKED(Object, value, 1);
1013 11265 : RETURN_RESULT_OR_FAILURE(isolate, StoreLookupSlot(name, value, STRICT));
1014 : }
1015 :
1016 : } // namespace internal
1017 : } // namespace v8
|