• 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 <memory>
6 
7 #include "src/ast/scopes.h"
8 #include "src/builtins/accessors.h"
9 #include "src/common/message-template.h"
10 #include "src/deoptimizer/deoptimizer.h"
11 #include "src/execution/arguments-inl.h"
12 #include "src/execution/frames-inl.h"
13 #include "src/execution/isolate-inl.h"
14 #include "src/execution/isolate.h"
15 #include "src/heap/heap-inl.h"  // For ToBoolean. TODO(jkummerow): Drop.
16 #include "src/init/bootstrapper.h"
17 #include "src/logging/counters.h"
18 #include "src/objects/arguments-inl.h"
19 #include "src/objects/heap-object-inl.h"
20 #include "src/objects/module-inl.h"
21 #include "src/objects/smi.h"
22 #include "src/runtime/runtime-utils.h"
23 
24 namespace v8 {
25 namespace internal {
26 
RUNTIME_FUNCTION(Runtime_ThrowConstAssignError)27 RUNTIME_FUNCTION(Runtime_ThrowConstAssignError) {
28   HandleScope scope(isolate);
29   THROW_NEW_ERROR_RETURN_FAILURE(isolate,
30                                  NewTypeError(MessageTemplate::kConstAssign));
31 }
32 
33 namespace {
34 
35 enum class RedeclarationType { kSyntaxError = 0, kTypeError = 1 };
36 
ThrowRedeclarationError(Isolate * isolate,Handle<String> name,RedeclarationType redeclaration_type)37 Object ThrowRedeclarationError(Isolate* isolate, Handle<String> name,
38                                RedeclarationType redeclaration_type) {
39   HandleScope scope(isolate);
40   if (redeclaration_type == RedeclarationType::kSyntaxError) {
41     THROW_NEW_ERROR_RETURN_FAILURE(
42         isolate, NewSyntaxError(MessageTemplate::kVarRedeclaration, name));
43   } else {
44     THROW_NEW_ERROR_RETURN_FAILURE(
45         isolate, NewTypeError(MessageTemplate::kVarRedeclaration, name));
46   }
47 }
48 
49 // May throw a RedeclarationError.
DeclareGlobal(Isolate * isolate,Handle<JSGlobalObject> global,Handle<String> name,Handle<Object> value,PropertyAttributes attr,bool is_var,RedeclarationType redeclaration_type)50 Object DeclareGlobal(Isolate* isolate, Handle<JSGlobalObject> global,
51                      Handle<String> name, Handle<Object> value,
52                      PropertyAttributes attr, bool is_var,
53                      RedeclarationType redeclaration_type) {
54   Handle<ScriptContextTable> script_contexts(
55       global->native_context().script_context_table(), isolate);
56   VariableLookupResult lookup;
57   if (script_contexts->Lookup(name, &lookup) &&
58       IsLexicalVariableMode(lookup.mode)) {
59     // ES#sec-globaldeclarationinstantiation 6.a:
60     // If envRec.HasLexicalDeclaration(name) is true, throw a SyntaxError
61     // exception.
62     return ThrowRedeclarationError(isolate, name,
63                                    RedeclarationType::kSyntaxError);
64   }
65 
66   // Do the lookup own properties only, see ES5 erratum.
67   LookupIterator::Configuration lookup_config(
68       LookupIterator::Configuration::OWN_SKIP_INTERCEPTOR);
69   if (!is_var) {
70     // For function declarations, use the interceptor on the declaration. For
71     // non-functions, use it only on initialization.
72     lookup_config = LookupIterator::Configuration::OWN;
73   }
74   LookupIterator it(isolate, global, name, global, lookup_config);
75   Maybe<PropertyAttributes> maybe = JSReceiver::GetPropertyAttributes(&it);
76   if (maybe.IsNothing()) return ReadOnlyRoots(isolate).exception();
77 
78   if (it.IsFound()) {
79     PropertyAttributes old_attributes = maybe.FromJust();
80     // The name was declared before; check for conflicting re-declarations.
81 
82     // Skip var re-declarations.
83     if (is_var) return ReadOnlyRoots(isolate).undefined_value();
84 
85     if ((old_attributes & DONT_DELETE) != 0) {
86       // Only allow reconfiguring globals to functions in user code (no
87       // natives, which are marked as read-only).
88       DCHECK_EQ(attr & READ_ONLY, 0);
89 
90       // Check whether we can reconfigure the existing property into a
91       // function.
92       if (old_attributes & READ_ONLY || old_attributes & DONT_ENUM ||
93           (it.state() == LookupIterator::ACCESSOR)) {
94         // ECMA-262 section 15.1.11 GlobalDeclarationInstantiation 5.d:
95         // If hasRestrictedGlobal is true, throw a SyntaxError exception.
96         // ECMA-262 section 18.2.1.3 EvalDeclarationInstantiation 8.a.iv.1.b:
97         // If fnDefinable is false, throw a TypeError exception.
98         return ThrowRedeclarationError(isolate, name, redeclaration_type);
99       }
100       // If the existing property is not configurable, keep its attributes. Do
101       attr = old_attributes;
102     }
103 
104     // If the current state is ACCESSOR, this could mean it's an AccessorInfo
105     // type property. We are not allowed to call into such setters during global
106     // function declaration since this would break e.g., onload. Meaning
107     // 'function onload() {}' would invalidly register that function as the
108     // onload callback. To avoid this situation, we first delete the property
109     // before readding it as a regular data property below.
110     if (it.state() == LookupIterator::ACCESSOR) it.Delete();
111   }
112 
113   if (!is_var) it.Restart();
114 
115   // Define or redefine own property.
116   RETURN_FAILURE_ON_EXCEPTION(
117       isolate, JSObject::DefineOwnPropertyIgnoreAttributes(&it, value, attr));
118 
119   return ReadOnlyRoots(isolate).undefined_value();
120 }
121 
122 }  // namespace
123 
RUNTIME_FUNCTION(Runtime_DeclareModuleExports)124 RUNTIME_FUNCTION(Runtime_DeclareModuleExports) {
125   HandleScope scope(isolate);
126   DCHECK_EQ(2, args.length());
127 
128   Handle<FixedArray> declarations = args.at<FixedArray>(0);
129   Handle<JSFunction> closure = args.at<JSFunction>(1);
130 
131   Handle<ClosureFeedbackCellArray> closure_feedback_cell_array =
132       Handle<ClosureFeedbackCellArray>::null();
133   if (closure->has_feedback_vector()) {
134     closure_feedback_cell_array = Handle<ClosureFeedbackCellArray>(
135         closure->feedback_vector().closure_feedback_cell_array(), isolate);
136   } else {
137     closure_feedback_cell_array = Handle<ClosureFeedbackCellArray>(
138         closure->closure_feedback_cell_array(), isolate);
139   }
140 
141   Handle<Context> context(isolate->context(), isolate);
142   DCHECK(context->IsModuleContext());
143   Handle<FixedArray> exports(
144       SourceTextModule::cast(context->extension()).regular_exports(), isolate);
145 
146   int length = declarations->length();
147   FOR_WITH_HANDLE_SCOPE(isolate, int, i = 0, i, i < length, i++, {
148     Object decl = declarations->get(i);
149     int index;
150     Object value;
151     if (decl.IsSmi()) {
152       index = Smi::ToInt(decl);
153       value = ReadOnlyRoots(isolate).the_hole_value();
154     } else {
155       Handle<SharedFunctionInfo> sfi(
156           SharedFunctionInfo::cast(declarations->get(i)), isolate);
157       int feedback_index = Smi::ToInt(declarations->get(++i));
158       index = Smi::ToInt(declarations->get(++i));
159       Handle<FeedbackCell> feedback_cell =
160           closure_feedback_cell_array->GetFeedbackCell(feedback_index);
161       value = *Factory::JSFunctionBuilder(isolate, sfi, context)
162                    .set_feedback_cell(feedback_cell)
163                    .Build();
164     }
165 
166     Cell::cast(exports->get(index - 1)).set_value(value);
167   });
168 
169   return ReadOnlyRoots(isolate).undefined_value();
170 }
171 
RUNTIME_FUNCTION(Runtime_DeclareGlobals)172 RUNTIME_FUNCTION(Runtime_DeclareGlobals) {
173   HandleScope scope(isolate);
174   DCHECK_EQ(2, args.length());
175 
176   Handle<FixedArray> declarations = args.at<FixedArray>(0);
177   Handle<JSFunction> closure = args.at<JSFunction>(1);
178 
179   Handle<JSGlobalObject> global(isolate->global_object());
180   Handle<Context> context(isolate->context(), isolate);
181 
182   Handle<ClosureFeedbackCellArray> closure_feedback_cell_array =
183       Handle<ClosureFeedbackCellArray>::null();
184   if (closure->has_feedback_vector()) {
185     closure_feedback_cell_array = Handle<ClosureFeedbackCellArray>(
186         closure->feedback_vector().closure_feedback_cell_array(), isolate);
187   } else {
188     closure_feedback_cell_array = Handle<ClosureFeedbackCellArray>(
189         closure->closure_feedback_cell_array(), isolate);
190   }
191 
192   // Traverse the name/value pairs and set the properties.
193   int length = declarations->length();
194   FOR_WITH_HANDLE_SCOPE(isolate, int, i = 0, i, i < length, i++, {
195     Handle<Object> decl(declarations->get(i), isolate);
196     Handle<String> name;
197     Handle<Object> value;
198     bool is_var = decl->IsString();
199 
200     if (is_var) {
201       name = Handle<String>::cast(decl);
202       value = isolate->factory()->undefined_value();
203     } else {
204       Handle<SharedFunctionInfo> sfi = Handle<SharedFunctionInfo>::cast(decl);
205       name = handle(sfi->Name(), isolate);
206       int index = Smi::ToInt(declarations->get(++i));
207       Handle<FeedbackCell> feedback_cell =
208           closure_feedback_cell_array->GetFeedbackCell(index);
209       value = Factory::JSFunctionBuilder(isolate, sfi, context)
210                   .set_feedback_cell(feedback_cell)
211                   .Build();
212     }
213 
214     // Compute the property attributes. According to ECMA-262,
215     // the property must be non-configurable except in eval.
216     Script script = Script::cast(closure->shared().script());
217     PropertyAttributes attr =
218         script.compilation_type() == Script::COMPILATION_TYPE_EVAL
219             ? NONE
220             : DONT_DELETE;
221 
222     // ES#sec-globaldeclarationinstantiation 5.d:
223     // If hasRestrictedGlobal is true, throw a SyntaxError exception.
224     Object result = DeclareGlobal(isolate, global, name, value, attr, is_var,
225                                   RedeclarationType::kSyntaxError);
226     if (isolate->has_pending_exception()) return result;
227   });
228 
229   return ReadOnlyRoots(isolate).undefined_value();
230 }
231 
232 namespace {
233 
DeclareEvalHelper(Isolate * isolate,Handle<String> name,Handle<Object> value)234 Object DeclareEvalHelper(Isolate* isolate, Handle<String> name,
235                          Handle<Object> value) {
236   // Declarations are always made in a function, native, eval, or script
237   // context, or a declaration block scope. Since this is called from eval, the
238   // context passed is the context of the caller, which may be some nested
239   // context and not the declaration context.
240   Handle<Context> context(isolate->context().declaration_context(), isolate);
241 
242   DCHECK(context->IsFunctionContext() || context->IsNativeContext() ||
243          context->IsScriptContext() || context->IsEvalContext() ||
244          (context->IsBlockContext() &&
245           context->scope_info().is_declaration_scope()));
246 
247   bool is_var = value->IsUndefined(isolate);
248   DCHECK_IMPLIES(!is_var, value->IsJSFunction());
249 
250   int index;
251   PropertyAttributes attributes;
252   InitializationFlag init_flag;
253   VariableMode mode;
254 
255   Handle<Object> holder =
256       Context::Lookup(context, name, DONT_FOLLOW_CHAINS, &index, &attributes,
257                       &init_flag, &mode);
258   DCHECK(holder.is_null() || !holder->IsSourceTextModule());
259   DCHECK(!isolate->has_pending_exception());
260 
261   Handle<JSObject> object;
262 
263   if (attributes != ABSENT && holder->IsJSGlobalObject()) {
264     // ES#sec-evaldeclarationinstantiation 8.a.iv.1.b:
265     // If fnDefinable is false, throw a TypeError exception.
266     return DeclareGlobal(isolate, Handle<JSGlobalObject>::cast(holder), name,
267                          value, NONE, is_var, RedeclarationType::kTypeError);
268   }
269   if (context->has_extension() && context->extension().IsJSGlobalObject()) {
270     Handle<JSGlobalObject> global(JSGlobalObject::cast(context->extension()),
271                                   isolate);
272     return DeclareGlobal(isolate, global, name, value, NONE, is_var,
273                          RedeclarationType::kTypeError);
274   } else if (context->IsScriptContext()) {
275     DCHECK(context->global_object().IsJSGlobalObject());
276     Handle<JSGlobalObject> global(
277         JSGlobalObject::cast(context->global_object()), isolate);
278     return DeclareGlobal(isolate, global, name, value, NONE, is_var,
279                          RedeclarationType::kTypeError);
280   }
281 
282   if (attributes != ABSENT) {
283     DCHECK_EQ(NONE, attributes);
284 
285     // Skip var re-declarations.
286     if (is_var) return ReadOnlyRoots(isolate).undefined_value();
287 
288     if (index != Context::kNotFound) {
289       DCHECK(holder.is_identical_to(context));
290       context->set(index, *value);
291       return ReadOnlyRoots(isolate).undefined_value();
292     }
293 
294     object = Handle<JSObject>::cast(holder);
295 
296   } else if (context->has_extension()) {
297     object = handle(context->extension_object(), isolate);
298     DCHECK(object->IsJSContextExtensionObject());
299   } else if (context->scope_info().HasContextExtensionSlot()) {
300     // Sloppy varblock and function contexts might not have an extension object
301     // yet. Sloppy eval will never have an extension object, as vars are hoisted
302     // out, and lets are known statically.
303     DCHECK((context->IsBlockContext() &&
304             context->scope_info().is_declaration_scope()) ||
305            context->IsFunctionContext());
306     object =
307         isolate->factory()->NewJSObject(isolate->context_extension_function());
308 
309     context->set_extension(*object);
310   } else {
311     THROW_NEW_ERROR_RETURN_FAILURE(
312         isolate,
313         NewEvalError(MessageTemplate::kVarNotAllowedInEvalScope, name));
314   }
315 
316   RETURN_FAILURE_ON_EXCEPTION(isolate, JSObject::SetOwnPropertyIgnoreAttributes(
317                                            object, name, value, NONE));
318 
319   return ReadOnlyRoots(isolate).undefined_value();
320 }
321 
322 }  // namespace
323 
RUNTIME_FUNCTION(Runtime_DeclareEvalFunction)324 RUNTIME_FUNCTION(Runtime_DeclareEvalFunction) {
325   HandleScope scope(isolate);
326   DCHECK_EQ(2, args.length());
327   Handle<String> name = args.at<String>(0);
328   Handle<Object> value = args.at(1);
329   return DeclareEvalHelper(isolate, name, value);
330 }
331 
RUNTIME_FUNCTION(Runtime_DeclareEvalVar)332 RUNTIME_FUNCTION(Runtime_DeclareEvalVar) {
333   HandleScope scope(isolate);
334   DCHECK_EQ(1, args.length());
335   Handle<String> name = args.at<String>(0);
336   return DeclareEvalHelper(isolate, name,
337                            isolate->factory()->undefined_value());
338 }
339 
340 namespace {
341 
342 // Find the arguments of the JavaScript function invocation that called
343 // into C++ code. Collect these in a newly allocated array of handles.
GetCallerArguments(Isolate * isolate,int * total_argc)344 std::unique_ptr<Handle<Object>[]> GetCallerArguments(Isolate* isolate,
345                                                      int* total_argc) {
346   // Find frame containing arguments passed to the caller.
347   JavaScriptFrameIterator it(isolate);
348   JavaScriptFrame* frame = it.frame();
349   std::vector<SharedFunctionInfo> functions;
350   frame->GetFunctions(&functions);
351   if (functions.size() > 1) {
352     int inlined_jsframe_index = static_cast<int>(functions.size()) - 1;
353     TranslatedState translated_values(frame);
354     translated_values.Prepare(frame->fp());
355 
356     int argument_count = 0;
357     TranslatedFrame* translated_frame =
358         translated_values.GetArgumentsInfoFromJSFrameIndex(
359             inlined_jsframe_index, &argument_count);
360     TranslatedFrame::iterator iter = translated_frame->begin();
361 
362     // Skip the function.
363     iter++;
364 
365     // Skip the receiver.
366     iter++;
367     argument_count--;
368 
369     *total_argc = argument_count;
370     std::unique_ptr<Handle<Object>[]> param_data(
371         NewArray<Handle<Object>>(*total_argc));
372     bool should_deoptimize = false;
373     for (int i = 0; i < argument_count; i++) {
374       // If we materialize any object, we should deoptimize the frame because we
375       // might alias an object that was eliminated by escape analysis.
376       should_deoptimize = should_deoptimize || iter->IsMaterializedObject();
377       Handle<Object> value = iter->GetValue();
378       param_data[i] = value;
379       iter++;
380     }
381 
382     if (should_deoptimize) {
383       translated_values.StoreMaterializedValuesAndDeopt(frame);
384     }
385 
386     return param_data;
387   } else {
388     int args_count = frame->GetActualArgumentCount();
389     *total_argc = args_count;
390     std::unique_ptr<Handle<Object>[]> param_data(
391         NewArray<Handle<Object>>(*total_argc));
392     for (int i = 0; i < args_count; i++) {
393       Handle<Object> val = Handle<Object>(frame->GetParameter(i), isolate);
394       param_data[i] = val;
395     }
396     return param_data;
397   }
398 }
399 
400 template <typename T>
NewSloppyArguments(Isolate * isolate,Handle<JSFunction> callee,T parameters,int argument_count)401 Handle<JSObject> NewSloppyArguments(Isolate* isolate, Handle<JSFunction> callee,
402                                     T parameters, int argument_count) {
403   CHECK(!IsDerivedConstructor(callee->shared().kind()));
404   DCHECK(callee->shared().has_simple_parameters());
405   Handle<JSObject> result =
406       isolate->factory()->NewArgumentsObject(callee, argument_count);
407 
408   // Allocate the elements if needed.
409   int parameter_count =
410       callee->shared().internal_formal_parameter_count_without_receiver();
411   if (argument_count > 0) {
412     if (parameter_count > 0) {
413       int mapped_count = std::min(argument_count, parameter_count);
414 
415       // Store the context and the arguments array at the beginning of the
416       // parameter map.
417       Handle<Context> context(isolate->context(), isolate);
418       Handle<FixedArray> arguments = isolate->factory()->NewFixedArray(
419           argument_count, AllocationType::kYoung);
420 
421       Handle<SloppyArgumentsElements> parameter_map =
422           isolate->factory()->NewSloppyArgumentsElements(
423               mapped_count, context, arguments, AllocationType::kYoung);
424 
425       result->set_map(isolate->native_context()->fast_aliased_arguments_map());
426       result->set_elements(*parameter_map);
427 
428       // Loop over the actual parameters backwards.
429       int index = argument_count - 1;
430       while (index >= mapped_count) {
431         // These go directly in the arguments array and have no
432         // corresponding slot in the parameter map.
433         arguments->set(index, parameters[index]);
434         --index;
435       }
436 
437       Handle<ScopeInfo> scope_info(callee->shared().scope_info(), isolate);
438 
439       // First mark all mappable slots as unmapped and copy the values into the
440       // arguments object.
441       for (int i = 0; i < mapped_count; i++) {
442         arguments->set(i, parameters[i]);
443         parameter_map->set_mapped_entries(
444             i, *isolate->factory()->the_hole_value());
445       }
446 
447       // Walk all context slots to find context allocated parameters. Mark each
448       // found parameter as mapped.
449       for (int i = 0; i < scope_info->ContextLocalCount(); i++) {
450         if (!scope_info->ContextLocalIsParameter(i)) continue;
451         int parameter = scope_info->ContextLocalParameterNumber(i);
452         if (parameter >= mapped_count) continue;
453         arguments->set_the_hole(parameter);
454         Smi slot = Smi::FromInt(scope_info->ContextHeaderLength() + i);
455         parameter_map->set_mapped_entries(parameter, slot);
456       }
457     } else {
458       // If there is no aliasing, the arguments object elements are not
459       // special in any way.
460       Handle<FixedArray> elements = isolate->factory()->NewFixedArray(
461           argument_count, AllocationType::kYoung);
462       result->set_elements(*elements);
463       for (int i = 0; i < argument_count; ++i) {
464         elements->set(i, parameters[i]);
465       }
466     }
467   }
468   return result;
469 }
470 
471 class HandleArguments {
472  public:
HandleArguments(Handle<Object> * array)473   explicit HandleArguments(Handle<Object>* array) : array_(array) {}
operator [](int index)474   Object operator[](int index) { return *array_[index]; }
475 
476  private:
477   Handle<Object>* array_;
478 };
479 
480 class ParameterArguments {
481  public:
ParameterArguments(Address parameters)482   explicit ParameterArguments(Address parameters) : parameters_(parameters) {}
operator [](int index)483   Object operator[](int index) {
484     return *FullObjectSlot(parameters_ - (index + 1) * kSystemPointerSize);
485   }
486 
487  private:
488   Address parameters_;
489 };
490 
491 }  // namespace
492 
RUNTIME_FUNCTION(Runtime_NewSloppyArguments)493 RUNTIME_FUNCTION(Runtime_NewSloppyArguments) {
494   HandleScope scope(isolate);
495   DCHECK_EQ(1, args.length());
496   Handle<JSFunction> callee = args.at<JSFunction>(0);
497   // This generic runtime function can also be used when the caller has been
498   // inlined, we use the slow but accurate {GetCallerArguments}.
499   int argument_count = 0;
500   std::unique_ptr<Handle<Object>[]> arguments =
501       GetCallerArguments(isolate, &argument_count);
502   HandleArguments argument_getter(arguments.get());
503   return *NewSloppyArguments(isolate, callee, argument_getter, argument_count);
504 }
505 
RUNTIME_FUNCTION(Runtime_NewStrictArguments)506 RUNTIME_FUNCTION(Runtime_NewStrictArguments) {
507   HandleScope scope(isolate);
508   DCHECK_EQ(1, args.length());
509   Handle<JSFunction> callee = args.at<JSFunction>(0);
510   // This generic runtime function can also be used when the caller has been
511   // inlined, we use the slow but accurate {GetCallerArguments}.
512   int argument_count = 0;
513   std::unique_ptr<Handle<Object>[]> arguments =
514       GetCallerArguments(isolate, &argument_count);
515   Handle<JSObject> result =
516       isolate->factory()->NewArgumentsObject(callee, argument_count);
517   if (argument_count) {
518     Handle<FixedArray> array =
519         isolate->factory()->NewFixedArray(argument_count);
520     DisallowGarbageCollection no_gc;
521     WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
522     for (int i = 0; i < argument_count; i++) {
523       array->set(i, *arguments[i], mode);
524     }
525     result->set_elements(*array);
526   }
527   return *result;
528 }
529 
530 
RUNTIME_FUNCTION(Runtime_NewRestParameter)531 RUNTIME_FUNCTION(Runtime_NewRestParameter) {
532   HandleScope scope(isolate);
533   DCHECK_EQ(1, args.length());
534   Handle<JSFunction> callee = args.at<JSFunction>(0);
535   int start_index =
536       callee->shared().internal_formal_parameter_count_without_receiver();
537   // This generic runtime function can also be used when the caller has been
538   // inlined, we use the slow but accurate {GetCallerArguments}.
539   int argument_count = 0;
540   std::unique_ptr<Handle<Object>[]> arguments =
541       GetCallerArguments(isolate, &argument_count);
542   int num_elements = std::max(0, argument_count - start_index);
543   Handle<JSObject> result = isolate->factory()->NewJSArray(
544       PACKED_ELEMENTS, num_elements, num_elements,
545       DONT_INITIALIZE_ARRAY_ELEMENTS);
546   {
547     DisallowGarbageCollection no_gc;
548     FixedArray elements = FixedArray::cast(result->elements());
549     WriteBarrierMode mode = elements.GetWriteBarrierMode(no_gc);
550     for (int i = 0; i < num_elements; i++) {
551       elements.set(i, *arguments[i + start_index], mode);
552     }
553   }
554   return *result;
555 }
556 
RUNTIME_FUNCTION(Runtime_NewClosure)557 RUNTIME_FUNCTION(Runtime_NewClosure) {
558   HandleScope scope(isolate);
559   DCHECK_EQ(2, args.length());
560   Handle<SharedFunctionInfo> shared = args.at<SharedFunctionInfo>(0);
561   Handle<FeedbackCell> feedback_cell = args.at<FeedbackCell>(1);
562   Handle<Context> context(isolate->context(), isolate);
563   return *Factory::JSFunctionBuilder{isolate, shared, context}
564               .set_feedback_cell(feedback_cell)
565               .set_allocation_type(AllocationType::kYoung)
566               .Build();
567 }
568 
RUNTIME_FUNCTION(Runtime_NewClosure_Tenured)569 RUNTIME_FUNCTION(Runtime_NewClosure_Tenured) {
570   HandleScope scope(isolate);
571   DCHECK_EQ(2, args.length());
572   Handle<SharedFunctionInfo> shared = args.at<SharedFunctionInfo>(0);
573   Handle<FeedbackCell> feedback_cell = args.at<FeedbackCell>(1);
574   Handle<Context> context(isolate->context(), isolate);
575   // The caller ensures that we pretenure closures that are assigned
576   // directly to properties.
577   return *Factory::JSFunctionBuilder{isolate, shared, context}
578               .set_feedback_cell(feedback_cell)
579               .set_allocation_type(AllocationType::kOld)
580               .Build();
581 }
582 
RUNTIME_FUNCTION(Runtime_NewFunctionContext)583 RUNTIME_FUNCTION(Runtime_NewFunctionContext) {
584   HandleScope scope(isolate);
585   DCHECK_EQ(1, args.length());
586 
587   Handle<ScopeInfo> scope_info = args.at<ScopeInfo>(0);
588 
589   Handle<Context> outer(isolate->context(), isolate);
590   return *isolate->factory()->NewFunctionContext(outer, scope_info);
591 }
592 
593 // TODO(jgruber): Rename these functions to 'New...Context'.
RUNTIME_FUNCTION(Runtime_PushWithContext)594 RUNTIME_FUNCTION(Runtime_PushWithContext) {
595   HandleScope scope(isolate);
596   DCHECK_EQ(2, args.length());
597   Handle<JSReceiver> extension_object = args.at<JSReceiver>(0);
598   Handle<ScopeInfo> scope_info = args.at<ScopeInfo>(1);
599   Handle<Context> current(isolate->context(), isolate);
600   return *isolate->factory()->NewWithContext(current, scope_info,
601                                              extension_object);
602 }
603 
604 // TODO(jgruber): Rename these functions to 'New...Context'.
RUNTIME_FUNCTION(Runtime_PushCatchContext)605 RUNTIME_FUNCTION(Runtime_PushCatchContext) {
606   HandleScope scope(isolate);
607   DCHECK_EQ(2, args.length());
608   Handle<Object> thrown_object = args.at(0);
609   Handle<ScopeInfo> scope_info = args.at<ScopeInfo>(1);
610   Handle<Context> current(isolate->context(), isolate);
611   return *isolate->factory()->NewCatchContext(current, scope_info,
612                                               thrown_object);
613 }
614 
615 // TODO(jgruber): Rename these functions to 'New...Context'.
RUNTIME_FUNCTION(Runtime_PushBlockContext)616 RUNTIME_FUNCTION(Runtime_PushBlockContext) {
617   HandleScope scope(isolate);
618   DCHECK_EQ(1, args.length());
619   Handle<ScopeInfo> scope_info = args.at<ScopeInfo>(0);
620   Handle<Context> current(isolate->context(), isolate);
621   return *isolate->factory()->NewBlockContext(current, scope_info);
622 }
623 
624 
RUNTIME_FUNCTION(Runtime_DeleteLookupSlot)625 RUNTIME_FUNCTION(Runtime_DeleteLookupSlot) {
626   HandleScope scope(isolate);
627   DCHECK_EQ(1, args.length());
628   Handle<String> name = args.at<String>(0);
629 
630   int index;
631   PropertyAttributes attributes;
632   InitializationFlag flag;
633   VariableMode mode;
634   Handle<Context> context(isolate->context(), isolate);
635   Handle<Object> holder = Context::Lookup(context, name, FOLLOW_CHAINS, &index,
636                                           &attributes, &flag, &mode);
637 
638   // If the slot was not found the result is true.
639   if (holder.is_null()) {
640     // In case of JSProxy, an exception might have been thrown.
641     if (isolate->has_pending_exception())
642       return ReadOnlyRoots(isolate).exception();
643     return ReadOnlyRoots(isolate).true_value();
644   }
645 
646   // If the slot was found in a context or in module imports and exports it
647   // should be DONT_DELETE.
648   if (holder->IsContext() || holder->IsSourceTextModule()) {
649     return ReadOnlyRoots(isolate).false_value();
650   }
651 
652   // The slot was found in a JSReceiver, either a context extension object,
653   // the global object, or the subject of a with.  Try to delete it
654   // (respecting DONT_DELETE).
655   Handle<JSReceiver> object = Handle<JSReceiver>::cast(holder);
656   Maybe<bool> result = JSReceiver::DeleteProperty(object, name);
657   MAYBE_RETURN(result, ReadOnlyRoots(isolate).exception());
658   return isolate->heap()->ToBoolean(result.FromJust());
659 }
660 
661 
662 namespace {
663 
LoadLookupSlot(Isolate * isolate,Handle<String> name,ShouldThrow should_throw,Handle<Object> * receiver_return=nullptr)664 MaybeHandle<Object> LoadLookupSlot(Isolate* isolate, Handle<String> name,
665                                    ShouldThrow should_throw,
666                                    Handle<Object>* receiver_return = nullptr) {
667   int index;
668   PropertyAttributes attributes;
669   InitializationFlag flag;
670   VariableMode mode;
671   Handle<Context> context(isolate->context(), isolate);
672   Handle<Object> holder = Context::Lookup(context, name, FOLLOW_CHAINS, &index,
673                                           &attributes, &flag, &mode);
674   if (isolate->has_pending_exception()) return MaybeHandle<Object>();
675 
676   if (!holder.is_null() && holder->IsSourceTextModule()) {
677     Handle<Object> receiver = isolate->factory()->undefined_value();
678     if (receiver_return) *receiver_return = receiver;
679     return SourceTextModule::LoadVariable(
680         isolate, Handle<SourceTextModule>::cast(holder), index);
681   }
682   if (index != Context::kNotFound) {
683     DCHECK(holder->IsContext());
684     // If the "property" we were looking for is a local variable, the
685     // receiver is the global object; see ECMA-262, 3rd., 10.1.6 and 10.2.3.
686     Handle<Object> receiver = isolate->factory()->undefined_value();
687     Handle<Object> value = handle(Context::cast(*holder).get(index), isolate);
688     // Check for uninitialized bindings.
689     if (flag == kNeedsInitialization && value->IsTheHole(isolate)) {
690       THROW_NEW_ERROR(isolate,
691                       NewReferenceError(MessageTemplate::kNotDefined, name),
692                       Object);
693     }
694     DCHECK(!value->IsTheHole(isolate));
695     if (receiver_return) *receiver_return = receiver;
696     return value;
697   }
698 
699   // Otherwise, if the slot was found the holder is a context extension
700   // object, subject of a with, or a global object.  We read the named
701   // property from it.
702   if (!holder.is_null()) {
703     // No need to unhole the value here.  This is taken care of by the
704     // GetProperty function.
705     Handle<Object> value;
706     ASSIGN_RETURN_ON_EXCEPTION(
707         isolate, value, Object::GetProperty(isolate, holder, name), Object);
708     if (receiver_return) {
709       *receiver_return =
710           (holder->IsJSGlobalObject() || holder->IsJSContextExtensionObject())
711               ? Handle<Object>::cast(isolate->factory()->undefined_value())
712               : holder;
713     }
714     return value;
715   }
716 
717   if (should_throw == kThrowOnError) {
718     // The property doesn't exist - throw exception.
719     THROW_NEW_ERROR(
720         isolate, NewReferenceError(MessageTemplate::kNotDefined, name), Object);
721   }
722 
723   // The property doesn't exist - return undefined.
724   if (receiver_return) *receiver_return = isolate->factory()->undefined_value();
725   return isolate->factory()->undefined_value();
726 }
727 
728 }  // namespace
729 
730 
RUNTIME_FUNCTION(Runtime_LoadLookupSlot)731 RUNTIME_FUNCTION(Runtime_LoadLookupSlot) {
732   HandleScope scope(isolate);
733   DCHECK_EQ(1, args.length());
734   Handle<String> name = args.at<String>(0);
735   RETURN_RESULT_OR_FAILURE(isolate,
736                            LoadLookupSlot(isolate, name, kThrowOnError));
737 }
738 
739 
RUNTIME_FUNCTION(Runtime_LoadLookupSlotInsideTypeof)740 RUNTIME_FUNCTION(Runtime_LoadLookupSlotInsideTypeof) {
741   HandleScope scope(isolate);
742   DCHECK_EQ(1, args.length());
743   Handle<String> name = args.at<String>(0);
744   RETURN_RESULT_OR_FAILURE(isolate, LoadLookupSlot(isolate, name, kDontThrow));
745 }
746 
747 
RUNTIME_FUNCTION_RETURN_PAIR(Runtime_LoadLookupSlotForCall)748 RUNTIME_FUNCTION_RETURN_PAIR(Runtime_LoadLookupSlotForCall) {
749   HandleScope scope(isolate);
750   DCHECK_EQ(1, args.length());
751   Handle<String> name = args.at<String>(0);
752   Handle<Object> value;
753   Handle<Object> receiver;
754   ASSIGN_RETURN_ON_EXCEPTION_VALUE(
755       isolate, value, LoadLookupSlot(isolate, name, kThrowOnError, &receiver),
756       MakePair(ReadOnlyRoots(isolate).exception(), Object()));
757   return MakePair(*value, *receiver);
758 }
759 
760 
761 namespace {
762 
StoreLookupSlot(Isolate * isolate,Handle<Context> context,Handle<String> name,Handle<Object> value,LanguageMode language_mode,ContextLookupFlags context_lookup_flags=FOLLOW_CHAINS)763 MaybeHandle<Object> StoreLookupSlot(
764     Isolate* isolate, Handle<Context> context, Handle<String> name,
765     Handle<Object> value, LanguageMode language_mode,
766     ContextLookupFlags context_lookup_flags = FOLLOW_CHAINS) {
767   int index;
768   PropertyAttributes attributes;
769   InitializationFlag flag;
770   VariableMode mode;
771   bool is_sloppy_function_name;
772   Handle<Object> holder =
773       Context::Lookup(context, name, context_lookup_flags, &index, &attributes,
774                       &flag, &mode, &is_sloppy_function_name);
775   if (holder.is_null()) {
776     // In case of JSProxy, an exception might have been thrown.
777     if (isolate->has_pending_exception()) return MaybeHandle<Object>();
778   } else if (holder->IsSourceTextModule()) {
779     if ((attributes & READ_ONLY) == 0) {
780       SourceTextModule::StoreVariable(Handle<SourceTextModule>::cast(holder),
781                                       index, value);
782     } else {
783       THROW_NEW_ERROR(
784           isolate, NewTypeError(MessageTemplate::kConstAssign, name), Object);
785     }
786     return value;
787   }
788   // The property was found in a context slot.
789   if (index != Context::kNotFound) {
790     if (flag == kNeedsInitialization &&
791         Handle<Context>::cast(holder)->get(index).IsTheHole(isolate)) {
792       THROW_NEW_ERROR(isolate,
793                       NewReferenceError(MessageTemplate::kNotDefined, name),
794                       Object);
795     }
796     if ((attributes & READ_ONLY) == 0) {
797       Handle<Context>::cast(holder)->set(index, *value);
798     } else if (!is_sloppy_function_name || is_strict(language_mode)) {
799       THROW_NEW_ERROR(
800           isolate, NewTypeError(MessageTemplate::kConstAssign, name), Object);
801     }
802     return value;
803   }
804 
805   // Slow case: The property is not in a context slot.  It is either in a
806   // context extension object, a property of the subject of a with, or a
807   // property of the global object.
808   Handle<JSReceiver> object;
809   if (attributes != ABSENT) {
810     // The property exists on the holder.
811     object = Handle<JSReceiver>::cast(holder);
812   } else if (is_strict(language_mode)) {
813     // If absent in strict mode: throw.
814     THROW_NEW_ERROR(
815         isolate, NewReferenceError(MessageTemplate::kNotDefined, name), Object);
816   } else {
817     // If absent in sloppy mode: add the property to the global object.
818     object = handle(context->global_object(), isolate);
819   }
820 
821   ASSIGN_RETURN_ON_EXCEPTION(isolate, value,
822                              Object::SetProperty(isolate, object, name, value),
823                              Object);
824   return value;
825 }
826 
827 }  // namespace
828 
829 
RUNTIME_FUNCTION(Runtime_StoreLookupSlot_Sloppy)830 RUNTIME_FUNCTION(Runtime_StoreLookupSlot_Sloppy) {
831   HandleScope scope(isolate);
832   DCHECK_EQ(2, args.length());
833   Handle<String> name = args.at<String>(0);
834   Handle<Object> value = args.at(1);
835   Handle<Context> context(isolate->context(), isolate);
836   RETURN_RESULT_OR_FAILURE(
837       isolate,
838       StoreLookupSlot(isolate, context, name, value, LanguageMode::kSloppy));
839 }
840 
RUNTIME_FUNCTION(Runtime_StoreLookupSlot_Strict)841 RUNTIME_FUNCTION(Runtime_StoreLookupSlot_Strict) {
842   HandleScope scope(isolate);
843   DCHECK_EQ(2, args.length());
844   Handle<String> name = args.at<String>(0);
845   Handle<Object> value = args.at(1);
846   Handle<Context> context(isolate->context(), isolate);
847   RETURN_RESULT_OR_FAILURE(
848       isolate,
849       StoreLookupSlot(isolate, context, name, value, LanguageMode::kStrict));
850 }
851 
852 // Store into a dynamic declaration context for sloppy-mode block-scoped
853 // function hoisting which leaks out of an eval.
RUNTIME_FUNCTION(Runtime_StoreLookupSlot_SloppyHoisting)854 RUNTIME_FUNCTION(Runtime_StoreLookupSlot_SloppyHoisting) {
855   HandleScope scope(isolate);
856   DCHECK_EQ(2, args.length());
857   Handle<String> name = args.at<String>(0);
858   Handle<Object> value = args.at(1);
859   const ContextLookupFlags lookup_flags =
860       static_cast<ContextLookupFlags>(DONT_FOLLOW_CHAINS);
861   Handle<Context> declaration_context(isolate->context().declaration_context(),
862                                       isolate);
863   RETURN_RESULT_OR_FAILURE(
864       isolate, StoreLookupSlot(isolate, declaration_context, name, value,
865                                LanguageMode::kSloppy, lookup_flags));
866 }
867 
RUNTIME_FUNCTION(Runtime_StoreGlobalNoHoleCheckForReplLetOrConst)868 RUNTIME_FUNCTION(Runtime_StoreGlobalNoHoleCheckForReplLetOrConst) {
869   HandleScope scope(isolate);
870   DCHECK_EQ(2, args.length());
871   Handle<String> name = args.at<String>(0);
872   Handle<Object> value = args.at(1);
873 
874   Handle<Context> native_context = isolate->native_context();
875   Handle<ScriptContextTable> script_contexts(
876       native_context->script_context_table(), isolate);
877 
878   VariableLookupResult lookup_result;
879   bool found = script_contexts->Lookup(name, &lookup_result);
880   CHECK(found);
881   Handle<Context> script_context = ScriptContextTable::GetContext(
882       isolate, script_contexts, lookup_result.context_index);
883 
884   script_context->set(lookup_result.slot_index, *value);
885   return *value;
886 }
887 
888 }  // namespace internal
889 }  // namespace v8
890