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