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