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
24namespace v8 {
25namespace internal {
26
27RUNTIME_FUNCTION(Runtime_ThrowConstAssignError) {
28  HandleScope scope(isolate);
29  THROW_NEW_ERROR_RETURN_FAILURE(isolate,
30                                 NewTypeError(MessageTemplate::kConstAssign));
31}
32
33namespace {
34
35enum class RedeclarationType { kSyntaxError = 0, kTypeError = 1 };
36
37Object 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.
50Object 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
124RUNTIME_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
172RUNTIME_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
232namespace {
233
234Object 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
324RUNTIME_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
332RUNTIME_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
340namespace {
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.
344std::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
400template <typename T>
401Handle<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
471class HandleArguments {
472 public:
473  explicit HandleArguments(Handle<Object>* array) : array_(array) {}
474  Object operator[](int index) { return *array_[index]; }
475
476 private:
477  Handle<Object>* array_;
478};
479
480class ParameterArguments {
481 public:
482  explicit ParameterArguments(Address parameters) : parameters_(parameters) {}
483  Object operator[](int index) {
484    return *FullObjectSlot(parameters_ - (index + 1) * kSystemPointerSize);
485  }
486
487 private:
488  Address parameters_;
489};
490
491}  // namespace
492
493RUNTIME_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
506RUNTIME_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
531RUNTIME_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
557RUNTIME_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
569RUNTIME_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
583RUNTIME_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'.
594RUNTIME_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'.
605RUNTIME_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'.
616RUNTIME_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
625RUNTIME_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
662namespace {
663
664MaybeHandle<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
731RUNTIME_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
740RUNTIME_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
748RUNTIME_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
761namespace {
762
763MaybeHandle<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
830RUNTIME_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
841RUNTIME_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.
854RUNTIME_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
868RUNTIME_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