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