runtime-scopes.cc 33.8 KB
Newer Older
1 2 3 4
// Copyright 2014 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

5 6
#include <memory>

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 12 13
#include "src/execution/arguments-inl.h"
#include "src/execution/frames-inl.h"
#include "src/execution/isolate-inl.h"
14
#include "src/heap/heap-inl.h"  // For ToBoolean. TODO(jkummerow): Drop.
15
#include "src/init/bootstrapper.h"
16
#include "src/logging/counters.h"
17
#include "src/objects/heap-object-inl.h"
18
#include "src/objects/module-inl.h"
19
#include "src/objects/smi.h"
20
#include "src/runtime/runtime-utils.h"
21 22 23 24

namespace v8 {
namespace internal {

25 26 27 28 29 30 31 32
RUNTIME_FUNCTION(Runtime_ThrowConstAssignError) {
  HandleScope scope(isolate);
  THROW_NEW_ERROR_RETURN_FAILURE(isolate,
                                 NewTypeError(MessageTemplate::kConstAssign));
}

namespace {

33 34
enum class RedeclarationType { kSyntaxError = 0, kTypeError = 1 };

35 36
Object ThrowRedeclarationError(Isolate* isolate, Handle<String> name,
                               RedeclarationType redeclaration_type) {
37
  HandleScope scope(isolate);
38 39 40 41 42 43 44
  if (redeclaration_type == RedeclarationType::kSyntaxError) {
    THROW_NEW_ERROR_RETURN_FAILURE(
        isolate, NewSyntaxError(MessageTemplate::kVarRedeclaration, name));
  } else {
    THROW_NEW_ERROR_RETURN_FAILURE(
        isolate, NewTypeError(MessageTemplate::kVarRedeclaration, name));
  }
45 46 47
}

// May throw a RedeclarationError.
48 49 50 51
Object DeclareGlobal(Isolate* isolate, Handle<JSGlobalObject> global,
                     Handle<String> name, Handle<Object> value,
                     PropertyAttributes attr, bool is_var,
                     RedeclarationType redeclaration_type) {
52
  Handle<ScriptContextTable> script_contexts(
53
      global->native_context().script_context_table(), isolate);
54
  ScriptContextTable::LookupResult lookup;
55
  if (ScriptContextTable::Lookup(isolate, *script_contexts, *name, &lookup) &&
56
      IsLexicalVariableMode(lookup.mode)) {
57 58 59 60 61
    // ES#sec-globaldeclarationinstantiation 6.a:
    // If envRec.HasLexicalDeclaration(name) is true, throw a SyntaxError
    // exception.
    return ThrowRedeclarationError(isolate, name,
                                   RedeclarationType::kSyntaxError);
62 63
  }

64
  // Do the lookup own properties only, see ES5 erratum.
65 66
  LookupIterator::Configuration lookup_config(
      LookupIterator::Configuration::OWN_SKIP_INTERCEPTOR);
67
  if (!is_var) {
68 69 70 71
    // For function declarations, use the interceptor on the declaration. For
    // non-functions, use it only on initialization.
    lookup_config = LookupIterator::Configuration::OWN;
  }
72
  LookupIterator it(isolate, global, name, global, lookup_config);
73
  Maybe<PropertyAttributes> maybe = JSReceiver::GetPropertyAttributes(&it);
74
  if (maybe.IsNothing()) return ReadOnlyRoots(isolate).exception();
75 76

  if (it.IsFound()) {
77
    PropertyAttributes old_attributes = maybe.FromJust();
78 79 80
    // The name was declared before; check for conflicting re-declarations.

    // Skip var re-declarations.
81
    if (is_var) return ReadOnlyRoots(isolate).undefined_value();
82 83 84 85

    if ((old_attributes & DONT_DELETE) != 0) {
      // Only allow reconfiguring globals to functions in user code (no
      // natives, which are marked as read-only).
86
      DCHECK_EQ(attr & READ_ONLY, 0);
87 88 89

      // Check whether we can reconfigure the existing property into a
      // function.
90
      if (old_attributes & READ_ONLY || old_attributes & DONT_ENUM ||
91
          (it.state() == LookupIterator::ACCESSOR)) {
92
        // ECMA-262 section 15.1.11 GlobalDeclarationInstantiation 5.d:
93
        // If hasRestrictedGlobal is true, throw a SyntaxError exception.
94
        // ECMA-262 section 18.2.1.3 EvalDeclarationInstantiation 8.a.iv.1.b:
95 96
        // If fnDefinable is false, throw a TypeError exception.
        return ThrowRedeclarationError(isolate, name, redeclaration_type);
97 98 99 100
      }
      // If the existing property is not configurable, keep its attributes. Do
      attr = old_attributes;
    }
101 102 103 104 105 106 107 108

    // If the current state is ACCESSOR, this could mean it's an AccessorInfo
    // type property. We are not allowed to call into such setters during global
    // function declaration since this would break e.g., onload. Meaning
    // 'function onload() {}' would invalidly register that function as the
    // onload callback. To avoid this situation, we first delete the property
    // before readding it as a regular data property below.
    if (it.state() == LookupIterator::ACCESSOR) it.Delete();
109 110
  }

111
  if (!is_var) it.Restart();
112

113
  // Define or redefine own property.
114 115
  RETURN_FAILURE_ON_EXCEPTION(
      isolate, JSObject::DefineOwnPropertyIgnoreAttributes(&it, value, attr));
116

117
  return ReadOnlyRoots(isolate).undefined_value();
118 119
}

120 121 122
}  // namespace

RUNTIME_FUNCTION(Runtime_DeclareModuleExports) {
123
  HandleScope scope(isolate);
124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175
  DCHECK_EQ(2, args.length());

  CONVERT_ARG_HANDLE_CHECKED(FixedArray, declarations, 0);
  CONVERT_ARG_HANDLE_CHECKED(JSFunction, closure, 1);

  Handle<ClosureFeedbackCellArray> closure_feedback_cell_array =
      Handle<ClosureFeedbackCellArray>::null();
  if (closure->has_feedback_vector()) {
    closure_feedback_cell_array = Handle<ClosureFeedbackCellArray>(
        closure->feedback_vector().closure_feedback_cell_array(), isolate);
  } else {
    closure_feedback_cell_array = Handle<ClosureFeedbackCellArray>(
        closure->closure_feedback_cell_array(), isolate);
  }

  Handle<Context> context(isolate->context(), isolate);
  DCHECK(context->IsModuleContext());
  Handle<FixedArray> exports(
      SourceTextModule::cast(context->extension()).regular_exports(), isolate);

  int length = declarations->length();
  FOR_WITH_HANDLE_SCOPE(isolate, int, i = 0, i, i < length, i++, {
    Object decl = declarations->get(i);
    int index;
    Object value;
    if (decl.IsSmi()) {
      index = Smi::ToInt(decl);
      value = ReadOnlyRoots(isolate).the_hole_value();
    } else {
      Handle<SharedFunctionInfo> sfi(
          SharedFunctionInfo::cast(declarations->get(i)), isolate);
      int feedback_index = Smi::ToInt(declarations->get(++i));
      index = Smi::ToInt(declarations->get(++i));
      Handle<FeedbackCell> feedback_cell =
          closure_feedback_cell_array->GetFeedbackCell(feedback_index);
      value = *isolate->factory()->NewFunctionFromSharedFunctionInfo(
          sfi, context, feedback_cell, AllocationType::kOld);
    }

    Cell::cast(exports->get(index - 1)).set_value(value);
  });

  return ReadOnlyRoots(isolate).undefined_value();
}

RUNTIME_FUNCTION(Runtime_DeclareGlobals) {
  HandleScope scope(isolate);
  DCHECK_EQ(2, args.length());

  CONVERT_ARG_HANDLE_CHECKED(FixedArray, declarations, 0);
  CONVERT_ARG_HANDLE_CHECKED(JSFunction, closure, 1);

176
  Handle<JSGlobalObject> global(isolate->global_object());
177
  Handle<Context> context(isolate->context(), isolate);
178

179 180
  Handle<ClosureFeedbackCellArray> closure_feedback_cell_array =
      Handle<ClosureFeedbackCellArray>::null();
181
  if (closure->has_feedback_vector()) {
182
    closure_feedback_cell_array = Handle<ClosureFeedbackCellArray>(
183
        closure->feedback_vector().closure_feedback_cell_array(), isolate);
184
  } else {
185 186
    closure_feedback_cell_array = Handle<ClosureFeedbackCellArray>(
        closure->closure_feedback_cell_array(), isolate);
187 188
  }

189
  // Traverse the name/value pairs and set the properties.
190
  int length = declarations->length();
191 192 193
  FOR_WITH_HANDLE_SCOPE(isolate, int, i = 0, i, i < length, i++, {
    Handle<Object> decl(declarations->get(i), isolate);
    Handle<String> name;
194
    Handle<Object> value;
195 196 197 198
    bool is_var = decl->IsString();

    if (is_var) {
      name = Handle<String>::cast(decl);
199
      value = isolate->factory()->undefined_value();
200 201 202 203 204 205 206 207
    } else {
      Handle<SharedFunctionInfo> sfi = Handle<SharedFunctionInfo>::cast(decl);
      name = handle(sfi->Name(), isolate);
      int index = Smi::ToInt(declarations->get(++i));
      Handle<FeedbackCell> feedback_cell =
          closure_feedback_cell_array->GetFeedbackCell(index);
      value = isolate->factory()->NewFunctionFromSharedFunctionInfo(
          sfi, context, feedback_cell, AllocationType::kOld);
208 209 210 211
    }

    // Compute the property attributes. According to ECMA-262,
    // the property must be non-configurable except in eval.
212 213 214 215 216
    Script script = Script::cast(closure->shared().script());
    PropertyAttributes attr =
        script.compilation_type() == Script::COMPILATION_TYPE_EVAL
            ? NONE
            : DONT_DELETE;
217

218 219
    // ES#sec-globaldeclarationinstantiation 5.d:
    // If hasRestrictedGlobal is true, throw a SyntaxError exception.
220 221
    Object result = DeclareGlobal(isolate, global, name, value, attr, is_var,
                                  RedeclarationType::kSyntaxError);
222
    if (isolate->has_pending_exception()) return result;
223
  });
224

225
  return ReadOnlyRoots(isolate).undefined_value();
226 227
}

228
namespace {
229

230 231
Object DeclareEvalHelper(Isolate* isolate, Handle<String> name,
                         Handle<Object> value) {
232 233 234 235
  // Declarations are always made in a function, native, eval, or script
  // context, or a declaration block scope. Since this is called from eval, the
  // context passed is the context of the caller, which may be some nested
  // context and not the declaration context.
236
  Handle<Context> context(isolate->context().declaration_context(), isolate);
237

238
  DCHECK(context->IsFunctionContext() || context->IsNativeContext() ||
239
         context->IsScriptContext() || context->IsEvalContext() ||
240
         (context->IsBlockContext() &&
241
          context->scope_info().is_declaration_scope()));
242

243 244
  bool is_var = value->IsUndefined(isolate);
  DCHECK_IMPLIES(!is_var, value->IsJSFunction());
245 246 247

  int index;
  PropertyAttributes attributes;
248
  InitializationFlag init_flag;
249
  VariableMode mode;
250

251 252 253
  Handle<Object> holder =
      Context::Lookup(context, name, DONT_FOLLOW_CHAINS, &index, &attributes,
                      &init_flag, &mode);
254
  DCHECK(holder.is_null() || !holder->IsSourceTextModule());
255
  DCHECK(!isolate->has_pending_exception());
256 257 258

  Handle<JSObject> object;

259
  if (attributes != ABSENT && holder->IsJSGlobalObject()) {
260 261
    // ES#sec-evaldeclarationinstantiation 8.a.iv.1.b:
    // If fnDefinable is false, throw a TypeError exception.
262
    return DeclareGlobal(isolate, Handle<JSGlobalObject>::cast(holder), name,
263
                         value, NONE, is_var, RedeclarationType::kTypeError);
264
  }
265
  if (context->has_extension() && context->extension().IsJSGlobalObject()) {
266 267
    Handle<JSGlobalObject> global(JSGlobalObject::cast(context->extension()),
                                  isolate);
268
    return DeclareGlobal(isolate, global, name, value, NONE, is_var,
269
                         RedeclarationType::kTypeError);
270
  } else if (context->IsScriptContext()) {
271
    DCHECK(context->global_object().IsJSGlobalObject());
272 273
    Handle<JSGlobalObject> global(
        JSGlobalObject::cast(context->global_object()), isolate);
274
    return DeclareGlobal(isolate, global, name, value, NONE, is_var,
275
                         RedeclarationType::kTypeError);
276
  }
277 278

  if (attributes != ABSENT) {
279
    DCHECK_EQ(NONE, attributes);
280 281

    // Skip var re-declarations.
282
    if (is_var) return ReadOnlyRoots(isolate).undefined_value();
283

284
    if (index != Context::kNotFound) {
285
      DCHECK(holder.is_identical_to(context));
286
      context->set(index, *value);
287
      return ReadOnlyRoots(isolate).undefined_value();
288 289 290 291 292
    }

    object = Handle<JSObject>::cast(holder);

  } else if (context->has_extension()) {
293
    object = handle(context->extension_object(), isolate);
294
    DCHECK(object->IsJSContextExtensionObject());
295
  } else {
296 297 298 299
    // Sloppy varblock and function contexts might not have an extension object
    // yet. Sloppy eval will never have an extension object, as vars are hoisted
    // out, and lets are known statically.
    DCHECK((context->IsBlockContext() &&
300
            context->scope_info().is_declaration_scope()) ||
301
           context->IsFunctionContext());
302 303
    object =
        isolate->factory()->NewJSObject(isolate->context_extension_function());
304

305
    context->set_extension(*object);
306 307 308
  }

  RETURN_FAILURE_ON_EXCEPTION(isolate, JSObject::SetOwnPropertyIgnoreAttributes(
309
                                           object, name, value, NONE));
310

311
  return ReadOnlyRoots(isolate).undefined_value();
312 313
}

314 315
}  // namespace

316
RUNTIME_FUNCTION(Runtime_DeclareEvalFunction) {
317
  HandleScope scope(isolate);
318
  DCHECK_EQ(2, args.length());
319
  CONVERT_ARG_HANDLE_CHECKED(String, name, 0);
320 321
  CONVERT_ARG_HANDLE_CHECKED(Object, value, 1);
  return DeclareEvalHelper(isolate, name, value);
322 323
}

324 325 326 327 328 329 330
RUNTIME_FUNCTION(Runtime_DeclareEvalVar) {
  HandleScope scope(isolate);
  DCHECK_EQ(1, args.length());
  CONVERT_ARG_HANDLE_CHECKED(String, name, 0);
  return DeclareEvalHelper(isolate, name,
                           isolate->factory()->undefined_value());
}
331

332 333
namespace {

334
// Find the arguments of the JavaScript function invocation that called
335
// into C++ code. Collect these in a newly allocated array of handles.
336 337
std::unique_ptr<Handle<Object>[]> GetCallerArguments(Isolate* isolate,
                                                     int* total_argc) {
338 339 340
  // Find frame containing arguments passed to the caller.
  JavaScriptFrameIterator it(isolate);
  JavaScriptFrame* frame = it.frame();
341
  std::vector<SharedFunctionInfo> functions;
342
  frame->GetFunctions(&functions);
343 344
  if (functions.size() > 1) {
    int inlined_jsframe_index = static_cast<int>(functions.size()) - 1;
345
    TranslatedState translated_values(frame);
346
    translated_values.Prepare(frame->fp());
347 348 349 350 351 352 353 354 355 356 357 358 359 360

    int argument_count = 0;
    TranslatedFrame* translated_frame =
        translated_values.GetArgumentsInfoFromJSFrameIndex(
            inlined_jsframe_index, &argument_count);
    TranslatedFrame::iterator iter = translated_frame->begin();

    // Skip the function.
    iter++;

    // Skip the receiver.
    iter++;
    argument_count--;

361
    *total_argc = argument_count;
362
    std::unique_ptr<Handle<Object>[]> param_data(
363 364 365
        NewArray<Handle<Object>>(*total_argc));
    bool should_deoptimize = false;
    for (int i = 0; i < argument_count; i++) {
366 367
      // If we materialize any object, we should deoptimize the frame because we
      // might alias an object that was eliminated by escape analysis.
368 369
      should_deoptimize = should_deoptimize || iter->IsMaterializedObject();
      Handle<Object> value = iter->GetValue();
370
      param_data[i] = value;
371 372 373 374
      iter++;
    }

    if (should_deoptimize) {
375
      translated_values.StoreMaterializedValuesAndDeopt(frame);
376 377 378 379
    }

    return param_data;
  } else {
380 381 382 383
    if (it.frame()->has_adapted_arguments()) {
      it.AdvanceOneFrame();
      DCHECK(it.frame()->is_arguments_adaptor());
    }
384 385 386
    frame = it.frame();
    int args_count = frame->ComputeParametersCount();

387
    *total_argc = args_count;
388
    std::unique_ptr<Handle<Object>[]> param_data(
389 390 391
        NewArray<Handle<Object>>(*total_argc));
    for (int i = 0; i < args_count; i++) {
      Handle<Object> val = Handle<Object>(frame->GetParameter(i), isolate);
392
      param_data[i] = val;
393 394 395 396 397
    }
    return param_data;
  }
}

398 399 400
template <typename T>
Handle<JSObject> NewSloppyArguments(Isolate* isolate, Handle<JSFunction> callee,
                                    T parameters, int argument_count) {
401 402
  CHECK(!IsDerivedConstructor(callee->shared().kind()));
  DCHECK(callee->shared().has_simple_parameters());
403 404 405 406
  Handle<JSObject> result =
      isolate->factory()->NewArgumentsObject(callee, argument_count);

  // Allocate the elements if needed.
407
  int parameter_count = callee->shared().internal_formal_parameter_count();
408 409 410
  if (argument_count > 0) {
    if (parameter_count > 0) {
      int mapped_count = Min(argument_count, parameter_count);
411 412
      Handle<FixedArray> parameter_map = isolate->factory()->NewFixedArray(
          mapped_count + 2, AllocationType::kYoung);
413 414
      parameter_map->set_map(
          ReadOnlyRoots(isolate).sloppy_arguments_elements_map());
415
      result->set_map(isolate->native_context()->fast_aliased_arguments_map());
416 417 418 419
      result->set_elements(*parameter_map);

      // Store the context and the arguments array at the beginning of the
      // parameter map.
420
      Handle<Context> context(isolate->context(), isolate);
421 422
      Handle<FixedArray> arguments = isolate->factory()->NewFixedArray(
          argument_count, AllocationType::kYoung);
423 424 425 426 427 428 429 430
      parameter_map->set(0, *context);
      parameter_map->set(1, *arguments);

      // Loop over the actual parameters backwards.
      int index = argument_count - 1;
      while (index >= mapped_count) {
        // These go directly in the arguments array and have no
        // corresponding slot in the parameter map.
431
        arguments->set(index, parameters[index]);
432 433 434
        --index;
      }

435
      Handle<ScopeInfo> scope_info(callee->shared().scope_info(), isolate);
436

437 438 439 440 441 442 443 444 445 446 447 448 449 450
      // First mark all mappable slots as unmapped and copy the values into the
      // arguments object.
      for (int i = 0; i < mapped_count; i++) {
        arguments->set(i, parameters[i]);
        parameter_map->set_the_hole(i + 2);
      }

      // Walk all context slots to find context allocated parameters. Mark each
      // found parameter as mapped.
      for (int i = 0; i < scope_info->ContextLocalCount(); i++) {
        if (!scope_info->ContextLocalIsParameter(i)) continue;
        int parameter = scope_info->ContextLocalParameterNumber(i);
        if (parameter >= mapped_count) continue;
        arguments->set_the_hole(parameter);
451
        Smi slot = Smi::FromInt(scope_info->ContextHeaderLength() + i);
452
        parameter_map->set(parameter + 2, slot);
453 454 455 456
      }
    } else {
      // If there is no aliasing, the arguments object elements are not
      // special in any way.
457 458
      Handle<FixedArray> elements = isolate->factory()->NewFixedArray(
          argument_count, AllocationType::kYoung);
459 460
      result->set_elements(*elements);
      for (int i = 0; i < argument_count; ++i) {
461
        elements->set(i, parameters[i]);
462 463 464 465 466 467
      }
    }
  }
  return result;
}

468
class HandleArguments {
469 470
 public:
  explicit HandleArguments(Handle<Object>* array) : array_(array) {}
471
  Object operator[](int index) { return *array_[index]; }
472 473 474 475 476

