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.
7 #include "src/accessors.h"
8 #include "src/arguments.h"
9 #include "src/frames-inl.h"
10 #include "src/runtime/runtime-utils.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 Handle<Object> args[1] = {name};
20 THROW_NEW_ERROR_RETURN_FAILURE(
21 isolate, NewTypeError("var_redeclaration", HandleVector(args, 1)));
25 RUNTIME_FUNCTION(Runtime_ThrowConstAssignError) {
26 HandleScope scope(isolate);
27 THROW_NEW_ERROR_RETURN_FAILURE(
29 NewTypeError("harmony_const_assign", HandleVector<Object>(NULL, 0)));
33 // May throw a RedeclarationError.
34 static Object* DeclareGlobals(Isolate* isolate, Handle<GlobalObject> global,
35 Handle<String> name, Handle<Object> value,
36 PropertyAttributes attr, bool is_var,
37 bool is_const, bool is_function) {
38 Handle<ScriptContextTable> script_contexts(
39 global->native_context()->script_context_table());
40 ScriptContextTable::LookupResult lookup;
41 if (ScriptContextTable::Lookup(script_contexts, name, &lookup) &&
42 IsLexicalVariableMode(lookup.mode)) {
43 return ThrowRedeclarationError(isolate, name);
46 // Do the lookup own properties only, see ES5 erratum.
47 LookupIterator it(global, name, LookupIterator::HIDDEN_SKIP_INTERCEPTOR);
48 Maybe<PropertyAttributes> maybe = JSReceiver::GetPropertyAttributes(&it);
49 if (!maybe.has_value) return isolate->heap()->exception();
52 PropertyAttributes old_attributes = maybe.value;
53 // The name was declared before; check for conflicting re-declarations.
54 if (is_const) return ThrowRedeclarationError(isolate, name);
56 // Skip var re-declarations.
57 if (is_var) return isolate->heap()->undefined_value();
60 if ((old_attributes & DONT_DELETE) != 0) {
61 // Only allow reconfiguring globals to functions in user code (no
62 // natives, which are marked as read-only).
63 DCHECK((attr & READ_ONLY) == 0);
65 // Check whether we can reconfigure the existing property into a
67 PropertyDetails old_details = it.property_details();
68 // TODO(verwaest): ACCESSOR_CONSTANT invalidly includes
69 // ExecutableAccessInfo,
70 // which are actually data properties, not accessor properties.
71 if (old_details.IsReadOnly() || old_details.IsDontEnum() ||
72 old_details.type() == ACCESSOR_CONSTANT) {
73 return ThrowRedeclarationError(isolate, name);
75 // If the existing property is not configurable, keep its attributes. Do
76 attr = old_attributes;
80 // Define or redefine own property.
81 RETURN_FAILURE_ON_EXCEPTION(isolate, JSObject::SetOwnPropertyIgnoreAttributes(
82 global, name, value, attr));
84 return isolate->heap()->undefined_value();
88 RUNTIME_FUNCTION(Runtime_DeclareGlobals) {
89 HandleScope scope(isolate);
90 DCHECK(args.length() == 3);
91 Handle<GlobalObject> global(isolate->global_object());
93 CONVERT_ARG_HANDLE_CHECKED(Context, context, 0);
94 CONVERT_ARG_HANDLE_CHECKED(FixedArray, pairs, 1);
95 CONVERT_SMI_ARG_CHECKED(flags, 2);
97 // Traverse the name/value pairs and set the properties.
98 int length = pairs->length();
99 for (int i = 0; i < length; i += 2) {
100 HandleScope scope(isolate);
101 Handle<String> name(String::cast(pairs->get(i)));
102 Handle<Object> initial_value(pairs->get(i + 1), isolate);
104 // We have to declare a global const property. To capture we only
105 // assign to it when evaluating the assignment for "const x =
106 // <expr>" the initial value is the hole.
107 bool is_var = initial_value->IsUndefined();
108 bool is_const = initial_value->IsTheHole();
109 bool is_function = initial_value->IsSharedFunctionInfo();
111 BoolToInt(is_var) + BoolToInt(is_const) + BoolToInt(is_function));
113 Handle<Object> value;
115 // Copy the function and update its context. Use it as value.
116 Handle<SharedFunctionInfo> shared =
117 Handle<SharedFunctionInfo>::cast(initial_value);
118 Handle<JSFunction> function =
119 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared, context,
123 value = isolate->factory()->undefined_value();
126 // Compute the property attributes. According to ECMA-262,
127 // the property must be non-configurable except in eval.
128 bool is_native = DeclareGlobalsNativeFlag::decode(flags);
129 bool is_eval = DeclareGlobalsEvalFlag::decode(flags);
131 if (is_const) attr |= READ_ONLY;
132 if (is_function && is_native) attr |= READ_ONLY;
133 if (!is_const && !is_eval) attr |= DONT_DELETE;
135 Object* result = DeclareGlobals(isolate, global, name, value,
136 static_cast<PropertyAttributes>(attr),
137 is_var, is_const, is_function);
138 if (isolate->has_pending_exception()) return result;
141 return isolate->heap()->undefined_value();
145 RUNTIME_FUNCTION(Runtime_InitializeVarGlobal) {
146 HandleScope scope(isolate);
148 // args[1] == language_mode
149 // args[2] == value (optional)
151 // Determine if we need to assign to the variable if it already
152 // exists (based on the number of arguments).
153 RUNTIME_ASSERT(args.length() == 3);
155 CONVERT_ARG_HANDLE_CHECKED(String, name, 0);
156 CONVERT_LANGUAGE_MODE_ARG_CHECKED(language_mode, 1);
157 CONVERT_ARG_HANDLE_CHECKED(Object, value, 2);
159 Handle<GlobalObject> global(isolate->context()->global_object());
160 Handle<Object> result;
161 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
162 isolate, result, Object::SetProperty(global, name, value, language_mode));
167 RUNTIME_FUNCTION(Runtime_InitializeConstGlobal) {
168 HandleScope handle_scope(isolate);
169 // All constants are declared with an initial value. The name
170 // of the constant is the first argument and the initial value
172 RUNTIME_ASSERT(args.length() == 2);
173 CONVERT_ARG_HANDLE_CHECKED(String, name, 0);
174 CONVERT_ARG_HANDLE_CHECKED(Object, value, 1);
176 Handle<GlobalObject> global = isolate->global_object();
178 // Lookup the property as own on the global object.
179 LookupIterator it(global, name, LookupIterator::HIDDEN_SKIP_INTERCEPTOR);
180 Maybe<PropertyAttributes> maybe = JSReceiver::GetPropertyAttributes(&it);
181 DCHECK(maybe.has_value);
182 PropertyAttributes old_attributes = maybe.value;
184 PropertyAttributes attr =
185 static_cast<PropertyAttributes>(DONT_DELETE | READ_ONLY);
186 // Set the value if the property is either missing, or the property attributes
187 // allow setting the value without invoking an accessor.
189 // Ignore if we can't reconfigure the value.
190 if ((old_attributes & DONT_DELETE) != 0) {
191 if ((old_attributes & READ_ONLY) != 0 ||
192 it.state() == LookupIterator::ACCESSOR) {
195 attr = static_cast<PropertyAttributes>(old_attributes | READ_ONLY);
199 RETURN_FAILURE_ON_EXCEPTION(isolate, JSObject::SetOwnPropertyIgnoreAttributes(
200 global, name, value, attr));
206 RUNTIME_FUNCTION(Runtime_DeclareLookupSlot) {
207 HandleScope scope(isolate);
208 DCHECK(args.length() == 4);
210 // Declarations are always made in a function, eval or script context. In
211 // 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 CONVERT_ARG_HANDLE_CHECKED(Context, context_arg, 0);
214 Handle<Context> context(context_arg->declaration_context());
215 CONVERT_ARG_HANDLE_CHECKED(String, name, 1);
216 CONVERT_SMI_ARG_CHECKED(attr_arg, 2);
217 PropertyAttributes attr = static_cast<PropertyAttributes>(attr_arg);
218 RUNTIME_ASSERT(attr == READ_ONLY || attr == NONE);
219 CONVERT_ARG_HANDLE_CHECKED(Object, initial_value, 3);
221 // TODO(verwaest): Unify the encoding indicating "var" with DeclareGlobals.
222 bool is_var = *initial_value == NULL;
223 bool is_const = initial_value->IsTheHole();
224 bool is_function = initial_value->IsJSFunction();
226 BoolToInt(is_var) + BoolToInt(is_const) + BoolToInt(is_function));
229 PropertyAttributes attributes;
230 ContextLookupFlags flags = DONT_FOLLOW_CHAINS;
231 BindingFlags binding_flags;
232 Handle<Object> holder =
233 context->Lookup(name, flags, &index, &attributes, &binding_flags);
235 Handle<JSObject> object;
236 Handle<Object> value =
237 is_function ? initial_value
238 : Handle<Object>::cast(isolate->factory()->undefined_value());
240 // TODO(verwaest): This case should probably not be covered by this function,
241 // but by DeclareGlobals instead.
242 if ((attributes != ABSENT && holder->IsJSGlobalObject()) ||
243 (context_arg->has_extension() &&
244 context_arg->extension()->IsJSGlobalObject())) {
245 return DeclareGlobals(isolate, Handle<JSGlobalObject>::cast(holder), name,
246 value, attr, is_var, is_const, is_function);
249 if (attributes != ABSENT) {
250 // The name was declared before; check for conflicting re-declarations.
251 if (is_const || (attributes & READ_ONLY) != 0) {
252 return ThrowRedeclarationError(isolate, name);
255 // Skip var re-declarations.
256 if (is_var) return isolate->heap()->undefined_value();
260 DCHECK(holder.is_identical_to(context));
261 context->set(index, *initial_value);
262 return isolate->heap()->undefined_value();
265 object = Handle<JSObject>::cast(holder);
267 } else if (context->has_extension()) {
268 object = handle(JSObject::cast(context->extension()));
269 DCHECK(object->IsJSContextExtensionObject() || object->IsJSGlobalObject());
271 DCHECK(context->IsFunctionContext());
273 isolate->factory()->NewJSObject(isolate->context_extension_function());
274 context->set_extension(*object);
277 RETURN_FAILURE_ON_EXCEPTION(isolate, JSObject::SetOwnPropertyIgnoreAttributes(
278 object, name, value, attr));
280 return isolate->heap()->undefined_value();
284 RUNTIME_FUNCTION(Runtime_InitializeLegacyConstLookupSlot) {
285 HandleScope scope(isolate);
286 DCHECK(args.length() == 3);
288 CONVERT_ARG_HANDLE_CHECKED(Object, value, 0);
289 DCHECK(!value->IsTheHole());
290 // Initializations are always done in a function or native context.
291 CONVERT_ARG_HANDLE_CHECKED(Context, context_arg, 1);
292 Handle<Context> context(context_arg->declaration_context());
293 CONVERT_ARG_HANDLE_CHECKED(String, name, 2);
296 PropertyAttributes attributes;
297 ContextLookupFlags flags = DONT_FOLLOW_CHAINS;
298 BindingFlags binding_flags;
299 Handle<Object> holder =
300 context->Lookup(name, flags, &index, &attributes, &binding_flags);
303 DCHECK(holder->IsContext());
304 // Property was found in a context. Perform the assignment if the constant
305 // was uninitialized.
306 Handle<Context> context = Handle<Context>::cast(holder);
307 DCHECK((attributes & READ_ONLY) != 0);
308 if (context->get(index)->IsTheHole()) context->set(index, *value);
312 PropertyAttributes attr =
313 static_cast<PropertyAttributes>(DONT_DELETE | READ_ONLY);
315 // Strict mode handling not needed (legacy const is disallowed in strict
318 // The declared const was configurable, and may have been deleted in the
319 // meanwhile. If so, re-introduce the variable in the context extension.
320 if (attributes == ABSENT) {
321 Handle<Context> declaration_context(context_arg->declaration_context());
322 DCHECK(declaration_context->has_extension());
323 holder = handle(declaration_context->extension(), isolate);
324 CHECK(holder->IsJSObject());
326 // For JSContextExtensionObjects, the initializer can be run multiple times
327 // if in a for loop: for (var i = 0; i < 2; i++) { const x = i; }. Only the
328 // first assignment should go through. For JSGlobalObjects, additionally any
329 // code can run in between that modifies the declared property.
330 DCHECK(holder->IsJSGlobalObject() || holder->IsJSContextExtensionObject());
332 LookupIterator it(holder, name, LookupIterator::HIDDEN_SKIP_INTERCEPTOR);
333 Maybe<PropertyAttributes> maybe = JSReceiver::GetPropertyAttributes(&it);
334 if (!maybe.has_value) return isolate->heap()->exception();
335 PropertyAttributes old_attributes = maybe.value;
337 // Ignore if we can't reconfigure the value.
338 if ((old_attributes & DONT_DELETE) != 0) {
339 if ((old_attributes & READ_ONLY) != 0 ||
340 it.state() == LookupIterator::ACCESSOR) {
343 attr = static_cast<PropertyAttributes>(old_attributes | READ_ONLY);
347 RETURN_FAILURE_ON_EXCEPTION(
348 isolate, JSObject::SetOwnPropertyIgnoreAttributes(
349 Handle<JSObject>::cast(holder), name, value, attr));
355 static Handle<JSObject> NewSloppyArguments(Isolate* isolate,
356 Handle<JSFunction> callee,
358 int argument_count) {
359 CHECK(!IsSubclassConstructor(callee->shared()->kind()));
360 DCHECK(callee->is_simple_parameter_list());
361 Handle<JSObject> result =
362 isolate->factory()->NewArgumentsObject(callee, argument_count);
364 // Allocate the elements if needed.
365 int parameter_count = callee->shared()->internal_formal_parameter_count();
366 if (argument_count > 0) {
367 if (parameter_count > 0) {
368 int mapped_count = Min(argument_count, parameter_count);
369 Handle<FixedArray> parameter_map =
370 isolate->factory()->NewFixedArray(mapped_count + 2, NOT_TENURED);
371 parameter_map->set_map(isolate->heap()->sloppy_arguments_elements_map());
373 Handle<Map> map = Map::Copy(handle(result->map()), "NewSloppyArguments");
374 map->set_elements_kind(SLOPPY_ARGUMENTS_ELEMENTS);
376 result->set_map(*map);
377 result->set_elements(*parameter_map);
379 // Store the context and the arguments array at the beginning of the
381 Handle<Context> context(isolate->context());
382 Handle<FixedArray> arguments =
383 isolate->factory()->NewFixedArray(argument_count, NOT_TENURED);
384 parameter_map->set(0, *context);
385 parameter_map->set(1, *arguments);
387 // Loop over the actual parameters backwards.
388 int index = argument_count - 1;
389 while (index >= mapped_count) {
390 // These go directly in the arguments array and have no
391 // corresponding slot in the parameter map.
392 arguments->set(index, *(parameters - index - 1));
396 Handle<ScopeInfo> scope_info(callee->shared()->scope_info());
398 // Detect duplicate names to the right in the parameter list.
399 Handle<String> name(scope_info->ParameterName(index));
400 int context_local_count = scope_info->ContextLocalCount();
401 bool duplicate = false;
402 for (int j = index + 1; j < parameter_count; ++j) {
403 if (scope_info->ParameterName(j) == *name) {
410 // This goes directly in the arguments array with a hole in the
412 arguments->set(index, *(parameters - index - 1));
413 parameter_map->set_the_hole(index + 2);
415 // The context index goes in the parameter map with a hole in the
417 int context_index = -1;
418 for (int j = 0; j < context_local_count; ++j) {
419 if (scope_info->ContextLocalName(j) == *name) {
425 DCHECK(context_index >= 0);
426 arguments->set_the_hole(index);
429 Smi::FromInt(Context::MIN_CONTEXT_SLOTS + context_index));
435 // If there is no aliasing, the arguments object elements are not
436 // special in any way.
437 Handle<FixedArray> elements =
438 isolate->factory()->NewFixedArray(argument_count, NOT_TENURED);
439 result->set_elements(*elements);
440 for (int i = 0; i < argument_count; ++i) {
441 elements->set(i, *(parameters - i - 1));
449 static Handle<JSObject> NewStrictArguments(Isolate* isolate,
450 Handle<JSFunction> callee,
452 int argument_count) {
453 Handle<JSObject> result =
454 isolate->factory()->NewArgumentsObject(callee, argument_count);
456 if (argument_count > 0) {
457 Handle<FixedArray> array =
458 isolate->factory()->NewUninitializedFixedArray(argument_count);
459 DisallowHeapAllocation no_gc;
460 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
461 for (int i = 0; i < argument_count; i++) {
462 array->set(i, *--parameters, mode);
464 result->set_elements(*array);
470 RUNTIME_FUNCTION(Runtime_NewArguments) {
471 HandleScope scope(isolate);
472 DCHECK(args.length() == 1);
473 CONVERT_ARG_HANDLE_CHECKED(JSFunction, callee, 0);
474 JavaScriptFrameIterator it(isolate);
476 // Find the frame that holds the actual arguments passed to the function.
477 it.AdvanceToArgumentsFrame();
478 JavaScriptFrame* frame = it.frame();
480 // Determine parameter location on the stack and dispatch on language mode.
481 int argument_count = frame->GetArgumentsLength();
482 Object** parameters = reinterpret_cast<Object**>(frame->GetParameterSlot(-1));
484 return (is_strict(callee->shared()->language_mode()) ||
485 !callee->is_simple_parameter_list())
486 ? *NewStrictArguments(isolate, callee, parameters, argument_count)
487 : *NewSloppyArguments(isolate, callee, parameters, argument_count);
491 RUNTIME_FUNCTION(Runtime_NewSloppyArguments) {
492 HandleScope scope(isolate);
493 DCHECK(args.length() == 3);
494 CONVERT_ARG_HANDLE_CHECKED(JSFunction, callee, 0);
495 Object** parameters = reinterpret_cast<Object**>(args[1]);
496 CONVERT_SMI_ARG_CHECKED(argument_count, 2);
497 return *NewSloppyArguments(isolate, callee, parameters, argument_count);
501 RUNTIME_FUNCTION(Runtime_NewStrictArguments) {
502 HandleScope scope(isolate);
503 DCHECK(args.length() == 3);
504 CONVERT_ARG_HANDLE_CHECKED(JSFunction, callee, 0)
505 Object** parameters = reinterpret_cast<Object**>(args[1]);
506 CONVERT_SMI_ARG_CHECKED(argument_count, 2);
507 return *NewStrictArguments(isolate, callee, parameters, argument_count);
511 static Handle<JSArray> NewRestParam(Isolate* isolate,
515 parameters -= rest_index;
516 int num_elements = std::max(0, num_params - rest_index);
517 Handle<FixedArray> elements =
518 isolate->factory()->NewUninitializedFixedArray(num_elements);
519 for (int i = 0; i < num_elements; ++i) {
520 elements->set(i, *--parameters);
522 return isolate->factory()->NewJSArrayWithElements(elements, FAST_ELEMENTS,
527 RUNTIME_FUNCTION(Runtime_NewRestParam) {
528 HandleScope scope(isolate);
529 DCHECK(args.length() == 3);
530 Object** parameters = reinterpret_cast<Object**>(args[0]);
531 CONVERT_SMI_ARG_CHECKED(num_params, 1);
532 CONVERT_SMI_ARG_CHECKED(rest_index, 2);
534 return *NewRestParam(isolate, parameters, num_params, rest_index);
538 RUNTIME_FUNCTION(Runtime_NewRestParamSlow) {
539 HandleScope scope(isolate);
540 DCHECK(args.length() == 1);
541 CONVERT_SMI_ARG_CHECKED(rest_index, 0);
543 JavaScriptFrameIterator it(isolate);
545 // Find the frame that holds the actual arguments passed to the function.
546 it.AdvanceToArgumentsFrame();
547 JavaScriptFrame* frame = it.frame();
549 int argument_count = frame->GetArgumentsLength();
550 Object** parameters = reinterpret_cast<Object**>(frame->GetParameterSlot(-1));
552 return *NewRestParam(isolate, parameters, argument_count, rest_index);
556 RUNTIME_FUNCTION(Runtime_NewClosureFromStubFailure) {
557 HandleScope scope(isolate);
558 DCHECK(args.length() == 1);
559 CONVERT_ARG_HANDLE_CHECKED(SharedFunctionInfo, shared, 0);
560 Handle<Context> context(isolate->context());
561 PretenureFlag pretenure_flag = NOT_TENURED;
562 return *isolate->factory()->NewFunctionFromSharedFunctionInfo(shared, context,
567 RUNTIME_FUNCTION(Runtime_NewClosure) {
568 HandleScope scope(isolate);
569 DCHECK(args.length() == 3);
570 CONVERT_ARG_HANDLE_CHECKED(Context, context, 0);
571 CONVERT_ARG_HANDLE_CHECKED(SharedFunctionInfo, shared, 1);
572 CONVERT_BOOLEAN_ARG_CHECKED(pretenure, 2);
574 // The caller ensures that we pretenure closures that are assigned
575 // directly to properties.
576 PretenureFlag pretenure_flag = pretenure ? TENURED : NOT_TENURED;
577 return *isolate->factory()->NewFunctionFromSharedFunctionInfo(shared, context,
581 static Object* FindNameClash(Handle<ScopeInfo> scope_info,
582 Handle<GlobalObject> global_object,
583 Handle<ScriptContextTable> script_context) {
584 Isolate* isolate = scope_info->GetIsolate();
585 for (int var = 0; var < scope_info->ContextLocalCount(); var++) {
586 Handle<String> name(scope_info->ContextLocalName(var));
587 VariableMode mode = scope_info->ContextLocalMode(var);
588 ScriptContextTable::LookupResult lookup;
589 if (ScriptContextTable::Lookup(script_context, name, &lookup)) {
590 if (IsLexicalVariableMode(mode) || IsLexicalVariableMode(lookup.mode)) {
591 return ThrowRedeclarationError(isolate, name);
595 if (IsLexicalVariableMode(mode)) {
596 LookupIterator it(global_object, name,
597 LookupIterator::HIDDEN_SKIP_INTERCEPTOR);
598 Maybe<PropertyAttributes> maybe = JSReceiver::GetPropertyAttributes(&it);
599 if (!maybe.has_value) return isolate->heap()->exception();
600 if ((maybe.value & DONT_DELETE) != 0) {
601 return ThrowRedeclarationError(isolate, name);
604 GlobalObject::InvalidatePropertyCell(global_object, name);
607 return isolate->heap()->undefined_value();
611 RUNTIME_FUNCTION(Runtime_NewScriptContext) {
612 HandleScope scope(isolate);
613 DCHECK(args.length() == 2);
615 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
616 CONVERT_ARG_HANDLE_CHECKED(ScopeInfo, scope_info, 1);
617 Handle<GlobalObject> global_object(function->context()->global_object());
618 Handle<Context> native_context(global_object->native_context());
619 Handle<ScriptContextTable> script_context_table(
620 native_context->script_context_table());
622 Handle<String> clashed_name;
623 Object* name_clash_result =
624 FindNameClash(scope_info, global_object, script_context_table);
625 if (isolate->has_pending_exception()) return name_clash_result;
627 Handle<Context> result =
628 isolate->factory()->NewScriptContext(function, scope_info);
630 DCHECK(function->context() == isolate->context());
631 DCHECK(function->context()->global_object() == result->global_object());
633 Handle<ScriptContextTable> new_script_context_table =
634 ScriptContextTable::Extend(script_context_table, result);
635 native_context->set_script_context_table(*new_script_context_table);
640 RUNTIME_FUNCTION(Runtime_NewFunctionContext) {
641 HandleScope scope(isolate);
642 DCHECK(args.length() == 1);
644 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
646 DCHECK(function->context() == isolate->context());
647 int length = function->shared()->scope_info()->ContextLength();
648 return *isolate->factory()->NewFunctionContext(length, function);
652 RUNTIME_FUNCTION(Runtime_PushWithContext) {
653 HandleScope scope(isolate);
654 DCHECK(args.length() == 2);
655 Handle<JSReceiver> extension_object;
656 if (args[0]->IsJSReceiver()) {
657 extension_object = args.at<JSReceiver>(0);
659 // Try to convert the object to a proper JavaScript object.
660 MaybeHandle<JSReceiver> maybe_object =
661 Object::ToObject(isolate, args.at<Object>(0));
662 if (!maybe_object.ToHandle(&extension_object)) {
663 Handle<Object> handle = args.at<Object>(0);
664 THROW_NEW_ERROR_RETURN_FAILURE(
665 isolate, NewTypeError("with_expression", HandleVector(&handle, 1)));
669 Handle<JSFunction> function;
670 if (args[1]->IsSmi()) {
671 // A smi sentinel indicates a context nested inside global code rather
672 // than some function. There is a canonical empty function that can be
673 // gotten from the native context.
674 function = handle(isolate->native_context()->closure());
676 function = args.at<JSFunction>(1);
679 Handle<Context> current(isolate->context());
680 Handle<Context> context =
681 isolate->factory()->NewWithContext(function, current, extension_object);
682 isolate->set_context(*context);
687 RUNTIME_FUNCTION(Runtime_PushCatchContext) {
688 HandleScope scope(isolate);
689 DCHECK(args.length() == 3);
690 CONVERT_ARG_HANDLE_CHECKED(String, name, 0);
691 CONVERT_ARG_HANDLE_CHECKED(Object, thrown_object, 1);
692 Handle<JSFunction> function;
693 if (args[2]->IsSmi()) {
694 // A smi sentinel indicates a context nested inside global code rather
695 // than some function. There is a canonical empty function that can be
696 // gotten from the native context.
697 function = handle(isolate->native_context()->closure());
699 function = args.at<JSFunction>(2);
701 Handle<Context> current(isolate->context());
702 Handle<Context> context = isolate->factory()->NewCatchContext(
703 function, current, name, thrown_object);
704 isolate->set_context(*context);
709 RUNTIME_FUNCTION(Runtime_PushBlockContext) {
710 HandleScope scope(isolate);
711 DCHECK(args.length() == 2);
712 CONVERT_ARG_HANDLE_CHECKED(ScopeInfo, scope_info, 0);
713 Handle<JSFunction> function;
714 if (args[1]->IsSmi()) {
715 // A smi sentinel indicates a context nested inside global code rather
716 // than some function. There is a canonical empty function that can be
717 // gotten from the native context.
718 function = handle(isolate->native_context()->closure());
720 function = args.at<JSFunction>(1);
722 Handle<Context> current(isolate->context());
723 Handle<Context> context =
724 isolate->factory()->NewBlockContext(function, current, scope_info);
725 isolate->set_context(*context);
730 RUNTIME_FUNCTION(Runtime_IsJSModule) {
731 SealHandleScope shs(isolate);
732 DCHECK(args.length() == 1);
733 CONVERT_ARG_CHECKED(Object, obj, 0);
734 return isolate->heap()->ToBoolean(obj->IsJSModule());
738 RUNTIME_FUNCTION(Runtime_PushModuleContext) {
739 SealHandleScope shs(isolate);
740 DCHECK(args.length() == 2);
741 CONVERT_SMI_ARG_CHECKED(index, 0);
743 if (!args[1]->IsScopeInfo()) {
744 // Module already initialized. Find hosting context and retrieve context.
745 Context* host = Context::cast(isolate->context())->script_context();
746 Context* context = Context::cast(host->get(index));
747 DCHECK(context->previous() == isolate->context());
748 isolate->set_context(context);
752 CONVERT_ARG_HANDLE_CHECKED(ScopeInfo, scope_info, 1);
754 // Allocate module context.
755 HandleScope scope(isolate);
756 Factory* factory = isolate->factory();
757 Handle<Context> context = factory->NewModuleContext(scope_info);
758 Handle<JSModule> module = factory->NewJSModule(context, scope_info);
759 context->set_module(*module);
760 Context* previous = isolate->context();
761 context->set_previous(previous);
762 context->set_closure(previous->closure());
763 context->set_global_object(previous->global_object());
764 isolate->set_context(*context);
766 // Find hosting scope and initialize internal variable holding module there.
767 previous->script_context()->set(index, *context);
773 RUNTIME_FUNCTION(Runtime_DeclareModules) {
774 HandleScope scope(isolate);
775 DCHECK(args.length() == 1);
776 CONVERT_ARG_HANDLE_CHECKED(FixedArray, descriptions, 0);
777 Context* host_context = isolate->context();
779 for (int i = 0; i < descriptions->length(); ++i) {
780 Handle<ModuleInfo> description(ModuleInfo::cast(descriptions->get(i)));
781 int host_index = description->host_index();
782 Handle<Context> context(Context::cast(host_context->get(host_index)));
783 Handle<JSModule> module(context->module());
785 for (int j = 0; j < description->length(); ++j) {
786 Handle<String> name(description->name(j));
787 VariableMode mode = description->mode(j);
788 int index = description->index(j);
794 PropertyAttributes attr =
795 IsImmutableVariableMode(mode) ? FROZEN : SEALED;
796 Handle<AccessorInfo> info =
797 Accessors::MakeModuleExport(name, index, attr);
798 Handle<Object> result =
799 JSObject::SetAccessor(module, info).ToHandleChecked();
800 DCHECK(!result->IsUndefined());
813 JSObject::PreventExtensions(module).Assert();
816 DCHECK(!isolate->has_pending_exception());
817 return isolate->heap()->undefined_value();
821 RUNTIME_FUNCTION(Runtime_DeleteLookupSlot) {
822 HandleScope scope(isolate);
823 DCHECK(args.length() == 2);
825 CONVERT_ARG_HANDLE_CHECKED(Context, context, 0);
826 CONVERT_ARG_HANDLE_CHECKED(String, name, 1);
829 PropertyAttributes attributes;
830 ContextLookupFlags flags = FOLLOW_CHAINS;
831 BindingFlags binding_flags;
832 Handle<Object> holder =
833 context->Lookup(name, flags, &index, &attributes, &binding_flags);
835 // If the slot was not found the result is true.
836 if (holder.is_null()) {
837 return isolate->heap()->true_value();
840 // If the slot was found in a context, it should be DONT_DELETE.
841 if (holder->IsContext()) {
842 return isolate->heap()->false_value();
845 // The slot was found in a JSObject, 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<JSObject> object = Handle<JSObject>::cast(holder);
849 Handle<Object> result;
850 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result,
851 JSReceiver::DeleteProperty(object, name));
856 static Object* ComputeReceiverForNonGlobal(Isolate* isolate, JSObject* holder) {
857 DCHECK(!holder->IsGlobalObject());
858 Context* top = isolate->context();
859 // Get the context extension function.
860 JSFunction* context_extension_function =
861 top->native_context()->context_extension_function();
862 // If the holder isn't a context extension object, we just return it
863 // as the receiver. This allows arguments objects to be used as
864 // receivers, but only if they are put in the context scope chain
865 // explicitly via a with-statement.
866 Object* constructor = holder->map()->constructor();
867 if (constructor != context_extension_function) return holder;
868 // Fall back to using the global object as the implicit receiver if
869 // the property turns out to be a local variable allocated in a
870 // context extension object - introduced via eval.
871 return isolate->heap()->undefined_value();
875 static ObjectPair LoadLookupSlotHelper(Arguments args, Isolate* isolate,
877 HandleScope scope(isolate);
878 DCHECK_EQ(2, args.length());
880 if (!args[0]->IsContext() || !args[1]->IsString()) {
881 return MakePair(isolate->ThrowIllegalOperation(), NULL);
883 Handle<Context> context = args.at<Context>(0);
884 Handle<String> name = args.at<String>(1);
887 PropertyAttributes attributes;
888 ContextLookupFlags flags = FOLLOW_CHAINS;
889 BindingFlags binding_flags;
890 Handle<Object> holder =
891 context->Lookup(name, flags, &index, &attributes, &binding_flags);
892 if (isolate->has_pending_exception()) {
893 return MakePair(isolate->heap()->exception(), NULL);
896 // If the index is non-negative, the slot has been found in a context.
898 DCHECK(holder->IsContext());
899 // If the "property" we were looking for is a local variable, the
900 // receiver is the global object; see ECMA-262, 3rd., 10.1.6 and 10.2.3.
901 Handle<Object> receiver = isolate->factory()->undefined_value();
902 Object* value = Context::cast(*holder)->get(index);
903 // Check for uninitialized bindings.
904 switch (binding_flags) {
905 case MUTABLE_CHECK_INITIALIZED:
906 case IMMUTABLE_CHECK_INITIALIZED_HARMONY:
907 if (value->IsTheHole()) {
908 Handle<Object> error;
909 MaybeHandle<Object> maybe_error =
910 isolate->factory()->NewReferenceError("not_defined",
911 HandleVector(&name, 1));
912 if (maybe_error.ToHandle(&error)) isolate->Throw(*error);
913 return MakePair(isolate->heap()->exception(), NULL);
916 case MUTABLE_IS_INITIALIZED:
917 case IMMUTABLE_IS_INITIALIZED:
918 case IMMUTABLE_IS_INITIALIZED_HARMONY:
919 DCHECK(!value->IsTheHole());
920 return MakePair(value, *receiver);
921 case IMMUTABLE_CHECK_INITIALIZED:
922 if (value->IsTheHole()) {
923 DCHECK((attributes & READ_ONLY) != 0);
924 value = isolate->heap()->undefined_value();
926 return MakePair(value, *receiver);
927 case MISSING_BINDING:
929 return MakePair(NULL, NULL);
933 // Otherwise, if the slot was found the holder is a context extension
934 // object, subject of a with, or a global object. We read the named
936 if (!holder.is_null()) {
937 Handle<JSReceiver> object = Handle<JSReceiver>::cast(holder);
939 if (!object->IsJSProxy()) {
940 Maybe<bool> maybe = JSReceiver::HasProperty(object, name);
941 DCHECK(maybe.has_value);
945 // GetProperty below can cause GC.
946 Handle<Object> receiver_handle(
947 object->IsGlobalObject()
948 ? Object::cast(isolate->heap()->undefined_value())
949 : object->IsJSProxy() ? static_cast<Object*>(*object)
950 : ComputeReceiverForNonGlobal(
951 isolate, JSObject::cast(*object)),
954 // No need to unhole the value here. This is taken care of by the
955 // GetProperty function.
956 Handle<Object> value;
957 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
958 isolate, value, Object::GetProperty(object, name),
959 MakePair(isolate->heap()->exception(), NULL));
960 return MakePair(*value, *receiver_handle);
964 // The property doesn't exist - throw exception.
965 Handle<Object> error;
966 MaybeHandle<Object> maybe_error = isolate->factory()->NewReferenceError(
967 "not_defined", HandleVector(&name, 1));
968 if (maybe_error.ToHandle(&error)) isolate->Throw(*error);
969 return MakePair(isolate->heap()->exception(), NULL);
971 // The property doesn't exist - return undefined.
972 return MakePair(isolate->heap()->undefined_value(),
973 isolate->heap()->undefined_value());
978 RUNTIME_FUNCTION_RETURN_PAIR(Runtime_LoadLookupSlot) {
979 return LoadLookupSlotHelper(args, isolate, true);
983 RUNTIME_FUNCTION_RETURN_PAIR(Runtime_LoadLookupSlotNoReferenceError) {
984 return LoadLookupSlotHelper(args, isolate, false);
988 RUNTIME_FUNCTION(Runtime_StoreLookupSlot) {
989 HandleScope scope(isolate);
990 DCHECK(args.length() == 4);
992 CONVERT_ARG_HANDLE_CHECKED(Object, value, 0);
993 CONVERT_ARG_HANDLE_CHECKED(Context, context, 1);
994 CONVERT_ARG_HANDLE_CHECKED(String, name, 2);
995 CONVERT_LANGUAGE_MODE_ARG_CHECKED(language_mode, 3);
998 PropertyAttributes attributes;
999 ContextLookupFlags flags = FOLLOW_CHAINS;
1000 BindingFlags binding_flags;
1001 Handle<Object> holder =
1002 context->Lookup(name, flags, &index, &attributes, &binding_flags);
1003 // In case of JSProxy, an exception might have been thrown.
1004 if (isolate->has_pending_exception()) return isolate->heap()->exception();
1006 // The property was found in a context slot.
1008 if ((attributes & READ_ONLY) == 0) {
1009 Handle<Context>::cast(holder)->set(index, *value);
1010 } else if (is_strict(language_mode)) {
1011 // Setting read only property in strict mode.
1012 THROW_NEW_ERROR_RETURN_FAILURE(
1014 NewTypeError("strict_cannot_assign", HandleVector(&name, 1)));
1019 // Slow case: The property is not in a context slot. It is either in a
1020 // context extension object, a property of the subject of a with, or a
1021 // property of the global object.
1022 Handle<JSReceiver> object;
1023 if (attributes != ABSENT) {
1024 // The property exists on the holder.
1025 object = Handle<JSReceiver>::cast(holder);
1026 } else if (is_strict(language_mode)) {
1027 // If absent in strict mode: throw.
1028 THROW_NEW_ERROR_RETURN_FAILURE(
1029 isolate, NewReferenceError("not_defined", HandleVector(&name, 1)));
1031 // If absent in sloppy mode: add the property to the global object.
1032 object = Handle<JSReceiver>(context->global_object());
1035 RETURN_FAILURE_ON_EXCEPTION(
1036 isolate, Object::SetProperty(object, name, value, language_mode));
1042 RUNTIME_FUNCTION(Runtime_GetArgumentsProperty) {
1043 SealHandleScope shs(isolate);
1044 DCHECK(args.length() == 1);
1045 CONVERT_ARG_HANDLE_CHECKED(Object, raw_key, 0);
1047 // Compute the frame holding the arguments.
1048 JavaScriptFrameIterator it(isolate);
1049 it.AdvanceToArgumentsFrame();
1050 JavaScriptFrame* frame = it.frame();
1052 // Get the actual number of provided arguments.
1053 const uint32_t n = frame->ComputeParametersCount();
1055 // Try to convert the key to an index. If successful and within
1056 // index return the the argument from the frame.
1058 if (raw_key->ToArrayIndex(&index) && index < n) {
1059 return frame->GetParameter(index);
1062 HandleScope scope(isolate);
1063 if (raw_key->IsSymbol()) {
1064 Handle<Symbol> symbol = Handle<Symbol>::cast(raw_key);
1065 if (Name::Equals(symbol, isolate->factory()->iterator_symbol())) {
1066 return isolate->native_context()->array_values_iterator();
1068 // Lookup in the initial Object.prototype object.
1069 Handle<Object> result;
1070 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
1072 Object::GetProperty(isolate->initial_object_prototype(),
1073 Handle<Symbol>::cast(raw_key)));
1077 // Convert the key to a string.
1078 Handle<Object> converted;
1079 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, converted,
1080 Execution::ToString(isolate, raw_key));
1081 Handle<String> key = Handle<String>::cast(converted);
1083 // Try to convert the string key into an array index.
1084 if (key->AsArrayIndex(&index)) {
1086 return frame->GetParameter(index);
1088 Handle<Object> initial_prototype(isolate->initial_object_prototype());
1089 Handle<Object> result;
1090 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
1092 Object::GetElement(isolate, initial_prototype, index));
1097 // Handle special arguments properties.
1098 if (String::Equals(isolate->factory()->length_string(), key)) {
1099 return Smi::FromInt(n);
1101 if (String::Equals(isolate->factory()->callee_string(), key)) {
1102 JSFunction* function = frame->function();
1103 if (is_strict(function->shared()->language_mode())) {
1104 THROW_NEW_ERROR_RETURN_FAILURE(
1105 isolate, NewTypeError("strict_arguments_callee",
1106 HandleVector<Object>(NULL, 0)));
1111 // Lookup in the initial Object.prototype object.
1112 Handle<Object> result;
1113 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
1115 Object::GetProperty(isolate->initial_object_prototype(), key));
1120 RUNTIME_FUNCTION(RuntimeReference_ArgumentsLength) {
1121 SealHandleScope shs(isolate);
1122 DCHECK(args.length() == 0);
1123 JavaScriptFrameIterator it(isolate);
1124 JavaScriptFrame* frame = it.frame();
1125 return Smi::FromInt(frame->GetArgumentsLength());
1129 RUNTIME_FUNCTION(RuntimeReference_Arguments) {
1130 SealHandleScope shs(isolate);
1131 return __RT_impl_Runtime_GetArgumentsProperty(args, isolate);
1134 } // namespace v8::internal