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