 private:
  Handle<Object>* array_;
};

477
class ParameterArguments {
478
 public:
479
  explicit ParameterArguments(Address parameters) : parameters_(parameters) {}
480
  Object operator[](int index) {
481
    return *FullObjectSlot(parameters_ - (index + 1) * kSystemPointerSize);
482
  }
483 484

 private:
485
  Address parameters_;
486 487 488 489
};

}  // namespace

490
RUNTIME_FUNCTION(Runtime_NewSloppyArguments) {
491
  HandleScope scope(isolate);
492
  DCHECK_EQ(1, args.length());
493
  CONVERT_ARG_HANDLE_CHECKED(JSFunction, callee, 0);
494
  // This generic runtime function can also be used when the caller has been
495
  // inlined, we use the slow but accurate {GetCallerArguments}.
496
  int argument_count = 0;
497
  std::unique_ptr<Handle<Object>[]> arguments =
498
      GetCallerArguments(isolate, &argument_count);
499 500 501
  HandleArguments argument_getter(arguments.get());
  return *NewSloppyArguments(isolate, callee, argument_getter, argument_count);
}
502

503
RUNTIME_FUNCTION(Runtime_NewStrictArguments) {
504
  HandleScope scope(isolate);
505
  DCHECK_EQ(1, args.length());
506 507
  CONVERT_ARG_HANDLE_CHECKED(JSFunction, callee, 0);
  // This generic runtime function can also be used when the caller has been
508
  // inlined, we use the slow but accurate {GetCallerArguments}.
509
  int argument_count = 0;
510
  std::unique_ptr<Handle<Object>[]> arguments =
511
      GetCallerArguments(isolate, &argument_count);
512 513 514 515 516 517 518 519 520 521 522 523 524
  Handle<JSObject> result =
      isolate->factory()->NewArgumentsObject(callee, argument_count);
  if (argument_count) {
    Handle<FixedArray> array =
        isolate->factory()->NewUninitializedFixedArray(argument_count);
    DisallowHeapAllocation no_gc;
    WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
    for (int i = 0; i < argument_count; i++) {
      array->set(i, *arguments[i], mode);
    }
    result->set_elements(*array);
  }
  return *result;
525 526 527
}


528
RUNTIME_FUNCTION(Runtime_NewRestParameter) {
529
  HandleScope scope(isolate);
530
  DCHECK_EQ(1, args.length());
531
  CONVERT_ARG_HANDLE_CHECKED(JSFunction, callee, 0)
532
  int start_index = callee->shared().internal_formal_parameter_count();
533
  // This generic runtime function can also be used when the caller has been
534
  // inlined, we use the slow but accurate {GetCallerArguments}.
535
  int argument_count = 0;
536
  std::unique_ptr<Handle<Object>[]> arguments =
537
      GetCallerArguments(isolate, &argument_count);
538
  int num_elements = std::max(0, argument_count - start_index);
539 540 541
  Handle<JSObject> result = isolate->factory()->NewJSArray(
      PACKED_ELEMENTS, num_elements, num_elements,
      DONT_INITIALIZE_ARRAY_ELEMENTS);
542 543
  {
    DisallowHeapAllocation no_gc;
544
    FixedArray elements = FixedArray::cast(result->elements());
545
    WriteBarrierMode mode = elements.GetWriteBarrierMode(no_gc);
546
    for (int i = 0; i < num_elements; i++) {
547
      elements.set(i, *arguments[i + start_index], mode);
548 549 550
    }
  }
  return *result;
551 552
}

553 554
RUNTIME_FUNCTION(Runtime_NewArgumentsElements) {
  HandleScope scope(isolate);
555
  DCHECK_EQ(3, args.length());
556 557
  // Note that args[0] is the address of an array of full object pointers
  // (a.k.a. FullObjectSlot), which looks like a Smi because it's aligned.
558
  DCHECK(args[0].IsSmi());
559
  FullObjectSlot frame(args[0].ptr());
560
  CONVERT_SMI_ARG_CHECKED(length, 1);
561
  CONVERT_SMI_ARG_CHECKED(mapped_count, 2);
562 563 564 565 566
  Handle<FixedArray> result =
      isolate->factory()->NewUninitializedFixedArray(length);
  int const offset = length + 1;
  DisallowHeapAllocation no_gc;
  WriteBarrierMode mode = result->GetWriteBarrierMode(no_gc);
567 568 569 570 571
  int number_of_holes = Min(mapped_count, length);
  for (int index = 0; index < number_of_holes; ++index) {
    result->set_the_hole(isolate, index);
  }
  for (int index = number_of_holes; index < length; ++index) {
572
    result->set(index, *(frame + (offset - index)), mode);
573 574 575
  }
  return *result;
}
576

577
RUNTIME_FUNCTION(Runtime_NewClosure) {
578
  HandleScope scope(isolate);
579
  DCHECK_EQ(2, args.length());
580
  CONVERT_ARG_HANDLE_CHECKED(SharedFunctionInfo, shared, 0);
581
  CONVERT_ARG_HANDLE_CHECKED(FeedbackCell, feedback_cell, 1);
582
  Handle<Context> context(isolate->context(), isolate);
583
  Handle<JSFunction> function =
584
      isolate->factory()->NewFunctionFromSharedFunctionInfo(
585
          shared, context, feedback_cell, AllocationType::kYoung);
586
  return *function;
587 588
}

589
RUNTIME_FUNCTION(Runtime_NewClosure_Tenured) {
590
  HandleScope scope(isolate);
591
  DCHECK_EQ(2, args.length());
592
  CONVERT_ARG_HANDLE_CHECKED(SharedFunctionInfo, shared, 0);
593
  CONVERT_ARG_HANDLE_CHECKED(FeedbackCell, feedback_cell, 1);
594
  Handle<Context> context(isolate->context(), isolate);
595 596
  // The caller ensures that we pretenure closures that are assigned
  // directly to properties.
597
  Handle<JSFunction> function =
598
      isolate->factory()->NewFunctionFromSharedFunctionInfo(
599
          shared, context, feedback_cell, AllocationType::kOld);
600
  return *function;
601 602 603 604
}

RUNTIME_FUNCTION(Runtime_NewFunctionContext) {
  HandleScope scope(isolate);
605
  DCHECK_EQ(1, args.length());
606

607
  CONVERT_ARG_HANDLE_CHECKED(ScopeInfo, scope_info, 0);
608

609 610
  Handle<Context> outer(isolate->context(), isolate);
  return *isolate->factory()->NewFunctionContext(outer, scope_info);
611 612 613 614
}

RUNTIME_FUNCTION(Runtime_PushWithContext) {
  HandleScope scope(isolate);
615
  DCHECK_EQ(2, args.length());
616
  CONVERT_ARG_HANDLE_CHECKED(JSReceiver, extension_object, 0);
617
  CONVERT_ARG_HANDLE_CHECKED(ScopeInfo, scope_info, 1);
618
  Handle<Context> current(isolate->context(), isolate);
619 620
  Handle<Context> context =
      isolate->factory()->NewWithContext(current, scope_info, extension_object);
621 622 623 624 625 626
  isolate->set_context(*context);
  return *context;
}

RUNTIME_FUNCTION(Runtime_PushCatchContext) {
  HandleScope scope(isolate);
627 628 629
  DCHECK_EQ(2, args.length());
  CONVERT_ARG_HANDLE_CHECKED(Object, thrown_object, 0);
  CONVERT_ARG_HANDLE_CHECKED(ScopeInfo, scope_info, 1);
630
  Handle<Context> current(isolate->context(), isolate);
631 632
  Handle<Context> context =
      isolate->factory()->NewCatchContext(current, scope_info, thrown_object);
633 634 635 636 637 638 639
  isolate->set_context(*context);
  return *context;
}


RUNTIME_FUNCTION(Runtime_PushBlockContext) {
  HandleScope scope(isolate);
640
  DCHECK_EQ(1, args.length());
641
  CONVERT_ARG_HANDLE_CHECKED(ScopeInfo, scope_info, 0);
642
  Handle<Context> current(isolate->context(), isolate);
643
  Handle<Context> context =
644
      isolate->factory()->NewBlockContext(current, scope_info);
645 646 647 648 649 650 651
  isolate->set_context(*context);
  return *context;
}


RUNTIME_FUNCTION(Runtime_DeleteLookupSlot) {
  HandleScope scope(isolate);
652 653
  DCHECK_EQ(1, args.length());
  CONVERT_ARG_HANDLE_CHECKED(String, name, 0);
654 655 656

  int index;
  PropertyAttributes attributes;
657
  InitializationFlag flag;
658
  VariableMode mode;
659 660 661
  Handle<Context> context(isolate->context(), isolate);
  Handle<Object> holder = Context::Lookup(context, name, FOLLOW_CHAINS, &index,
                                          &attributes, &flag, &mode);
662 663 664

  // If the slot was not found the result is true.
  if (holder.is_null()) {
665
    // In case of JSProxy, an exception might have been thrown.
666 667 668
    if (isolate->has_pending_exception())
      return ReadOnlyRoots(isolate).exception();
    return ReadOnlyRoots(isolate).true_value();
669 670
  }

671 672
  // If the slot was found in a context or in module imports and exports it
  // should be DONT_DELETE.
673
  if (holder->IsContext() || holder->IsSourceTextModule()) {
674
    return ReadOnlyRoots(isolate).false_value();
675 676
  }

677
  // The slot was found in a JSReceiver, either a context extension object,
678 679
  // the global object, or the subject of a with.  Try to delete it
  // (respecting DONT_DELETE).
680
  Handle<JSReceiver> object = Handle<JSReceiver>::cast(holder);
neis's avatar
neis committed
681
  Maybe<bool> result = JSReceiver::DeleteProperty(object, name);
682
  MAYBE_RETURN(result, ReadOnlyRoots(isolate).exception());
neis's avatar
neis committed
683
  return isolate->heap()->ToBoolean(result.FromJust());
684 685 686
}


687
namespace {
688

689
MaybeHandle<Object> LoadLookupSlot(Isolate* isolate, Handle<String> name,
690
                                   ShouldThrow should_throw,
691
                                   Handle<Object>* receiver_return = nullptr) {
692 693
  int index;
  PropertyAttributes attributes;
694
  InitializationFlag flag;
695
  VariableMode mode;
696 697 698
  Handle<Context> context(isolate->context(), isolate);
  Handle<Object> holder = Context::Lookup(context, name, FOLLOW_CHAINS, &index,
                                          &attributes, &flag, &mode);
699
  if (isolate->has_pending_exception()) return MaybeHandle<Object>();
700

701
  if (!holder.is_null() && holder->IsSourceTextModule()) {
702 703
    Handle<Object> receiver = isolate->factory()->undefined_value();
    if (receiver_return) *receiver_return = receiver;
704 705
    return SourceTextModule::LoadVariable(
        isolate, Handle<SourceTextModule>::cast(holder), index);
706
  }
707
  if (index != Context::kNotFound) {
708 709 710 711
    DCHECK(holder->IsContext());
    // If the "property" we were looking for is a local variable, the
    // receiver is the global object; see ECMA-262, 3rd., 10.1.6 and 10.2.3.
    Handle<Object> receiver = isolate->factory()->undefined_value();
712
    Handle<Object> value = handle(Context::cast(*holder).get(index), isolate);
713
    // Check for uninitialized bindings.
714 715 716 717
    if (flag == kNeedsInitialization && value->IsTheHole(isolate)) {
      THROW_NEW_ERROR(isolate,
                      NewReferenceError(MessageTemplate::kNotDefined, name),
                      Object);
718
    }
719 720 721
    DCHECK(!value->IsTheHole(isolate));
    if (receiver_return) *receiver_return = receiver;
    return value;
722 723 724 725 726 727 728 729 730
  }

  // Otherwise, if the slot was found the holder is a context extension
  // object, subject of a with, or a global object.  We read the named
  // property from it.
  if (!holder.is_null()) {
    // No need to unhole the value here.  This is taken care of by the
    // GetProperty function.
    Handle<Object> value;
731
    ASSIGN_RETURN_ON_EXCEPTION(
732
        isolate, value, Object::GetProperty(isolate, holder, name), Object);
733 734 735 736 737 738 739
    if (receiver_return) {
      *receiver_return =
          (holder->IsJSGlobalObject() || holder->IsJSContextExtensionObject())
              ? Handle<Object>::cast(isolate->factory()->undefined_value())
              : holder;
    }
    return value;
740 741
  }

742
  if (should_throw == kThrowOnError) {
743
    // The property doesn't exist - throw exception.
744 745
    THROW_NEW_ERROR(
        isolate, NewReferenceError(MessageTemplate::kNotDefined, name), Object);
746
  }
747 748 749 750

  // The property doesn't exist - return undefined.
  if (receiver_return) *receiver_return = isolate->factory()->undefined_value();
  return isolate->factory()->undefined_value();
751 752
}

753
}  // namespace
754

755 756 757 758 759

RUNTIME_FUNCTION(Runtime_LoadLookupSlot) {
  HandleScope scope(isolate);
  DCHECK_EQ(1, args.length());
  CONVERT_ARG_HANDLE_CHECKED(String, name, 0);
760 761
  RETURN_RESULT_OR_FAILURE(isolate,
                           LoadLookupSlot(isolate, name, kThrowOnError));
762 763 764
}


765 766 767 768
RUNTIME_FUNCTION(Runtime_LoadLookupSlotInsideTypeof) {
  HandleScope scope(isolate);
  DCHECK_EQ(1, args.length());
  CONVERT_ARG_HANDLE_CHECKED(String, name, 0);
769
  RETURN_RESULT_OR_FAILURE(isolate, LoadLookupSlot(isolate, name, kDontThrow));
770 771 772
}


773
RUNTIME_FUNCTION_RETURN_PAIR(Runtime_LoadLookupSlotForCall) {
774
  HandleScope scope(isolate);
775
  DCHECK_EQ(1, args.length());
776
  DCHECK(args[0].IsString());
777 778 779 780
  Handle<String> name = args.at<String>(0);
  Handle<Object> value;
  Handle<Object> receiver;
  ASSIGN_RETURN_ON_EXCEPTION_VALUE(
781
      isolate, value, LoadLookupSlot(isolate, name, kThrowOnError, &receiver),
782
      MakePair(ReadOnlyRoots(isolate).exception(), Object()));
783 784
  return MakePair(*value, *receiver);
}
785

786 787 788

namespace {

789
MaybeHandle<Object> StoreLookupSlot(
790 791
    Isolate* isolate, Handle<Context> context, Handle<String> name,
    Handle<Object> value, LanguageMode language_mode,
792
    ContextLookupFlags context_lookup_flags = FOLLOW_CHAINS) {
793 794
  int index;
  PropertyAttributes attributes;
795
  InitializationFlag flag;
796
  VariableMode mode;
797 798
  bool is_sloppy_function_name;
  Handle<Object> holder =
799 800
      Context::Lookup(context, name, context_lookup_flags, &index, &attributes,
                      &flag, &mode, &is_sloppy_function_name);
801 802
  if (holder.is_null()) {
    // In case of JSProxy, an exception might have been thrown.
803
    if (isolate->has_pending_exception()) return MaybeHandle<Object>();
804
  } else if (holder->IsSourceTextModule()) {
805
    if ((attributes & READ_ONLY) == 0) {
806 807
      SourceTextModule::StoreVariable(Handle<SourceTextModule>::cast(holder),
                                      index, value);
808 809 810
    } else {
      THROW_NEW_ERROR(
          isolate, NewTypeError(MessageTemplate::kConstAssign, name), Object);
811 812
    }
    return value;
813
  }
814
  // The property was found in a context slot.
815
  if (index != Context::kNotFound) {
816
    if (flag == kNeedsInitialization &&
817
        Handle<Context>::cast(holder)->get(index).IsTheHole(isolate)) {
818 819 820
      THROW_NEW_ERROR(isolate,
                      NewReferenceError(MessageTemplate::kNotDefined, name),
                      Object);
821
    }
822 823
    if ((attributes & READ_ONLY) == 0) {
      Handle<Context>::cast(holder)->set(index, *value);
824 825 826
    } else if (!is_sloppy_function_name || is_strict(language_mode)) {
      THROW_NEW_ERROR(
          isolate, NewTypeError(MessageTemplate::kConstAssign, name), Object);
827
    }
828
    return value;
829 830 831 832 833
  }

  // Slow case: The property is not in a context slot.  It is either in a
  // context extension object, a property of the subject of a with, or a
  // property of the global object.
834
  Handle<JSReceiver> object;
835 836
  if (attributes != ABSENT) {
    // The property exists on the holder.
837
    object = Handle<JSReceiver>::cast(holder);
838
  } else if (is_strict(language_mode)) {
839
    // If absent in strict mode: throw.
840 841
    THROW_NEW_ERROR(
        isolate, NewReferenceError(MessageTemplate::kNotDefined, name), Object);
842 843
  } else {
    // If absent in sloppy mode: add the property to the global object.
844
    object = handle(context->global_object(), isolate);
845 846
  }

847 848 849
  ASSIGN_RETURN_ON_EXCEPTION(isolate, value,
                             Object::SetProperty(isolate, object, name, value),
                             Object);
850 851 852 853 854 855 856 857 858 859 860
  return value;
}

}  // namespace


RUNTIME_FUNCTION(Runtime_StoreLookupSlot_Sloppy) {
  HandleScope scope(isolate);
  DCHECK_EQ(2, args.length());
  CONVERT_ARG_HANDLE_CHECKED(String, name, 0);
  CONVERT_ARG_HANDLE_CHECKED(Object, value, 1);
861
  Handle<Context> context(isolate->context(), isolate);
862
  RETURN_RESULT_OR_FAILURE(
863 864
      isolate,
      StoreLookupSlot(isolate, context, name, value, LanguageMode::kSloppy));
865 866
}

867
RUNTIME_FUNCTION(Runtime_StoreLookupSlot_Strict) {
868 869 870 871
  HandleScope scope(isolate);
  DCHECK_EQ(2, args.length());
  CONVERT_ARG_HANDLE_CHECKED(String, name, 0);
  CONVERT_ARG_HANDLE_CHECKED(Object, value, 1);
872
  Handle<Context> context(isolate->context(), isolate);
873
  RETURN_RESULT_OR_FAILURE(
874 875
      isolate,
      StoreLookupSlot(isolate, context, name, value, LanguageMode::kStrict));
876
}
877

878 879 880
// Store into a dynamic declaration context for sloppy-mode block-scoped
// function hoisting which leaks out of an eval.
RUNTIME_FUNCTION(Runtime_StoreLookupSlot_SloppyHoisting) {
881 882 883 884
  HandleScope scope(isolate);
  DCHECK_EQ(2, args.length());
  CONVERT_ARG_HANDLE_CHECKED(String, name, 0);
  CONVERT_ARG_HANDLE_CHECKED(Object, value, 1);
885 886
  const ContextLookupFlags lookup_flags =
      static_cast<ContextLookupFlags>(DONT_FOLLOW_CHAINS);
887
  Handle<Context> declaration_context(isolate->context().declaration_context(),
888
                                      isolate);
889
  RETURN_RESULT_OR_FAILURE(
890 891
      isolate, StoreLookupSlot(isolate, declaration_context, name, value,
                               LanguageMode::kSloppy, lookup_flags));
892 893
}

Simon Zünd's avatar
Simon Zünd committed
894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914
RUNTIME_FUNCTION(Runtime_StoreGlobalNoHoleCheckForReplLet) {
  HandleScope scope(isolate);
  DCHECK_EQ(2, args.length());
  CONVERT_ARG_HANDLE_CHECKED(String, name, 0);
  CONVERT_ARG_HANDLE_CHECKED(Object, value, 1);

  Handle<Context> native_context = isolate->native_context();
  Handle<ScriptContextTable> script_contexts(
      native_context->script_context_table(), isolate);

  ScriptContextTable::LookupResult lookup_result;
  bool found = ScriptContextTable::Lookup(isolate, *script_contexts, *name,
                                          &lookup_result);
  CHECK(found);
  Handle<Context> script_context = ScriptContextTable::GetContext(
      isolate, script_contexts, lookup_result.context_index);

  script_context->set(lookup_result.slot_index, *value);
  return *value;
}

915 916
}  // namespace internal
}  // namespace v8