Line data Source code
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/accessors.h"
8 : #include "src/arguments-inl.h"
9 : #include "src/ast/scopes.h"
10 : #include "src/bootstrapper.h"
11 : #include "src/counters.h"
12 : #include "src/deoptimizer.h"
13 : #include "src/frames-inl.h"
14 : #include "src/heap/heap-inl.h" // For ToBoolean. TODO(jkummerow): Drop.
15 : #include "src/isolate-inl.h"
16 : #include "src/message-template.h"
17 : #include "src/objects/heap-object-inl.h"
18 : #include "src/objects/module-inl.h"
19 : #include "src/objects/smi.h"
20 : #include "src/runtime/runtime-utils.h"
21 :
22 : namespace v8 {
23 : namespace internal {
24 :
25 23668 : RUNTIME_FUNCTION(Runtime_ThrowConstAssignError) {
26 23668 : HandleScope scope(isolate);
27 47336 : THROW_NEW_ERROR_RETURN_FAILURE(isolate,
28 23668 : NewTypeError(MessageTemplate::kConstAssign));
29 : }
30 :
31 : namespace {
32 :
33 : enum class RedeclarationType { kSyntaxError = 0, kTypeError = 1 };
34 :
35 172 : Object ThrowRedeclarationError(Isolate* isolate, Handle<String> name,
36 : RedeclarationType redeclaration_type) {
37 : HandleScope scope(isolate);
38 172 : if (redeclaration_type == RedeclarationType::kSyntaxError) {
39 272 : THROW_NEW_ERROR_RETURN_FAILURE(
40 : isolate, NewSyntaxError(MessageTemplate::kVarRedeclaration, name));
41 : } else {
42 72 : THROW_NEW_ERROR_RETURN_FAILURE(
43 : isolate, NewTypeError(MessageTemplate::kVarRedeclaration, name));
44 : }
45 : }
46 :
47 : // May throw a RedeclarationError.
48 2205326 : Object DeclareGlobal(
49 : Isolate* isolate, Handle<JSGlobalObject> global, Handle<String> name,
50 : Handle<Object> value, PropertyAttributes attr, bool is_var,
51 : bool is_function_declaration, RedeclarationType redeclaration_type,
52 : Handle<FeedbackVector> feedback_vector = Handle<FeedbackVector>(),
53 : FeedbackSlot slot = FeedbackSlot::Invalid()) {
54 : Handle<ScriptContextTable> script_contexts(
55 4410652 : global->native_context()->script_context_table(), isolate);
56 : ScriptContextTable::LookupResult lookup;
57 2205355 : if (ScriptContextTable::Lookup(isolate, *script_contexts, *name, &lookup) &&
58 29 : 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 29 : 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 2205297 : if (is_function_declaration) {
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 2205297 : LookupIterator it(global, name, global, lookup_config);
75 2205297 : Maybe<PropertyAttributes> maybe = JSReceiver::GetPropertyAttributes(&it);
76 2205296 : if (maybe.IsNothing()) return ReadOnlyRoots(isolate).exception();
77 :
78 2205296 : 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 529742 : if (is_var) return ReadOnlyRoots(isolate).undefined_value();
84 :
85 : DCHECK(is_function_declaration);
86 40118 : if ((old_attributes & DONT_DELETE) != 0) {
87 : // Only allow reconfiguring globals to functions in user code (no
88 : // natives, which are marked as read-only).
89 : DCHECK_EQ(attr & READ_ONLY, 0);
90 :
91 : // Check whether we can reconfigure the existing property into a
92 : // function.
93 74689 : if (old_attributes & READ_ONLY || old_attributes & DONT_ENUM ||
94 37319 : (it.state() == LookupIterator::ACCESSOR)) {
95 : // ECMA-262 section 15.1.11 GlobalDeclarationInstantiation 5.d:
96 : // If hasRestrictedGlobal is true, throw a SyntaxError exception.
97 : // ECMA-262 section 18.2.1.3 EvalDeclarationInstantiation 8.a.iv.1.b:
98 : // If fnDefinable is false, throw a TypeError exception.
99 56 : return ThrowRedeclarationError(isolate, name, redeclaration_type);
100 : }
101 : // If the existing property is not configurable, keep its attributes. Do
102 : attr = old_attributes;
103 : }
104 :
105 : // If the current state is ACCESSOR, this could mean it's an AccessorInfo
106 : // type property. We are not allowed to call into such setters during global
107 : // function declaration since this would break e.g., onload. Meaning
108 : // 'function onload() {}' would invalidly register that function as the
109 : // onload callback. To avoid this situation, we first delete the property
110 : // before readding it as a regular data property below.
111 40062 : if (it.state() == LookupIterator::ACCESSOR) it.Delete();
112 : }
113 :
114 1960428 : if (is_function_declaration) {
115 345874 : it.Restart();
116 : }
117 :
118 : // Define or redefine own property.
119 3920867 : RETURN_FAILURE_ON_EXCEPTION(
120 : isolate, JSObject::DefineOwnPropertyIgnoreAttributes(&it, value, attr));
121 :
122 3917189 : if (!feedback_vector.is_null() &&
123 1956769 : it.state() != LookupIterator::State::INTERCEPTOR) {
124 : DCHECK_EQ(*global, *it.GetHolder<Object>());
125 : // Preinitialize the feedback slot if the global object does not have
126 : // named interceptor or the interceptor is not masking.
127 3913767 : if (!global->HasNamedInterceptor() ||
128 1957004 : global->GetNamedInterceptor()->non_masking()) {
129 1956521 : FeedbackNexus nexus(feedback_vector, slot);
130 1956522 : nexus.ConfigurePropertyCellMode(it.GetPropertyCell());
131 : }
132 : }
133 1960420 : return ReadOnlyRoots(isolate).undefined_value();
134 : }
135 :
136 155856 : Object DeclareGlobals(Isolate* isolate, Handle<FixedArray> declarations,
137 : int flags, Handle<FeedbackVector> feedback_vector) {
138 : HandleScope scope(isolate);
139 155856 : Handle<JSGlobalObject> global(isolate->global_object());
140 : Handle<Context> context(isolate->context(), isolate);
141 :
142 : // Traverse the name/value pairs and set the properties.
143 : int length = declarations->length();
144 24803752 : FOR_WITH_HANDLE_SCOPE(isolate, int, i = 0, i, i < length, i += 4, {
145 : Handle<String> name(String::cast(declarations->get(i)), isolate);
146 : FeedbackSlot slot(Smi::ToInt(declarations->get(i + 1)));
147 : Handle<Object> possibly_feedback_cell_slot(declarations->get(i + 2),
148 : isolate);
149 : Handle<Object> initial_value(declarations->get(i + 3), isolate);
150 :
151 : bool is_var = initial_value->IsUndefined(isolate);
152 : bool is_function = initial_value->IsSharedFunctionInfo();
153 : DCHECK_NE(is_var, is_function);
154 :
155 : Handle<Object> value;
156 : if (is_function) {
157 : // If feedback vector was not allocated for this function, then we don't
158 : // have any information about number of closures. Use NoFeedbackCell to
159 : // indicate that.
160 : Handle<FeedbackCell> feedback_cell =
161 : isolate->factory()->no_feedback_cell();
162 : if (!feedback_vector.is_null()) {
163 : DCHECK(possibly_feedback_cell_slot->IsSmi());
164 : FeedbackSlot feedback_cells_slot(
165 : Smi::ToInt(*possibly_feedback_cell_slot));
166 : feedback_cell = Handle<FeedbackCell>(
167 : FeedbackCell::cast(feedback_vector->Get(feedback_cells_slot)
168 : ->GetHeapObjectAssumeStrong()),
169 : isolate);
170 : }
171 : // Copy the function and update its context. Use it as value.
172 : Handle<SharedFunctionInfo> shared =
173 : Handle<SharedFunctionInfo>::cast(initial_value);
174 : Handle<JSFunction> function =
175 : isolate->factory()->NewFunctionFromSharedFunctionInfo(
176 : shared, context, feedback_cell, TENURED);
177 : value = function;
178 : } else {
179 : value = isolate->factory()->undefined_value();
180 : }
181 :
182 : // Compute the property attributes. According to ECMA-262,
183 : // the property must be non-configurable except in eval.
184 : bool is_native = DeclareGlobalsNativeFlag::decode(flags);
185 : bool is_eval = DeclareGlobalsEvalFlag::decode(flags);
186 : int attr = NONE;
187 : if (is_function && is_native) attr |= READ_ONLY;
188 : if (!is_eval) attr |= DONT_DELETE;
189 :
190 : // ES#sec-globaldeclarationinstantiation 5.d:
191 : // If hasRestrictedGlobal is true, throw a SyntaxError exception.
192 : Object result = DeclareGlobal(isolate, global, name, value,
193 : static_cast<PropertyAttributes>(attr), is_var,
194 : is_function, RedeclarationType::kSyntaxError,
195 : feedback_vector, slot);
196 : if (isolate->has_pending_exception()) return result;
197 : });
198 :
199 155808 : return ReadOnlyRoots(isolate).undefined_value();
200 : }
201 :
202 : } // namespace
203 :
204 155866 : RUNTIME_FUNCTION(Runtime_DeclareGlobals) {
205 155856 : HandleScope scope(isolate);
206 : DCHECK_EQ(3, args.length());
207 :
208 311713 : CONVERT_ARG_HANDLE_CHECKED(FixedArray, declarations, 0);
209 311714 : CONVERT_SMI_ARG_CHECKED(flags, 1);
210 311714 : CONVERT_ARG_HANDLE_CHECKED(JSFunction, closure, 2);
211 :
212 : Handle<FeedbackVector> feedback_vector = Handle<FeedbackVector>();
213 155856 : if (closure->has_feedback_vector()) {
214 : feedback_vector =
215 311714 : Handle<FeedbackVector>(closure->feedback_vector(), isolate);
216 : }
217 155857 : return DeclareGlobals(isolate, declarations, flags, feedback_vector);
218 : }
219 :
220 : namespace {
221 :
222 409686 : Object DeclareEvalHelper(Isolate* isolate, Handle<String> name,
223 : Handle<Object> value) {
224 : // Declarations are always made in a function, native, eval, or script
225 : // context, or a declaration block scope. Since this is called from eval, the
226 : // context passed is the context of the caller, which may be some nested
227 : // context and not the declaration context.
228 819372 : Handle<Context> context(isolate->context()->declaration_context(), isolate);
229 :
230 : DCHECK(context->IsFunctionContext() || context->IsNativeContext() ||
231 : context->IsScriptContext() || context->IsEvalContext() ||
232 : (context->IsBlockContext() &&
233 : context->scope_info()->is_declaration_scope()));
234 :
235 819372 : bool is_function = value->IsJSFunction();
236 409686 : bool is_var = !is_function;
237 : DCHECK(!is_var || value->IsUndefined(isolate));
238 :
239 : int index;
240 : PropertyAttributes attributes;
241 : InitializationFlag init_flag;
242 : VariableMode mode;
243 :
244 : Handle<Object> holder =
245 : Context::Lookup(context, name, DONT_FOLLOW_CHAINS, &index, &attributes,
246 409686 : &init_flag, &mode);
247 : DCHECK(holder.is_null() || !holder->IsModule());
248 : DCHECK(!isolate->has_pending_exception());
249 :
250 : Handle<JSObject> object;
251 :
252 650984 : if (attributes != ABSENT && holder->IsJSGlobalObject()) {
253 : // ES#sec-evaldeclarationinstantiation 8.a.iv.1.b:
254 : // If fnDefinable is false, throw a TypeError exception.
255 : return DeclareGlobal(isolate, Handle<JSGlobalObject>::cast(holder), name,
256 : value, NONE, is_var, is_function,
257 116495 : RedeclarationType::kTypeError);
258 : }
259 586382 : if (context->extension()->IsJSGlobalObject()) {
260 2148 : Handle<JSGlobalObject> global(JSGlobalObject::cast(context->extension()),
261 2148 : isolate);
262 : return DeclareGlobal(isolate, global, name, value, NONE, is_var,
263 1074 : is_function, RedeclarationType::kTypeError);
264 292117 : } else if (context->IsScriptContext()) {
265 : DCHECK(context->global_object()->IsJSGlobalObject());
266 : Handle<JSGlobalObject> global(
267 108 : JSGlobalObject::cast(context->global_object()), isolate);
268 : return DeclareGlobal(isolate, global, name, value, NONE, is_var,
269 54 : is_function, RedeclarationType::kTypeError);
270 : }
271 :
272 292063 : if (attributes != ABSENT) {
273 : DCHECK_EQ(NONE, attributes);
274 :
275 : // Skip var re-declarations.
276 7750 : if (is_var) return ReadOnlyRoots(isolate).undefined_value();
277 :
278 : DCHECK(is_function);
279 558 : if (index != Context::kNotFound) {
280 : DCHECK(holder.is_identical_to(context));
281 306 : context->set(index, *value);
282 102 : return ReadOnlyRoots(isolate).undefined_value();
283 : }
284 :
285 456 : object = Handle<JSObject>::cast(holder);
286 :
287 287909 : } else if (context->has_extension()) {
288 532062 : object = handle(context->extension_object(), isolate);
289 : DCHECK(object->IsJSContextExtensionObject());
290 : } else {
291 : // Sloppy varblock and function contexts might not have an extension object
292 : // yet. Sloppy eval will never have an extension object, as vars are hoisted
293 : // out, and lets are known statically.
294 : DCHECK((context->IsBlockContext() &&
295 : context->scope_info()->is_declaration_scope()) ||
296 : context->IsFunctionContext());
297 : object =
298 21878 : isolate->factory()->NewJSObject(isolate->context_extension_function());
299 :
300 43756 : context->set_extension(*object);
301 : }
302 :
303 576730 : RETURN_FAILURE_ON_EXCEPTION(isolate, JSObject::SetOwnPropertyIgnoreAttributes(
304 : object, name, value, NONE));
305 :
306 288365 : return ReadOnlyRoots(isolate).undefined_value();
307 : }
308 :
309 : } // namespace
310 :
311 10048 : RUNTIME_FUNCTION(Runtime_DeclareEvalFunction) {
312 10048 : HandleScope scope(isolate);
313 : DCHECK_EQ(2, args.length());
314 20096 : CONVERT_ARG_HANDLE_CHECKED(String, name, 0);
315 10048 : CONVERT_ARG_HANDLE_CHECKED(Object, value, 1);
316 10048 : return DeclareEvalHelper(isolate, name, value);
317 : }
318 :
319 399638 : RUNTIME_FUNCTION(Runtime_DeclareEvalVar) {
320 399638 : HandleScope scope(isolate);
321 : DCHECK_EQ(1, args.length());
322 799276 : CONVERT_ARG_HANDLE_CHECKED(String, name, 0);
323 : return DeclareEvalHelper(isolate, name,
324 799276 : isolate->factory()->undefined_value());
325 : }
326 :
327 : namespace {
328 :
329 : // Find the arguments of the JavaScript function invocation that called
330 : // into C++ code. Collect these in a newly allocated array of handles.
331 121 : std::unique_ptr<Handle<Object>[]> GetCallerArguments(Isolate* isolate,
332 : int* total_argc) {
333 : // Find frame containing arguments passed to the caller.
334 121 : JavaScriptFrameIterator it(isolate);
335 : JavaScriptFrame* frame = it.frame();
336 : std::vector<SharedFunctionInfo> functions;
337 121 : frame->GetFunctions(&functions);
338 242 : if (functions.size() > 1) {
339 0 : int inlined_jsframe_index = static_cast<int>(functions.size()) - 1;
340 0 : TranslatedState translated_values(frame);
341 0 : translated_values.Prepare(frame->fp());
342 :
343 0 : int argument_count = 0;
344 : TranslatedFrame* translated_frame =
345 : translated_values.GetArgumentsInfoFromJSFrameIndex(
346 0 : inlined_jsframe_index, &argument_count);
347 : TranslatedFrame::iterator iter = translated_frame->begin();
348 :
349 : // Skip the function.
350 0 : iter++;
351 :
352 : // Skip the receiver.
353 0 : iter++;
354 0 : argument_count--;
355 :
356 0 : *total_argc = argument_count;
357 : std::unique_ptr<Handle<Object>[]> param_data(
358 0 : NewArray<Handle<Object>>(*total_argc));
359 : bool should_deoptimize = false;
360 0 : for (int i = 0; i < argument_count; i++) {
361 : // If we materialize any object, we should deoptimize the frame because we
362 : // might alias an object that was eliminated by escape analysis.
363 0 : should_deoptimize = should_deoptimize || iter->IsMaterializedObject();
364 0 : Handle<Object> value = iter->GetValue();
365 0 : param_data[i] = value;
366 0 : iter++;
367 : }
368 :
369 0 : if (should_deoptimize) {
370 0 : translated_values.StoreMaterializedValuesAndDeopt(frame);
371 : }
372 :
373 : return param_data;
374 : } else {
375 121 : if (it.frame()->has_adapted_arguments()) {
376 : it.AdvanceOneFrame();
377 : DCHECK(it.frame()->is_arguments_adaptor());
378 : }
379 : frame = it.frame();
380 121 : int args_count = frame->ComputeParametersCount();
381 :
382 121 : *total_argc = args_count;
383 : std::unique_ptr<Handle<Object>[]> param_data(
384 121 : NewArray<Handle<Object>>(*total_argc));
385 1573383 : for (int i = 0; i < args_count; i++) {
386 1573262 : Handle<Object> val = Handle<Object>(frame->GetParameter(i), isolate);
387 3146524 : param_data[i] = val;
388 : }
389 : return param_data;
390 : }
391 : }
392 :
393 : template <typename T>
394 114 : Handle<JSObject> NewSloppyArguments(Isolate* isolate, Handle<JSFunction> callee,
395 : T parameters, int argument_count) {
396 228 : CHECK(!IsDerivedConstructor(callee->shared()->kind()));
397 : DCHECK(callee->shared()->has_simple_parameters());
398 : Handle<JSObject> result =
399 114 : isolate->factory()->NewArgumentsObject(callee, argument_count);
400 :
401 : // Allocate the elements if needed.
402 228 : int parameter_count = callee->shared()->internal_formal_parameter_count();
403 114 : if (argument_count > 0) {
404 109 : if (parameter_count > 0) {
405 : int mapped_count = Min(argument_count, parameter_count);
406 : Handle<FixedArray> parameter_map =
407 101 : isolate->factory()->NewFixedArray(mapped_count + 2, NOT_TENURED);
408 101 : parameter_map->set_map(
409 202 : ReadOnlyRoots(isolate).sloppy_arguments_elements_map());
410 303 : result->set_map(isolate->native_context()->fast_aliased_arguments_map());
411 202 : result->set_elements(*parameter_map);
412 :
413 : // Store the context and the arguments array at the beginning of the
414 : // parameter map.
415 : Handle<Context> context(isolate->context(), isolate);
416 : Handle<FixedArray> arguments =
417 101 : isolate->factory()->NewFixedArray(argument_count, NOT_TENURED);
418 202 : parameter_map->set(0, *context);
419 202 : parameter_map->set(1, *arguments);
420 :
421 : // Loop over the actual parameters backwards.
422 101 : int index = argument_count - 1;
423 69878 : while (index >= mapped_count) {
424 : // These go directly in the arguments array and have no
425 : // corresponding slot in the parameter map.
426 69721 : arguments->set(index, parameters[index]);
427 69676 : --index;
428 : }
429 :
430 202 : Handle<ScopeInfo> scope_info(callee->shared()->scope_info(), isolate);
431 :
432 : // First mark all mappable slots as unmapped and copy the values into the
433 : // arguments object.
434 456 : for (int i = 0; i < mapped_count; i++) {
435 707 : arguments->set(i, parameters[i]);
436 708 : parameter_map->set_the_hole(i + 2);
437 : }
438 :
439 : // Walk all context slots to find context allocated parameters. Mark each
440 : // found parameter as mapped.
441 359 : for (int i = 0; i < scope_info->ContextLocalCount(); i++) {
442 129 : if (!scope_info->ContextLocalIsParameter(i)) continue;
443 129 : int parameter = scope_info->ContextLocalParameterNumber(i);
444 129 : if (parameter >= mapped_count) continue;
445 110 : arguments->set_the_hole(parameter);
446 110 : Smi slot = Smi::FromInt(Context::MIN_CONTEXT_SLOTS + i);
447 : parameter_map->set(parameter + 2, slot);
448 : }
449 : } else {
450 : // If there is no aliasing, the arguments object elements are not
451 : // special in any way.
452 : Handle<FixedArray> elements =
453 8 : isolate->factory()->NewFixedArray(argument_count, NOT_TENURED);
454 16 : result->set_elements(*elements);
455 540600 : for (int i = 0; i < argument_count; ++i) {
456 540584 : elements->set(i, parameters[i]);
457 : }
458 : }
459 : }
460 114 : return result;
461 : }
462 :
463 : class HandleArguments {
464 : public:
465 105 : explicit HandleArguments(Handle<Object>* array) : array_(array) {}
466 796 : Object operator[](int index) { return *array_[index]; }
467 :
468 : private:
469 : Handle<Object>* array_;
470 : };
471 :
472 : class ParameterArguments {
473 : public:
474 9 : explicit ParameterArguments(Address parameters) : parameters_(parameters) {}
475 : Object operator[](int index) {
476 610216 : return *FullObjectSlot(parameters_ - (index + 1) * kSystemPointerSize);
477 : }
478 :
479 : private:
480 : Address parameters_;
481 : };
482 :
483 : } // namespace
484 :
485 :
486 105 : RUNTIME_FUNCTION(Runtime_NewSloppyArguments_Generic) {
487 105 : HandleScope scope(isolate);
488 : DCHECK_EQ(1, args.length());
489 210 : CONVERT_ARG_HANDLE_CHECKED(JSFunction, callee, 0);
490 : // This generic runtime function can also be used when the caller has been
491 : // inlined, we use the slow but accurate {GetCallerArguments}.
492 105 : int argument_count = 0;
493 : std::unique_ptr<Handle<Object>[]> arguments =
494 210 : GetCallerArguments(isolate, &argument_count);
495 105 : HandleArguments argument_getter(arguments.get());
496 315 : return *NewSloppyArguments(isolate, callee, argument_getter, argument_count);
497 : }
498 :
499 :
500 8 : RUNTIME_FUNCTION(Runtime_NewStrictArguments) {
501 8 : HandleScope scope(isolate);
502 : DCHECK_EQ(1, args.length());
503 16 : CONVERT_ARG_HANDLE_CHECKED(JSFunction, callee, 0);
504 : // This generic runtime function can also be used when the caller has been
505 : // inlined, we use the slow but accurate {GetCallerArguments}.
506 8 : int argument_count = 0;
507 : std::unique_ptr<Handle<Object>[]> arguments =
508 16 : GetCallerArguments(isolate, &argument_count);
509 : Handle<JSObject> result =
510 8 : isolate->factory()->NewArgumentsObject(callee, argument_count);
511 8 : if (argument_count) {
512 : Handle<FixedArray> array =
513 8 : isolate->factory()->NewUninitializedFixedArray(argument_count);
514 : DisallowHeapAllocation no_gc;
515 8 : WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
516 786432 : for (int i = 0; i < argument_count; i++) {
517 1572864 : array->set(i, *arguments[i], mode);
518 : }
519 16 : result->set_elements(*array);
520 : }
521 8 : return *result;
522 : }
523 :
524 :
525 8 : RUNTIME_FUNCTION(Runtime_NewRestParameter) {
526 8 : HandleScope scope(isolate);
527 : DCHECK_EQ(1, args.length());
528 16 : CONVERT_ARG_HANDLE_CHECKED(JSFunction, callee, 0)
529 8 : int start_index = callee->shared()->internal_formal_parameter_count();
530 : // This generic runtime function can also be used when the caller has been
531 : // inlined, we use the slow but accurate {GetCallerArguments}.
532 8 : int argument_count = 0;
533 : std::unique_ptr<Handle<Object>[]> arguments =
534 16 : GetCallerArguments(isolate, &argument_count);
535 8 : int num_elements = std::max(0, argument_count - start_index);
536 : Handle<JSObject> result = isolate->factory()->NewJSArray(
537 : PACKED_ELEMENTS, num_elements, num_elements,
538 8 : DONT_INITIALIZE_ARRAY_ELEMENTS);
539 : {
540 : DisallowHeapAllocation no_gc;
541 16 : FixedArray elements = FixedArray::cast(result->elements());
542 8 : WriteBarrierMode mode = elements->GetWriteBarrierMode(no_gc);
543 786432 : for (int i = 0; i < num_elements; i++) {
544 1572864 : elements->set(i, *arguments[i + start_index], mode);
545 : }
546 : }
547 8 : return *result;
548 : }
549 :
550 :
551 9 : RUNTIME_FUNCTION(Runtime_NewSloppyArguments) {
552 9 : HandleScope scope(isolate);
553 : DCHECK_EQ(1, args.length());
554 18 : CONVERT_ARG_HANDLE_CHECKED(JSFunction, callee, 0);
555 18 : StackFrameIterator iterator(isolate);
556 :
557 : // Stub/interpreter handler frame
558 9 : iterator.Advance();
559 : DCHECK(iterator.frame()->type() == StackFrame::STUB);
560 :
561 : // Function frame
562 9 : iterator.Advance();
563 9 : JavaScriptFrame* function_frame = JavaScriptFrame::cast(iterator.frame());
564 : DCHECK(function_frame->is_java_script());
565 9 : int argc = function_frame->ComputeParametersCount();
566 9 : Address fp = function_frame->fp();
567 9 : if (function_frame->has_adapted_arguments()) {
568 9 : iterator.Advance();
569 : ArgumentsAdaptorFrame* adaptor_frame =
570 9 : ArgumentsAdaptorFrame::cast(iterator.frame());
571 9 : argc = adaptor_frame->ComputeParametersCount();
572 9 : fp = adaptor_frame->fp();
573 : }
574 :
575 : Address parameters =
576 9 : fp + argc * kSystemPointerSize + StandardFrameConstants::kCallerSPOffset;
577 9 : ParameterArguments argument_getter(parameters);
578 27 : return *NewSloppyArguments(isolate, callee, argument_getter, argc);
579 : }
580 :
581 5 : RUNTIME_FUNCTION(Runtime_NewArgumentsElements) {
582 5 : HandleScope scope(isolate);
583 : DCHECK_EQ(3, args.length());
584 : // Note that args[0] is the address of an array of full object pointers
585 : // (a.k.a. FullObjectSlot), which looks like a Smi because it's aligned.
586 : DCHECK(args[0].IsSmi());
587 5 : FullObjectSlot frame(args[0]->ptr());
588 10 : CONVERT_SMI_ARG_CHECKED(length, 1);
589 10 : CONVERT_SMI_ARG_CHECKED(mapped_count, 2);
590 : Handle<FixedArray> result =
591 5 : isolate->factory()->NewUninitializedFixedArray(length);
592 5 : int const offset = length + 1;
593 : DisallowHeapAllocation no_gc;
594 5 : WriteBarrierMode mode = result->GetWriteBarrierMode(no_gc);
595 5 : int number_of_holes = Min(mapped_count, length);
596 1 : for (int index = 0; index < number_of_holes; ++index) {
597 1 : result->set_the_hole(isolate, index);
598 : }
599 413607 : for (int index = number_of_holes; index < length; ++index) {
600 827214 : result->set(index, *(frame + (offset - index)), mode);
601 : }
602 5 : return *result;
603 : }
604 :
605 5193763 : RUNTIME_FUNCTION(Runtime_NewClosure) {
606 5193763 : HandleScope scope(isolate);
607 : DCHECK_EQ(2, args.length());
608 10387534 : CONVERT_ARG_HANDLE_CHECKED(SharedFunctionInfo, shared, 0);
609 10387534 : CONVERT_ARG_HANDLE_CHECKED(FeedbackCell, feedback_cell, 1);
610 5193767 : Handle<Context> context(isolate->context(), isolate);
611 : Handle<JSFunction> function =
612 : isolate->factory()->NewFunctionFromSharedFunctionInfo(
613 5193766 : shared, context, feedback_cell, NOT_TENURED);
614 5193765 : return *function;
615 : }
616 :
617 208687 : RUNTIME_FUNCTION(Runtime_NewClosure_Tenured) {
618 208687 : HandleScope scope(isolate);
619 : DCHECK_EQ(2, args.length());
620 417374 : CONVERT_ARG_HANDLE_CHECKED(SharedFunctionInfo, shared, 0);
621 417374 : CONVERT_ARG_HANDLE_CHECKED(FeedbackCell, feedback_cell, 1);
622 208687 : Handle<Context> context(isolate->context(), isolate);
623 : // The caller ensures that we pretenure closures that are assigned
624 : // directly to properties.
625 : Handle<JSFunction> function =
626 : isolate->factory()->NewFunctionFromSharedFunctionInfo(
627 208687 : shared, context, feedback_cell, TENURED);
628 208687 : return *function;
629 : }
630 :
631 15681 : static Object FindNameClash(Isolate* isolate, Handle<ScopeInfo> scope_info,
632 : Handle<JSGlobalObject> global_object,
633 : Handle<ScriptContextTable> script_context) {
634 1679200 : for (int var = 0; var < scope_info->ContextLocalCount(); var++) {
635 1648012 : Handle<String> name(scope_info->ContextLocalName(var), isolate);
636 824006 : VariableMode mode = scope_info->ContextLocalMode(var);
637 : ScriptContextTable::LookupResult lookup;
638 824006 : if (ScriptContextTable::Lookup(isolate, *script_context, *name, &lookup)) {
639 49 : if (IsLexicalVariableMode(mode) || IsLexicalVariableMode(lookup.mode)) {
640 : // ES#sec-globaldeclarationinstantiation 5.b:
641 : // If envRec.HasLexicalDeclaration(name) is true, throw a SyntaxError
642 : // exception.
643 : return ThrowRedeclarationError(isolate, name,
644 136 : RedeclarationType::kSyntaxError);
645 : }
646 : }
647 :
648 823957 : if (IsLexicalVariableMode(mode)) {
649 : LookupIterator it(global_object, name, global_object,
650 823957 : LookupIterator::OWN_SKIP_INTERCEPTOR);
651 823957 : Maybe<PropertyAttributes> maybe = JSReceiver::GetPropertyAttributes(&it);
652 823957 : if (maybe.IsNothing()) return ReadOnlyRoots(isolate).exception();
653 823957 : if ((maybe.FromJust() & DONT_DELETE) != 0) {
654 : // ES#sec-globaldeclarationinstantiation 5.a:
655 : // If envRec.HasVarDeclaration(name) is true, throw a SyntaxError
656 : // exception.
657 : // ES#sec-globaldeclarationinstantiation 5.d:
658 : // If hasRestrictedGlobal is true, throw a SyntaxError exception.
659 : return ThrowRedeclarationError(isolate, name,
660 38 : RedeclarationType::kSyntaxError);
661 : }
662 :
663 823919 : JSGlobalObject::InvalidatePropertyCell(global_object, name);
664 : }
665 : }
666 15594 : return ReadOnlyRoots(isolate).undefined_value();
667 : }
668 :
669 15681 : RUNTIME_FUNCTION(Runtime_NewScriptContext) {
670 15681 : HandleScope scope(isolate);
671 : DCHECK_EQ(1, args.length());
672 :
673 31362 : CONVERT_ARG_HANDLE_CHECKED(ScopeInfo, scope_info, 0);
674 : Handle<NativeContext> native_context(NativeContext::cast(isolate->context()),
675 31362 : isolate);
676 31362 : Handle<JSGlobalObject> global_object(native_context->global_object(),
677 15681 : isolate);
678 : Handle<ScriptContextTable> script_context_table(
679 31362 : native_context->script_context_table(), isolate);
680 :
681 : Object name_clash_result =
682 15681 : FindNameClash(isolate, scope_info, global_object, script_context_table);
683 15681 : if (isolate->has_pending_exception()) return name_clash_result;
684 :
685 : // We do not need script contexts here during bootstrap.
686 : DCHECK(!isolate->bootstrapper()->IsActive());
687 :
688 : Handle<Context> result =
689 15594 : isolate->factory()->NewScriptContext(native_context, scope_info);
690 :
691 : Handle<ScriptContextTable> new_script_context_table =
692 15594 : ScriptContextTable::Extend(script_context_table, result);
693 15594 : native_context->set_script_context_table(*new_script_context_table);
694 15681 : return *result;
695 : }
696 :
697 23 : RUNTIME_FUNCTION(Runtime_NewFunctionContext) {
698 23 : HandleScope scope(isolate);
699 : DCHECK_EQ(1, args.length());
700 :
701 46 : CONVERT_ARG_HANDLE_CHECKED(ScopeInfo, scope_info, 0);
702 :
703 23 : Handle<Context> outer(isolate->context(), isolate);
704 46 : return *isolate->factory()->NewFunctionContext(outer, scope_info);
705 : }
706 :
707 242653 : RUNTIME_FUNCTION(Runtime_PushWithContext) {
708 242653 : HandleScope scope(isolate);
709 : DCHECK_EQ(2, args.length());
710 485306 : CONVERT_ARG_HANDLE_CHECKED(JSReceiver, extension_object, 0);
711 485306 : CONVERT_ARG_HANDLE_CHECKED(ScopeInfo, scope_info, 1);
712 242653 : Handle<Context> current(isolate->context(), isolate);
713 : Handle<Context> context =
714 242653 : isolate->factory()->NewWithContext(current, scope_info, extension_object);
715 242653 : isolate->set_context(*context);
716 242653 : return *context;
717 : }
718 :
719 1577 : RUNTIME_FUNCTION(Runtime_PushModuleContext) {
720 1577 : HandleScope scope(isolate);
721 : DCHECK_EQ(2, args.length());
722 3154 : CONVERT_ARG_HANDLE_CHECKED(Module, module, 0);
723 3154 : CONVERT_ARG_HANDLE_CHECKED(ScopeInfo, scope_info, 1);
724 :
725 3154 : Handle<NativeContext> outer(NativeContext::cast(isolate->context()), isolate);
726 : Handle<Context> context =
727 1577 : isolate->factory()->NewModuleContext(module, outer, scope_info);
728 1577 : isolate->set_context(*context);
729 1577 : return *context;
730 : }
731 :
732 809624 : RUNTIME_FUNCTION(Runtime_PushCatchContext) {
733 809624 : HandleScope scope(isolate);
734 : DCHECK_EQ(2, args.length());
735 809624 : CONVERT_ARG_HANDLE_CHECKED(Object, thrown_object, 0);
736 1619248 : CONVERT_ARG_HANDLE_CHECKED(ScopeInfo, scope_info, 1);
737 809624 : Handle<Context> current(isolate->context(), isolate);
738 : Handle<Context> context =
739 809624 : isolate->factory()->NewCatchContext(current, scope_info, thrown_object);
740 809624 : isolate->set_context(*context);
741 809624 : return *context;
742 : }
743 :
744 :
745 174834 : RUNTIME_FUNCTION(Runtime_PushBlockContext) {
746 174834 : HandleScope scope(isolate);
747 : DCHECK_EQ(1, args.length());
748 349669 : CONVERT_ARG_HANDLE_CHECKED(ScopeInfo, scope_info, 0);
749 174835 : Handle<Context> current(isolate->context(), isolate);
750 : Handle<Context> context =
751 174833 : isolate->factory()->NewBlockContext(current, scope_info);
752 174833 : isolate->set_context(*context);
753 174830 : return *context;
754 : }
755 :
756 :
757 900906 : RUNTIME_FUNCTION(Runtime_DeleteLookupSlot) {
758 900906 : HandleScope scope(isolate);
759 : DCHECK_EQ(1, args.length());
760 1801812 : CONVERT_ARG_HANDLE_CHECKED(String, name, 0);
761 :
762 : int index;
763 : PropertyAttributes attributes;
764 : InitializationFlag flag;
765 : VariableMode mode;
766 900906 : Handle<Context> context(isolate->context(), isolate);
767 : Handle<Object> holder = Context::Lookup(context, name, FOLLOW_CHAINS, &index,
768 900906 : &attributes, &flag, &mode);
769 :
770 : // If the slot was not found the result is true.
771 900906 : if (holder.is_null()) {
772 : // In case of JSProxy, an exception might have been thrown.
773 900059 : if (isolate->has_pending_exception())
774 : return ReadOnlyRoots(isolate).exception();
775 : return ReadOnlyRoots(isolate).true_value();
776 : }
777 :
778 : // If the slot was found in a context or in module imports and exports it
779 : // should be DONT_DELETE.
780 3172 : if (holder->IsContext() || holder->IsModule()) {
781 : return ReadOnlyRoots(isolate).false_value();
782 : }
783 :
784 : // The slot was found in a JSReceiver, either a context extension object,
785 : // the global object, or the subject of a with. Try to delete it
786 : // (respecting DONT_DELETE).
787 739 : Handle<JSReceiver> object = Handle<JSReceiver>::cast(holder);
788 739 : Maybe<bool> result = JSReceiver::DeleteProperty(object, name);
789 739 : MAYBE_RETURN(result, ReadOnlyRoots(isolate).exception());
790 739 : return isolate->heap()->ToBoolean(result.FromJust());
791 : }
792 :
793 :
794 : namespace {
795 :
796 2554966 : MaybeHandle<Object> LoadLookupSlot(Isolate* isolate, Handle<String> name,
797 : ShouldThrow should_throw,
798 : Handle<Object>* receiver_return = nullptr) {
799 : int index;
800 : PropertyAttributes attributes;
801 : InitializationFlag flag;
802 : VariableMode mode;
803 : Handle<Context> context(isolate->context(), isolate);
804 : Handle<Object> holder = Context::Lookup(context, name, FOLLOW_CHAINS, &index,
805 2554966 : &attributes, &flag, &mode);
806 2554966 : if (isolate->has_pending_exception()) return MaybeHandle<Object>();
807 :
808 7664147 : if (!holder.is_null() && holder->IsModule()) {
809 : Handle<Object> receiver = isolate->factory()->undefined_value();
810 165 : if (receiver_return) *receiver_return = receiver;
811 165 : return Module::LoadVariable(isolate, Handle<Module>::cast(holder), index);
812 : }
813 2554768 : if (index != Context::kNotFound) {
814 : DCHECK(holder->IsContext());
815 : // If the "property" we were looking for is a local variable, the
816 : // receiver is the global object; see ECMA-262, 3rd., 10.1.6 and 10.2.3.
817 : Handle<Object> receiver = isolate->factory()->undefined_value();
818 563830 : Handle<Object> value = handle(Context::cast(*holder)->get(index), isolate);
819 : // Check for uninitialized bindings.
820 283579 : if (flag == kNeedsInitialization && value->IsTheHole(isolate)) {
821 234 : THROW_NEW_ERROR(isolate,
822 : NewReferenceError(MessageTemplate::kNotDefined, name),
823 : Object);
824 : }
825 : DCHECK(!value->IsTheHole(isolate));
826 281681 : if (receiver_return) *receiver_return = receiver;
827 281681 : return value;
828 : }
829 :
830 : // Otherwise, if the slot was found the holder is a context extension
831 : // object, subject of a with, or a global object. We read the named
832 : // property from it.
833 2272853 : if (!holder.is_null()) {
834 : // No need to unhole the value here. This is taken care of by the
835 : // GetProperty function.
836 : Handle<Object> value;
837 4545054 : ASSIGN_RETURN_ON_EXCEPTION(
838 : isolate, value, Object::GetProperty(isolate, holder, name), Object);
839 2272500 : if (receiver_return) {
840 : *receiver_return =
841 856076 : (holder->IsJSGlobalObject() || holder->IsJSContextExtensionObject())
842 : ? Handle<Object>::cast(isolate->factory()->undefined_value())
843 818067 : : holder;
844 : }
845 2272500 : return value;
846 : }
847 :
848 326 : if (should_throw == kThrowOnError) {
849 : // The property doesn't exist - throw exception.
850 278 : THROW_NEW_ERROR(
851 : isolate, NewReferenceError(MessageTemplate::kNotDefined, name), Object);
852 : }
853 :
854 : // The property doesn't exist - return undefined.
855 48 : if (receiver_return) *receiver_return = isolate->factory()->undefined_value();
856 48 : return isolate->factory()->undefined_value();
857 : }
858 :
859 : } // namespace
860 :
861 :
862 2139384 : RUNTIME_FUNCTION(Runtime_LoadLookupSlot) {
863 2139384 : HandleScope scope(isolate);
864 : DCHECK_EQ(1, args.length());
865 4278768 : CONVERT_ARG_HANDLE_CHECKED(String, name, 0);
866 4278768 : RETURN_RESULT_OR_FAILURE(isolate,
867 2139384 : LoadLookupSlot(isolate, name, kThrowOnError));
868 : }
869 :
870 :
871 289 : RUNTIME_FUNCTION(Runtime_LoadLookupSlotInsideTypeof) {
872 289 : HandleScope scope(isolate);
873 : DCHECK_EQ(1, args.length());
874 578 : CONVERT_ARG_HANDLE_CHECKED(String, name, 0);
875 867 : RETURN_RESULT_OR_FAILURE(isolate, LoadLookupSlot(isolate, name, kDontThrow));
876 : }
877 :
878 :
879 415293 : RUNTIME_FUNCTION_RETURN_PAIR(Runtime_LoadLookupSlotForCall) {
880 415293 : HandleScope scope(isolate);
881 : DCHECK_EQ(1, args.length());
882 : DCHECK(args[0]->IsString());
883 415293 : Handle<String> name = args.at<String>(0);
884 : Handle<Object> value;
885 : Handle<Object> receiver;
886 830609 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(
887 : isolate, value, LoadLookupSlot(isolate, name, kThrowOnError, &receiver),
888 : MakePair(ReadOnlyRoots(isolate).exception(), Object()));
889 415270 : return MakePair(*value, *receiver);
890 : }
891 :
892 :
893 : namespace {
894 :
895 2669156 : MaybeHandle<Object> StoreLookupSlot(
896 : Isolate* isolate, Handle<Context> context, Handle<String> name,
897 : Handle<Object> value, LanguageMode language_mode,
898 : ContextLookupFlags context_lookup_flags = FOLLOW_CHAINS) {
899 : int index;
900 : PropertyAttributes attributes;
901 : InitializationFlag flag;
902 : VariableMode mode;
903 : bool is_sloppy_function_name;
904 : Handle<Object> holder =
905 : Context::Lookup(context, name, context_lookup_flags, &index, &attributes,
906 2669156 : &flag, &mode, &is_sloppy_function_name);
907 2669156 : if (holder.is_null()) {
908 : // In case of JSProxy, an exception might have been thrown.
909 539 : if (isolate->has_pending_exception()) return MaybeHandle<Object>();
910 5337234 : } else if (holder->IsModule()) {
911 70 : if ((attributes & READ_ONLY) == 0) {
912 50 : Module::StoreVariable(Handle<Module>::cast(holder), index, value);
913 : } else {
914 20 : THROW_NEW_ERROR(
915 : isolate, NewTypeError(MessageTemplate::kConstAssign, name), Object);
916 : }
917 50 : return value;
918 : }
919 : // The property was found in a context slot.
920 2669044 : if (index != Context::kNotFound) {
921 4222236 : if (flag == kNeedsInitialization &&
922 1410460 : Handle<Context>::cast(holder)->get(index)->IsTheHole(isolate)) {
923 54 : THROW_NEW_ERROR(isolate,
924 : NewReferenceError(MessageTemplate::kNotDefined, name),
925 : Object);
926 : }
927 1407358 : if ((attributes & READ_ONLY) == 0) {
928 4221804 : Handle<Context>::cast(holder)->set(index, *value);
929 90 : } else if (!is_sloppy_function_name || is_strict(language_mode)) {
930 36 : THROW_NEW_ERROR(
931 : isolate, NewTypeError(MessageTemplate::kConstAssign, name), Object);
932 : }
933 1407322 : return value;
934 : }
935 :
936 : // Slow case: The property is not in a context slot. It is either in a
937 : // context extension object, a property of the subject of a with, or a
938 : // property of the global object.
939 : Handle<JSReceiver> object;
940 1261632 : if (attributes != ABSENT) {
941 : // The property exists on the holder.
942 1261135 : object = Handle<JSReceiver>::cast(holder);
943 497 : } else if (is_strict(language_mode)) {
944 : // If absent in strict mode: throw.
945 27 : THROW_NEW_ERROR(
946 : isolate, NewReferenceError(MessageTemplate::kNotDefined, name), Object);
947 : } else {
948 : // If absent in sloppy mode: add the property to the global object.
949 940 : object = handle(context->global_object(), isolate);
950 : }
951 :
952 2523210 : ASSIGN_RETURN_ON_EXCEPTION(isolate, value,
953 : Object::SetProperty(isolate, object, name, value),
954 : Object);
955 1261515 : return value;
956 : }
957 :
958 : } // namespace
959 :
960 :
961 2666391 : RUNTIME_FUNCTION(Runtime_StoreLookupSlot_Sloppy) {
962 2666391 : HandleScope scope(isolate);
963 : DCHECK_EQ(2, args.length());
964 5332782 : CONVERT_ARG_HANDLE_CHECKED(String, name, 0);
965 2666391 : CONVERT_ARG_HANDLE_CHECKED(Object, value, 1);
966 2666391 : Handle<Context> context(isolate->context(), isolate);
967 5332782 : RETURN_RESULT_OR_FAILURE(
968 : isolate,
969 2666391 : StoreLookupSlot(isolate, context, name, value, LanguageMode::kSloppy));
970 : }
971 :
972 2234 : RUNTIME_FUNCTION(Runtime_StoreLookupSlot_Strict) {
973 2234 : HandleScope scope(isolate);
974 : DCHECK_EQ(2, args.length());
975 4468 : CONVERT_ARG_HANDLE_CHECKED(String, name, 0);
976 2234 : CONVERT_ARG_HANDLE_CHECKED(Object, value, 1);
977 2234 : Handle<Context> context(isolate->context(), isolate);
978 4468 : RETURN_RESULT_OR_FAILURE(
979 : isolate,
980 2234 : StoreLookupSlot(isolate, context, name, value, LanguageMode::kStrict));
981 : }
982 :
983 : // Store into a dynamic declaration context for sloppy-mode block-scoped
984 : // function hoisting which leaks out of an eval.
985 531 : RUNTIME_FUNCTION(Runtime_StoreLookupSlot_SloppyHoisting) {
986 531 : HandleScope scope(isolate);
987 : DCHECK_EQ(2, args.length());
988 1062 : CONVERT_ARG_HANDLE_CHECKED(String, name, 0);
989 531 : CONVERT_ARG_HANDLE_CHECKED(Object, value, 1);
990 : const ContextLookupFlags lookup_flags =
991 : static_cast<ContextLookupFlags>(DONT_FOLLOW_CHAINS);
992 : Handle<Context> declaration_context(isolate->context()->declaration_context(),
993 1062 : isolate);
994 1062 : RETURN_RESULT_OR_FAILURE(
995 : isolate, StoreLookupSlot(isolate, declaration_context, name, value,
996 531 : LanguageMode::kSloppy, lookup_flags));
997 : }
998 :
999 : } // namespace internal
1000 178779 : } // namespace v8
|