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