blob: 2a0b435872b67d5ef7a553b480cb9007fba1cc4e [file] [log] [blame]
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001// 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/v8.h"
6
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"
13
14namespace v8 {
15namespace internal {
16
17static 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)));
22}
23
24
25RUNTIME_FUNCTION(Runtime_ThrowConstAssignError) {
26 HandleScope scope(isolate);
27 THROW_NEW_ERROR_RETURN_FAILURE(
28 isolate,
29 NewTypeError("harmony_const_assign", HandleVector<Object>(NULL, 0)));
30}
31
32
33// May throw a RedeclarationError.
34static 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);
44 }
45
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();
50
51 if (it.IsFound()) {
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);
55
56 // Skip var re-declarations.
57 if (is_var) return isolate->heap()->undefined_value();
58
59 DCHECK(is_function);
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);
64
65 // Check whether we can reconfigure the existing property into a
66 // function.
67 PropertyDetails old_details = it.property_details();
68 // TODO(verwaest): CALLBACKS invalidly includes ExecutableAccessInfo,
69 // which are actually data properties, not accessor properties.
70 if (old_details.IsReadOnly() || old_details.IsDontEnum() ||
71 old_details.type() == CALLBACKS) {
72 return ThrowRedeclarationError(isolate, name);
73 }
74 // If the existing property is not configurable, keep its attributes. Do
75 attr = old_attributes;
76 }
77 }
78
79 // Define or redefine own property.
80 RETURN_FAILURE_ON_EXCEPTION(isolate, JSObject::SetOwnPropertyIgnoreAttributes(
81 global, name, value, attr));
82
83 return isolate->heap()->undefined_value();
84}
85
86
87RUNTIME_FUNCTION(Runtime_DeclareGlobals) {
88 HandleScope scope(isolate);
89 DCHECK(args.length() == 3);
90 Handle<GlobalObject> global(isolate->global_object());
91
92 CONVERT_ARG_HANDLE_CHECKED(Context, context, 0);
93 CONVERT_ARG_HANDLE_CHECKED(FixedArray, pairs, 1);
94 CONVERT_SMI_ARG_CHECKED(flags, 2);
95
96 // Traverse the name/value pairs and set the properties.
97 int length = pairs->length();
98 for (int i = 0; i < length; i += 2) {
99 HandleScope scope(isolate);
100 Handle<String> name(String::cast(pairs->get(i)));
101 Handle<Object> initial_value(pairs->get(i + 1), isolate);
102
103 // We have to declare a global const property. To capture we only
104 // assign to it when evaluating the assignment for "const x =
105 // <expr>" the initial value is the hole.
106 bool is_var = initial_value->IsUndefined();
107 bool is_const = initial_value->IsTheHole();
108 bool is_function = initial_value->IsSharedFunctionInfo();
109 DCHECK(is_var + is_const + is_function == 1);
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
143RUNTIME_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_STRICT_MODE_ARG_CHECKED(strict_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, strict_mode));
161 return *result;
162}
163
164
165RUNTIME_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.has_value);
180 PropertyAttributes old_attributes = maybe.value;
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
204RUNTIME_FUNCTION(Runtime_DeclareLookupSlot) {
205 HandleScope scope(isolate);
206 DCHECK(args.length() == 4);
207
208 // Declarations are always made in a function, eval or script context. In
209 // the case of eval code, the context passed is the context of the caller,
210 // which may be some nested context and not the declaration context.
211 CONVERT_ARG_HANDLE_CHECKED(Context, context_arg, 0);
212 Handle<Context> context(context_arg->declaration_context());
213 CONVERT_ARG_HANDLE_CHECKED(String, name, 1);
214 CONVERT_SMI_ARG_CHECKED(attr_arg, 2);
215 PropertyAttributes attr = static_cast<PropertyAttributes>(attr_arg);
216 RUNTIME_ASSERT(attr == READ_ONLY || attr == NONE);
217 CONVERT_ARG_HANDLE_CHECKED(Object, initial_value, 3);
218
219 // TODO(verwaest): Unify the encoding indicating "var" with DeclareGlobals.
220 bool is_var = *initial_value == NULL;
221 bool is_const = initial_value->IsTheHole();
222 bool is_function = initial_value->IsJSFunction();
223 DCHECK(is_var + is_const + is_function == 1);
224
225 int index;
226 PropertyAttributes attributes;
227 ContextLookupFlags flags = DONT_FOLLOW_CHAINS;
228 BindingFlags binding_flags;
229 Handle<Object> holder =
230 context->Lookup(name, flags, &index, &attributes, &binding_flags);
231
232 Handle<JSObject> object;
233 Handle<Object> value =
234 is_function ? initial_value
235 : Handle<Object>::cast(isolate->factory()->undefined_value());
236
237 // TODO(verwaest): This case should probably not be covered by this function,
238 // but by DeclareGlobals instead.
239 if ((attributes != ABSENT && holder->IsJSGlobalObject()) ||
240 (context_arg->has_extension() &&
241 context_arg->extension()->IsJSGlobalObject())) {
242 return DeclareGlobals(isolate, Handle<JSGlobalObject>::cast(holder), name,
243 value, attr, is_var, is_const, is_function);
244 }
245
246 if (attributes != ABSENT) {
247 // The name was declared before; check for conflicting re-declarations.
248 if (is_const || (attributes & READ_ONLY) != 0) {
249 return ThrowRedeclarationError(isolate, name);
250 }
251
252 // Skip var re-declarations.
253 if (is_var) return isolate->heap()->undefined_value();
254
255 DCHECK(is_function);
256 if (index >= 0) {
257 DCHECK(holder.is_identical_to(context));
258 context->set(index, *initial_value);
259 return isolate->heap()->undefined_value();
260 }
261
262 object = Handle<JSObject>::cast(holder);
263
264 } else if (context->has_extension()) {
265 object = handle(JSObject::cast(context->extension()));
266 DCHECK(object->IsJSContextExtensionObject() || object->IsJSGlobalObject());
267 } else {
268 DCHECK(context->IsFunctionContext());
269 object =
270 isolate->factory()->NewJSObject(isolate->context_extension_function());
271 context->set_extension(*object);
272 }
273
274 RETURN_FAILURE_ON_EXCEPTION(isolate, JSObject::SetOwnPropertyIgnoreAttributes(
275 object, name, value, attr));
276
277 return isolate->heap()->undefined_value();
278}
279
280
281RUNTIME_FUNCTION(Runtime_InitializeLegacyConstLookupSlot) {
282 HandleScope scope(isolate);
283 DCHECK(args.length() == 3);
284
285 CONVERT_ARG_HANDLE_CHECKED(Object, value, 0);
286 DCHECK(!value->IsTheHole());
287 // Initializations are always done in a function or native context.
288 CONVERT_ARG_HANDLE_CHECKED(Context, context_arg, 1);
289 Handle<Context> context(context_arg->declaration_context());
290 CONVERT_ARG_HANDLE_CHECKED(String, name, 2);
291
292 int index;
293 PropertyAttributes attributes;
294 ContextLookupFlags flags = DONT_FOLLOW_CHAINS;
295 BindingFlags binding_flags;
296 Handle<Object> holder =
297 context->Lookup(name, flags, &index, &attributes, &binding_flags);
298
299 if (index >= 0) {
300 DCHECK(holder->IsContext());
301 // Property was found in a context. Perform the assignment if the constant
302 // was uninitialized.
303 Handle<Context> context = Handle<Context>::cast(holder);
304 DCHECK((attributes & READ_ONLY) != 0);
305 if (context->get(index)->IsTheHole()) context->set(index, *value);
306 return *value;
307 }
308
309 PropertyAttributes attr =
310 static_cast<PropertyAttributes>(DONT_DELETE | READ_ONLY);
311
312 // Strict mode handling not needed (legacy const is disallowed in strict
313 // mode).
314
315 // The declared const was configurable, and may have been deleted in the
316 // meanwhile. If so, re-introduce the variable in the context extension.
317 if (attributes == ABSENT) {
318 Handle<Context> declaration_context(context_arg->declaration_context());
319 DCHECK(declaration_context->has_extension());
320 holder = handle(declaration_context->extension(), isolate);
321 CHECK(holder->IsJSObject());
322 } else {
323 // For JSContextExtensionObjects, the initializer can be run multiple times
324 // if in a for loop: for (var i = 0; i < 2; i++) { const x = i; }. Only the
325 // first assignment should go through. For JSGlobalObjects, additionally any
326 // code can run in between that modifies the declared property.
327 DCHECK(holder->IsJSGlobalObject() || holder->IsJSContextExtensionObject());
328
329 LookupIterator it(holder, name, LookupIterator::HIDDEN_SKIP_INTERCEPTOR);
330 Maybe<PropertyAttributes> maybe = JSReceiver::GetPropertyAttributes(&it);
331 if (!maybe.has_value) return isolate->heap()->exception();
332 PropertyAttributes old_attributes = maybe.value;
333
334 // Ignore if we can't reconfigure the value.
335 if ((old_attributes & DONT_DELETE) != 0) {
336 if ((old_attributes & READ_ONLY) != 0 ||
337 it.state() == LookupIterator::ACCESSOR) {
338 return *value;
339 }
340 attr = static_cast<PropertyAttributes>(old_attributes | READ_ONLY);
341 }
342 }
343
344 RETURN_FAILURE_ON_EXCEPTION(
345 isolate, JSObject::SetOwnPropertyIgnoreAttributes(
346 Handle<JSObject>::cast(holder), name, value, attr));
347
348 return *value;
349}
350
351
352static Handle<JSObject> NewSloppyArguments(Isolate* isolate,
353 Handle<JSFunction> callee,
354 Object** parameters,
355 int argument_count) {
356 Handle<JSObject> result =
357 isolate->factory()->NewArgumentsObject(callee, argument_count);
358
359 // Allocate the elements if needed.
360 int parameter_count = callee->shared()->formal_parameter_count();
361 if (argument_count > 0) {
362 if (parameter_count > 0) {
363 int mapped_count = Min(argument_count, parameter_count);
364 Handle<FixedArray> parameter_map =
365 isolate->factory()->NewFixedArray(mapped_count + 2, NOT_TENURED);
366 parameter_map->set_map(isolate->heap()->sloppy_arguments_elements_map());
367
368 Handle<Map> map = Map::Copy(handle(result->map()), "NewSloppyArguments");
369 map->set_elements_kind(SLOPPY_ARGUMENTS_ELEMENTS);
370
371 result->set_map(*map);
372 result->set_elements(*parameter_map);
373
374 // Store the context and the arguments array at the beginning of the
375 // parameter map.
376 Handle<Context> context(isolate->context());
377 Handle<FixedArray> arguments =
378 isolate->factory()->NewFixedArray(argument_count, NOT_TENURED);
379 parameter_map->set(0, *context);
380 parameter_map->set(1, *arguments);
381
382 // Loop over the actual parameters backwards.
383 int index = argument_count - 1;
384 while (index >= mapped_count) {
385 // These go directly in the arguments array and have no
386 // corresponding slot in the parameter map.
387 arguments->set(index, *(parameters - index - 1));
388 --index;
389 }
390
391 Handle<ScopeInfo> scope_info(callee->shared()->scope_info());
392 while (index >= 0) {
393 // Detect duplicate names to the right in the parameter list.
394 Handle<String> name(scope_info->ParameterName(index));
395 int context_local_count = scope_info->ContextLocalCount();
396 bool duplicate = false;
397 for (int j = index + 1; j < parameter_count; ++j) {
398 if (scope_info->ParameterName(j) == *name) {
399 duplicate = true;
400 break;
401 }
402 }
403
404 if (duplicate) {
405 // This goes directly in the arguments array with a hole in the
406 // parameter map.
407 arguments->set(index, *(parameters - index - 1));
408 parameter_map->set_the_hole(index + 2);
409 } else {
410 // The context index goes in the parameter map with a hole in the
411 // arguments array.
412 int context_index = -1;
413 for (int j = 0; j < context_local_count; ++j) {
414 if (scope_info->ContextLocalName(j) == *name) {
415 context_index = j;
416 break;
417 }
418 }
419 DCHECK(context_index >= 0);
420 arguments->set_the_hole(index);
421 parameter_map->set(
422 index + 2,
423 Smi::FromInt(Context::MIN_CONTEXT_SLOTS + context_index));
424 }
425
426 --index;
427 }
428 } else {
429 // If there is no aliasing, the arguments object elements are not
430 // special in any way.
431 Handle<FixedArray> elements =
432 isolate->factory()->NewFixedArray(argument_count, NOT_TENURED);
433 result->set_elements(*elements);
434 for (int i = 0; i < argument_count; ++i) {
435 elements->set(i, *(parameters - i - 1));
436 }
437 }
438 }
439 return result;
440}
441
442
443static Handle<JSObject> NewStrictArguments(Isolate* isolate,
444 Handle<JSFunction> callee,
445 Object** parameters,
446 int argument_count) {
447 Handle<JSObject> result =
448 isolate->factory()->NewArgumentsObject(callee, argument_count);
449
450 if (argument_count > 0) {
451 Handle<FixedArray> array =
452 isolate->factory()->NewUninitializedFixedArray(argument_count);
453 DisallowHeapAllocation no_gc;
454 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
455 for (int i = 0; i < argument_count; i++) {
456 array->set(i, *--parameters, mode);
457 }
458 result->set_elements(*array);
459 }
460 return result;
461}
462
463
464RUNTIME_FUNCTION(Runtime_NewArguments) {
465 HandleScope scope(isolate);
466 DCHECK(args.length() == 1);
467 CONVERT_ARG_HANDLE_CHECKED(JSFunction, callee, 0);
468 JavaScriptFrameIterator it(isolate);
469
470 // Find the frame that holds the actual arguments passed to the function.
471 it.AdvanceToArgumentsFrame();
472 JavaScriptFrame* frame = it.frame();
473
474 // Determine parameter location on the stack and dispatch on language mode.
475 int argument_count = frame->GetArgumentsLength();
476 Object** parameters = reinterpret_cast<Object**>(frame->GetParameterSlot(-1));
477 return callee->shared()->strict_mode() == STRICT
478 ? *NewStrictArguments(isolate, callee, parameters, argument_count)
479 : *NewSloppyArguments(isolate, callee, parameters, argument_count);
480}
481
482
483RUNTIME_FUNCTION(Runtime_NewSloppyArguments) {
484 HandleScope scope(isolate);
485 DCHECK(args.length() == 3);
486 CONVERT_ARG_HANDLE_CHECKED(JSFunction, callee, 0);
487 Object** parameters = reinterpret_cast<Object**>(args[1]);
488 CONVERT_SMI_ARG_CHECKED(argument_count, 2);
489 return *NewSloppyArguments(isolate, callee, parameters, argument_count);
490}
491
492
493RUNTIME_FUNCTION(Runtime_NewStrictArguments) {
494 HandleScope scope(isolate);
495 DCHECK(args.length() == 3);
496 CONVERT_ARG_HANDLE_CHECKED(JSFunction, callee, 0)
497 Object** parameters = reinterpret_cast<Object**>(args[1]);
498 CONVERT_SMI_ARG_CHECKED(argument_count, 2);
499 return *NewStrictArguments(isolate, callee, parameters, argument_count);
500}
501
502
503RUNTIME_FUNCTION(Runtime_NewClosureFromStubFailure) {
504 HandleScope scope(isolate);
505 DCHECK(args.length() == 1);
506 CONVERT_ARG_HANDLE_CHECKED(SharedFunctionInfo, shared, 0);
507 Handle<Context> context(isolate->context());
508 PretenureFlag pretenure_flag = NOT_TENURED;
509 return *isolate->factory()->NewFunctionFromSharedFunctionInfo(shared, context,
510 pretenure_flag);
511}
512
513
514RUNTIME_FUNCTION(Runtime_NewClosure) {
515 HandleScope scope(isolate);
516 DCHECK(args.length() == 3);
517 CONVERT_ARG_HANDLE_CHECKED(Context, context, 0);
518 CONVERT_ARG_HANDLE_CHECKED(SharedFunctionInfo, shared, 1);
519 CONVERT_BOOLEAN_ARG_CHECKED(pretenure, 2);
520
521 // The caller ensures that we pretenure closures that are assigned
522 // directly to properties.
523 PretenureFlag pretenure_flag = pretenure ? TENURED : NOT_TENURED;
524 return *isolate->factory()->NewFunctionFromSharedFunctionInfo(shared, context,
525 pretenure_flag);
526}
527
528static Object* FindNameClash(Handle<ScopeInfo> scope_info,
529 Handle<GlobalObject> global_object,
530 Handle<ScriptContextTable> script_context) {
531 Isolate* isolate = scope_info->GetIsolate();
532 for (int var = 0; var < scope_info->ContextLocalCount(); var++) {
533 Handle<String> name(scope_info->ContextLocalName(var));
534 VariableMode mode = scope_info->ContextLocalMode(var);
535 ScriptContextTable::LookupResult lookup;
536 if (ScriptContextTable::Lookup(script_context, name, &lookup)) {
537 if (IsLexicalVariableMode(mode) || IsLexicalVariableMode(lookup.mode)) {
538 return ThrowRedeclarationError(isolate, name);
539 }
540 }
541
542 if (IsLexicalVariableMode(mode)) {
543 LookupIterator it(global_object, name,
544 LookupIterator::HIDDEN_SKIP_INTERCEPTOR);
545 Maybe<PropertyAttributes> maybe = JSReceiver::GetPropertyAttributes(&it);
546 if (!maybe.has_value) return isolate->heap()->exception();
547 if ((maybe.value & DONT_DELETE) != 0) {
548 return ThrowRedeclarationError(isolate, name);
549 }
550
551 GlobalObject::InvalidatePropertyCell(global_object, name);
552 }
553 }
554 return isolate->heap()->undefined_value();
555}
556
557
558RUNTIME_FUNCTION(Runtime_NewScriptContext) {
559 HandleScope scope(isolate);
560 DCHECK(args.length() == 2);
561
562 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
563 CONVERT_ARG_HANDLE_CHECKED(ScopeInfo, scope_info, 1);
564 Handle<GlobalObject> global_object(function->context()->global_object());
565 Handle<Context> native_context(global_object->native_context());
566 Handle<ScriptContextTable> script_context_table(
567 native_context->script_context_table());
568
569 Handle<String> clashed_name;
570 Object* name_clash_result =
571 FindNameClash(scope_info, global_object, script_context_table);
572 if (isolate->has_pending_exception()) return name_clash_result;
573
574 Handle<Context> result =
575 isolate->factory()->NewScriptContext(function, scope_info);
576
577 DCHECK(function->context() == isolate->context());
578 DCHECK(function->context()->global_object() == result->global_object());
579
580 Handle<ScriptContextTable> new_script_context_table =
581 ScriptContextTable::Extend(script_context_table, result);
582 native_context->set_script_context_table(*new_script_context_table);
583 return *result;
584}
585
586
587RUNTIME_FUNCTION(Runtime_NewFunctionContext) {
588 HandleScope scope(isolate);
589 DCHECK(args.length() == 1);
590
591 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
592
593 DCHECK(function->context() == isolate->context());
594 int length = function->shared()->scope_info()->ContextLength();
595 return *isolate->factory()->NewFunctionContext(length, function);
596}
597
598
599RUNTIME_FUNCTION(Runtime_PushWithContext) {
600 HandleScope scope(isolate);
601 DCHECK(args.length() == 2);
602 Handle<JSReceiver> extension_object;
603 if (args[0]->IsJSReceiver()) {
604 extension_object = args.at<JSReceiver>(0);
605 } else {
606 // Try to convert the object to a proper JavaScript object.
607 MaybeHandle<JSReceiver> maybe_object =
608 Object::ToObject(isolate, args.at<Object>(0));
609 if (!maybe_object.ToHandle(&extension_object)) {
610 Handle<Object> handle = args.at<Object>(0);
611 THROW_NEW_ERROR_RETURN_FAILURE(
612 isolate, NewTypeError("with_expression", HandleVector(&handle, 1)));
613 }
614 }
615
616 Handle<JSFunction> function;
617 if (args[1]->IsSmi()) {
618 // A smi sentinel indicates a context nested inside global code rather
619 // than some function. There is a canonical empty function that can be
620 // gotten from the native context.
621 function = handle(isolate->native_context()->closure());
622 } else {
623 function = args.at<JSFunction>(1);
624 }
625
626 Handle<Context> current(isolate->context());
627 Handle<Context> context =
628 isolate->factory()->NewWithContext(function, current, extension_object);
629 isolate->set_context(*context);
630 return *context;
631}
632
633
634RUNTIME_FUNCTION(Runtime_PushCatchContext) {
635 HandleScope scope(isolate);
636 DCHECK(args.length() == 3);
637 CONVERT_ARG_HANDLE_CHECKED(String, name, 0);
638 CONVERT_ARG_HANDLE_CHECKED(Object, thrown_object, 1);
639 Handle<JSFunction> function;
640 if (args[2]->IsSmi()) {
641 // A smi sentinel indicates a context nested inside global code rather
642 // than some function. There is a canonical empty function that can be
643 // gotten from the native context.
644 function = handle(isolate->native_context()->closure());
645 } else {
646 function = args.at<JSFunction>(2);
647 }
648 Handle<Context> current(isolate->context());
649 Handle<Context> context = isolate->factory()->NewCatchContext(
650 function, current, name, thrown_object);
651 isolate->set_context(*context);
652 return *context;
653}
654
655
656RUNTIME_FUNCTION(Runtime_PushBlockContext) {
657 HandleScope scope(isolate);
658 DCHECK(args.length() == 2);
659 CONVERT_ARG_HANDLE_CHECKED(ScopeInfo, scope_info, 0);
660 Handle<JSFunction> function;
661 if (args[1]->IsSmi()) {
662 // A smi sentinel indicates a context nested inside global code rather
663 // than some function. There is a canonical empty function that can be
664 // gotten from the native context.
665 function = handle(isolate->native_context()->closure());
666 } else {
667 function = args.at<JSFunction>(1);
668 }
669 Handle<Context> current(isolate->context());
670 Handle<Context> context =
671 isolate->factory()->NewBlockContext(function, current, scope_info);
672 isolate->set_context(*context);
673 return *context;
674}
675
676
677RUNTIME_FUNCTION(Runtime_IsJSModule) {
678 SealHandleScope shs(isolate);
679 DCHECK(args.length() == 1);
680 CONVERT_ARG_CHECKED(Object, obj, 0);
681 return isolate->heap()->ToBoolean(obj->IsJSModule());
682}
683
684
685RUNTIME_FUNCTION(Runtime_PushModuleContext) {
686 SealHandleScope shs(isolate);
687 DCHECK(args.length() == 2);
688 CONVERT_SMI_ARG_CHECKED(index, 0);
689
690 if (!args[1]->IsScopeInfo()) {
691 // Module already initialized. Find hosting context and retrieve context.
692 Context* host = Context::cast(isolate->context())->script_context();
693 Context* context = Context::cast(host->get(index));
694 DCHECK(context->previous() == isolate->context());
695 isolate->set_context(context);
696 return context;
697 }
698
699 CONVERT_ARG_HANDLE_CHECKED(ScopeInfo, scope_info, 1);
700
701 // Allocate module context.
702 HandleScope scope(isolate);
703 Factory* factory = isolate->factory();
704 Handle<Context> context = factory->NewModuleContext(scope_info);
705 Handle<JSModule> module = factory->NewJSModule(context, scope_info);
706 context->set_module(*module);
707 Context* previous = isolate->context();
708 context->set_previous(previous);
709 context->set_closure(previous->closure());
710 context->set_global_object(previous->global_object());
711 isolate->set_context(*context);
712
713 // Find hosting scope and initialize internal variable holding module there.
714 previous->script_context()->set(index, *context);
715
716 return *context;
717}
718
719
720RUNTIME_FUNCTION(Runtime_DeclareModules) {
721 HandleScope scope(isolate);
722 DCHECK(args.length() == 1);
723 CONVERT_ARG_HANDLE_CHECKED(FixedArray, descriptions, 0);
724 Context* host_context = isolate->context();
725
726 for (int i = 0; i < descriptions->length(); ++i) {
727 Handle<ModuleInfo> description(ModuleInfo::cast(descriptions->get(i)));
728 int host_index = description->host_index();
729 Handle<Context> context(Context::cast(host_context->get(host_index)));
730 Handle<JSModule> module(context->module());
731
732 for (int j = 0; j < description->length(); ++j) {
733 Handle<String> name(description->name(j));
734 VariableMode mode = description->mode(j);
735 int index = description->index(j);
736 switch (mode) {
737 case VAR:
738 case LET:
739 case CONST:
740 case CONST_LEGACY: {
741 PropertyAttributes attr =
742 IsImmutableVariableMode(mode) ? FROZEN : SEALED;
743 Handle<AccessorInfo> info =
744 Accessors::MakeModuleExport(name, index, attr);
745 Handle<Object> result =
746 JSObject::SetAccessor(module, info).ToHandleChecked();
747 DCHECK(!result->IsUndefined());
748 USE(result);
749 break;
750 }
751 case MODULE: {
752 Object* referenced_context = Context::cast(host_context)->get(index);
753 Handle<JSModule> value(Context::cast(referenced_context)->module());
754 JSObject::SetOwnPropertyIgnoreAttributes(module, name, value, FROZEN)
755 .Assert();
756 break;
757 }
758 case INTERNAL:
759 case TEMPORARY:
760 case DYNAMIC:
761 case DYNAMIC_GLOBAL:
762 case DYNAMIC_LOCAL:
763 UNREACHABLE();
764 }
765 }
766
767 JSObject::PreventExtensions(module).Assert();
768 }
769
770 DCHECK(!isolate->has_pending_exception());
771 return isolate->heap()->undefined_value();
772}
773
774
775RUNTIME_FUNCTION(Runtime_DeleteLookupSlot) {
776 HandleScope scope(isolate);
777 DCHECK(args.length() == 2);
778
779 CONVERT_ARG_HANDLE_CHECKED(Context, context, 0);
780 CONVERT_ARG_HANDLE_CHECKED(String, name, 1);
781
782 int index;
783 PropertyAttributes attributes;
784 ContextLookupFlags flags = FOLLOW_CHAINS;
785 BindingFlags binding_flags;
786 Handle<Object> holder =
787 context->Lookup(name, flags, &index, &attributes, &binding_flags);
788
789 // If the slot was not found the result is true.
790 if (holder.is_null()) {
791 return isolate->heap()->true_value();
792 }
793
794 // If the slot was found in a context, it should be DONT_DELETE.
795 if (holder->IsContext()) {
796 return isolate->heap()->false_value();
797 }
798
799 // The slot was found in a JSObject, either a context extension object,
800 // the global object, or the subject of a with. Try to delete it
801 // (respecting DONT_DELETE).
802 Handle<JSObject> object = Handle<JSObject>::cast(holder);
803 Handle<Object> result;
804 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result,
805 JSReceiver::DeleteProperty(object, name));
806 return *result;
807}
808
809
810static Object* ComputeReceiverForNonGlobal(Isolate* isolate, JSObject* holder) {
811 DCHECK(!holder->IsGlobalObject());
812 Context* top = isolate->context();
813 // Get the context extension function.
814 JSFunction* context_extension_function =
815 top->native_context()->context_extension_function();
816 // If the holder isn't a context extension object, we just return it
817 // as the receiver. This allows arguments objects to be used as
818 // receivers, but only if they are put in the context scope chain
819 // explicitly via a with-statement.
820 Object* constructor = holder->map()->constructor();
821 if (constructor != context_extension_function) return holder;
822 // Fall back to using the global object as the implicit receiver if
823 // the property turns out to be a local variable allocated in a
824 // context extension object - introduced via eval.
825 return isolate->heap()->undefined_value();
826}
827
828
829static ObjectPair LoadLookupSlotHelper(Arguments args, Isolate* isolate,
830 bool throw_error) {
831 HandleScope scope(isolate);
832 DCHECK_EQ(2, args.length());
833
834 if (!args[0]->IsContext() || !args[1]->IsString()) {
835 return MakePair(isolate->ThrowIllegalOperation(), NULL);
836 }
837 Handle<Context> context = args.at<Context>(0);
838 Handle<String> name = args.at<String>(1);
839
840 int index;
841 PropertyAttributes attributes;
842 ContextLookupFlags flags = FOLLOW_CHAINS;
843 BindingFlags binding_flags;
844 Handle<Object> holder =
845 context->Lookup(name, flags, &index, &attributes, &binding_flags);
846 if (isolate->has_pending_exception()) {
847 return MakePair(isolate->heap()->exception(), NULL);
848 }
849
850 // If the index is non-negative, the slot has been found in a context.
851 if (index >= 0) {
852 DCHECK(holder->IsContext());
853 // If the "property" we were looking for is a local variable, the
854 // receiver is the global object; see ECMA-262, 3rd., 10.1.6 and 10.2.3.
855 Handle<Object> receiver = isolate->factory()->undefined_value();
856 Object* value = Context::cast(*holder)->get(index);
857 // Check for uninitialized bindings.
858 switch (binding_flags) {
859 case MUTABLE_CHECK_INITIALIZED:
860 case IMMUTABLE_CHECK_INITIALIZED_HARMONY:
861 if (value->IsTheHole()) {
862 Handle<Object> error;
863 MaybeHandle<Object> maybe_error =
864 isolate->factory()->NewReferenceError("not_defined",
865 HandleVector(&name, 1));
866 if (maybe_error.ToHandle(&error)) isolate->Throw(*error);
867 return MakePair(isolate->heap()->exception(), NULL);
868 }
869 // FALLTHROUGH
870 case MUTABLE_IS_INITIALIZED:
871 case IMMUTABLE_IS_INITIALIZED:
872 case IMMUTABLE_IS_INITIALIZED_HARMONY:
873 DCHECK(!value->IsTheHole());
874 return MakePair(value, *receiver);
875 case IMMUTABLE_CHECK_INITIALIZED:
876 if (value->IsTheHole()) {
877 DCHECK((attributes & READ_ONLY) != 0);
878 value = isolate->heap()->undefined_value();
879 }
880 return MakePair(value, *receiver);
881 case MISSING_BINDING:
882 UNREACHABLE();
883 return MakePair(NULL, NULL);
884 }
885 }
886
887 // Otherwise, if the slot was found the holder is a context extension
888 // object, subject of a with, or a global object. We read the named
889 // property from it.
890 if (!holder.is_null()) {
891 Handle<JSReceiver> object = Handle<JSReceiver>::cast(holder);
892#ifdef DEBUG
893 if (!object->IsJSProxy()) {
894 Maybe<bool> maybe = JSReceiver::HasProperty(object, name);
895 DCHECK(maybe.has_value);
896 DCHECK(maybe.value);
897 }
898#endif
899 // GetProperty below can cause GC.
900 Handle<Object> receiver_handle(
901 object->IsGlobalObject()
902 ? Object::cast(isolate->heap()->undefined_value())
903 : object->IsJSProxy() ? static_cast<Object*>(*object)
904 : ComputeReceiverForNonGlobal(
905 isolate, JSObject::cast(*object)),
906 isolate);
907
908 // No need to unhole the value here. This is taken care of by the
909 // GetProperty function.
910 Handle<Object> value;
911 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
912 isolate, value, Object::GetProperty(object, name),
913 MakePair(isolate->heap()->exception(), NULL));
914 return MakePair(*value, *receiver_handle);
915 }
916
917 if (throw_error) {
918 // The property doesn't exist - throw exception.
919 Handle<Object> error;
920 MaybeHandle<Object> maybe_error = isolate->factory()->NewReferenceError(
921 "not_defined", HandleVector(&name, 1));
922 if (maybe_error.ToHandle(&error)) isolate->Throw(*error);
923 return MakePair(isolate->heap()->exception(), NULL);
924 } else {
925 // The property doesn't exist - return undefined.
926 return MakePair(isolate->heap()->undefined_value(),
927 isolate->heap()->undefined_value());
928 }
929}
930
931
932RUNTIME_FUNCTION_RETURN_PAIR(Runtime_LoadLookupSlot) {
933 return LoadLookupSlotHelper(args, isolate, true);
934}
935
936
937RUNTIME_FUNCTION_RETURN_PAIR(Runtime_LoadLookupSlotNoReferenceError) {
938 return LoadLookupSlotHelper(args, isolate, false);
939}
940
941
942RUNTIME_FUNCTION(Runtime_StoreLookupSlot) {
943 HandleScope scope(isolate);
944 DCHECK(args.length() == 4);
945
946 CONVERT_ARG_HANDLE_CHECKED(Object, value, 0);
947 CONVERT_ARG_HANDLE_CHECKED(Context, context, 1);
948 CONVERT_ARG_HANDLE_CHECKED(String, name, 2);
949 CONVERT_STRICT_MODE_ARG_CHECKED(strict_mode, 3);
950
951 int index;
952 PropertyAttributes attributes;
953 ContextLookupFlags flags = FOLLOW_CHAINS;
954 BindingFlags binding_flags;
955 Handle<Object> holder =
956 context->Lookup(name, flags, &index, &attributes, &binding_flags);
957 // In case of JSProxy, an exception might have been thrown.
958 if (isolate->has_pending_exception()) return isolate->heap()->exception();
959
960 // The property was found in a context slot.
961 if (index >= 0) {
962 if ((attributes & READ_ONLY) == 0) {
963 Handle<Context>::cast(holder)->set(index, *value);
964 } else if (strict_mode == STRICT) {
965 // Setting read only property in strict mode.
966 THROW_NEW_ERROR_RETURN_FAILURE(
967 isolate,
968 NewTypeError("strict_cannot_assign", HandleVector(&name, 1)));
969 }
970 return *value;
971 }
972
973 // Slow case: The property is not in a context slot. It is either in a
974 // context extension object, a property of the subject of a with, or a
975 // property of the global object.
976 Handle<JSReceiver> object;
977 if (attributes != ABSENT) {
978 // The property exists on the holder.
979 object = Handle<JSReceiver>::cast(holder);
980 } else if (strict_mode == STRICT) {
981 // If absent in strict mode: throw.
982 THROW_NEW_ERROR_RETURN_FAILURE(
983 isolate, NewReferenceError("not_defined", HandleVector(&name, 1)));
984 } else {
985 // If absent in sloppy mode: add the property to the global object.
986 object = Handle<JSReceiver>(context->global_object());
987 }
988
989 RETURN_FAILURE_ON_EXCEPTION(
990 isolate, Object::SetProperty(object, name, value, strict_mode));
991
992 return *value;
993}
994
995
996RUNTIME_FUNCTION(Runtime_GetArgumentsProperty) {
997 SealHandleScope shs(isolate);
998 DCHECK(args.length() == 1);
999 CONVERT_ARG_HANDLE_CHECKED(Object, raw_key, 0);
1000
1001 // Compute the frame holding the arguments.
1002 JavaScriptFrameIterator it(isolate);
1003 it.AdvanceToArgumentsFrame();
1004 JavaScriptFrame* frame = it.frame();
1005
1006 // Get the actual number of provided arguments.
1007 const uint32_t n = frame->ComputeParametersCount();
1008
1009 // Try to convert the key to an index. If successful and within
1010 // index return the the argument from the frame.
1011 uint32_t index;
1012 if (raw_key->ToArrayIndex(&index) && index < n) {
1013 return frame->GetParameter(index);
1014 }
1015
1016 HandleScope scope(isolate);
1017 if (raw_key->IsSymbol()) {
1018 Handle<Symbol> symbol = Handle<Symbol>::cast(raw_key);
1019 if (Name::Equals(symbol, isolate->factory()->iterator_symbol())) {
1020 return isolate->native_context()->array_values_iterator();
1021 }
1022 // Lookup in the initial Object.prototype object.
1023 Handle<Object> result;
1024 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
1025 isolate, result,
1026 Object::GetProperty(isolate->initial_object_prototype(),
1027 Handle<Symbol>::cast(raw_key)));
1028 return *result;
1029 }
1030
1031 // Convert the key to a string.
1032 Handle<Object> converted;
1033 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, converted,
1034 Execution::ToString(isolate, raw_key));
1035 Handle<String> key = Handle<String>::cast(converted);
1036
1037 // Try to convert the string key into an array index.
1038 if (key->AsArrayIndex(&index)) {
1039 if (index < n) {
1040 return frame->GetParameter(index);
1041 } else {
1042 Handle<Object> initial_prototype(isolate->initial_object_prototype());
1043 Handle<Object> result;
1044 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
1045 isolate, result,
1046 Object::GetElement(isolate, initial_prototype, index));
1047 return *result;
1048 }
1049 }
1050
1051 // Handle special arguments properties.
1052 if (String::Equals(isolate->factory()->length_string(), key)) {
1053 return Smi::FromInt(n);
1054 }
1055 if (String::Equals(isolate->factory()->callee_string(), key)) {
1056 JSFunction* function = frame->function();
1057 if (function->shared()->strict_mode() == STRICT) {
1058 THROW_NEW_ERROR_RETURN_FAILURE(
1059 isolate, NewTypeError("strict_arguments_callee",
1060 HandleVector<Object>(NULL, 0)));
1061 }
1062 return function;
1063 }
1064
1065 // Lookup in the initial Object.prototype object.
1066 Handle<Object> result;
1067 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
1068 isolate, result,
1069 Object::GetProperty(isolate->initial_object_prototype(), key));
1070 return *result;
1071}
1072
1073
1074RUNTIME_FUNCTION(RuntimeReference_ArgumentsLength) {
1075 SealHandleScope shs(isolate);
1076 DCHECK(args.length() == 0);
1077 JavaScriptFrameIterator it(isolate);
1078 JavaScriptFrame* frame = it.frame();
1079 return Smi::FromInt(frame->GetArgumentsLength());
1080}
1081
1082
1083RUNTIME_FUNCTION(RuntimeReference_Arguments) {
1084 SealHandleScope shs(isolate);
1085 return __RT_impl_Runtime_GetArgumentsProperty(args, isolate);
1086}
1087}
1088} // namespace v8::internal