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 <memory>
6
7 #include "src/ast/scopes.h"
8 #include "src/builtins/accessors.h"
9 #include "src/common/message-template.h"
10 #include "src/deoptimizer/deoptimizer.h"
11 #include "src/execution/arguments-inl.h"
12 #include "src/execution/frames-inl.h"
13 #include "src/execution/isolate-inl.h"
14 #include "src/execution/isolate.h"
15 #include "src/heap/heap-inl.h" // For ToBoolean. TODO(jkummerow): Drop.
16 #include "src/init/bootstrapper.h"
17 #include "src/logging/counters.h"
18 #include "src/objects/arguments-inl.h"
19 #include "src/objects/heap-object-inl.h"
20 #include "src/objects/module-inl.h"
21 #include "src/objects/smi.h"
22 #include "src/runtime/runtime-utils.h"
23
24 namespace v8 {
25 namespace internal {
26
RUNTIME_FUNCTION(Runtime_ThrowConstAssignError)27 RUNTIME_FUNCTION(Runtime_ThrowConstAssignError) {
28 HandleScope scope(isolate);
29 THROW_NEW_ERROR_RETURN_FAILURE(isolate,
30 NewTypeError(MessageTemplate::kConstAssign));
31 }
32
33 namespace {
34
35 enum class RedeclarationType { kSyntaxError = 0, kTypeError = 1 };
36
ThrowRedeclarationError(Isolate * isolate,Handle<String> name,RedeclarationType redeclaration_type)37 Object ThrowRedeclarationError(Isolate* isolate, Handle<String> name,
38 RedeclarationType redeclaration_type) {
39 HandleScope scope(isolate);
40 if (redeclaration_type == RedeclarationType::kSyntaxError) {
41 THROW_NEW_ERROR_RETURN_FAILURE(
42 isolate, NewSyntaxError(MessageTemplate::kVarRedeclaration, name));
43 } else {
44 THROW_NEW_ERROR_RETURN_FAILURE(
45 isolate, NewTypeError(MessageTemplate::kVarRedeclaration, name));
46 }
47 }
48
49 // May throw a RedeclarationError.
DeclareGlobal(Isolate * isolate,Handle<JSGlobalObject> global,Handle<String> name,Handle<Object> value,PropertyAttributes attr,bool is_var,RedeclarationType redeclaration_type)50 Object DeclareGlobal(Isolate* isolate, Handle<JSGlobalObject> global,
51 Handle<String> name, Handle<Object> value,
52 PropertyAttributes attr, bool is_var,
53 RedeclarationType redeclaration_type) {
54 Handle<ScriptContextTable> script_contexts(
55 global->native_context().script_context_table(), isolate);
56 VariableLookupResult lookup;
57 if (script_contexts->Lookup(name, &lookup) &&
58 IsLexicalVariableMode(lookup.mode)) {
59 // ES#sec-globaldeclarationinstantiation 6.a:
60 // If envRec.HasLexicalDeclaration(name) is true, throw a SyntaxError
61 // exception.
62 return ThrowRedeclarationError(isolate, name,
63 RedeclarationType::kSyntaxError);
64 }
65
66 // Do the lookup own properties only, see ES5 erratum.
67 LookupIterator::Configuration lookup_config(
68 LookupIterator::Configuration::OWN_SKIP_INTERCEPTOR);
69 if (!is_var) {
70 // For function declarations, use the interceptor on the declaration. For
71 // non-functions, use it only on initialization.
72 lookup_config = LookupIterator::Configuration::OWN;
73 }
74 LookupIterator it(isolate, global, name, global, lookup_config);
75 Maybe<PropertyAttributes> maybe = JSReceiver::GetPropertyAttributes(&it);
76 if (maybe.IsNothing()) return ReadOnlyRoots(isolate).exception();
77
78 if (it.IsFound()) {
79 PropertyAttributes old_attributes = maybe.FromJust();
80 // The name was declared before; check for conflicting re-declarations.
81
82 // Skip var re-declarations.
83 if (is_var) return ReadOnlyRoots(isolate).undefined_value();
84
85 if ((old_attributes & DONT_DELETE) != 0) {
86 // Only allow reconfiguring globals to functions in user code (no
87 // natives, which are marked as read-only).
88 DCHECK_EQ(attr & READ_ONLY, 0);
89
90 // Check whether we can reconfigure the existing property into a
91 // function.
92 if (old_attributes & READ_ONLY || old_attributes & DONT_ENUM ||
93 (it.state() == LookupIterator::ACCESSOR)) {
94 // ECMA-262 section 15.1.11 GlobalDeclarationInstantiation 5.d:
95 // If hasRestrictedGlobal is true, throw a SyntaxError exception.
96 // ECMA-262 section 18.2.1.3 EvalDeclarationInstantiation 8.a.iv.1.b:
97 // If fnDefinable is false, throw a TypeError exception.
98 return ThrowRedeclarationError(isolate, name, redeclaration_type);
99 }
100 // If the existing property is not configurable, keep its attributes. Do
101 attr = old_attributes;
102 }
103
104 // If the current state is ACCESSOR, this could mean it's an AccessorInfo
105 // type property. We are not allowed to call into such setters during global
106 // function declaration since this would break e.g., onload. Meaning
107 // 'function onload() {}' would invalidly register that function as the
108 // onload callback. To avoid this situation, we first delete the property
109 // before readding it as a regular data property below.
110 if (it.state() == LookupIterator::ACCESSOR) it.Delete();
111 }
112
113 if (!is_var) it.Restart();
114
115 // Define or redefine own property.
116 RETURN_FAILURE_ON_EXCEPTION(
117 isolate, JSObject::DefineOwnPropertyIgnoreAttributes(&it, value, attr));
118
119 return ReadOnlyRoots(isolate).undefined_value();
120 }
121
122 } // namespace
123
RUNTIME_FUNCTION(Runtime_DeclareModuleExports)124 RUNTIME_FUNCTION(Runtime_DeclareModuleExports) {
125 HandleScope scope(isolate);
126 DCHECK_EQ(2, args.length());
127
128 Handle<FixedArray> declarations = args.at<FixedArray>(0);
129 Handle<JSFunction> closure = args.at<JSFunction>(1);
130
131 Handle<ClosureFeedbackCellArray> closure_feedback_cell_array =
132 Handle<ClosureFeedbackCellArray>::null();
133 if (closure->has_feedback_vector()) {
134 closure_feedback_cell_array = Handle<ClosureFeedbackCellArray>(
135 closure->feedback_vector().closure_feedback_cell_array(), isolate);
136 } else {
137 closure_feedback_cell_array = Handle<ClosureFeedbackCellArray>(
138 closure->closure_feedback_cell_array(), isolate);
139 }
140
141 Handle<Context> context(isolate->context(), isolate);
142 DCHECK(context->IsModuleContext());
143 Handle<FixedArray> exports(
144 SourceTextModule::cast(context->extension()).regular_exports(), isolate);
145
146 int length = declarations->length();
147 FOR_WITH_HANDLE_SCOPE(isolate, int, i = 0, i, i < length, i++, {
148 Object decl = declarations->get(i);
149 int index;
150 Object value;
151 if (decl.IsSmi()) {
152 index = Smi::ToInt(decl);
153 value = ReadOnlyRoots(isolate).the_hole_value();
154 } else {
155 Handle<SharedFunctionInfo> sfi(
156 SharedFunctionInfo::cast(declarations->get(i)), isolate);
157 int feedback_index = Smi::ToInt(declarations->get(++i));
158 index = Smi::ToInt(declarations->get(++i));
159 Handle<FeedbackCell> feedback_cell =
160 closure_feedback_cell_array->GetFeedbackCell(feedback_index);
161 value = *Factory::JSFunctionBuilder(isolate, sfi, context)
162 .set_feedback_cell(feedback_cell)
163 .Build();
164 }
165
166 Cell::cast(exports->get(index - 1)).set_value(value);
167 });
168
169 return ReadOnlyRoots(isolate).undefined_value();
170 }
171
RUNTIME_FUNCTION(Runtime_DeclareGlobals)172 RUNTIME_FUNCTION(Runtime_DeclareGlobals) {
173 HandleScope scope(isolate);
174 DCHECK_EQ(2, args.length());
175
176 Handle<FixedArray> declarations = args.at<FixedArray>(0);
177 Handle<JSFunction> closure = args.at<JSFunction>(1);
178
179 Handle<JSGlobalObject> global(isolate->global_object());
180 Handle<Context> context(isolate->context(), isolate);
181
182 Handle<ClosureFeedbackCellArray> closure_feedback_cell_array =
183 Handle<ClosureFeedbackCellArray>::null();
184 if (closure->has_feedback_vector()) {
185 closure_feedback_cell_array = Handle<ClosureFeedbackCellArray>(
186 closure->feedback_vector().closure_feedback_cell_array(), isolate);
187 } else {
188 closure_feedback_cell_array = Handle<ClosureFeedbackCellArray>(
189 closure->closure_feedback_cell_array(), isolate);
190 }
191
192 // Traverse the name/value pairs and set the properties.
193 int length = declarations->length();
194 FOR_WITH_HANDLE_SCOPE(isolate, int, i = 0, i, i < length, i++, {
195 Handle<Object> decl(declarations->get(i), isolate);
196 Handle<String> name;
197 Handle<Object> value;
198 bool is_var = decl->IsString();
199
200 if (is_var) {
201 name = Handle<String>::cast(decl);
202 value = isolate->factory()->undefined_value();
203 } else {
204 Handle<SharedFunctionInfo> sfi = Handle<SharedFunctionInfo>::cast(decl);
205 name = handle(sfi->Name(), isolate);
206 int index = Smi::ToInt(declarations->get(++i));
207 Handle<FeedbackCell> feedback_cell =
208 closure_feedback_cell_array->GetFeedbackCell(index);
209 value = Factory::JSFunctionBuilder(isolate, sfi, context)
210 .set_feedback_cell(feedback_cell)
211 .Build();
212 }
213
214 // Compute the property attributes. According to ECMA-262,
215 // the property must be non-configurable except in eval.
216 Script script = Script::cast(closure->shared().script());
217 PropertyAttributes attr =
218 script.compilation_type() == Script::COMPILATION_TYPE_EVAL
219 ? NONE
220 : DONT_DELETE;
221
222 // ES#sec-globaldeclarationinstantiation 5.d:
223 // If hasRestrictedGlobal is true, throw a SyntaxError exception.
224 Object result = DeclareGlobal(isolate, global, name, value, attr, is_var,
225 RedeclarationType::kSyntaxError);
226 if (isolate->has_pending_exception()) return result;
227 });
228
229 return ReadOnlyRoots(isolate).undefined_value();
230 }
231
232 namespace {
233
DeclareEvalHelper(Isolate * isolate,Handle<String> name,Handle<Object> value)234 Object DeclareEvalHelper(Isolate* isolate, Handle<String> name,
235 Handle<Object> value) {
236 // Declarations are always made in a function, native, eval, or script
237 // context, or a declaration block scope. Since this is called from eval, the
238 // context passed is the context of the caller, which may be some nested
239 // context and not the declaration context.
240 Handle<Context> context(isolate->context().declaration_context(), isolate);
241
242 DCHECK(context->IsFunctionContext() || context->IsNativeContext() ||
243 context->IsScriptContext() || context->IsEvalContext() ||
244 (context->IsBlockContext() &&
245 context->scope_info().is_declaration_scope()));
246
247 bool is_var = value->IsUndefined(isolate);
248 DCHECK_IMPLIES(!is_var, value->IsJSFunction());
249
250 int index;
251 PropertyAttributes attributes;
252 InitializationFlag init_flag;
253 VariableMode mode;
254
255 Handle<Object> holder =
256 Context::Lookup(context, name, DONT_FOLLOW_CHAINS, &index, &attributes,
257 &init_flag, &mode);
258 DCHECK(holder.is_null() || !holder->IsSourceTextModule());
259 DCHECK(!isolate->has_pending_exception());
260
261 Handle<JSObject> object;
262
263 if (attributes != ABSENT && holder->IsJSGlobalObject()) {
264 // ES#sec-evaldeclarationinstantiation 8.a.iv.1.b:
265 // If fnDefinable is false, throw a TypeError exception.
266 return DeclareGlobal(isolate, Handle<JSGlobalObject>::cast(holder), name,
267 value, NONE, is_var, RedeclarationType::kTypeError);
268 }
269 if (context->has_extension() && context->extension().IsJSGlobalObject()) {
270 Handle<JSGlobalObject> global(JSGlobalObject::cast(context->extension()),
271 isolate);
272 return DeclareGlobal(isolate, global, name, value, NONE, is_var,
273 RedeclarationType::kTypeError);
274 } else if (context->IsScriptContext()) {
275 DCHECK(context->global_object().IsJSGlobalObject());
276 Handle<JSGlobalObject> global(
277 JSGlobalObject::cast(context->global_object()), isolate);
278 return DeclareGlobal(isolate, global, name, value, NONE, is_var,
279 RedeclarationType::kTypeError);
280 }
281
282 if (attributes != ABSENT) {
283 DCHECK_EQ(NONE, attributes);
284
285 // Skip var re-declarations.
286 if (is_var) return ReadOnlyRoots(isolate).undefined_value();
287
288 if (index != Context::kNotFound) {
289 DCHECK(holder.is_identical_to(context));
290 context->set(index, *value);
291 return ReadOnlyRoots(isolate).undefined_value();
292 }
293
294 object = Handle<JSObject>::cast(holder);
295
296 } else if (context->has_extension()) {
297 object = handle(context->extension_object(), isolate);
298 DCHECK(object->IsJSContextExtensionObject());
299 } else if (context->scope_info().HasContextExtensionSlot()) {
300 // Sloppy varblock and function contexts might not have an extension object
301 // yet. Sloppy eval will never have an extension object, as vars are hoisted
302 // out, and lets are known statically.
303 DCHECK((context->IsBlockContext() &&
304 context->scope_info().is_declaration_scope()) ||
305 context->IsFunctionContext());
306 object =
307 isolate->factory()->NewJSObject(isolate->context_extension_function());
308
309 context->set_extension(*object);
310 } else {
311 THROW_NEW_ERROR_RETURN_FAILURE(
312 isolate,
313 NewEvalError(MessageTemplate::kVarNotAllowedInEvalScope, name));
314 }
315
316 RETURN_FAILURE_ON_EXCEPTION(isolate, JSObject::SetOwnPropertyIgnoreAttributes(
317 object, name, value, NONE));
318
319 return ReadOnlyRoots(isolate).undefined_value();
320 }
321
322 } // namespace
323
RUNTIME_FUNCTION(Runtime_DeclareEvalFunction)324 RUNTIME_FUNCTION(Runtime_DeclareEvalFunction) {
325 HandleScope scope(isolate);
326 DCHECK_EQ(2, args.length());
327 Handle<String> name = args.at<String>(0);
328 Handle<Object> value = args.at(1);
329 return DeclareEvalHelper(isolate, name, value);
330 }
331
RUNTIME_FUNCTION(Runtime_DeclareEvalVar)332 RUNTIME_FUNCTION(Runtime_DeclareEvalVar) {
333 HandleScope scope(isolate);
334 DCHECK_EQ(1, args.length());
335 Handle<String> name = args.at<String>(0);
336 return DeclareEvalHelper(isolate, name,
337 isolate->factory()->undefined_value());
338 }
339
340 namespace {
341
342 // Find the arguments of the JavaScript function invocation that called
343 // into C++ code. Collect these in a newly allocated array of handles.
GetCallerArguments(Isolate * isolate,int * total_argc)344 std::unique_ptr<Handle<Object>[]> GetCallerArguments(Isolate* isolate,
345 int* total_argc) {
346 // Find frame containing arguments passed to the caller.
347 JavaScriptFrameIterator it(isolate);
348 JavaScriptFrame* frame = it.frame();
349 std::vector<SharedFunctionInfo> functions;
350 frame->GetFunctions(&functions);
351 if (functions.size() > 1) {
352 int inlined_jsframe_index = static_cast<int>(functions.size()) - 1;
353 TranslatedState translated_values(frame);
354 translated_values.Prepare(frame->fp());
355
356 int argument_count = 0;
357 TranslatedFrame* translated_frame =
358 translated_values.GetArgumentsInfoFromJSFrameIndex(
359 inlined_jsframe_index, &argument_count);
360 TranslatedFrame::iterator iter = translated_frame->begin();
361
362 // Skip the function.
363 iter++;
364
365 // Skip the receiver.
366 iter++;
367 argument_count--;
368
369 *total_argc = argument_count;
370 std::unique_ptr<Handle<Object>[]> param_data(
371 NewArray<Handle<Object>>(*total_argc));
372 bool should_deoptimize = false;
373 for (int i = 0; i < argument_count; i++) {
374 // If we materialize any object, we should deoptimize the frame because we
375 // might alias an object that was eliminated by escape analysis.
376 should_deoptimize = should_deoptimize || iter->IsMaterializedObject();
377 Handle<Object> value = iter->GetValue();
378 param_data[i] = value;
379 iter++;
380 }
381
382 if (should_deoptimize) {
383 translated_values.StoreMaterializedValuesAndDeopt(frame);
384 }
385
386 return param_data;
387 } else {
388 int args_count = frame->GetActualArgumentCount();
389 *total_argc = args_count;
390 std::unique_ptr<Handle<Object>[]> param_data(
391 NewArray<Handle<Object>>(*total_argc));
392 for (int i = 0; i < args_count; i++) {
393 Handle<Object> val = Handle<Object>(frame->GetParameter(i), isolate);
394 param_data[i] = val;
395 }
396 return param_data;
397 }
398 }
399
400 template <typename T>
NewSloppyArguments(Isolate * isolate,Handle<JSFunction> callee,T parameters,int argument_count)401 Handle<JSObject> NewSloppyArguments(Isolate* isolate, Handle<JSFunction> callee,
402 T parameters, int argument_count) {
403 CHECK(!IsDerivedConstructor(callee->shared().kind()));
404 DCHECK(callee->shared().has_simple_parameters());
405 Handle<JSObject> result =
406 isolate->factory()->NewArgumentsObject(callee, argument_count);
407
408 // Allocate the elements if needed.
409 int parameter_count =
410 callee->shared().internal_formal_parameter_count_without_receiver();
411 if (argument_count > 0) {
412 if (parameter_count > 0) {
413 int mapped_count = std::min(argument_count, parameter_count);
414
415 // Store the context and the arguments array at the beginning of the
416 // parameter map.
417 Handle<Context> context(isolate->context(), isolate);
418 Handle<FixedArray> arguments = isolate->factory()->NewFixedArray(
419 argument_count, AllocationType::kYoung);
420
421 Handle<SloppyArgumentsElements> parameter_map =
422 isolate->factory()->NewSloppyArgumentsElements(
423 mapped_count, context, arguments, AllocationType::kYoung);
424
425 result->set_map(isolate->native_context()->fast_aliased_arguments_map());
426 result->set_elements(*parameter_map);
427
428 // Loop over the actual parameters backwards.
429 int index = argument_count - 1;
430 while (index >= mapped_count) {
431 // These go directly in the arguments array and have no
432 // corresponding slot in the parameter map.
433 arguments->set(index, parameters[index]);
434 --index;
435 }
436
437 Handle<ScopeInfo> scope_info(callee->shared().scope_info(), isolate);
438
439 // First mark all mappable slots as unmapped and copy the values into the
440 // arguments object.
441 for (int i = 0; i < mapped_count; i++) {
442 arguments->set(i, parameters[i]);
443 parameter_map->set_mapped_entries(
444 i, *isolate->factory()->the_hole_value());
445 }
446
447 // Walk all context slots to find context allocated parameters. Mark each
448 // found parameter as mapped.
449 for (int i = 0; i < scope_info->ContextLocalCount(); i++) {
450 if (!scope_info->ContextLocalIsParameter(i)) continue;
451 int parameter = scope_info->ContextLocalParameterNumber(i);
452 if (parameter >= mapped_count) continue;
453 arguments->set_the_hole(parameter);
454 Smi slot = Smi::FromInt(scope_info->ContextHeaderLength() + i);
455 parameter_map->set_mapped_entries(parameter, slot);
456 }
457 } else {
458 // If there is no aliasing, the arguments object elements are not
459 // special in any way.
460 Handle<FixedArray> elements = isolate->factory()->NewFixedArray(
461 argument_count, AllocationType::kYoung);
462 result->set_elements(*elements);
463 for (int i = 0; i < argument_count; ++i) {
464 elements->set(i, parameters[i]);
465 }
466 }
467 }
468 return result;
469 }
470
471 class HandleArguments {
472 public:
HandleArguments(Handle<Object> * array)473 explicit HandleArguments(Handle<Object>* array) : array_(array) {}
operator [](int index)474 Object operator[](int index) { return *array_[index]; }
475
476 private:
477 Handle<Object>* array_;
478 };
479
480 class ParameterArguments {
481 public:
ParameterArguments(Address parameters)482 explicit ParameterArguments(Address parameters) : parameters_(parameters) {}
operator [](int index)483 Object operator[](int index) {
484 return *FullObjectSlot(parameters_ - (index + 1) * kSystemPointerSize);
485 }
486
487 private:
488 Address parameters_;
489 };
490
491 } // namespace
492
RUNTIME_FUNCTION(Runtime_NewSloppyArguments)493 RUNTIME_FUNCTION(Runtime_NewSloppyArguments) {
494 HandleScope scope(isolate);
495 DCHECK_EQ(1, args.length());
496 Handle<JSFunction> callee = args.at<JSFunction>(0);
497 // This generic runtime function can also be used when the caller has been
498 // inlined, we use the slow but accurate {GetCallerArguments}.
499 int argument_count = 0;
500 std::unique_ptr<Handle<Object>[]> arguments =
501 GetCallerArguments(isolate, &argument_count);
502 HandleArguments argument_getter(arguments.get());
503 return *NewSloppyArguments(isolate, callee, argument_getter, argument_count);
504 }
505
RUNTIME_FUNCTION(Runtime_NewStrictArguments)506 RUNTIME_FUNCTION(Runtime_NewStrictArguments) {
507 HandleScope scope(isolate);
508 DCHECK_EQ(1, args.length());
509 Handle<JSFunction> callee = args.at<JSFunction>(0);
510 // This generic runtime function can also be used when the caller has been
511 // inlined, we use the slow but accurate {GetCallerArguments}.
512 int argument_count = 0;
513 std::unique_ptr<Handle<Object>[]> arguments =
514 GetCallerArguments(isolate, &argument_count);
515 Handle<JSObject> result =
516 isolate->factory()->NewArgumentsObject(callee, argument_count);
517 if (argument_count) {
518 Handle<FixedArray> array =
519 isolate->factory()->NewFixedArray(argument_count);
520 DisallowGarbageCollection no_gc;
521 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
522 for (int i = 0; i < argument_count; i++) {
523 array->set(i, *arguments[i], mode);
524 }
525 result->set_elements(*array);
526 }
527 return *result;
528 }
529
530
RUNTIME_FUNCTION(Runtime_NewRestParameter)531 RUNTIME_FUNCTION(Runtime_NewRestParameter) {
532 HandleScope scope(isolate);
533 DCHECK_EQ(1, args.length());
534 Handle<JSFunction> callee = args.at<JSFunction>(0);
535 int start_index =
536 callee->shared().internal_formal_parameter_count_without_receiver();
537 // This generic runtime function can also be used when the caller has been
538 // inlined, we use the slow but accurate {GetCallerArguments}.
539 int argument_count = 0;
540 std::unique_ptr<Handle<Object>[]> arguments =
541 GetCallerArguments(isolate, &argument_count);
542 int num_elements = std::max(0, argument_count - start_index);
543 Handle<JSObject> result = isolate->factory()->NewJSArray(
544 PACKED_ELEMENTS, num_elements, num_elements,
545 DONT_INITIALIZE_ARRAY_ELEMENTS);
546 {
547 DisallowGarbageCollection no_gc;
548 FixedArray elements = FixedArray::cast(result->elements());
549 WriteBarrierMode mode = elements.GetWriteBarrierMode(no_gc);
550 for (int i = 0; i < num_elements; i++) {
551 elements.set(i, *arguments[i + start_index], mode);
552 }
553 }
554 return *result;
555 }
556
RUNTIME_FUNCTION(Runtime_NewClosure)557 RUNTIME_FUNCTION(Runtime_NewClosure) {
558 HandleScope scope(isolate);
559 DCHECK_EQ(2, args.length());
560 Handle<SharedFunctionInfo> shared = args.at<SharedFunctionInfo>(0);
561 Handle<FeedbackCell> feedback_cell = args.at<FeedbackCell>(1);
562 Handle<Context> context(isolate->context(), isolate);
563 return *Factory::JSFunctionBuilder{isolate, shared, context}
564 .set_feedback_cell(feedback_cell)
565 .set_allocation_type(AllocationType::kYoung)
566 .Build();
567 }
568
RUNTIME_FUNCTION(Runtime_NewClosure_Tenured)569 RUNTIME_FUNCTION(Runtime_NewClosure_Tenured) {
570 HandleScope scope(isolate);
571 DCHECK_EQ(2, args.length());
572 Handle<SharedFunctionInfo> shared = args.at<SharedFunctionInfo>(0);
573 Handle<FeedbackCell> feedback_cell = args.at<FeedbackCell>(1);
574 Handle<Context> context(isolate->context(), isolate);
575 // The caller ensures that we pretenure closures that are assigned
576 // directly to properties.
577 return *Factory::JSFunctionBuilder{isolate, shared, context}
578 .set_feedback_cell(feedback_cell)
579 .set_allocation_type(AllocationType::kOld)
580 .Build();
581 }
582
RUNTIME_FUNCTION(Runtime_NewFunctionContext)583 RUNTIME_FUNCTION(Runtime_NewFunctionContext) {
584 HandleScope scope(isolate);
585 DCHECK_EQ(1, args.length());
586
587 Handle<ScopeInfo> scope_info = args.at<ScopeInfo>(0);
588
589 Handle<Context> outer(isolate->context(), isolate);
590 return *isolate->factory()->NewFunctionContext(outer, scope_info);
591 }
592
593 // TODO(jgruber): Rename these functions to 'New...Context'.
RUNTIME_FUNCTION(Runtime_PushWithContext)594 RUNTIME_FUNCTION(Runtime_PushWithContext) {
595 HandleScope scope(isolate);
596 DCHECK_EQ(2, args.length());
597 Handle<JSReceiver> extension_object = args.at<JSReceiver>(0);
598 Handle<ScopeInfo> scope_info = args.at<ScopeInfo>(1);
599 Handle<Context> current(isolate->context(), isolate);
600 return *isolate->factory()->NewWithContext(current, scope_info,
601 extension_object);
602 }
603
604 // TODO(jgruber): Rename these functions to 'New...Context'.
RUNTIME_FUNCTION(Runtime_PushCatchContext)605 RUNTIME_FUNCTION(Runtime_PushCatchContext) {
606 HandleScope scope(isolate);
607 DCHECK_EQ(2, args.length());
608 Handle<Object> thrown_object = args.at(0);
609 Handle<ScopeInfo> scope_info = args.at<ScopeInfo>(1);
610 Handle<Context> current(isolate->context(), isolate);
611 return *isolate->factory()->NewCatchContext(current, scope_info,
612 thrown_object);
613 }
614
615 // TODO(jgruber): Rename these functions to 'New...Context'.
RUNTIME_FUNCTION(Runtime_PushBlockContext)616 RUNTIME_FUNCTION(Runtime_PushBlockContext) {
617 HandleScope scope(isolate);
618 DCHECK_EQ(1, args.length());
619 Handle<ScopeInfo> scope_info = args.at<ScopeInfo>(0);
620 Handle<Context> current(isolate->context(), isolate);
621 return *isolate->factory()->NewBlockContext(current, scope_info);
622 }
623
624
RUNTIME_FUNCTION(Runtime_DeleteLookupSlot)625 RUNTIME_FUNCTION(Runtime_DeleteLookupSlot) {
626 HandleScope scope(isolate);
627 DCHECK_EQ(1, args.length());
628 Handle<String> name = args.at<String>(0);
629
630 int index;
631 PropertyAttributes attributes;
632 InitializationFlag flag;
633 VariableMode mode;
634 Handle<Context> context(isolate->context(), isolate);
635 Handle<Object> holder = Context::Lookup(context, name, FOLLOW_CHAINS, &index,
636 &attributes, &flag, &mode);
637
638 // If the slot was not found the result is true.
639 if (holder.is_null()) {
640 // In case of JSProxy, an exception might have been thrown.
641 if (isolate->has_pending_exception())
642 return ReadOnlyRoots(isolate).exception();
643 return ReadOnlyRoots(isolate).true_value();
644 }
645
646 // If the slot was found in a context or in module imports and exports it
647 // should be DONT_DELETE.
648 if (holder->IsContext() || holder->IsSourceTextModule()) {
649 return ReadOnlyRoots(isolate).false_value();
650 }
651
652 // The slot was found in a JSReceiver, either a context extension object,
653 // the global object, or the subject of a with. Try to delete it
654 // (respecting DONT_DELETE).
655 Handle<JSReceiver> object = Handle<JSReceiver>::cast(holder);
656 Maybe<bool> result = JSReceiver::DeleteProperty(object, name);
657 MAYBE_RETURN(result, ReadOnlyRoots(isolate).exception());
658 return isolate->heap()->ToBoolean(result.FromJust());
659 }
660
661
662 namespace {
663
LoadLookupSlot(Isolate * isolate,Handle<String> name,ShouldThrow should_throw,Handle<Object> * receiver_return=nullptr)664 MaybeHandle<Object> LoadLookupSlot(Isolate* isolate, Handle<String> name,
665 ShouldThrow should_throw,
666 Handle<Object>* receiver_return = nullptr) {
667 int index;
668 PropertyAttributes attributes;
669 InitializationFlag flag;
670 VariableMode mode;
671 Handle<Context> context(isolate->context(), isolate);
672 Handle<Object> holder = Context::Lookup(context, name, FOLLOW_CHAINS, &index,
673 &attributes, &flag, &mode);
674 if (isolate->has_pending_exception()) return MaybeHandle<Object>();
675
676 if (!holder.is_null() && holder->IsSourceTextModule()) {
677 Handle<Object> receiver = isolate->factory()->undefined_value();
678 if (receiver_return) *receiver_return = receiver;
679 return SourceTextModule::LoadVariable(
680 isolate, Handle<SourceTextModule>::cast(holder), index);
681 }
682 if (index != Context::kNotFound) {
683 DCHECK(holder->IsContext());
684 // If the "property" we were looking for is a local variable, the
685 // receiver is the global object; see ECMA-262, 3rd., 10.1.6 and 10.2.3.
686 Handle<Object> receiver = isolate->factory()->undefined_value();
687 Handle<Object> value = handle(Context::cast(*holder).get(index), isolate);
688 // Check for uninitialized bindings.
689 if (flag == kNeedsInitialization && value->IsTheHole(isolate)) {
690 THROW_NEW_ERROR(isolate,
691 NewReferenceError(MessageTemplate::kNotDefined, name),
692 Object);
693 }
694 DCHECK(!value->IsTheHole(isolate));
695 if (receiver_return) *receiver_return = receiver;
696 return value;
697 }
698
699 // Otherwise, if the slot was found the holder is a context extension
700 // object, subject of a with, or a global object. We read the named
701 // property from it.
702 if (!holder.is_null()) {
703 // No need to unhole the value here. This is taken care of by the
704 // GetProperty function.
705 Handle<Object> value;
706 ASSIGN_RETURN_ON_EXCEPTION(
707 isolate, value, Object::GetProperty(isolate, holder, name), Object);
708 if (receiver_return) {
709 *receiver_return =
710 (holder->IsJSGlobalObject() || holder->IsJSContextExtensionObject())
711 ? Handle<Object>::cast(isolate->factory()->undefined_value())
712 : holder;
713 }
714 return value;
715 }
716
717 if (should_throw == kThrowOnError) {
718 // The property doesn't exist - throw exception.
719 THROW_NEW_ERROR(
720 isolate, NewReferenceError(MessageTemplate::kNotDefined, name), Object);
721 }
722
723 // The property doesn't exist - return undefined.
724 if (receiver_return) *receiver_return = isolate->factory()->undefined_value();
725 return isolate->factory()->undefined_value();
726 }
727
728 } // namespace
729
730
RUNTIME_FUNCTION(Runtime_LoadLookupSlot)731 RUNTIME_FUNCTION(Runtime_LoadLookupSlot) {
732 HandleScope scope(isolate);
733 DCHECK_EQ(1, args.length());
734 Handle<String> name = args.at<String>(0);
735 RETURN_RESULT_OR_FAILURE(isolate,
736 LoadLookupSlot(isolate, name, kThrowOnError));
737 }
738
739
RUNTIME_FUNCTION(Runtime_LoadLookupSlotInsideTypeof)740 RUNTIME_FUNCTION(Runtime_LoadLookupSlotInsideTypeof) {
741 HandleScope scope(isolate);
742 DCHECK_EQ(1, args.length());
743 Handle<String> name = args.at<String>(0);
744 RETURN_RESULT_OR_FAILURE(isolate, LoadLookupSlot(isolate, name, kDontThrow));
745 }
746
747
RUNTIME_FUNCTION_RETURN_PAIR(Runtime_LoadLookupSlotForCall)748 RUNTIME_FUNCTION_RETURN_PAIR(Runtime_LoadLookupSlotForCall) {
749 HandleScope scope(isolate);
750 DCHECK_EQ(1, args.length());
751 Handle<String> name = args.at<String>(0);
752 Handle<Object> value;
753 Handle<Object> receiver;
754 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
755 isolate, value, LoadLookupSlot(isolate, name, kThrowOnError, &receiver),
756 MakePair(ReadOnlyRoots(isolate).exception(), Object()));
757 return MakePair(*value, *receiver);
758 }
759
760
761 namespace {
762
StoreLookupSlot(Isolate * isolate,Handle<Context> context,Handle<String> name,Handle<Object> value,LanguageMode language_mode,ContextLookupFlags context_lookup_flags=FOLLOW_CHAINS)763 MaybeHandle<Object> StoreLookupSlot(
764 Isolate* isolate, Handle<Context> context, Handle<String> name,
765 Handle<Object> value, LanguageMode language_mode,
766 ContextLookupFlags context_lookup_flags = FOLLOW_CHAINS) {
767 int index;
768 PropertyAttributes attributes;
769 InitializationFlag flag;
770 VariableMode mode;
771 bool is_sloppy_function_name;
772 Handle<Object> holder =
773 Context::Lookup(context, name, context_lookup_flags, &index, &attributes,
774 &flag, &mode, &is_sloppy_function_name);
775 if (holder.is_null()) {
776 // In case of JSProxy, an exception might have been thrown.
777 if (isolate->has_pending_exception()) return MaybeHandle<Object>();
778 } else if (holder->IsSourceTextModule()) {
779 if ((attributes & READ_ONLY) == 0) {
780 SourceTextModule::StoreVariable(Handle<SourceTextModule>::cast(holder),
781 index, value);
782 } else {
783 THROW_NEW_ERROR(
784 isolate, NewTypeError(MessageTemplate::kConstAssign, name), Object);
785 }
786 return value;
787 }
788 // The property was found in a context slot.
789 if (index != Context::kNotFound) {
790 if (flag == kNeedsInitialization &&
791 Handle<Context>::cast(holder)->get(index).IsTheHole(isolate)) {
792 THROW_NEW_ERROR(isolate,
793 NewReferenceError(MessageTemplate::kNotDefined, name),
794 Object);
795 }
796 if ((attributes & READ_ONLY) == 0) {
797 Handle<Context>::cast(holder)->set(index, *value);
798 } else if (!is_sloppy_function_name || is_strict(language_mode)) {
799 THROW_NEW_ERROR(
800 isolate, NewTypeError(MessageTemplate::kConstAssign, name), Object);
801 }
802 return value;
803 }
804
805 // Slow case: The property is not in a context slot. It is either in a
806 // context extension object, a property of the subject of a with, or a
807 // property of the global object.
808 Handle<JSReceiver> object;
809 if (attributes != ABSENT) {
810 // The property exists on the holder.
811 object = Handle<JSReceiver>::cast(holder);
812 } else if (is_strict(language_mode)) {
813 // If absent in strict mode: throw.
814 THROW_NEW_ERROR(
815 isolate, NewReferenceError(MessageTemplate::kNotDefined, name), Object);
816 } else {
817 // If absent in sloppy mode: add the property to the global object.
818 object = handle(context->global_object(), isolate);
819 }
820
821 ASSIGN_RETURN_ON_EXCEPTION(isolate, value,
822 Object::SetProperty(isolate, object, name, value),
823 Object);
824 return value;
825 }
826
827 } // namespace
828
829
RUNTIME_FUNCTION(Runtime_StoreLookupSlot_Sloppy)830 RUNTIME_FUNCTION(Runtime_StoreLookupSlot_Sloppy) {
831 HandleScope scope(isolate);
832 DCHECK_EQ(2, args.length());
833 Handle<String> name = args.at<String>(0);
834 Handle<Object> value = args.at(1);
835 Handle<Context> context(isolate->context(), isolate);
836 RETURN_RESULT_OR_FAILURE(
837 isolate,
838 StoreLookupSlot(isolate, context, name, value, LanguageMode::kSloppy));
839 }
840
RUNTIME_FUNCTION(Runtime_StoreLookupSlot_Strict)841 RUNTIME_FUNCTION(Runtime_StoreLookupSlot_Strict) {
842 HandleScope scope(isolate);
843 DCHECK_EQ(2, args.length());
844 Handle<String> name = args.at<String>(0);
845 Handle<Object> value = args.at(1);
846 Handle<Context> context(isolate->context(), isolate);
847 RETURN_RESULT_OR_FAILURE(
848 isolate,
849 StoreLookupSlot(isolate, context, name, value, LanguageMode::kStrict));
850 }
851
852 // Store into a dynamic declaration context for sloppy-mode block-scoped
853 // function hoisting which leaks out of an eval.
RUNTIME_FUNCTION(Runtime_StoreLookupSlot_SloppyHoisting)854 RUNTIME_FUNCTION(Runtime_StoreLookupSlot_SloppyHoisting) {
855 HandleScope scope(isolate);
856 DCHECK_EQ(2, args.length());
857 Handle<String> name = args.at<String>(0);
858 Handle<Object> value = args.at(1);
859 const ContextLookupFlags lookup_flags =
860 static_cast<ContextLookupFlags>(DONT_FOLLOW_CHAINS);
861 Handle<Context> declaration_context(isolate->context().declaration_context(),
862 isolate);
863 RETURN_RESULT_OR_FAILURE(
864 isolate, StoreLookupSlot(isolate, declaration_context, name, value,
865 LanguageMode::kSloppy, lookup_flags));
866 }
867
RUNTIME_FUNCTION(Runtime_StoreGlobalNoHoleCheckForReplLetOrConst)868 RUNTIME_FUNCTION(Runtime_StoreGlobalNoHoleCheckForReplLetOrConst) {
869 HandleScope scope(isolate);
870 DCHECK_EQ(2, args.length());
871 Handle<String> name = args.at<String>(0);
872 Handle<Object> value = args.at(1);
873
874 Handle<Context> native_context = isolate->native_context();
875 Handle<ScriptContextTable> script_contexts(
876 native_context->script_context_table(), isolate);
877
878 VariableLookupResult lookup_result;
879 bool found = script_contexts->Lookup(name, &lookup_result);
880 CHECK(found);
881 Handle<Context> script_context = ScriptContextTable::GetContext(
882 isolate, script_contexts, lookup_result.context_index);
883
884 script_context->set(lookup_result.slot_index, *value);
885 return *value;
886 }
887
888 } // namespace internal
889 } // namespace v8
890