• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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<FeedbackVector> feedback_vector=Handle<FeedbackVector> (),FeedbackSlot slot=FeedbackSlot::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<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   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       if (old_attributes & READ_ONLY || old_attributes & DONT_ENUM ||
90           (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         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     if (it.state() == LookupIterator::ACCESSOR) it.Delete();
108   }
109 
110   if (is_function_declaration) {
111     it.Restart();
112   }
113 
114   // Define or redefine own property.
115   RETURN_FAILURE_ON_EXCEPTION(
116       isolate, JSObject::DefineOwnPropertyIgnoreAttributes(&it, value, attr));
117 
118   if (!feedback_vector.is_null() &&
119       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     if (!global->HasNamedInterceptor() ||
124         global->GetNamedInterceptor()->non_masking()) {
125       LoadGlobalICNexus nexus(feedback_vector, slot);
126       nexus.ConfigurePropertyCellMode(it.GetPropertyCell());
127     }
128   }
129   return isolate->heap()->undefined_value();
130 }
131 
DeclareGlobals(Isolate * isolate,Handle<FixedArray> declarations,int flags,Handle<FeedbackVector> feedback_vector)132 Object* DeclareGlobals(Isolate* isolate, Handle<FixedArray> declarations,
133                        int flags, Handle<FeedbackVector> feedback_vector) {
134   HandleScope scope(isolate);
135   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   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   return isolate->heap()->undefined_value();
185 }
186 
187 }  // namespace
188 
RUNTIME_FUNCTION(Runtime_DeclareGlobals)189 RUNTIME_FUNCTION(Runtime_DeclareGlobals) {
190   HandleScope scope(isolate);
191   DCHECK_EQ(3, args.length());
192 
193   CONVERT_ARG_HANDLE_CHECKED(FixedArray, declarations, 0);
194   CONVERT_SMI_ARG_CHECKED(flags, 1);
195   CONVERT_ARG_HANDLE_CHECKED(FeedbackVector, feedback_vector, 2);
196 
197   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.
RUNTIME_FUNCTION(Runtime_DeclareGlobalsForInterpreter)202 RUNTIME_FUNCTION(Runtime_DeclareGlobalsForInterpreter) {
203   HandleScope scope(isolate);
204   DCHECK_EQ(3, args.length());
205 
206   CONVERT_ARG_HANDLE_CHECKED(FixedArray, declarations, 0);
207   CONVERT_SMI_ARG_CHECKED(flags, 1);
208   CONVERT_ARG_HANDLE_CHECKED(JSFunction, closure, 2);
209 
210   Handle<FeedbackVector> feedback_vector(closure->feedback_vector(), isolate);
211   return DeclareGlobals(isolate, declarations, flags, feedback_vector);
212 }
213 
RUNTIME_FUNCTION(Runtime_InitializeVarGlobal)214 RUNTIME_FUNCTION(Runtime_InitializeVarGlobal) {
215   HandleScope scope(isolate);
216   DCHECK_EQ(3, args.length());
217   CONVERT_ARG_HANDLE_CHECKED(String, name, 0);
218   CONVERT_LANGUAGE_MODE_ARG_CHECKED(language_mode, 1);
219   CONVERT_ARG_HANDLE_CHECKED(Object, value, 2);
220 
221   Handle<JSGlobalObject> global(isolate->global_object());
222   RETURN_RESULT_OR_FAILURE(
223       isolate, Object::SetProperty(global, name, value, language_mode));
224 }
225 
226 namespace {
227 
DeclareEvalHelper(Isolate * isolate,Handle<String> name,Handle<Object> value)228 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   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   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                       &mode);
253   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                                    RedeclarationType::kSyntaxError);
261   }
262 
263   Handle<Object> holder = context->Lookup(name, DONT_FOLLOW_CHAINS, &index,
264                                           &attributes, &init_flag, &mode);
265   DCHECK(!isolate->has_pending_exception());
266 
267   Handle<JSObject> object;
268 
269   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                          RedeclarationType::kTypeError);
275   }
276   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                          is_function, RedeclarationType::kTypeError);
281   } else if (context->IsScriptContext()) {
282     DCHECK(context->global_object()->IsJSGlobalObject());
283     Handle<JSGlobalObject> global(
284         JSGlobalObject::cast(context->global_object()), isolate);
285     return DeclareGlobal(isolate, global, name, value, NONE, is_var,
286                          is_function, RedeclarationType::kTypeError);
287   }
288 
289   if (attributes != ABSENT) {
290     DCHECK_EQ(NONE, attributes);
291 
292     // Skip var re-declarations.
293     if (is_var) return isolate->heap()->undefined_value();
294 
295     DCHECK(is_function);
296     if (index != Context::kNotFound) {
297       DCHECK(holder.is_identical_to(context));
298       context->set(index, *value);
299       return isolate->heap()->undefined_value();
300     }
301 
302     object = Handle<JSObject>::cast(holder);
303 
304   } 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     if (context->extension()->IsScopeInfo()) {
308       DCHECK(context->IsBlockContext());
309       object = isolate->factory()->NewJSObject(
310           isolate->context_extension_function());
311       Handle<HeapObject> extension = isolate->factory()->NewContextExtension(
312           handle(context->scope_info()), object);
313       context->set_extension(*extension);
314     } else {
315       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         isolate->factory()->NewJSObject(isolate->context_extension_function());
324     context->set_extension(*object);
325   }
326 
327   RETURN_FAILURE_ON_EXCEPTION(isolate, JSObject::SetOwnPropertyIgnoreAttributes(
328                                            object, name, value, NONE));
329 
330   return isolate->heap()->undefined_value();
331 }
332 
333 }  // namespace
334 
RUNTIME_FUNCTION(Runtime_DeclareEvalFunction)335 RUNTIME_FUNCTION(Runtime_DeclareEvalFunction) {
336   HandleScope scope(isolate);
337   DCHECK_EQ(2, args.length());
338   CONVERT_ARG_HANDLE_CHECKED(String, name, 0);
339   CONVERT_ARG_HANDLE_CHECKED(Object, value, 1);
340   return DeclareEvalHelper(isolate, name, value);
341 }
342 
RUNTIME_FUNCTION(Runtime_DeclareEvalVar)343 RUNTIME_FUNCTION(Runtime_DeclareEvalVar) {
344   HandleScope scope(isolate);
345   DCHECK_EQ(1, args.length());
346   CONVERT_ARG_HANDLE_CHECKED(String, name, 0);
347   return DeclareEvalHelper(isolate, name,
348                            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.
GetCallerArguments(Isolate * isolate,int * total_argc)355 std::unique_ptr<Handle<Object>[]> GetCallerArguments(Isolate* isolate,
356                                                      int* total_argc) {
357   // Find frame containing arguments passed to the caller.
358   JavaScriptFrameIterator it(isolate);
359   JavaScriptFrame* frame = it.frame();
360   List<SharedFunctionInfo*> functions(2);
361   frame->GetFunctions(&functions);
362   if (functions.length() > 1) {
363     int inlined_jsframe_index = functions.length() - 1;
364     TranslatedState translated_values(frame);
365     translated_values.Prepare(false, frame->fp());
366 
367     int argument_count = 0;
368     TranslatedFrame* translated_frame =
369         translated_values.GetArgumentsInfoFromJSFrameIndex(
370             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     argument_count--;
379 
380     *total_argc = argument_count;
381     std::unique_ptr<Handle<Object>[]> param_data(
382         NewArray<Handle<Object>>(*total_argc));
383     bool should_deoptimize = false;
384     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       should_deoptimize = should_deoptimize || iter->IsMaterializedObject();
388       Handle<Object> value = iter->GetValue();
389       param_data[i] = value;
390       iter++;
391     }
392 
393     if (should_deoptimize) {
394       translated_values.StoreMaterializedValuesAndDeopt(frame);
395     }
396 
397     return param_data;
398   } else {
399     it.AdvanceToArgumentsFrame();
400     frame = it.frame();
401     int args_count = frame->ComputeParametersCount();
402 
403     *total_argc = args_count;
404     std::unique_ptr<Handle<Object>[]> param_data(
405         NewArray<Handle<Object>>(*total_argc));
406     for (int i = 0; i < args_count; i++) {
407       Handle<Object> val = Handle<Object>(frame->GetParameter(i), isolate);
408       param_data[i] = val;
409     }
410     return param_data;
411   }
412 }
413 
414 template <typename T>
NewSloppyArguments(Isolate * isolate,Handle<JSFunction> callee,T parameters,int argument_count)415 Handle<JSObject> NewSloppyArguments(Isolate* isolate, Handle<JSFunction> callee,
416                                     T parameters, int argument_count) {
417   CHECK(!IsDerivedConstructor(callee->shared()->kind()));
418   DCHECK(callee->shared()->has_simple_parameters());
419   Handle<JSObject> result =
420       isolate->factory()->NewArgumentsObject(callee, argument_count);
421 
422   // Allocate the elements if needed.
423   int parameter_count = callee->shared()->internal_formal_parameter_count();
424   if (argument_count > 0) {
425     if (parameter_count > 0) {
426       int mapped_count = Min(argument_count, parameter_count);
427       Handle<FixedArray> parameter_map =
428           isolate->factory()->NewFixedArray(mapped_count + 2, NOT_TENURED);
429       parameter_map->set_map(isolate->heap()->sloppy_arguments_elements_map());
430       result->set_map(isolate->native_context()->fast_aliased_arguments_map());
431       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           isolate->factory()->NewFixedArray(argument_count, NOT_TENURED);
438       parameter_map->set(0, *context);
439       parameter_map->set(1, *arguments);
440 
441       // Loop over the actual parameters backwards.
442       int index = argument_count - 1;
443       while (index >= mapped_count) {
444         // These go directly in the arguments array and have no
445         // corresponding slot in the parameter map.
446         arguments->set(index, parameters[index]);
447         --index;
448       }
449 
450       Handle<ScopeInfo> scope_info(callee->shared()->scope_info());
451       while (index >= 0) {
452         // Detect duplicate names to the right in the parameter list.
453         Handle<String> name(scope_info->ParameterName(index));
454         int context_local_count = scope_info->ContextLocalCount();
455         bool duplicate = false;
456         for (int j = index + 1; j < parameter_count; ++j) {
457           if (scope_info->ParameterName(j) == *name) {
458             duplicate = true;
459             break;
460           }
461         }
462 
463         if (duplicate) {
464           // This goes directly in the arguments array with a hole in the
465           // parameter map.
466           arguments->set(index, parameters[index]);
467           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           for (int j = 0; j < context_local_count; ++j) {
473             if (scope_info->ContextLocalName(j) == *name) {
474               context_index = j;
475               break;
476             }
477           }
478 
479           DCHECK(context_index >= 0);
480           arguments->set_the_hole(index);
481           parameter_map->set(
482               index + 2,
483               Smi::FromInt(Context::MIN_CONTEXT_SLOTS + context_index));
484         }
485 
486         --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           isolate->factory()->NewFixedArray(argument_count, NOT_TENURED);
493       result->set_elements(*elements);
494       for (int i = 0; i < argument_count; ++i) {
495         elements->set(i, parameters[i]);
496       }
497     }
498   }
499   return result;
500 }
501 
502 
503 class HandleArguments BASE_EMBEDDED {
504  public:
HandleArguments(Handle<Object> * array)505   explicit HandleArguments(Handle<Object>* array) : array_(array) {}
operator [](int index)506   Object* operator[](int index) { return *array_[index]; }
507 
508  private:
509   Handle<Object>* array_;
510 };
511 
512 
513 class ParameterArguments BASE_EMBEDDED {
514  public:
ParameterArguments(Object ** parameters)515   explicit ParameterArguments(Object** parameters) : parameters_(parameters) {}
operator [](int index)516   Object*& operator[](int index) { return *(parameters_ - index - 1); }
517 
518  private:
519   Object** parameters_;
520 };
521 
522 }  // namespace
523 
524 
RUNTIME_FUNCTION(Runtime_NewSloppyArguments_Generic)525 RUNTIME_FUNCTION(Runtime_NewSloppyArguments_Generic) {
526   HandleScope scope(isolate);
527   DCHECK_EQ(1, args.length());
528   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   int argument_count = 0;
532   std::unique_ptr<Handle<Object>[]> arguments =
533       GetCallerArguments(isolate, &argument_count);
534   HandleArguments argument_getter(arguments.get());
535   return *NewSloppyArguments(isolate, callee, argument_getter, argument_count);
536 }
537 
538 
RUNTIME_FUNCTION(Runtime_NewStrictArguments)539 RUNTIME_FUNCTION(Runtime_NewStrictArguments) {
540   HandleScope scope(isolate);
541   DCHECK_EQ(1, args.length());
542   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   int argument_count = 0;
546   std::unique_ptr<Handle<Object>[]> arguments =
547       GetCallerArguments(isolate, &argument_count);
548   Handle<JSObject> result =
549       isolate->factory()->NewArgumentsObject(callee, argument_count);
550   if (argument_count) {
551     Handle<FixedArray> array =
552         isolate->factory()->NewUninitializedFixedArray(argument_count);
553     DisallowHeapAllocation no_gc;
554     WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
555     for (int i = 0; i < argument_count; i++) {
556       array->set(i, *arguments[i], mode);
557     }
558     result->set_elements(*array);
559   }
560   return *result;
561 }
562 
563 
RUNTIME_FUNCTION(Runtime_NewRestParameter)564 RUNTIME_FUNCTION(Runtime_NewRestParameter) {
565   HandleScope scope(isolate);
566   DCHECK_EQ(1, args.length());
567   CONVERT_ARG_HANDLE_CHECKED(JSFunction, callee, 0)
568   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   int argument_count = 0;
572   std::unique_ptr<Handle<Object>[]> arguments =
573       GetCallerArguments(isolate, &argument_count);
574   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                                      DONT_INITIALIZE_ARRAY_ELEMENTS);
578   {
579     DisallowHeapAllocation no_gc;
580     FixedArray* elements = FixedArray::cast(result->elements());
581     WriteBarrierMode mode = elements->GetWriteBarrierMode(no_gc);
582     for (int i = 0; i < num_elements; i++) {
583       elements->set(i, *arguments[i + start_index], mode);
584     }
585   }
586   return *result;
587 }
588 
589 
RUNTIME_FUNCTION(Runtime_NewSloppyArguments)590 RUNTIME_FUNCTION(Runtime_NewSloppyArguments) {
591   HandleScope scope(isolate);
592   DCHECK_EQ(1, args.length());
593   CONVERT_ARG_HANDLE_CHECKED(JSFunction, callee, 0);
594   StackFrameIterator iterator(isolate);
595 
596   // Stub/interpreter handler frame
597   iterator.Advance();
598   DCHECK(iterator.frame()->type() == StackFrame::STUB);
599 
600   // Function frame
601   iterator.Advance();
602   JavaScriptFrame* function_frame = JavaScriptFrame::cast(iterator.frame());
603   DCHECK(function_frame->is_java_script());
604   int argc = function_frame->GetArgumentsLength();
605   Address fp = function_frame->fp();
606   if (function_frame->has_adapted_arguments()) {
607     iterator.Advance();
608     fp = iterator.frame()->fp();
609   }
610 
611   Object** parameters = reinterpret_cast<Object**>(
612       fp + argc * kPointerSize + StandardFrameConstants::kCallerSPOffset);
613   ParameterArguments argument_getter(parameters);
614   return *NewSloppyArguments(isolate, callee, argument_getter, argc);
615 }
616 
RUNTIME_FUNCTION(Runtime_NewArgumentsElements)617 RUNTIME_FUNCTION(Runtime_NewArgumentsElements) {
618   HandleScope scope(isolate);
619   DCHECK_EQ(2, args.length());
620   Object** frame = reinterpret_cast<Object**>(args[0]);
621   CONVERT_SMI_ARG_CHECKED(length, 1);
622   Handle<FixedArray> result =
623       isolate->factory()->NewUninitializedFixedArray(length);
624   int const offset = length + 1;
625   DisallowHeapAllocation no_gc;
626   WriteBarrierMode mode = result->GetWriteBarrierMode(no_gc);
627   for (int index = 0; index < length; ++index) {
628     result->set(index, frame[offset - index], mode);
629   }
630   return *result;
631 }
632 
RUNTIME_FUNCTION(Runtime_NewClosure)633 RUNTIME_FUNCTION(Runtime_NewClosure) {
634   HandleScope scope(isolate);
635   DCHECK_EQ(3, args.length());
636   CONVERT_ARG_HANDLE_CHECKED(SharedFunctionInfo, shared, 0);
637   CONVERT_ARG_HANDLE_CHECKED(FeedbackVector, vector, 1);
638   CONVERT_SMI_ARG_CHECKED(index, 2);
639   Handle<Context> context(isolate->context(), isolate);
640   FeedbackSlot slot = FeedbackVector::ToSlot(index);
641   Handle<Cell> vector_cell(Cell::cast(vector->Get(slot)), isolate);
642   Handle<JSFunction> function =
643       isolate->factory()->NewFunctionFromSharedFunctionInfo(
644           shared, context, vector_cell, NOT_TENURED);
645   return *function;
646 }
647 
648 
RUNTIME_FUNCTION(Runtime_NewClosure_Tenured)649 RUNTIME_FUNCTION(Runtime_NewClosure_Tenured) {
650   HandleScope scope(isolate);
651   DCHECK_EQ(3, args.length());
652   CONVERT_ARG_HANDLE_CHECKED(SharedFunctionInfo, shared, 0);
653   CONVERT_ARG_HANDLE_CHECKED(FeedbackVector, vector, 1);
654   CONVERT_SMI_ARG_CHECKED(index, 2);
655   Handle<Context> context(isolate->context(), isolate);
656   FeedbackSlot slot = FeedbackVector::ToSlot(index);
657   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           shared, context, vector_cell, TENURED);
663   return *function;
664 }
665 
FindNameClash(Handle<ScopeInfo> scope_info,Handle<JSGlobalObject> global_object,Handle<ScriptContextTable> script_context)666 static Object* FindNameClash(Handle<ScopeInfo> scope_info,
667                              Handle<JSGlobalObject> global_object,
668                              Handle<ScriptContextTable> script_context) {
669   Isolate* isolate = scope_info->GetIsolate();
670   for (int var = 0; var < scope_info->ContextLocalCount(); var++) {
671     Handle<String> name(scope_info->ContextLocalName(var));
672     VariableMode mode = scope_info->ContextLocalMode(var);
673     ScriptContextTable::LookupResult lookup;
674     if (ScriptContextTable::Lookup(script_context, name, &lookup)) {
675       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                                        RedeclarationType::kSyntaxError);
681       }
682     }
683 
684     if (IsLexicalVariableMode(mode)) {
685       LookupIterator it(global_object, name, global_object,
686                         LookupIterator::OWN_SKIP_INTERCEPTOR);
687       Maybe<PropertyAttributes> maybe = JSReceiver::GetPropertyAttributes(&it);
688       if (!maybe.IsJust()) return isolate->heap()->exception();
689       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                                        RedeclarationType::kSyntaxError);
697       }
698 
699       JSGlobalObject::InvalidatePropertyCell(global_object, name);
700     }
701   }
702   return isolate->heap()->undefined_value();
703 }
704 
705 
RUNTIME_FUNCTION(Runtime_NewScriptContext)706 RUNTIME_FUNCTION(Runtime_NewScriptContext) {
707   HandleScope scope(isolate);
708   DCHECK_EQ(2, args.length());
709 
710   CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
711   CONVERT_ARG_HANDLE_CHECKED(ScopeInfo, scope_info, 1);
712   Handle<JSGlobalObject> global_object(function->context()->global_object());
713   Handle<Context> native_context(global_object->native_context());
714   Handle<ScriptContextTable> script_context_table(
715       native_context->script_context_table());
716 
717   Object* name_clash_result =
718       FindNameClash(scope_info, global_object, script_context_table);
719   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   Handle<JSFunction> closure(function->shared()->IsUserJavaScript()
725                                  ? native_context->closure()
726                                  : *function);
727   Handle<Context> result =
728       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       ScriptContextTable::Extend(script_context_table, result);
735   native_context->set_script_context_table(*new_script_context_table);
736   return *result;
737 }
738 
RUNTIME_FUNCTION(Runtime_NewFunctionContext)739 RUNTIME_FUNCTION(Runtime_NewFunctionContext) {
740   HandleScope scope(isolate);
741   DCHECK_EQ(2, args.length());
742 
743   CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
744   CONVERT_SMI_ARG_CHECKED(scope_type, 1);
745 
746   DCHECK(function->context() == isolate->context());
747   int length = function->shared()->scope_info()->ContextLength();
748   return *isolate->factory()->NewFunctionContext(
749       length, function, static_cast<ScopeType>(scope_type));
750 }
751 
RUNTIME_FUNCTION(Runtime_PushWithContext)752 RUNTIME_FUNCTION(Runtime_PushWithContext) {
753   HandleScope scope(isolate);
754   DCHECK_EQ(3, args.length());
755   CONVERT_ARG_HANDLE_CHECKED(JSReceiver, extension_object, 0);
756   CONVERT_ARG_HANDLE_CHECKED(ScopeInfo, scope_info, 1);
757   CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 2);
758   Handle<Context> current(isolate->context());
759   Handle<Context> context = isolate->factory()->NewWithContext(
760       function, current, scope_info, extension_object);
761   isolate->set_context(*context);
762   return *context;
763 }
764 
RUNTIME_FUNCTION(Runtime_PushModuleContext)765 RUNTIME_FUNCTION(Runtime_PushModuleContext) {
766   HandleScope scope(isolate);
767   DCHECK_EQ(3, args.length());
768   CONVERT_ARG_HANDLE_CHECKED(Module, module, 0);
769   CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 1);
770   CONVERT_ARG_HANDLE_CHECKED(ScopeInfo, scope_info, 2);
771   DCHECK(function->context() == isolate->context());
772 
773   Handle<Context> context =
774       isolate->factory()->NewModuleContext(module, function, scope_info);
775   isolate->set_context(*context);
776   return *context;
777 }
778 
RUNTIME_FUNCTION(Runtime_PushCatchContext)779 RUNTIME_FUNCTION(Runtime_PushCatchContext) {
780   HandleScope scope(isolate);
781   DCHECK_EQ(4, args.length());
782   CONVERT_ARG_HANDLE_CHECKED(String, name, 0);
783   CONVERT_ARG_HANDLE_CHECKED(Object, thrown_object, 1);
784   CONVERT_ARG_HANDLE_CHECKED(ScopeInfo, scope_info, 2);
785   CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 3);
786   Handle<Context> current(isolate->context());
787   Handle<Context> context = isolate->factory()->NewCatchContext(
788       function, current, scope_info, name, thrown_object);
789   isolate->set_context(*context);
790   return *context;
791 }
792 
793 
RUNTIME_FUNCTION(Runtime_PushBlockContext)794 RUNTIME_FUNCTION(Runtime_PushBlockContext) {
795   HandleScope scope(isolate);
796   DCHECK_EQ(2, args.length());
797   CONVERT_ARG_HANDLE_CHECKED(ScopeInfo, scope_info, 0);
798   CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 1);
799   Handle<Context> current(isolate->context());
800   Handle<Context> context =
801       isolate->factory()->NewBlockContext(function, current, scope_info);
802   isolate->set_context(*context);
803   return *context;
804 }
805 
806 
RUNTIME_FUNCTION(Runtime_DeleteLookupSlot)807 RUNTIME_FUNCTION(Runtime_DeleteLookupSlot) {
808   HandleScope scope(isolate);
809   DCHECK_EQ(1, args.length());
810   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       name, FOLLOW_CHAINS, &index, &attributes, &flag, &mode);
818 
819   // If the slot was not found the result is true.
820   if (holder.is_null()) {
821     // In case of JSProxy, an exception might have been thrown.
822     if (isolate->has_pending_exception()) return isolate->heap()->exception();
823     return isolate->heap()->true_value();
824   }
825 
826   // If the slot was found in a context, it should be DONT_DELETE.
827   if (holder->IsContext()) {
828     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   Handle<JSReceiver> object = Handle<JSReceiver>::cast(holder);
835   Maybe<bool> result = JSReceiver::DeleteProperty(object, name);
836   MAYBE_RETURN(result, isolate->heap()->exception());
837   return isolate->heap()->ToBoolean(result.FromJust());
838 }
839 
840 
841 namespace {
842 
LoadLookupSlot(Handle<String> name,Object::ShouldThrow should_throw,Handle<Object> * receiver_return=nullptr)843 MaybeHandle<Object> LoadLookupSlot(Handle<String> name,
844                                    Object::ShouldThrow should_throw,
845                                    Handle<Object>* receiver_return = nullptr) {
846   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       name, FOLLOW_CHAINS, &index, &attributes, &flag, &mode);
854   if (isolate->has_pending_exception()) return MaybeHandle<Object>();
855 
856   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     if (flag == kNeedsInitialization && value->IsTheHole(isolate)) {
864       THROW_NEW_ERROR(isolate,
865                       NewReferenceError(MessageTemplate::kNotDefined, name),
866                       Object);
867     }
868     DCHECK(!value->IsTheHole(isolate));
869     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   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     ASSIGN_RETURN_ON_EXCEPTION(
881         isolate, value, Object::GetProperty(holder, name),
882         Object);
883     if (receiver_return) {
884       *receiver_return =
885           (holder->IsJSGlobalObject() || holder->IsJSContextExtensionObject())
886               ? Handle<Object>::cast(isolate->factory()->undefined_value())
887               : holder;
888     }
889     return value;
890   }
891 
892   if (should_throw == Object::THROW_ON_ERROR) {
893     // The property doesn't exist - throw exception.
894     THROW_NEW_ERROR(
895         isolate, NewReferenceError(MessageTemplate::kNotDefined, name), Object);
896   }
897 
898   // The property doesn't exist - return undefined.
899   if (receiver_return) *receiver_return = isolate->factory()->undefined_value();
900   return isolate->factory()->undefined_value();
901 }
902 
903 }  // namespace
904 
905 
RUNTIME_FUNCTION(Runtime_LoadLookupSlot)906 RUNTIME_FUNCTION(Runtime_LoadLookupSlot) {
907   HandleScope scope(isolate);
908   DCHECK_EQ(1, args.length());
909   CONVERT_ARG_HANDLE_CHECKED(String, name, 0);
910   RETURN_RESULT_OR_FAILURE(isolate,
911                            LoadLookupSlot(name, Object::THROW_ON_ERROR));
912 }
913 
914 
RUNTIME_FUNCTION(Runtime_LoadLookupSlotInsideTypeof)915 RUNTIME_FUNCTION(Runtime_LoadLookupSlotInsideTypeof) {
916   HandleScope scope(isolate);
917   DCHECK_EQ(1, args.length());
918   CONVERT_ARG_HANDLE_CHECKED(String, name, 0);
919   RETURN_RESULT_OR_FAILURE(isolate, LoadLookupSlot(name, Object::DONT_THROW));
920 }
921 
922 
RUNTIME_FUNCTION_RETURN_PAIR(Runtime_LoadLookupSlotForCall)923 RUNTIME_FUNCTION_RETURN_PAIR(Runtime_LoadLookupSlotForCall) {
924   HandleScope scope(isolate);
925   DCHECK_EQ(1, args.length());
926   DCHECK(args[0]->IsString());
927   Handle<String> name = args.at<String>(0);
928   Handle<Object> value;
929   Handle<Object> receiver;
930   ASSIGN_RETURN_ON_EXCEPTION_VALUE(
931       isolate, value, LoadLookupSlot(name, Object::THROW_ON_ERROR, &receiver),
932       MakePair(isolate->heap()->exception(), nullptr));
933   return MakePair(*value, *receiver);
934 }
935 
936 
937 namespace {
938 
StoreLookupSlot(Handle<String> name,Handle<Object> value,LanguageMode language_mode)939 MaybeHandle<Object> StoreLookupSlot(Handle<String> name, Handle<Object> value,
940                                     LanguageMode language_mode) {
941   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       context->Lookup(name, FOLLOW_CHAINS, &index, &attributes, &flag, &mode);
950   if (holder.is_null()) {
951     // In case of JSProxy, an exception might have been thrown.
952     if (isolate->has_pending_exception()) return MaybeHandle<Object>();
953   }
954 
955   // The property was found in a context slot.
956   if (index != Context::kNotFound) {
957     if (flag == kNeedsInitialization &&
958         Handle<Context>::cast(holder)->is_the_hole(isolate, index)) {
959       THROW_NEW_ERROR(isolate,
960                       NewReferenceError(MessageTemplate::kNotDefined, name),
961                       Object);
962     }
963     if ((attributes & READ_ONLY) == 0) {
964       Handle<Context>::cast(holder)->set(index, *value);
965     } else if (is_strict(language_mode)) {
966       // Setting read only property in strict mode.
967       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   if (attributes != ABSENT) {
979     // The property exists on the holder.
980     object = Handle<JSReceiver>::cast(holder);
981   } else if (is_strict(language_mode)) {
982     // If absent in strict mode: throw.
983     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     object = Handle<JSReceiver>(context->global_object());
988   }
989 
990   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 
RUNTIME_FUNCTION(Runtime_StoreLookupSlot_Sloppy)999 RUNTIME_FUNCTION(Runtime_StoreLookupSlot_Sloppy) {
1000   HandleScope scope(isolate);
1001   DCHECK_EQ(2, args.length());
1002   CONVERT_ARG_HANDLE_CHECKED(String, name, 0);
1003   CONVERT_ARG_HANDLE_CHECKED(Object, value, 1);
1004   RETURN_RESULT_OR_FAILURE(isolate, StoreLookupSlot(name, value, SLOPPY));
1005 }
1006 
1007 
RUNTIME_FUNCTION(Runtime_StoreLookupSlot_Strict)1008 RUNTIME_FUNCTION(Runtime_StoreLookupSlot_Strict) {
1009   HandleScope scope(isolate);
1010   DCHECK_EQ(2, args.length());
1011   CONVERT_ARG_HANDLE_CHECKED(String, name, 0);
1012   CONVERT_ARG_HANDLE_CHECKED(Object, value, 1);
1013   RETURN_RESULT_OR_FAILURE(isolate, StoreLookupSlot(name, value, STRICT));
1014 }
1015 
1016 }  // namespace internal
1017 }  // namespace v8
1018