[es6] Implement spec compliant ToPrimitive in the runtime.
[platform/upstream/v8.git] / src / runtime / runtime-scopes.cc
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/frames-inl.h"
10 #include "src/messages.h"
11 #include "src/scopeinfo.h"
12 #include "src/scopes.h"
13
14 namespace v8 {
15 namespace internal {
16
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));
21 }
22
23
24 RUNTIME_FUNCTION(Runtime_ThrowConstAssignError) {
25   HandleScope scope(isolate);
26   THROW_NEW_ERROR_RETURN_FAILURE(isolate,
27                                  NewTypeError(MessageTemplate::kConstAssign));
28 }
29
30
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);
42   }
43
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();
48
49   if (it.IsFound()) {
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);
53
54     // Skip var re-declarations.
55     if (is_var) return isolate->heap()->undefined_value();
56
57     DCHECK(is_function);
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);
62
63       // Check whether we can reconfigure the existing property into a
64       // function.
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);
72       }
73       // If the existing property is not configurable, keep its attributes. Do
74       attr = old_attributes;
75     }
76   }
77
78   // Define or redefine own property.
79   RETURN_FAILURE_ON_EXCEPTION(isolate, JSObject::SetOwnPropertyIgnoreAttributes(
80                                            global, name, value, attr));
81
82   return isolate->heap()->undefined_value();
83 }
84
85
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());
91
92   CONVERT_ARG_HANDLE_CHECKED(FixedArray, pairs, 0);
93   CONVERT_SMI_ARG_CHECKED(flags, 1);
94
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);
101
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();
108     DCHECK_EQ(1,
109               BoolToInt(is_var) + BoolToInt(is_const) + BoolToInt(is_function));
110
111     Handle<Object> value;
112     if (is_function) {
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,
118                                                                 TENURED);
119       value = function;
120     } else {
121       value = isolate->factory()->undefined_value();
122     }
123
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);
128     int attr = NONE;
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;
132
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;
137   }
138
139   return isolate->heap()->undefined_value();
140 }
141
142
143 RUNTIME_FUNCTION(Runtime_InitializeVarGlobal) {
144   HandleScope scope(isolate);
145   // args[0] == name
146   // args[1] == language_mode
147   // args[2] == value (optional)
148
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);
152
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);
156
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));
161   return *result;
162 }
163
164
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
169   // is the second.
170   RUNTIME_ASSERT(args.length() == 2);
171   CONVERT_ARG_HANDLE_CHECKED(String, name, 0);
172   CONVERT_ARG_HANDLE_CHECKED(Object, value, 1);
173
174   Handle<GlobalObject> global = isolate->global_object();
175
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();
181
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.
186   if (it.IsFound()) {
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) {
191         return *value;
192       }
193       attr = static_cast<PropertyAttributes>(old_attributes | READ_ONLY);
194     }
195   }
196
197   RETURN_FAILURE_ON_EXCEPTION(isolate, JSObject::SetOwnPropertyIgnoreAttributes(
198                                            global, name, value, attr));
199
200   return *value;
201 }
202
203
204 namespace {
205
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);
215
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();
220   DCHECK_EQ(1,
221             BoolToInt(is_var) + BoolToInt(is_const) + BoolToInt(is_function));
222
223   int index;
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();
232   }
233
234   Handle<JSObject> object;
235   Handle<Object> value =
236       is_function ? initial_value
237                   : Handle<Object>::cast(isolate->factory()->undefined_value());
238
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);
244   }
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,
249                           is_function);
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,
255                           is_function);
256   }
257
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);
262     }
263
264     // Skip var re-declarations.
265     if (is_var) return isolate->heap()->undefined_value();
266
267     DCHECK(is_function);
268     if (index != Context::kNotFound) {
269       DCHECK(holder.is_identical_to(context));
270       context->set(index, *initial_value);
271       return isolate->heap()->undefined_value();
272     }
273
274     object = Handle<JSObject>::cast(holder);
275
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);
287     } else {
288       object = handle(context->extension_object(), isolate);
289     }
290     DCHECK(object->IsJSContextExtensionObject() || object->IsJSGlobalObject());
291   } else {
292     DCHECK(context->IsFunctionContext());
293     object =
294         isolate->factory()->NewJSObject(isolate->context_extension_function());
295     context->set_extension(*object);
296   }
297
298   RETURN_FAILURE_ON_EXCEPTION(isolate, JSObject::SetOwnPropertyIgnoreAttributes(
299                                            object, name, value, attr));
300
301   return isolate->heap()->undefined_value();
302 }
303
304 }  // namespace
305
306
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);
312
313   return DeclareLookupSlot(isolate, name, initial_value, NONE);
314 }
315
316
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);
322
323   return DeclareLookupSlot(isolate, name, initial_value, READ_ONLY);
324 }
325
326
327 RUNTIME_FUNCTION(Runtime_InitializeLegacyConstLookupSlot) {
328   HandleScope scope(isolate);
329   DCHECK(args.length() == 3);
330
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);
337
338   int index;
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();
347   }
348
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);
356     return *value;
357   }
358
359   PropertyAttributes attr =
360       static_cast<PropertyAttributes>(DONT_DELETE | READ_ONLY);
361
362   // Strict mode handling not needed (legacy const is disallowed in strict
363   // mode).
364
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);
371     } else {
372       holder = handle(declaration_context->extension_object(), isolate);
373       DCHECK(!holder.is_null());
374     }
375     CHECK(holder->IsJSObject());
376   } else {
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());
382
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();
387
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) {
392         return *value;
393       }
394       attr = static_cast<PropertyAttributes>(old_attributes | READ_ONLY);
395     }
396   }
397
398   RETURN_FAILURE_ON_EXCEPTION(
399       isolate, JSObject::SetOwnPropertyIgnoreAttributes(
400                    Handle<JSObject>::cast(holder), name, value, attr));
401
402   return *value;
403 }
404
405
406 static Handle<JSObject> NewSloppyArguments(Isolate* isolate,
407                                            Handle<JSFunction> callee,
408                                            Object** parameters,
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);
414
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);
425
426       // Store the context and the arguments array at the beginning of the
427       // parameter map.
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);
433
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));
440         --index;
441       }
442
443       Handle<ScopeInfo> scope_info(callee->shared()->scope_info());
444       while (index >= 0) {
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) {
451             duplicate = true;
452             break;
453           }
454         }
455
456         if (duplicate) {
457           // This goes directly in the arguments array with a hole in the
458           // parameter map.
459           arguments->set(index, *(parameters - index - 1));
460           parameter_map->set_the_hole(index + 2);
461         } else {
462           // The context index goes in the parameter map with a hole in the
463           // arguments array.
464           int context_index = -1;
465           for (int j = 0; j < context_local_count; ++j) {
466             if (scope_info->ContextLocalName(j) == *name) {
467               context_index = j;
468               break;
469             }
470           }
471
472           DCHECK(context_index >= 0);
473           arguments->set_the_hole(index);
474           parameter_map->set(
475               index + 2,
476               Smi::FromInt(Context::MIN_CONTEXT_SLOTS + context_index));
477         }
478
479         --index;
480       }
481     } else {
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));
489       }
490     }
491   }
492   return result;
493 }
494
495
496 static Handle<JSObject> NewStrictArguments(Isolate* isolate,
497                                            Handle<JSFunction> callee,
498                                            Object** parameters,
499                                            int argument_count) {
500   Handle<JSObject> result =
501       isolate->factory()->NewArgumentsObject(callee, argument_count);
502
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);
510     }
511     result->set_elements(*array);
512   }
513   return result;
514 }
515
516
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);
522
523   // Find the frame that holds the actual arguments passed to the function.
524   it.AdvanceToArgumentsFrame();
525   JavaScriptFrame* frame = it.frame();
526
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));
530
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);
535 }
536
537
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);
545 }
546
547
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);
555 }
556
557
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);
567   }
568   return isolate->factory()->NewJSArrayWithElements(
569       elements, FAST_ELEMENTS, num_elements, strength(language_mode));
570 }
571
572
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);
580
581   return *NewRestParam(isolate, parameters, num_params, rest_index,
582                        static_cast<LanguageMode>(language_mode));
583 }
584
585
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);
591
592   JavaScriptFrameIterator it(isolate);
593
594   // Find the frame that holds the actual arguments passed to the function.
595   it.AdvanceToArgumentsFrame();
596   JavaScriptFrame* frame = it.frame();
597
598   int argument_count = frame->GetArgumentsLength();
599   Object** parameters = reinterpret_cast<Object**>(frame->GetParameterSlot(-1));
600
601   return *NewRestParam(isolate, parameters, argument_count, rest_index,
602                        static_cast<LanguageMode>(language_mode));
603 }
604
605
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,
613                                                                 pretenure_flag);
614 }
615
616
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);
623
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,
628                                                                 pretenure_flag);
629 }
630
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);
642       }
643     }
644
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);
652       }
653
654       GlobalObject::InvalidatePropertyCell(global_object, name);
655     }
656   }
657   return isolate->heap()->undefined_value();
658 }
659
660
661 RUNTIME_FUNCTION(Runtime_NewScriptContext) {
662   HandleScope scope(isolate);
663   DCHECK(args.length() == 2);
664
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());
671
672   Object* name_clash_result =
673       FindNameClash(scope_info, global_object, script_context_table);
674   if (isolate->has_pending_exception()) return name_clash_result;
675
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()
680                                  ? *function
681                                  : native_context->closure());
682   Handle<Context> result =
683       isolate->factory()->NewScriptContext(closure, scope_info);
684
685   result->InitializeGlobalSlots();
686
687   DCHECK(function->context() == isolate->context());
688   DCHECK(*global_object == result->global_object());
689
690   Handle<ScriptContextTable> new_script_context_table =
691       ScriptContextTable::Extend(script_context_table, result);
692   native_context->set_script_context_table(*new_script_context_table);
693   return *result;
694 }
695
696
697 RUNTIME_FUNCTION(Runtime_NewFunctionContext) {
698   HandleScope scope(isolate);
699   DCHECK(args.length() == 1);
700
701   CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
702
703   DCHECK(function->context() == isolate->context());
704   int length = function->shared()->scope_info()->ContextLength();
705   return *isolate->factory()->NewFunctionContext(length, function);
706 }
707
708
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);
715   } else {
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));
723     }
724   }
725
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());
732   } else {
733     function = args.at<JSFunction>(1);
734   }
735
736   Handle<Context> current(isolate->context());
737   Handle<Context> context =
738       isolate->factory()->NewWithContext(function, current, extension_object);
739   isolate->set_context(*context);
740   return *context;
741 }
742
743
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());
755   } else {
756     function = args.at<JSFunction>(2);
757   }
758   Handle<Context> current(isolate->context());
759   Handle<Context> context = isolate->factory()->NewCatchContext(
760       function, current, name, thrown_object);
761   isolate->set_context(*context);
762   return *context;
763 }
764
765
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());
776   } else {
777     function = args.at<JSFunction>(1);
778   }
779   Handle<Context> current(isolate->context());
780   Handle<Context> context =
781       isolate->factory()->NewBlockContext(function, current, scope_info);
782   isolate->set_context(*context);
783   return *context;
784 }
785
786
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());
792 }
793
794
795 RUNTIME_FUNCTION(Runtime_PushModuleContext) {
796   SealHandleScope shs(isolate);
797   DCHECK(args.length() == 2);
798   CONVERT_SMI_ARG_CHECKED(index, 0);
799
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);
806     return context;
807   }
808
809   CONVERT_ARG_HANDLE_CHECKED(ScopeInfo, scope_info, 1);
810
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);
822
823   // Find hosting scope and initialize internal variable holding module there.
824   previous->script_context()->set(index, *context);
825
826   return *context;
827 }
828
829
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();
835
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());
841
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);
846       switch (mode) {
847         case VAR:
848         case LET:
849         case CONST:
850         case CONST_LEGACY:
851         case IMPORT: {
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());
859           USE(result);
860           break;
861         }
862         case TEMPORARY:
863         case DYNAMIC:
864         case DYNAMIC_GLOBAL:
865         case DYNAMIC_LOCAL:
866           UNREACHABLE();
867       }
868     }
869
870     JSObject::PreventExtensions(module).Assert();
871   }
872
873   DCHECK(!isolate->has_pending_exception());
874   return isolate->heap()->undefined_value();
875 }
876
877
878 RUNTIME_FUNCTION(Runtime_DeleteLookupSlot) {
879   HandleScope scope(isolate);
880   DCHECK(args.length() == 2);
881
882   CONVERT_ARG_HANDLE_CHECKED(Context, context, 0);
883   CONVERT_ARG_HANDLE_CHECKED(String, name, 1);
884
885   int index;
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);
891
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();
897   }
898
899   // If the slot was found in a context, it should be DONT_DELETE.
900   if (holder->IsContext()) {
901     return isolate->heap()->false_value();
902   }
903
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));
911   return *result;
912 }
913
914
915 static Object* ComputeReceiverForNonGlobal(Isolate* isolate, JSObject* holder) {
916   DCHECK(!holder->IsGlobalObject());
917
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) {
923     return holder;
924   }
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();
929 }
930
931
932 static ObjectPair LoadLookupSlotHelper(Arguments args, Isolate* isolate,
933                                        bool throw_error) {
934   HandleScope scope(isolate);
935   DCHECK_EQ(2, args.length());
936
937   if (!args[0]->IsContext() || !args[1]->IsString()) {
938     return MakePair(isolate->ThrowIllegalOperation(), NULL);
939   }
940   Handle<Context> context = args.at<Context>(0);
941   Handle<String> name = args.at<String>(1);
942
943   int index;
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);
951   }
952
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);
968         }
969       // FALLTHROUGH
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();
979         }
980         return MakePair(value, *receiver);
981       case MISSING_BINDING:
982         UNREACHABLE();
983         return MakePair(NULL, NULL);
984     }
985   }
986
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
989   // property from it.
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)),
999         isolate);
1000
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);
1008   }
1009
1010   if (throw_error) {
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);
1016   } else {
1017     // The property doesn't exist - return undefined.
1018     return MakePair(isolate->heap()->undefined_value(),
1019                     isolate->heap()->undefined_value());
1020   }
1021 }
1022
1023
1024 RUNTIME_FUNCTION_RETURN_PAIR(Runtime_LoadLookupSlot) {
1025   return LoadLookupSlotHelper(args, isolate, true);
1026 }
1027
1028
1029 RUNTIME_FUNCTION_RETURN_PAIR(Runtime_LoadLookupSlotNoReferenceError) {
1030   return LoadLookupSlotHelper(args, isolate, false);
1031 }
1032
1033
1034 RUNTIME_FUNCTION(Runtime_StoreLookupSlot) {
1035   HandleScope scope(isolate);
1036   DCHECK(args.length() == 4);
1037
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);
1042
1043   int index;
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();
1052   }
1053
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));
1061     }
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));
1068     }
1069     return *value;
1070   }
1071
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));
1083   } else {
1084     // If absent in sloppy mode: add the property to the global object.
1085     object = Handle<JSReceiver>(context->global_object());
1086   }
1087
1088   RETURN_FAILURE_ON_EXCEPTION(
1089       isolate, Object::SetProperty(object, name, value, language_mode));
1090
1091   return *value;
1092 }
1093
1094
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());
1101 }
1102
1103
1104 RUNTIME_FUNCTION(Runtime_Arguments) {
1105   SealHandleScope shs(isolate);
1106   DCHECK(args.length() == 1);
1107   CONVERT_ARG_HANDLE_CHECKED(Object, raw_key, 0);
1108
1109   // Compute the frame holding the arguments.
1110   JavaScriptFrameIterator it(isolate);
1111   it.AdvanceToArgumentsFrame();
1112   JavaScriptFrame* frame = it.frame();
1113
1114   // Get the actual number of provided arguments.
1115   const uint32_t n = frame->ComputeParametersCount();
1116
1117   // Try to convert the key to an index. If successful and within
1118   // index return the the argument from the frame.
1119   uint32_t index = 0;
1120   if (raw_key->ToArrayIndex(&index) && index < n) {
1121     return frame->GetParameter(index);
1122   }
1123
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();
1129     }
1130     // Lookup in the initial Object.prototype object.
1131     Handle<Object> result;
1132     ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
1133         isolate, result,
1134         Object::GetProperty(isolate->initial_object_prototype(),
1135                             Handle<Symbol>::cast(raw_key)));
1136     return *result;
1137   }
1138
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);
1144
1145   // Try to convert the string key into an array index.
1146   if (key->AsArrayIndex(&index)) {
1147     if (index < n) {
1148       return frame->GetParameter(index);
1149     } else {
1150       Handle<Object> initial_prototype(isolate->initial_object_prototype());
1151       Handle<Object> result;
1152       ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
1153           isolate, result,
1154           Object::GetElement(isolate, initial_prototype, index));
1155       return *result;
1156     }
1157   }
1158
1159   // Handle special arguments properties.
1160   if (String::Equals(isolate->factory()->length_string(), key)) {
1161     return Smi::FromInt(n);
1162   }
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));
1168     }
1169     return function;
1170   }
1171
1172   // Lookup in the initial Object.prototype object.
1173   Handle<Object> result;
1174   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
1175       isolate, result,
1176       Object::GetProperty(isolate->initial_object_prototype(), key));
1177   return *result;
1178 }
1179 }  // namespace internal
1180 }  // namespace v8