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