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.
5 #include "src/runtime/runtime-utils.h"
7 #include "src/accessors.h"
8 #include "src/arguments.h"
9 #include "src/frames-inl.h"
10 #include "src/messages.h"
11 #include "src/scopeinfo.h"
12 #include "src/scopes.h"
17 static Object* ThrowRedeclarationError(Isolate* isolate, Handle<String> name) {
18 HandleScope scope(isolate);
19 THROW_NEW_ERROR_RETURN_FAILURE(
20 isolate, NewTypeError(MessageTemplate::kVarRedeclaration, name));
24 RUNTIME_FUNCTION(Runtime_ThrowConstAssignError) {
25 HandleScope scope(isolate);
26 THROW_NEW_ERROR_RETURN_FAILURE(isolate,
27 NewTypeError(MessageTemplate::kConstAssign));
31 // May throw a RedeclarationError.
32 static Object* DeclareGlobals(Isolate* isolate, Handle<GlobalObject> global,
33 Handle<String> name, Handle<Object> value,
34 PropertyAttributes attr, bool is_var,
35 bool is_const, bool is_function) {
36 Handle<ScriptContextTable> script_contexts(
37 global->native_context()->script_context_table());
38 ScriptContextTable::LookupResult lookup;
39 if (ScriptContextTable::Lookup(script_contexts, name, &lookup) &&
40 IsLexicalVariableMode(lookup.mode)) {
41 return ThrowRedeclarationError(isolate, name);
44 // Do the lookup own properties only, see ES5 erratum.
45 LookupIterator it(global, name, LookupIterator::HIDDEN_SKIP_INTERCEPTOR);
46 Maybe<PropertyAttributes> maybe = JSReceiver::GetPropertyAttributes(&it);
47 if (!maybe.IsJust()) return isolate->heap()->exception();
50 PropertyAttributes old_attributes = maybe.FromJust();
51 // The name was declared before; check for conflicting re-declarations.
52 if (is_const) return ThrowRedeclarationError(isolate, name);
54 // Skip var re-declarations.
55 if (is_var) return isolate->heap()->undefined_value();
58 if ((old_attributes & DONT_DELETE) != 0) {
59 // Only allow reconfiguring globals to functions in user code (no
60 // natives, which are marked as read-only).
61 DCHECK((attr & READ_ONLY) == 0);
63 // Check whether we can reconfigure the existing property into a
65 PropertyDetails old_details = it.property_details();
66 // TODO(verwaest): ACCESSOR_CONSTANT invalidly includes
67 // ExecutableAccessInfo,
68 // which are actually data properties, not accessor properties.
69 if (old_details.IsReadOnly() || old_details.IsDontEnum() ||
70 old_details.type() == ACCESSOR_CONSTANT) {
71 return ThrowRedeclarationError(isolate, name);
73 // If the existing property is not configurable, keep its attributes. Do
74 attr = old_attributes;
78 // Define or redefine own property.
79 RETURN_FAILURE_ON_EXCEPTION(isolate, JSObject::SetOwnPropertyIgnoreAttributes(
80 global, name, value, attr));
82 return isolate->heap()->undefined_value();
86 RUNTIME_FUNCTION(Runtime_DeclareGlobals) {
87 HandleScope scope(isolate);
88 DCHECK_EQ(2, args.length());
89 Handle<GlobalObject> global(isolate->global_object());
90 Handle<Context> context(isolate->context());
92 CONVERT_ARG_HANDLE_CHECKED(FixedArray, pairs, 0);
93 CONVERT_SMI_ARG_CHECKED(flags, 1);
95 // Traverse the name/value pairs and set the properties.
96 int length = pairs->length();
97 for (int i = 0; i < length; i += 2) {
98 HandleScope scope(isolate);
99 Handle<String> name(String::cast(pairs->get(i)));
100 Handle<Object> initial_value(pairs->get(i + 1), isolate);
102 // We have to declare a global const property. To capture we only
103 // assign to it when evaluating the assignment for "const x =
104 // <expr>" the initial value is the hole.
105 bool is_var = initial_value->IsUndefined();
106 bool is_const = initial_value->IsTheHole();
107 bool is_function = initial_value->IsSharedFunctionInfo();
109 BoolToInt(is_var) + BoolToInt(is_const) + BoolToInt(is_function));
111 Handle<Object> value;
113 // Copy the function and update its context. Use it as value.
114 Handle<SharedFunctionInfo> shared =
115 Handle<SharedFunctionInfo>::cast(initial_value);
116 Handle<JSFunction> function =
117 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared, context,
121 value = isolate->factory()->undefined_value();
124 // Compute the property attributes. According to ECMA-262,
125 // the property must be non-configurable except in eval.
126 bool is_native = DeclareGlobalsNativeFlag::decode(flags);
127 bool is_eval = DeclareGlobalsEvalFlag::decode(flags);
129 if (is_const) attr |= READ_ONLY;
130 if (is_function && is_native) attr |= READ_ONLY;
131 if (!is_const && !is_eval) attr |= DONT_DELETE;
133 Object* result = DeclareGlobals(isolate, global, name, value,
134 static_cast<PropertyAttributes>(attr),
135 is_var, is_const, is_function);
136 if (isolate->has_pending_exception()) return result;
139 return isolate->heap()->undefined_value();
143 RUNTIME_FUNCTION(Runtime_InitializeVarGlobal) {
144 HandleScope scope(isolate);
146 // args[1] == language_mode
147 // args[2] == value (optional)
149 // Determine if we need to assign to the variable if it already
150 // exists (based on the number of arguments).
151 RUNTIME_ASSERT(args.length() == 3);
153 CONVERT_ARG_HANDLE_CHECKED(String, name, 0);
154 CONVERT_LANGUAGE_MODE_ARG_CHECKED(language_mode, 1);
155 CONVERT_ARG_HANDLE_CHECKED(Object, value, 2);
157 Handle<GlobalObject> global(isolate->context()->global_object());
158 Handle<Object> result;
159 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
160 isolate, result, Object::SetProperty(global, name, value, language_mode));
165 RUNTIME_FUNCTION(Runtime_InitializeConstGlobal) {
166 HandleScope handle_scope(isolate);
167 // All constants are declared with an initial value. The name
168 // of the constant is the first argument and the initial value
170 RUNTIME_ASSERT(args.length() == 2);
171 CONVERT_ARG_HANDLE_CHECKED(String, name, 0);
172 CONVERT_ARG_HANDLE_CHECKED(Object, value, 1);
174 Handle<GlobalObject> global = isolate->global_object();
176 // Lookup the property as own on the global object.
177 LookupIterator it(global, name, LookupIterator::HIDDEN_SKIP_INTERCEPTOR);
178 Maybe<PropertyAttributes> maybe = JSReceiver::GetPropertyAttributes(&it);
179 DCHECK(maybe.IsJust());
180 PropertyAttributes old_attributes = maybe.FromJust();
182 PropertyAttributes attr =
183 static_cast<PropertyAttributes>(DONT_DELETE | READ_ONLY);
184 // Set the value if the property is either missing, or the property attributes
185 // allow setting the value without invoking an accessor.
187 // Ignore if we can't reconfigure the value.
188 if ((old_attributes & DONT_DELETE) != 0) {
189 if ((old_attributes & READ_ONLY) != 0 ||
190 it.state() == LookupIterator::ACCESSOR) {
193 attr = static_cast<PropertyAttributes>(old_attributes | READ_ONLY);
197 RETURN_FAILURE_ON_EXCEPTION(isolate, JSObject::SetOwnPropertyIgnoreAttributes(
198 global, name, value, attr));
206 Object* DeclareLookupSlot(Isolate* isolate, Handle<String> name,
207 Handle<Object> initial_value,
208 PropertyAttributes attr) {
209 // Declarations are always made in a function, eval or script context, or
210 // a declaration block scope.
211 // In the case of eval code, the context passed is the context of the caller,
212 // which may be some nested context and not the declaration context.
213 Handle<Context> context_arg(isolate->context(), isolate);
214 Handle<Context> context(context_arg->declaration_context(), isolate);
216 // TODO(verwaest): Unify the encoding indicating "var" with DeclareGlobals.
217 bool is_var = *initial_value == NULL;
218 bool is_const = initial_value->IsTheHole();
219 bool is_function = initial_value->IsJSFunction();
221 BoolToInt(is_var) + BoolToInt(is_const) + BoolToInt(is_function));
224 PropertyAttributes attributes;
225 ContextLookupFlags flags = DONT_FOLLOW_CHAINS;
226 BindingFlags binding_flags;
227 Handle<Object> holder =
228 context->Lookup(name, flags, &index, &attributes, &binding_flags);
229 if (holder.is_null()) {
230 // In case of JSProxy, an exception might have been thrown.
231 if (isolate->has_pending_exception()) return isolate->heap()->exception();
234 Handle<JSObject> object;
235 Handle<Object> value =
236 is_function ? initial_value
237 : Handle<Object>::cast(isolate->factory()->undefined_value());
239 // TODO(verwaest): This case should probably not be covered by this function,
240 // but by DeclareGlobals instead.
241 if (attributes != ABSENT && holder->IsJSGlobalObject()) {
242 return DeclareGlobals(isolate, Handle<JSGlobalObject>::cast(holder), name,
243 value, attr, is_var, is_const, is_function);
245 if (context_arg->extension()->IsJSGlobalObject()) {
246 Handle<JSGlobalObject> global(
247 JSGlobalObject::cast(context_arg->extension()), isolate);
248 return DeclareGlobals(isolate, global, name, value, attr, is_var, is_const,
250 } else if (context->IsScriptContext()) {
251 DCHECK(context->global_object()->IsJSGlobalObject());
252 Handle<JSGlobalObject> global(
253 JSGlobalObject::cast(context->global_object()), isolate);
254 return DeclareGlobals(isolate, global, name, value, attr, is_var, is_const,
258 if (attributes != ABSENT) {
259 // The name was declared before; check for conflicting re-declarations.
260 if (is_const || (attributes & READ_ONLY) != 0) {
261 return ThrowRedeclarationError(isolate, name);
264 // Skip var re-declarations.
265 if (is_var) return isolate->heap()->undefined_value();
268 if (index != Context::kNotFound) {
269 DCHECK(holder.is_identical_to(context));
270 context->set(index, *initial_value);
271 return isolate->heap()->undefined_value();
274 object = Handle<JSObject>::cast(holder);
276 } else if (context->has_extension()) {
277 // Sloppy varblock contexts might not have an extension object yet,
278 // in which case their extension is a ScopeInfo.
279 if (context->extension()->IsScopeInfo()) {
280 DCHECK(context->IsBlockContext());
281 object = isolate->factory()->NewJSObject(
282 isolate->context_extension_function());
283 Handle<Object> extension =
284 isolate->factory()->NewSloppyBlockWithEvalContextExtension(
285 handle(context->scope_info()), object);
286 context->set_extension(*extension);
288 object = handle(context->extension_object(), isolate);
290 DCHECK(object->IsJSContextExtensionObject() || object->IsJSGlobalObject());
292 DCHECK(context->IsFunctionContext());
294 isolate->factory()->NewJSObject(isolate->context_extension_function());
295 context->set_extension(*object);
298 RETURN_FAILURE_ON_EXCEPTION(isolate, JSObject::SetOwnPropertyIgnoreAttributes(
299 object, name, value, attr));
301 return isolate->heap()->undefined_value();
307 RUNTIME_FUNCTION(Runtime_DeclareLookupSlot) {
308 HandleScope scope(isolate);
309 DCHECK_EQ(2, args.length());
310 CONVERT_ARG_HANDLE_CHECKED(String, name, 0);
311 CONVERT_ARG_HANDLE_CHECKED(Object, initial_value, 1);
313 return DeclareLookupSlot(isolate, name, initial_value, NONE);
317 RUNTIME_FUNCTION(Runtime_DeclareReadOnlyLookupSlot) {
318 HandleScope scope(isolate);
319 DCHECK_EQ(2, args.length());
320 CONVERT_ARG_HANDLE_CHECKED(String, name, 0);
321 CONVERT_ARG_HANDLE_CHECKED(Object, initial_value, 1);
323 return DeclareLookupSlot(isolate, name, initial_value, READ_ONLY);
327 RUNTIME_FUNCTION(Runtime_InitializeLegacyConstLookupSlot) {
328 HandleScope scope(isolate);
329 DCHECK(args.length() == 3);
331 CONVERT_ARG_HANDLE_CHECKED(Object, value, 0);
332 DCHECK(!value->IsTheHole());
333 // Initializations are always done in a function or native context.
334 CONVERT_ARG_HANDLE_CHECKED(Context, context_arg, 1);
335 Handle<Context> context(context_arg->declaration_context());
336 CONVERT_ARG_HANDLE_CHECKED(String, name, 2);
339 PropertyAttributes attributes;
340 ContextLookupFlags flags = DONT_FOLLOW_CHAINS;
341 BindingFlags binding_flags;
342 Handle<Object> holder =
343 context->Lookup(name, flags, &index, &attributes, &binding_flags);
344 if (holder.is_null()) {
345 // In case of JSProxy, an exception might have been thrown.
346 if (isolate->has_pending_exception()) return isolate->heap()->exception();
349 if (index != Context::kNotFound) {
350 DCHECK(holder->IsContext());
351 // Property was found in a context. Perform the assignment if the constant
352 // was uninitialized.
353 Handle<Context> context = Handle<Context>::cast(holder);
354 DCHECK((attributes & READ_ONLY) != 0);
355 if (context->get(index)->IsTheHole()) context->set(index, *value);
359 PropertyAttributes attr =
360 static_cast<PropertyAttributes>(DONT_DELETE | READ_ONLY);
362 // Strict mode handling not needed (legacy const is disallowed in strict
365 // The declared const was configurable, and may have been deleted in the
366 // meanwhile. If so, re-introduce the variable in the context extension.
367 if (attributes == ABSENT) {
368 Handle<Context> declaration_context(context_arg->declaration_context());
369 if (declaration_context->IsScriptContext()) {
370 holder = handle(declaration_context->global_object(), isolate);
372 holder = handle(declaration_context->extension_object(), isolate);
373 DCHECK(!holder.is_null());
375 CHECK(holder->IsJSObject());
377 // For JSContextExtensionObjects, the initializer can be run multiple times
378 // if in a for loop: for (var i = 0; i < 2; i++) { const x = i; }. Only the
379 // first assignment should go through. For JSGlobalObjects, additionally any
380 // code can run in between that modifies the declared property.
381 DCHECK(holder->IsJSGlobalObject() || holder->IsJSContextExtensionObject());
383 LookupIterator it(holder, name, LookupIterator::HIDDEN_SKIP_INTERCEPTOR);
384 Maybe<PropertyAttributes> maybe = JSReceiver::GetPropertyAttributes(&it);
385 if (!maybe.IsJust()) return isolate->heap()->exception();
386 PropertyAttributes old_attributes = maybe.FromJust();
388 // Ignore if we can't reconfigure the value.
389 if ((old_attributes & DONT_DELETE) != 0) {
390 if ((old_attributes & READ_ONLY) != 0 ||
391 it.state() == LookupIterator::ACCESSOR) {
394 attr = static_cast<PropertyAttributes>(old_attributes | READ_ONLY);
398 RETURN_FAILURE_ON_EXCEPTION(
399 isolate, JSObject::SetOwnPropertyIgnoreAttributes(
400 Handle<JSObject>::cast(holder), name, value, attr));
406 static Handle<JSObject> NewSloppyArguments(Isolate* isolate,
407 Handle<JSFunction> callee,
409 int argument_count) {
410 CHECK(!IsSubclassConstructor(callee->shared()->kind()));
411 DCHECK(callee->has_simple_parameters());
412 Handle<JSObject> result =
413 isolate->factory()->NewArgumentsObject(callee, argument_count);
415 // Allocate the elements if needed.
416 int parameter_count = callee->shared()->internal_formal_parameter_count();
417 if (argument_count > 0) {
418 if (parameter_count > 0) {
419 int mapped_count = Min(argument_count, parameter_count);
420 Handle<FixedArray> parameter_map =
421 isolate->factory()->NewFixedArray(mapped_count + 2, NOT_TENURED);
422 parameter_map->set_map(isolate->heap()->sloppy_arguments_elements_map());
423 result->set_map(isolate->native_context()->fast_aliased_arguments_map());
424 result->set_elements(*parameter_map);
426 // Store the context and the arguments array at the beginning of the
428 Handle<Context> context(isolate->context());
429 Handle<FixedArray> arguments =
430 isolate->factory()->NewFixedArray(argument_count, NOT_TENURED);
431 parameter_map->set(0, *context);
432 parameter_map->set(1, *arguments);
434 // Loop over the actual parameters backwards.
435 int index = argument_count - 1;
436 while (index >= mapped_count) {
437 // These go directly in the arguments array and have no
438 // corresponding slot in the parameter map.
439 arguments->set(index, *(parameters - index - 1));
443 Handle<ScopeInfo> scope_info(callee->shared()->scope_info());
445 // Detect duplicate names to the right in the parameter list.
446 Handle<String> name(scope_info->ParameterName(index));
447 int context_local_count = scope_info->ContextLocalCount();
448 bool duplicate = false;
449 for (int j = index + 1; j < parameter_count; ++j) {
450 if (scope_info->ParameterName(j) == *name) {
457 // This goes directly in the arguments array with a hole in the
459 arguments->set(index, *(parameters - index - 1));
460 parameter_map->set_the_hole(index + 2);
462 // The context index goes in the parameter map with a hole in the
464 int context_index = -1;
465 for (int j = 0; j < context_local_count; ++j) {
466 if (scope_info->ContextLocalName(j) == *name) {
472 DCHECK(context_index >= 0);
473 arguments->set_the_hole(index);
476 Smi::FromInt(Context::MIN_CONTEXT_SLOTS + context_index));
482 // If there is no aliasing, the arguments object elements are not
483 // special in any way.
484 Handle<FixedArray> elements =
485 isolate->factory()->NewFixedArray(argument_count, NOT_TENURED);
486 result->set_elements(*elements);
487 for (int i = 0; i < argument_count; ++i) {
488 elements->set(i, *(parameters - i - 1));
496 static Handle<JSObject> NewStrictArguments(Isolate* isolate,
497 Handle<JSFunction> callee,
499 int argument_count) {
500 Handle<JSObject> result =
501 isolate->factory()->NewArgumentsObject(callee, argument_count);
503 if (argument_count > 0) {
504 Handle<FixedArray> array =
505 isolate->factory()->NewUninitializedFixedArray(argument_count);
506 DisallowHeapAllocation no_gc;
507 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
508 for (int i = 0; i < argument_count; i++) {
509 array->set(i, *--parameters, mode);
511 result->set_elements(*array);
517 RUNTIME_FUNCTION(Runtime_NewArguments) {
518 HandleScope scope(isolate);
519 DCHECK(args.length() == 1);
520 CONVERT_ARG_HANDLE_CHECKED(JSFunction, callee, 0);
521 JavaScriptFrameIterator it(isolate);
523 // Find the frame that holds the actual arguments passed to the function.
524 it.AdvanceToArgumentsFrame();
525 JavaScriptFrame* frame = it.frame();
527 // Determine parameter location on the stack and dispatch on language mode.
528 int argument_count = frame->GetArgumentsLength();
529 Object** parameters = reinterpret_cast<Object**>(frame->GetParameterSlot(-1));
531 return (is_strict(callee->shared()->language_mode()) ||
532 !callee->has_simple_parameters())
533 ? *NewStrictArguments(isolate, callee, parameters, argument_count)
534 : *NewSloppyArguments(isolate, callee, parameters, argument_count);
538 RUNTIME_FUNCTION(Runtime_NewSloppyArguments) {
539 HandleScope scope(isolate);
540 DCHECK(args.length() == 3);
541 CONVERT_ARG_HANDLE_CHECKED(JSFunction, callee, 0);
542 Object** parameters = reinterpret_cast<Object**>(args[1]);
543 CONVERT_SMI_ARG_CHECKED(argument_count, 2);
544 return *NewSloppyArguments(isolate, callee, parameters, argument_count);
548 RUNTIME_FUNCTION(Runtime_NewStrictArguments) {
549 HandleScope scope(isolate);
550 DCHECK(args.length() == 3);
551 CONVERT_ARG_HANDLE_CHECKED(JSFunction, callee, 0)
552 Object** parameters = reinterpret_cast<Object**>(args[1]);
553 CONVERT_SMI_ARG_CHECKED(argument_count, 2);
554 return *NewStrictArguments(isolate, callee, parameters, argument_count);
558 static Handle<JSArray> NewRestParam(Isolate* isolate, Object** parameters,
559 int num_params, int rest_index,
560 LanguageMode language_mode) {
561 parameters -= rest_index;
562 int num_elements = std::max(0, num_params - rest_index);
563 Handle<FixedArray> elements =
564 isolate->factory()->NewUninitializedFixedArray(num_elements);
565 for (int i = 0; i < num_elements; ++i) {
566 elements->set(i, *--parameters);
568 return isolate->factory()->NewJSArrayWithElements(
569 elements, FAST_ELEMENTS, num_elements, strength(language_mode));
573 RUNTIME_FUNCTION(Runtime_NewRestParam) {
574 HandleScope scope(isolate);
575 DCHECK(args.length() == 4);
576 Object** parameters = reinterpret_cast<Object**>(args[0]);
577 CONVERT_SMI_ARG_CHECKED(num_params, 1);
578 CONVERT_SMI_ARG_CHECKED(rest_index, 2);
579 CONVERT_SMI_ARG_CHECKED(language_mode, 3);
581 return *NewRestParam(isolate, parameters, num_params, rest_index,
582 static_cast<LanguageMode>(language_mode));
586 RUNTIME_FUNCTION(Runtime_NewRestParamSlow) {
587 HandleScope scope(isolate);
588 DCHECK(args.length() == 2);
589 CONVERT_SMI_ARG_CHECKED(rest_index, 0);
590 CONVERT_SMI_ARG_CHECKED(language_mode, 1);
592 JavaScriptFrameIterator it(isolate);
594 // Find the frame that holds the actual arguments passed to the function.
595 it.AdvanceToArgumentsFrame();
596 JavaScriptFrame* frame = it.frame();
598 int argument_count = frame->GetArgumentsLength();
599 Object** parameters = reinterpret_cast<Object**>(frame->GetParameterSlot(-1));
601 return *NewRestParam(isolate, parameters, argument_count, rest_index,
602 static_cast<LanguageMode>(language_mode));
606 RUNTIME_FUNCTION(Runtime_NewClosureFromStubFailure) {
607 HandleScope scope(isolate);
608 DCHECK(args.length() == 1);
609 CONVERT_ARG_HANDLE_CHECKED(SharedFunctionInfo, shared, 0);
610 Handle<Context> context(isolate->context());
611 PretenureFlag pretenure_flag = NOT_TENURED;
612 return *isolate->factory()->NewFunctionFromSharedFunctionInfo(shared, context,
617 RUNTIME_FUNCTION(Runtime_NewClosure) {
618 HandleScope scope(isolate);
619 DCHECK(args.length() == 3);
620 CONVERT_ARG_HANDLE_CHECKED(Context, context, 0);
621 CONVERT_ARG_HANDLE_CHECKED(SharedFunctionInfo, shared, 1);
622 CONVERT_BOOLEAN_ARG_CHECKED(pretenure, 2);
624 // The caller ensures that we pretenure closures that are assigned
625 // directly to properties.
626 PretenureFlag pretenure_flag = pretenure ? TENURED : NOT_TENURED;
627 return *isolate->factory()->NewFunctionFromSharedFunctionInfo(shared, context,
631 static Object* FindNameClash(Handle<ScopeInfo> scope_info,
632 Handle<GlobalObject> global_object,
633 Handle<ScriptContextTable> script_context) {
634 Isolate* isolate = scope_info->GetIsolate();
635 for (int var = 0; var < scope_info->ContextLocalCount(); var++) {
636 Handle<String> name(scope_info->ContextLocalName(var));
637 VariableMode mode = scope_info->ContextLocalMode(var);
638 ScriptContextTable::LookupResult lookup;
639 if (ScriptContextTable::Lookup(script_context, name, &lookup)) {
640 if (IsLexicalVariableMode(mode) || IsLexicalVariableMode(lookup.mode)) {
641 return ThrowRedeclarationError(isolate, name);
645 if (IsLexicalVariableMode(mode)) {
646 LookupIterator it(global_object, name,
647 LookupIterator::HIDDEN_SKIP_INTERCEPTOR);
648 Maybe<PropertyAttributes> maybe = JSReceiver::GetPropertyAttributes(&it);
649 if (!maybe.IsJust()) return isolate->heap()->exception();
650 if ((maybe.FromJust() & DONT_DELETE) != 0) {
651 return ThrowRedeclarationError(isolate, name);
654 GlobalObject::InvalidatePropertyCell(global_object, name);
657 return isolate->heap()->undefined_value();
661 RUNTIME_FUNCTION(Runtime_NewScriptContext) {
662 HandleScope scope(isolate);
663 DCHECK(args.length() == 2);
665 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
666 CONVERT_ARG_HANDLE_CHECKED(ScopeInfo, scope_info, 1);
667 Handle<GlobalObject> global_object(function->context()->global_object());
668 Handle<Context> native_context(global_object->native_context());
669 Handle<ScriptContextTable> script_context_table(
670 native_context->script_context_table());
672 Object* name_clash_result =
673 FindNameClash(scope_info, global_object, script_context_table);
674 if (isolate->has_pending_exception()) return name_clash_result;
676 // Script contexts have a canonical empty function as their closure, not the
677 // anonymous closure containing the global code. See
678 // FullCodeGenerator::PushFunctionArgumentForContextAllocation.
679 Handle<JSFunction> closure(global_object->IsJSBuiltinsObject()
681 : native_context->closure());
682 Handle<Context> result =
683 isolate->factory()->NewScriptContext(closure, scope_info);
685 result->InitializeGlobalSlots();
687 DCHECK(function->context() == isolate->context());
688 DCHECK(*global_object == result->global_object());
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);
697 RUNTIME_FUNCTION(Runtime_NewFunctionContext) {
698 HandleScope scope(isolate);
699 DCHECK(args.length() == 1);
701 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
703 DCHECK(function->context() == isolate->context());
704 int length = function->shared()->scope_info()->ContextLength();
705 return *isolate->factory()->NewFunctionContext(length, function);
709 RUNTIME_FUNCTION(Runtime_PushWithContext) {
710 HandleScope scope(isolate);
711 DCHECK(args.length() == 2);
712 Handle<JSReceiver> extension_object;
713 if (args[0]->IsJSReceiver()) {
714 extension_object = args.at<JSReceiver>(0);
716 // Try to convert the object to a proper JavaScript object.
717 MaybeHandle<JSReceiver> maybe_object =
718 Object::ToObject(isolate, args.at<Object>(0));
719 if (!maybe_object.ToHandle(&extension_object)) {
720 Handle<Object> handle = args.at<Object>(0);
721 THROW_NEW_ERROR_RETURN_FAILURE(
722 isolate, NewTypeError(MessageTemplate::kWithExpression, handle));
726 Handle<JSFunction> function;
727 if (args[1]->IsSmi()) {
728 // A smi sentinel indicates a context nested inside global code rather
729 // than some function. There is a canonical empty function that can be
730 // gotten from the native context.
731 function = handle(isolate->native_context()->closure());
733 function = args.at<JSFunction>(1);
736 Handle<Context> current(isolate->context());
737 Handle<Context> context =
738 isolate->factory()->NewWithContext(function, current, extension_object);
739 isolate->set_context(*context);
744 RUNTIME_FUNCTION(Runtime_PushCatchContext) {
745 HandleScope scope(isolate);
746 DCHECK(args.length() == 3);
747 CONVERT_ARG_HANDLE_CHECKED(String, name, 0);
748 CONVERT_ARG_HANDLE_CHECKED(Object, thrown_object, 1);
749 Handle<JSFunction> function;
750 if (args[2]->IsSmi()) {
751 // A smi sentinel indicates a context nested inside global code rather
752 // than some function. There is a canonical empty function that can be
753 // gotten from the native context.
754 function = handle(isolate->native_context()->closure());
756 function = args.at<JSFunction>(2);
758 Handle<Context> current(isolate->context());
759 Handle<Context> context = isolate->factory()->NewCatchContext(
760 function, current, name, thrown_object);
761 isolate->set_context(*context);
766 RUNTIME_FUNCTION(Runtime_PushBlockContext) {
767 HandleScope scope(isolate);
768 DCHECK(args.length() == 2);
769 CONVERT_ARG_HANDLE_CHECKED(ScopeInfo, scope_info, 0);
770 Handle<JSFunction> function;
771 if (args[1]->IsSmi()) {
772 // A smi sentinel indicates a context nested inside global code rather
773 // than some function. There is a canonical empty function that can be
774 // gotten from the native context.
775 function = handle(isolate->native_context()->closure());
777 function = args.at<JSFunction>(1);
779 Handle<Context> current(isolate->context());
780 Handle<Context> context =
781 isolate->factory()->NewBlockContext(function, current, scope_info);
782 isolate->set_context(*context);
787 RUNTIME_FUNCTION(Runtime_IsJSModule) {
788 SealHandleScope shs(isolate);
789 DCHECK(args.length() == 1);
790 CONVERT_ARG_CHECKED(Object, obj, 0);
791 return isolate->heap()->ToBoolean(obj->IsJSModule());
795 RUNTIME_FUNCTION(Runtime_PushModuleContext) {
796 SealHandleScope shs(isolate);
797 DCHECK(args.length() == 2);
798 CONVERT_SMI_ARG_CHECKED(index, 0);
800 if (!args[1]->IsScopeInfo()) {
801 // Module already initialized. Find hosting context and retrieve context.
802 Context* host = Context::cast(isolate->context())->script_context();
803 Context* context = Context::cast(host->get(index));
804 DCHECK(context->previous() == isolate->context());
805 isolate->set_context(context);
809 CONVERT_ARG_HANDLE_CHECKED(ScopeInfo, scope_info, 1);
811 // Allocate module context.
812 HandleScope scope(isolate);
813 Factory* factory = isolate->factory();
814 Handle<Context> context = factory->NewModuleContext(scope_info);
815 Handle<JSModule> module = factory->NewJSModule(context, scope_info);
816 context->set_module(*module);
817 Context* previous = isolate->context();
818 context->set_previous(previous);
819 context->set_closure(previous->closure());
820 context->set_global_object(previous->global_object());
821 isolate->set_context(*context);
823 // Find hosting scope and initialize internal variable holding module there.
824 previous->script_context()->set(index, *context);
830 RUNTIME_FUNCTION(Runtime_DeclareModules) {
831 HandleScope scope(isolate);
832 DCHECK(args.length() == 1);
833 CONVERT_ARG_HANDLE_CHECKED(FixedArray, descriptions, 0);
834 Context* host_context = isolate->context();
836 for (int i = 0; i < descriptions->length(); ++i) {
837 Handle<ModuleInfo> description(ModuleInfo::cast(descriptions->get(i)));
838 int host_index = description->host_index();
839 Handle<Context> context(Context::cast(host_context->get(host_index)));
840 Handle<JSModule> module(context->module());
842 for (int j = 0; j < description->length(); ++j) {
843 Handle<String> name(description->name(j));
844 VariableMode mode = description->mode(j);
845 int index = description->index(j);
852 PropertyAttributes attr =
853 IsImmutableVariableMode(mode) ? FROZEN : SEALED;
854 Handle<AccessorInfo> info =
855 Accessors::MakeModuleExport(name, index, attr);
856 Handle<Object> result =
857 JSObject::SetAccessor(module, info).ToHandleChecked();
858 DCHECK(!result->IsUndefined());
870 JSObject::PreventExtensions(module).Assert();
873 DCHECK(!isolate->has_pending_exception());
874 return isolate->heap()->undefined_value();
878 RUNTIME_FUNCTION(Runtime_DeleteLookupSlot) {
879 HandleScope scope(isolate);
880 DCHECK(args.length() == 2);
882 CONVERT_ARG_HANDLE_CHECKED(Context, context, 0);
883 CONVERT_ARG_HANDLE_CHECKED(String, name, 1);
886 PropertyAttributes attributes;
887 ContextLookupFlags flags = FOLLOW_CHAINS;
888 BindingFlags binding_flags;
889 Handle<Object> holder =
890 context->Lookup(name, flags, &index, &attributes, &binding_flags);
892 // If the slot was not found the result is true.
893 if (holder.is_null()) {
894 // In case of JSProxy, an exception might have been thrown.
895 if (isolate->has_pending_exception()) return isolate->heap()->exception();
896 return isolate->heap()->true_value();
899 // If the slot was found in a context, it should be DONT_DELETE.
900 if (holder->IsContext()) {
901 return isolate->heap()->false_value();
904 // The slot was found in a JSObject, either a context extension object,
905 // the global object, or the subject of a with. Try to delete it
906 // (respecting DONT_DELETE).
907 Handle<JSObject> object = Handle<JSObject>::cast(holder);
908 Handle<Object> result;
909 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result,
910 JSReceiver::DeleteProperty(object, name));
915 static Object* ComputeReceiverForNonGlobal(Isolate* isolate, JSObject* holder) {
916 DCHECK(!holder->IsGlobalObject());
918 // If the holder isn't a context extension object, we just return it
919 // as the receiver. This allows arguments objects to be used as
920 // receivers, but only if they are put in the context scope chain
921 // explicitly via a with-statement.
922 if (holder->map()->instance_type() != JS_CONTEXT_EXTENSION_OBJECT_TYPE) {
925 // Fall back to using the global object as the implicit receiver if
926 // the property turns out to be a local variable allocated in a
927 // context extension object - introduced via eval.
928 return isolate->heap()->undefined_value();
932 static ObjectPair LoadLookupSlotHelper(Arguments args, Isolate* isolate,
934 HandleScope scope(isolate);
935 DCHECK_EQ(2, args.length());
937 if (!args[0]->IsContext() || !args[1]->IsString()) {
938 return MakePair(isolate->ThrowIllegalOperation(), NULL);
940 Handle<Context> context = args.at<Context>(0);
941 Handle<String> name = args.at<String>(1);
944 PropertyAttributes attributes;
945 ContextLookupFlags flags = FOLLOW_CHAINS;
946 BindingFlags binding_flags;
947 Handle<Object> holder =
948 context->Lookup(name, flags, &index, &attributes, &binding_flags);
949 if (isolate->has_pending_exception()) {
950 return MakePair(isolate->heap()->exception(), NULL);
953 if (index != Context::kNotFound) {
954 DCHECK(holder->IsContext());
955 // If the "property" we were looking for is a local variable, the
956 // receiver is the global object; see ECMA-262, 3rd., 10.1.6 and 10.2.3.
957 Handle<Object> receiver = isolate->factory()->undefined_value();
958 Object* value = Context::cast(*holder)->get(index);
959 // Check for uninitialized bindings.
960 switch (binding_flags) {
961 case MUTABLE_CHECK_INITIALIZED:
962 case IMMUTABLE_CHECK_INITIALIZED_HARMONY:
963 if (value->IsTheHole()) {
964 Handle<Object> error = isolate->factory()->NewReferenceError(
965 MessageTemplate::kNotDefined, name);
966 isolate->Throw(*error);
967 return MakePair(isolate->heap()->exception(), NULL);
970 case MUTABLE_IS_INITIALIZED:
971 case IMMUTABLE_IS_INITIALIZED:
972 case IMMUTABLE_IS_INITIALIZED_HARMONY:
973 DCHECK(!value->IsTheHole());
974 return MakePair(value, *receiver);
975 case IMMUTABLE_CHECK_INITIALIZED:
976 if (value->IsTheHole()) {
977 DCHECK((attributes & READ_ONLY) != 0);
978 value = isolate->heap()->undefined_value();
980 return MakePair(value, *receiver);
981 case MISSING_BINDING:
983 return MakePair(NULL, NULL);
987 // Otherwise, if the slot was found the holder is a context extension
988 // object, subject of a with, or a global object. We read the named
990 if (!holder.is_null()) {
991 Handle<JSReceiver> object = Handle<JSReceiver>::cast(holder);
992 // GetProperty below can cause GC.
993 Handle<Object> receiver_handle(
994 object->IsGlobalObject()
995 ? Object::cast(isolate->heap()->undefined_value())
996 : object->IsJSProxy() ? static_cast<Object*>(*object)
997 : ComputeReceiverForNonGlobal(
998 isolate, JSObject::cast(*object)),
1001 // No need to unhole the value here. This is taken care of by the
1002 // GetProperty function.
1003 Handle<Object> value;
1004 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
1005 isolate, value, Object::GetProperty(object, name),
1006 MakePair(isolate->heap()->exception(), NULL));
1007 return MakePair(*value, *receiver_handle);
1011 // The property doesn't exist - throw exception.
1012 Handle<Object> error = isolate->factory()->NewReferenceError(
1013 MessageTemplate::kNotDefined, name);
1014 isolate->Throw(*error);
1015 return MakePair(isolate->heap()->exception(), NULL);
1017 // The property doesn't exist - return undefined.
1018 return MakePair(isolate->heap()->undefined_value(),
1019 isolate->heap()->undefined_value());
1024 RUNTIME_FUNCTION_RETURN_PAIR(Runtime_LoadLookupSlot) {
1025 return LoadLookupSlotHelper(args, isolate, true);
1029 RUNTIME_FUNCTION_RETURN_PAIR(Runtime_LoadLookupSlotNoReferenceError) {
1030 return LoadLookupSlotHelper(args, isolate, false);
1034 RUNTIME_FUNCTION(Runtime_StoreLookupSlot) {
1035 HandleScope scope(isolate);
1036 DCHECK(args.length() == 4);
1038 CONVERT_ARG_HANDLE_CHECKED(Object, value, 0);
1039 CONVERT_ARG_HANDLE_CHECKED(Context, context, 1);
1040 CONVERT_ARG_HANDLE_CHECKED(String, name, 2);
1041 CONVERT_LANGUAGE_MODE_ARG_CHECKED(language_mode, 3);
1044 PropertyAttributes attributes;
1045 ContextLookupFlags flags = FOLLOW_CHAINS;
1046 BindingFlags binding_flags;
1047 Handle<Object> holder =
1048 context->Lookup(name, flags, &index, &attributes, &binding_flags);
1049 if (holder.is_null()) {
1050 // In case of JSProxy, an exception might have been thrown.
1051 if (isolate->has_pending_exception()) return isolate->heap()->exception();
1054 // The property was found in a context slot.
1055 if (index != Context::kNotFound) {
1056 if ((binding_flags == MUTABLE_CHECK_INITIALIZED ||
1057 binding_flags == IMMUTABLE_CHECK_INITIALIZED_HARMONY) &&
1058 Handle<Context>::cast(holder)->is_the_hole(index)) {
1059 THROW_NEW_ERROR_RETURN_FAILURE(
1060 isolate, NewReferenceError(MessageTemplate::kNotDefined, name));
1062 if ((attributes & READ_ONLY) == 0) {
1063 Handle<Context>::cast(holder)->set(index, *value);
1064 } else if (is_strict(language_mode)) {
1065 // Setting read only property in strict mode.
1066 THROW_NEW_ERROR_RETURN_FAILURE(
1067 isolate, NewTypeError(MessageTemplate::kStrictCannotAssign, name));
1072 // Slow case: The property is not in a context slot. It is either in a
1073 // context extension object, a property of the subject of a with, or a
1074 // property of the global object.
1075 Handle<JSReceiver> object;
1076 if (attributes != ABSENT) {
1077 // The property exists on the holder.
1078 object = Handle<JSReceiver>::cast(holder);
1079 } else if (is_strict(language_mode)) {
1080 // If absent in strict mode: throw.
1081 THROW_NEW_ERROR_RETURN_FAILURE(
1082 isolate, NewReferenceError(MessageTemplate::kNotDefined, name));
1084 // If absent in sloppy mode: add the property to the global object.
1085 object = Handle<JSReceiver>(context->global_object());
1088 RETURN_FAILURE_ON_EXCEPTION(
1089 isolate, Object::SetProperty(object, name, value, language_mode));
1095 RUNTIME_FUNCTION(Runtime_ArgumentsLength) {
1096 SealHandleScope shs(isolate);
1097 DCHECK(args.length() == 0);
1098 JavaScriptFrameIterator it(isolate);
1099 JavaScriptFrame* frame = it.frame();
1100 return Smi::FromInt(frame->GetArgumentsLength());
1104 RUNTIME_FUNCTION(Runtime_Arguments) {
1105 SealHandleScope shs(isolate);
1106 DCHECK(args.length() == 1);
1107 CONVERT_ARG_HANDLE_CHECKED(Object, raw_key, 0);
1109 // Compute the frame holding the arguments.
1110 JavaScriptFrameIterator it(isolate);
1111 it.AdvanceToArgumentsFrame();
1112 JavaScriptFrame* frame = it.frame();
1114 // Get the actual number of provided arguments.
1115 const uint32_t n = frame->ComputeParametersCount();
1117 // Try to convert the key to an index. If successful and within
1118 // index return the the argument from the frame.
1120 if (raw_key->ToArrayIndex(&index) && index < n) {
1121 return frame->GetParameter(index);
1124 HandleScope scope(isolate);
1125 if (raw_key->IsSymbol()) {
1126 Handle<Symbol> symbol = Handle<Symbol>::cast(raw_key);
1127 if (Name::Equals(symbol, isolate->factory()->iterator_symbol())) {
1128 return isolate->native_context()->array_values_iterator();
1130 // Lookup in the initial Object.prototype object.
1131 Handle<Object> result;
1132 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
1134 Object::GetProperty(isolate->initial_object_prototype(),
1135 Handle<Symbol>::cast(raw_key)));
1139 // Convert the key to a string.
1140 Handle<Object> converted;
1141 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, converted,
1142 Object::ToString(isolate, raw_key));
1143 Handle<String> key = Handle<String>::cast(converted);
1145 // Try to convert the string key into an array index.
1146 if (key->AsArrayIndex(&index)) {
1148 return frame->GetParameter(index);
1150 Handle<Object> initial_prototype(isolate->initial_object_prototype());
1151 Handle<Object> result;
1152 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
1154 Object::GetElement(isolate, initial_prototype, index));
1159 // Handle special arguments properties.
1160 if (String::Equals(isolate->factory()->length_string(), key)) {
1161 return Smi::FromInt(n);
1163 if (String::Equals(isolate->factory()->callee_string(), key)) {
1164 JSFunction* function = frame->function();
1165 if (is_strict(function->shared()->language_mode())) {
1166 THROW_NEW_ERROR_RETURN_FAILURE(
1167 isolate, NewTypeError(MessageTemplate::kStrictPoisonPill));
1172 // Lookup in the initial Object.prototype object.
1173 Handle<Object> result;
1174 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
1176 Object::GetProperty(isolate->initial_object_prototype(), key));
1179 } // namespace internal