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