full-codegen.cc revision 8389745919cae02139ddc085a63c00d024269cf2
1// Copyright 2012 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/full-codegen/full-codegen.h" 6 7#include "src/ast/ast.h" 8#include "src/ast/ast-numbering.h" 9#include "src/ast/prettyprinter.h" 10#include "src/ast/scopeinfo.h" 11#include "src/ast/scopes.h" 12#include "src/code-factory.h" 13#include "src/codegen.h" 14#include "src/compiler.h" 15#include "src/debug/debug.h" 16#include "src/debug/liveedit.h" 17#include "src/isolate-inl.h" 18#include "src/macro-assembler.h" 19#include "src/snapshot/snapshot.h" 20#include "src/tracing/trace-event.h" 21 22namespace v8 { 23namespace internal { 24 25#define __ ACCESS_MASM(masm()) 26 27bool FullCodeGenerator::MakeCode(CompilationInfo* info) { 28 Isolate* isolate = info->isolate(); 29 30 TimerEventScope<TimerEventCompileFullCode> timer(info->isolate()); 31 TRACE_EVENT0("v8", "V8.CompileFullCode"); 32 33 // Ensure that the feedback vector is large enough. 34 info->EnsureFeedbackVector(); 35 36 Handle<Script> script = info->script(); 37 if (!script->IsUndefined() && !script->source()->IsUndefined()) { 38 int len = String::cast(script->source())->length(); 39 isolate->counters()->total_full_codegen_source_size()->Increment(len); 40 } 41 CodeGenerator::MakeCodePrologue(info, "full"); 42 const int kInitialBufferSize = 4 * KB; 43 MacroAssembler masm(info->isolate(), NULL, kInitialBufferSize, 44 CodeObjectRequired::kYes); 45 if (info->will_serialize()) masm.enable_serializer(); 46 47 LOG_CODE_EVENT(isolate, 48 CodeStartLinePosInfoRecordEvent(masm.positions_recorder())); 49 50 FullCodeGenerator cgen(&masm, info); 51 cgen.Generate(); 52 if (cgen.HasStackOverflow()) { 53 DCHECK(!isolate->has_pending_exception()); 54 return false; 55 } 56 unsigned table_offset = cgen.EmitBackEdgeTable(); 57 58 Handle<Code> code = CodeGenerator::MakeCodeEpilogue(&masm, info); 59 cgen.PopulateDeoptimizationData(code); 60 cgen.PopulateTypeFeedbackInfo(code); 61 cgen.PopulateHandlerTable(code); 62 code->set_has_deoptimization_support(info->HasDeoptimizationSupport()); 63 code->set_has_reloc_info_for_serialization(info->will_serialize()); 64 code->set_allow_osr_at_loop_nesting_level(0); 65 code->set_profiler_ticks(0); 66 code->set_back_edge_table_offset(table_offset); 67 CodeGenerator::PrintCode(code, info); 68 info->SetCode(code); 69 void* line_info = masm.positions_recorder()->DetachJITHandlerData(); 70 LOG_CODE_EVENT(isolate, CodeEndLinePosInfoRecordEvent(*code, line_info)); 71 72#ifdef DEBUG 73 // Check that no context-specific object has been embedded. 74 code->VerifyEmbeddedObjects(Code::kNoContextSpecificPointers); 75#endif // DEBUG 76 return true; 77} 78 79 80unsigned FullCodeGenerator::EmitBackEdgeTable() { 81 // The back edge table consists of a length (in number of entries) 82 // field, and then a sequence of entries. Each entry is a pair of AST id 83 // and code-relative pc offset. 84 masm()->Align(kPointerSize); 85 unsigned offset = masm()->pc_offset(); 86 unsigned length = back_edges_.length(); 87 __ dd(length); 88 for (unsigned i = 0; i < length; ++i) { 89 __ dd(back_edges_[i].id.ToInt()); 90 __ dd(back_edges_[i].pc); 91 __ dd(back_edges_[i].loop_depth); 92 } 93 return offset; 94} 95 96 97void FullCodeGenerator::PopulateDeoptimizationData(Handle<Code> code) { 98 // Fill in the deoptimization information. 99 DCHECK(info_->HasDeoptimizationSupport() || bailout_entries_.is_empty()); 100 if (!info_->HasDeoptimizationSupport()) return; 101 int length = bailout_entries_.length(); 102 Handle<DeoptimizationOutputData> data = 103 DeoptimizationOutputData::New(isolate(), length, TENURED); 104 for (int i = 0; i < length; i++) { 105 data->SetAstId(i, bailout_entries_[i].id); 106 data->SetPcAndState(i, Smi::FromInt(bailout_entries_[i].pc_and_state)); 107 } 108 code->set_deoptimization_data(*data); 109} 110 111 112void FullCodeGenerator::PopulateTypeFeedbackInfo(Handle<Code> code) { 113 Handle<TypeFeedbackInfo> info = isolate()->factory()->NewTypeFeedbackInfo(); 114 info->set_ic_total_count(ic_total_count_); 115 DCHECK(!isolate()->heap()->InNewSpace(*info)); 116 code->set_type_feedback_info(*info); 117} 118 119 120void FullCodeGenerator::PopulateHandlerTable(Handle<Code> code) { 121 int handler_table_size = static_cast<int>(handler_table_.size()); 122 Handle<HandlerTable> table = 123 Handle<HandlerTable>::cast(isolate()->factory()->NewFixedArray( 124 HandlerTable::LengthForRange(handler_table_size), TENURED)); 125 for (int i = 0; i < handler_table_size; ++i) { 126 HandlerTable::CatchPrediction prediction = 127 handler_table_[i].try_catch_depth > 0 ? HandlerTable::CAUGHT 128 : HandlerTable::UNCAUGHT; 129 table->SetRangeStart(i, handler_table_[i].range_start); 130 table->SetRangeEnd(i, handler_table_[i].range_end); 131 table->SetRangeHandler(i, handler_table_[i].handler_offset, prediction); 132 table->SetRangeData(i, handler_table_[i].stack_depth); 133 } 134 code->set_handler_table(*table); 135} 136 137 138int FullCodeGenerator::NewHandlerTableEntry() { 139 int index = static_cast<int>(handler_table_.size()); 140 HandlerTableEntry entry = {0, 0, 0, 0, 0}; 141 handler_table_.push_back(entry); 142 return index; 143} 144 145 146bool FullCodeGenerator::MustCreateObjectLiteralWithRuntime( 147 ObjectLiteral* expr) const { 148 // FastCloneShallowObjectStub doesn't copy elements, and object literals don't 149 // support copy-on-write (COW) elements for now. 150 // TODO(mvstanton): make object literals support COW elements. 151 return masm()->serializer_enabled() || !expr->fast_elements() || 152 !expr->has_shallow_properties() || 153 expr->properties_count() > 154 FastCloneShallowObjectStub::kMaximumClonedProperties; 155} 156 157 158bool FullCodeGenerator::MustCreateArrayLiteralWithRuntime( 159 ArrayLiteral* expr) const { 160 // TODO(rossberg): Teach strong mode to FastCloneShallowArrayStub. 161 return expr->depth() > 1 || expr->is_strong() || 162 expr->values()->length() > JSArray::kInitialMaxFastElementArray; 163} 164 165 166void FullCodeGenerator::Initialize() { 167 InitializeAstVisitor(info_->isolate()); 168 masm_->set_emit_debug_code(FLAG_debug_code); 169 masm_->set_predictable_code_size(true); 170} 171 172 173void FullCodeGenerator::PrepareForBailout(Expression* node, State state) { 174 PrepareForBailoutForId(node->id(), state); 175} 176 177 178void FullCodeGenerator::CallLoadIC(TypeofMode typeof_mode, 179 TypeFeedbackId id) { 180 Handle<Code> ic = CodeFactory::LoadIC(isolate(), typeof_mode).code(); 181 CallIC(ic, id); 182} 183 184 185void FullCodeGenerator::CallStoreIC(TypeFeedbackId id) { 186 Handle<Code> ic = CodeFactory::StoreIC(isolate(), language_mode()).code(); 187 CallIC(ic, id); 188} 189 190 191void FullCodeGenerator::RecordJSReturnSite(Call* call) { 192 // We record the offset of the function return so we can rebuild the frame 193 // if the function was inlined, i.e., this is the return address in the 194 // inlined function's frame. 195 // 196 // The state is ignored. We defensively set it to TOS_REG, which is the 197 // real state of the unoptimized code at the return site. 198 PrepareForBailoutForId(call->ReturnId(), TOS_REG); 199#ifdef DEBUG 200 // In debug builds, mark the return so we can verify that this function 201 // was called. 202 DCHECK(!call->return_is_recorded_); 203 call->return_is_recorded_ = true; 204#endif 205} 206 207 208void FullCodeGenerator::PrepareForBailoutForId(BailoutId id, State state) { 209 // There's no need to prepare this code for bailouts from already optimized 210 // code or code that can't be optimized. 211 if (!info_->HasDeoptimizationSupport()) return; 212 unsigned pc_and_state = 213 StateField::encode(state) | PcField::encode(masm_->pc_offset()); 214 DCHECK(Smi::IsValid(pc_and_state)); 215#ifdef DEBUG 216 for (int i = 0; i < bailout_entries_.length(); ++i) { 217 DCHECK(bailout_entries_[i].id != id); 218 } 219#endif 220 BailoutEntry entry = { id, pc_and_state }; 221 bailout_entries_.Add(entry, zone()); 222} 223 224 225void FullCodeGenerator::RecordBackEdge(BailoutId ast_id) { 226 // The pc offset does not need to be encoded and packed together with a state. 227 DCHECK(masm_->pc_offset() > 0); 228 DCHECK(loop_depth() > 0); 229 uint8_t depth = Min(loop_depth(), Code::kMaxLoopNestingMarker); 230 BackEdgeEntry entry = 231 { ast_id, static_cast<unsigned>(masm_->pc_offset()), depth }; 232 back_edges_.Add(entry, zone()); 233} 234 235 236bool FullCodeGenerator::ShouldInlineSmiCase(Token::Value op) { 237 // Inline smi case inside loops, but not division and modulo which 238 // are too complicated and take up too much space. 239 if (op == Token::DIV ||op == Token::MOD) return false; 240 if (FLAG_always_inline_smi_code) return true; 241 return loop_depth_ > 0; 242} 243 244 245void FullCodeGenerator::EffectContext::Plug(Variable* var) const { 246 DCHECK(var->IsStackAllocated() || var->IsContextSlot()); 247} 248 249 250void FullCodeGenerator::AccumulatorValueContext::Plug(Variable* var) const { 251 DCHECK(var->IsStackAllocated() || var->IsContextSlot()); 252 codegen()->GetVar(result_register(), var); 253} 254 255 256void FullCodeGenerator::TestContext::Plug(Variable* var) const { 257 DCHECK(var->IsStackAllocated() || var->IsContextSlot()); 258 // For simplicity we always test the accumulator register. 259 codegen()->GetVar(result_register(), var); 260 codegen()->PrepareForBailoutBeforeSplit(condition(), false, NULL, NULL); 261 codegen()->DoTest(this); 262} 263 264 265void FullCodeGenerator::EffectContext::Plug(Register reg) const { 266} 267 268 269void FullCodeGenerator::AccumulatorValueContext::Plug(Register reg) const { 270 __ Move(result_register(), reg); 271} 272 273 274void FullCodeGenerator::StackValueContext::Plug(Register reg) const { 275 codegen()->PushOperand(reg); 276} 277 278 279void FullCodeGenerator::TestContext::Plug(Register reg) const { 280 // For simplicity we always test the accumulator register. 281 __ Move(result_register(), reg); 282 codegen()->PrepareForBailoutBeforeSplit(condition(), false, NULL, NULL); 283 codegen()->DoTest(this); 284} 285 286 287void FullCodeGenerator::EffectContext::Plug(bool flag) const {} 288 289void FullCodeGenerator::EffectContext::DropAndPlug(int count, 290 Register reg) const { 291 DCHECK(count > 0); 292 codegen()->DropOperands(count); 293} 294 295void FullCodeGenerator::AccumulatorValueContext::DropAndPlug( 296 int count, Register reg) const { 297 DCHECK(count > 0); 298 codegen()->DropOperands(count); 299 __ Move(result_register(), reg); 300} 301 302void FullCodeGenerator::TestContext::DropAndPlug(int count, 303 Register reg) const { 304 DCHECK(count > 0); 305 // For simplicity we always test the accumulator register. 306 codegen()->DropOperands(count); 307 __ Move(result_register(), reg); 308 codegen()->PrepareForBailoutBeforeSplit(condition(), false, NULL, NULL); 309 codegen()->DoTest(this); 310} 311 312void FullCodeGenerator::EffectContext::PlugTOS() const { 313 codegen()->DropOperands(1); 314} 315 316 317void FullCodeGenerator::AccumulatorValueContext::PlugTOS() const { 318 codegen()->PopOperand(result_register()); 319} 320 321 322void FullCodeGenerator::StackValueContext::PlugTOS() const { 323} 324 325 326void FullCodeGenerator::TestContext::PlugTOS() const { 327 // For simplicity we always test the accumulator register. 328 codegen()->PopOperand(result_register()); 329 codegen()->PrepareForBailoutBeforeSplit(condition(), false, NULL, NULL); 330 codegen()->DoTest(this); 331} 332 333 334void FullCodeGenerator::EffectContext::PrepareTest( 335 Label* materialize_true, 336 Label* materialize_false, 337 Label** if_true, 338 Label** if_false, 339 Label** fall_through) const { 340 // In an effect context, the true and the false case branch to the 341 // same label. 342 *if_true = *if_false = *fall_through = materialize_true; 343} 344 345 346void FullCodeGenerator::AccumulatorValueContext::PrepareTest( 347 Label* materialize_true, 348 Label* materialize_false, 349 Label** if_true, 350 Label** if_false, 351 Label** fall_through) const { 352 *if_true = *fall_through = materialize_true; 353 *if_false = materialize_false; 354} 355 356 357void FullCodeGenerator::StackValueContext::PrepareTest( 358 Label* materialize_true, 359 Label* materialize_false, 360 Label** if_true, 361 Label** if_false, 362 Label** fall_through) const { 363 *if_true = *fall_through = materialize_true; 364 *if_false = materialize_false; 365} 366 367 368void FullCodeGenerator::TestContext::PrepareTest( 369 Label* materialize_true, 370 Label* materialize_false, 371 Label** if_true, 372 Label** if_false, 373 Label** fall_through) const { 374 *if_true = true_label_; 375 *if_false = false_label_; 376 *fall_through = fall_through_; 377} 378 379 380void FullCodeGenerator::DoTest(const TestContext* context) { 381 DoTest(context->condition(), 382 context->true_label(), 383 context->false_label(), 384 context->fall_through()); 385} 386 387 388void FullCodeGenerator::VisitDeclarations( 389 ZoneList<Declaration*>* declarations) { 390 ZoneList<Handle<Object> >* saved_globals = globals_; 391 ZoneList<Handle<Object> > inner_globals(10, zone()); 392 globals_ = &inner_globals; 393 394 AstVisitor::VisitDeclarations(declarations); 395 396 if (!globals_->is_empty()) { 397 // Invoke the platform-dependent code generator to do the actual 398 // declaration of the global functions and variables. 399 Handle<FixedArray> array = 400 isolate()->factory()->NewFixedArray(globals_->length(), TENURED); 401 for (int i = 0; i < globals_->length(); ++i) 402 array->set(i, *globals_->at(i)); 403 DeclareGlobals(array); 404 } 405 406 globals_ = saved_globals; 407} 408 409 410void FullCodeGenerator::VisitImportDeclaration(ImportDeclaration* declaration) { 411 VariableProxy* proxy = declaration->proxy(); 412 Variable* variable = proxy->var(); 413 switch (variable->location()) { 414 case VariableLocation::GLOBAL: 415 case VariableLocation::UNALLOCATED: 416 // TODO(rossberg) 417 break; 418 419 case VariableLocation::CONTEXT: { 420 Comment cmnt(masm_, "[ ImportDeclaration"); 421 EmitDebugCheckDeclarationContext(variable); 422 // TODO(rossberg) 423 break; 424 } 425 426 case VariableLocation::PARAMETER: 427 case VariableLocation::LOCAL: 428 case VariableLocation::LOOKUP: 429 UNREACHABLE(); 430 } 431} 432 433 434void FullCodeGenerator::VisitExportDeclaration(ExportDeclaration* declaration) { 435 // TODO(rossberg) 436} 437 438 439void FullCodeGenerator::VisitVariableProxy(VariableProxy* expr) { 440 Comment cmnt(masm_, "[ VariableProxy"); 441 EmitVariableLoad(expr); 442} 443 444 445void FullCodeGenerator::VisitSloppyBlockFunctionStatement( 446 SloppyBlockFunctionStatement* declaration) { 447 Visit(declaration->statement()); 448} 449 450 451int FullCodeGenerator::DeclareGlobalsFlags() { 452 DCHECK(DeclareGlobalsLanguageMode::is_valid(language_mode())); 453 return DeclareGlobalsEvalFlag::encode(is_eval()) | 454 DeclareGlobalsNativeFlag::encode(is_native()) | 455 DeclareGlobalsLanguageMode::encode(language_mode()); 456} 457 458void FullCodeGenerator::PushOperand(Handle<Object> handle) { 459 OperandStackDepthIncrement(1); 460 __ Push(handle); 461} 462 463void FullCodeGenerator::PushOperand(Smi* smi) { 464 OperandStackDepthIncrement(1); 465 __ Push(smi); 466} 467 468void FullCodeGenerator::PushOperand(Register reg) { 469 OperandStackDepthIncrement(1); 470 __ Push(reg); 471} 472 473void FullCodeGenerator::PopOperand(Register reg) { 474 OperandStackDepthDecrement(1); 475 __ Pop(reg); 476} 477 478void FullCodeGenerator::DropOperands(int count) { 479 OperandStackDepthDecrement(count); 480 __ Drop(count); 481} 482 483void FullCodeGenerator::CallRuntimeWithOperands(Runtime::FunctionId id) { 484 OperandStackDepthDecrement(Runtime::FunctionForId(id)->nargs); 485 __ CallRuntime(id); 486} 487 488void FullCodeGenerator::OperandStackDepthIncrement(int count) { 489 DCHECK_GE(count, 0); 490 DCHECK_GE(operand_stack_depth_, 0); 491 operand_stack_depth_ += count; 492} 493 494void FullCodeGenerator::OperandStackDepthDecrement(int count) { 495 DCHECK_GE(count, 0); 496 DCHECK_GE(operand_stack_depth_, count); 497 operand_stack_depth_ -= count; 498} 499 500void FullCodeGenerator::EmitSubString(CallRuntime* expr) { 501 // Load the arguments on the stack and call the stub. 502 SubStringStub stub(isolate()); 503 ZoneList<Expression*>* args = expr->arguments(); 504 DCHECK(args->length() == 3); 505 VisitForStackValue(args->at(0)); 506 VisitForStackValue(args->at(1)); 507 VisitForStackValue(args->at(2)); 508 __ CallStub(&stub); 509 OperandStackDepthDecrement(3); 510 context()->Plug(result_register()); 511} 512 513 514void FullCodeGenerator::EmitRegExpExec(CallRuntime* expr) { 515 // Load the arguments on the stack and call the stub. 516 RegExpExecStub stub(isolate()); 517 ZoneList<Expression*>* args = expr->arguments(); 518 DCHECK(args->length() == 4); 519 VisitForStackValue(args->at(0)); 520 VisitForStackValue(args->at(1)); 521 VisitForStackValue(args->at(2)); 522 VisitForStackValue(args->at(3)); 523 __ CallStub(&stub); 524 OperandStackDepthDecrement(4); 525 context()->Plug(result_register()); 526} 527 528 529void FullCodeGenerator::EmitMathPow(CallRuntime* expr) { 530 // Load the arguments on the stack and call the runtime function. 531 MathPowStub stub(isolate(), MathPowStub::ON_STACK); 532 ZoneList<Expression*>* args = expr->arguments(); 533 DCHECK(args->length() == 2); 534 VisitForStackValue(args->at(0)); 535 VisitForStackValue(args->at(1)); 536 __ CallStub(&stub); 537 OperandStackDepthDecrement(2); 538 context()->Plug(result_register()); 539} 540 541 542void FullCodeGenerator::EmitIntrinsicAsStubCall(CallRuntime* expr, 543 const Callable& callable) { 544 ZoneList<Expression*>* args = expr->arguments(); 545 int param_count = callable.descriptor().GetRegisterParameterCount(); 546 DCHECK_EQ(args->length(), param_count); 547 548 if (param_count > 0) { 549 int last = param_count - 1; 550 // Put all but last arguments on stack. 551 for (int i = 0; i < last; i++) { 552 VisitForStackValue(args->at(i)); 553 } 554 // The last argument goes to the accumulator. 555 VisitForAccumulatorValue(args->at(last)); 556 557 // Move the arguments to the registers, as required by the stub. 558 __ Move(callable.descriptor().GetRegisterParameter(last), 559 result_register()); 560 for (int i = last; i-- > 0;) { 561 PopOperand(callable.descriptor().GetRegisterParameter(i)); 562 } 563 } 564 __ Call(callable.code(), RelocInfo::CODE_TARGET); 565 context()->Plug(result_register()); 566} 567 568 569void FullCodeGenerator::EmitNumberToString(CallRuntime* expr) { 570 EmitIntrinsicAsStubCall(expr, CodeFactory::NumberToString(isolate())); 571} 572 573 574void FullCodeGenerator::EmitToString(CallRuntime* expr) { 575 EmitIntrinsicAsStubCall(expr, CodeFactory::ToString(isolate())); 576} 577 578 579void FullCodeGenerator::EmitToName(CallRuntime* expr) { 580 EmitIntrinsicAsStubCall(expr, CodeFactory::ToName(isolate())); 581} 582 583 584void FullCodeGenerator::EmitToLength(CallRuntime* expr) { 585 EmitIntrinsicAsStubCall(expr, CodeFactory::ToLength(isolate())); 586} 587 588 589void FullCodeGenerator::EmitToNumber(CallRuntime* expr) { 590 EmitIntrinsicAsStubCall(expr, CodeFactory::ToNumber(isolate())); 591} 592 593 594void FullCodeGenerator::EmitToObject(CallRuntime* expr) { 595 EmitIntrinsicAsStubCall(expr, CodeFactory::ToObject(isolate())); 596} 597 598 599void FullCodeGenerator::EmitRegExpConstructResult(CallRuntime* expr) { 600 EmitIntrinsicAsStubCall(expr, CodeFactory::RegExpConstructResult(isolate())); 601} 602 603 604bool RecordStatementPosition(MacroAssembler* masm, int pos) { 605 if (pos == RelocInfo::kNoPosition) return false; 606 masm->positions_recorder()->RecordStatementPosition(pos); 607 masm->positions_recorder()->RecordPosition(pos); 608 return masm->positions_recorder()->WriteRecordedPositions(); 609} 610 611 612bool RecordPosition(MacroAssembler* masm, int pos) { 613 if (pos == RelocInfo::kNoPosition) return false; 614 masm->positions_recorder()->RecordPosition(pos); 615 return masm->positions_recorder()->WriteRecordedPositions(); 616} 617 618 619void FullCodeGenerator::SetFunctionPosition(FunctionLiteral* fun) { 620 RecordPosition(masm_, fun->start_position()); 621} 622 623 624void FullCodeGenerator::SetReturnPosition(FunctionLiteral* fun) { 625 // For default constructors, start position equals end position, and there 626 // is no source code besides the class literal. 627 int pos = std::max(fun->start_position(), fun->end_position() - 1); 628 RecordStatementPosition(masm_, pos); 629 if (info_->is_debug()) { 630 // Always emit a debug break slot before a return. 631 DebugCodegen::GenerateSlot(masm_, RelocInfo::DEBUG_BREAK_SLOT_AT_RETURN); 632 } 633} 634 635 636void FullCodeGenerator::SetStatementPosition( 637 Statement* stmt, FullCodeGenerator::InsertBreak insert_break) { 638 if (stmt->position() == RelocInfo::kNoPosition) return; 639 bool recorded = RecordStatementPosition(masm_, stmt->position()); 640 if (recorded && insert_break == INSERT_BREAK && info_->is_debug() && 641 !stmt->IsDebuggerStatement()) { 642 DebugCodegen::GenerateSlot(masm_, RelocInfo::DEBUG_BREAK_SLOT_AT_POSITION); 643 } 644} 645 646 647void FullCodeGenerator::SetExpressionPosition( 648 Expression* expr, FullCodeGenerator::InsertBreak insert_break) { 649 if (expr->position() == RelocInfo::kNoPosition) return; 650 bool recorded = RecordPosition(masm_, expr->position()); 651 if (recorded && insert_break == INSERT_BREAK && info_->is_debug()) { 652 DebugCodegen::GenerateSlot(masm_, RelocInfo::DEBUG_BREAK_SLOT_AT_POSITION); 653 } 654} 655 656 657void FullCodeGenerator::SetExpressionAsStatementPosition(Expression* expr) { 658 if (expr->position() == RelocInfo::kNoPosition) return; 659 bool recorded = RecordStatementPosition(masm_, expr->position()); 660 if (recorded && info_->is_debug()) { 661 DebugCodegen::GenerateSlot(masm_, RelocInfo::DEBUG_BREAK_SLOT_AT_POSITION); 662 } 663} 664 665 666void FullCodeGenerator::SetCallPosition(Expression* expr) { 667 if (expr->position() == RelocInfo::kNoPosition) return; 668 RecordPosition(masm_, expr->position()); 669 if (info_->is_debug()) { 670 // Always emit a debug break slot before a call. 671 DebugCodegen::GenerateSlot(masm_, RelocInfo::DEBUG_BREAK_SLOT_AT_CALL); 672 } 673} 674 675 676void FullCodeGenerator::VisitSuperPropertyReference( 677 SuperPropertyReference* super) { 678 __ CallRuntime(Runtime::kThrowUnsupportedSuperError); 679} 680 681 682void FullCodeGenerator::VisitSuperCallReference(SuperCallReference* super) { 683 __ CallRuntime(Runtime::kThrowUnsupportedSuperError); 684} 685 686 687void FullCodeGenerator::EmitGeneratorNext(CallRuntime* expr) { 688 ZoneList<Expression*>* args = expr->arguments(); 689 DCHECK(args->length() == 2); 690 EmitGeneratorResume(args->at(0), args->at(1), JSGeneratorObject::NEXT); 691} 692 693 694void FullCodeGenerator::EmitGeneratorReturn(CallRuntime* expr) { 695 ZoneList<Expression*>* args = expr->arguments(); 696 DCHECK(args->length() == 2); 697 EmitGeneratorResume(args->at(0), args->at(1), JSGeneratorObject::RETURN); 698} 699 700 701void FullCodeGenerator::EmitGeneratorThrow(CallRuntime* expr) { 702 ZoneList<Expression*>* args = expr->arguments(); 703 DCHECK(args->length() == 2); 704 EmitGeneratorResume(args->at(0), args->at(1), JSGeneratorObject::THROW); 705} 706 707 708void FullCodeGenerator::EmitDebugBreakInOptimizedCode(CallRuntime* expr) { 709 context()->Plug(handle(Smi::FromInt(0), isolate())); 710} 711 712 713void FullCodeGenerator::VisitBinaryOperation(BinaryOperation* expr) { 714 switch (expr->op()) { 715 case Token::COMMA: 716 return VisitComma(expr); 717 case Token::OR: 718 case Token::AND: 719 return VisitLogicalExpression(expr); 720 default: 721 return VisitArithmeticExpression(expr); 722 } 723} 724 725 726void FullCodeGenerator::VisitInDuplicateContext(Expression* expr) { 727 if (context()->IsEffect()) { 728 VisitForEffect(expr); 729 } else if (context()->IsAccumulatorValue()) { 730 VisitForAccumulatorValue(expr); 731 } else if (context()->IsStackValue()) { 732 VisitForStackValue(expr); 733 } else if (context()->IsTest()) { 734 const TestContext* test = TestContext::cast(context()); 735 VisitForControl(expr, test->true_label(), test->false_label(), 736 test->fall_through()); 737 } 738} 739 740 741void FullCodeGenerator::VisitComma(BinaryOperation* expr) { 742 Comment cmnt(masm_, "[ Comma"); 743 VisitForEffect(expr->left()); 744 VisitInDuplicateContext(expr->right()); 745} 746 747 748void FullCodeGenerator::VisitLogicalExpression(BinaryOperation* expr) { 749 bool is_logical_and = expr->op() == Token::AND; 750 Comment cmnt(masm_, is_logical_and ? "[ Logical AND" : "[ Logical OR"); 751 Expression* left = expr->left(); 752 Expression* right = expr->right(); 753 BailoutId right_id = expr->RightId(); 754 Label done; 755 756 if (context()->IsTest()) { 757 Label eval_right; 758 const TestContext* test = TestContext::cast(context()); 759 if (is_logical_and) { 760 VisitForControl(left, &eval_right, test->false_label(), &eval_right); 761 } else { 762 VisitForControl(left, test->true_label(), &eval_right, &eval_right); 763 } 764 PrepareForBailoutForId(right_id, NO_REGISTERS); 765 __ bind(&eval_right); 766 767 } else if (context()->IsAccumulatorValue()) { 768 VisitForAccumulatorValue(left); 769 // We want the value in the accumulator for the test, and on the stack in 770 // case we need it. 771 __ Push(result_register()); 772 Label discard, restore; 773 if (is_logical_and) { 774 DoTest(left, &discard, &restore, &restore); 775 } else { 776 DoTest(left, &restore, &discard, &restore); 777 } 778 __ bind(&restore); 779 __ Pop(result_register()); 780 __ jmp(&done); 781 __ bind(&discard); 782 __ Drop(1); 783 PrepareForBailoutForId(right_id, NO_REGISTERS); 784 785 } else if (context()->IsStackValue()) { 786 VisitForAccumulatorValue(left); 787 // We want the value in the accumulator for the test, and on the stack in 788 // case we need it. 789 __ Push(result_register()); 790 Label discard; 791 if (is_logical_and) { 792 DoTest(left, &discard, &done, &discard); 793 } else { 794 DoTest(left, &done, &discard, &discard); 795 } 796 __ bind(&discard); 797 __ Drop(1); 798 PrepareForBailoutForId(right_id, NO_REGISTERS); 799 800 } else { 801 DCHECK(context()->IsEffect()); 802 Label eval_right; 803 if (is_logical_and) { 804 VisitForControl(left, &eval_right, &done, &eval_right); 805 } else { 806 VisitForControl(left, &done, &eval_right, &eval_right); 807 } 808 PrepareForBailoutForId(right_id, NO_REGISTERS); 809 __ bind(&eval_right); 810 } 811 812 VisitInDuplicateContext(right); 813 __ bind(&done); 814} 815 816 817void FullCodeGenerator::VisitArithmeticExpression(BinaryOperation* expr) { 818 Token::Value op = expr->op(); 819 Comment cmnt(masm_, "[ ArithmeticExpression"); 820 Expression* left = expr->left(); 821 Expression* right = expr->right(); 822 823 VisitForStackValue(left); 824 VisitForAccumulatorValue(right); 825 826 SetExpressionPosition(expr); 827 if (ShouldInlineSmiCase(op)) { 828 EmitInlineSmiBinaryOp(expr, op, left, right); 829 } else { 830 EmitBinaryOp(expr, op); 831 } 832} 833 834 835void FullCodeGenerator::VisitForTypeofValue(Expression* expr) { 836 VariableProxy* proxy = expr->AsVariableProxy(); 837 DCHECK(!context()->IsEffect()); 838 DCHECK(!context()->IsTest()); 839 840 if (proxy != NULL && (proxy->var()->IsUnallocatedOrGlobalSlot() || 841 proxy->var()->IsLookupSlot())) { 842 EmitVariableLoad(proxy, INSIDE_TYPEOF); 843 PrepareForBailout(proxy, TOS_REG); 844 } else { 845 // This expression cannot throw a reference error at the top level. 846 VisitInDuplicateContext(expr); 847 } 848} 849 850 851void FullCodeGenerator::VisitBlock(Block* stmt) { 852 Comment cmnt(masm_, "[ Block"); 853 NestedBlock nested_block(this, stmt); 854 SetStatementPosition(stmt); 855 856 { 857 EnterBlockScopeIfNeeded block_scope_state( 858 this, stmt->scope(), stmt->EntryId(), stmt->DeclsId(), stmt->ExitId()); 859 VisitStatements(stmt->statements()); 860 __ bind(nested_block.break_label()); 861 } 862} 863 864 865void FullCodeGenerator::VisitDoExpression(DoExpression* expr) { 866 Comment cmnt(masm_, "[ Do Expression"); 867 NestedStatement nested_block(this); 868 SetExpressionPosition(expr); 869 VisitBlock(expr->block()); 870 EmitVariableLoad(expr->result()); 871} 872 873 874void FullCodeGenerator::VisitExpressionStatement(ExpressionStatement* stmt) { 875 Comment cmnt(masm_, "[ ExpressionStatement"); 876 SetStatementPosition(stmt); 877 VisitForEffect(stmt->expression()); 878} 879 880 881void FullCodeGenerator::VisitEmptyStatement(EmptyStatement* stmt) { 882 Comment cmnt(masm_, "[ EmptyStatement"); 883 SetStatementPosition(stmt); 884} 885 886 887void FullCodeGenerator::VisitIfStatement(IfStatement* stmt) { 888 Comment cmnt(masm_, "[ IfStatement"); 889 SetStatementPosition(stmt); 890 Label then_part, else_part, done; 891 892 if (stmt->HasElseStatement()) { 893 VisitForControl(stmt->condition(), &then_part, &else_part, &then_part); 894 PrepareForBailoutForId(stmt->ThenId(), NO_REGISTERS); 895 __ bind(&then_part); 896 Visit(stmt->then_statement()); 897 __ jmp(&done); 898 899 PrepareForBailoutForId(stmt->ElseId(), NO_REGISTERS); 900 __ bind(&else_part); 901 Visit(stmt->else_statement()); 902 } else { 903 VisitForControl(stmt->condition(), &then_part, &done, &then_part); 904 PrepareForBailoutForId(stmt->ThenId(), NO_REGISTERS); 905 __ bind(&then_part); 906 Visit(stmt->then_statement()); 907 908 PrepareForBailoutForId(stmt->ElseId(), NO_REGISTERS); 909 } 910 __ bind(&done); 911 PrepareForBailoutForId(stmt->IfId(), NO_REGISTERS); 912} 913 914void FullCodeGenerator::EmitContinue(Statement* target) { 915 NestedStatement* current = nesting_stack_; 916 int stack_depth = 0; 917 int context_length = 0; 918 // When continuing, we clobber the unpredictable value in the accumulator 919 // with one that's safe for GC. If we hit an exit from the try block of 920 // try...finally on our way out, we will unconditionally preserve the 921 // accumulator on the stack. 922 ClearAccumulator(); 923 while (!current->IsContinueTarget(target)) { 924 if (current->IsTryFinally()) { 925 Comment cmnt(masm(), "[ Deferred continue through finally"); 926 current->Exit(&stack_depth, &context_length); 927 DCHECK_EQ(0, stack_depth); 928 DCHECK_EQ(0, context_length); 929 current->AsTryFinally()->deferred_commands()->RecordContinue(target); 930 return; 931 } 932 current = current->Exit(&stack_depth, &context_length); 933 } 934 __ Drop(stack_depth); 935 if (context_length > 0) { 936 while (context_length > 0) { 937 LoadContextField(context_register(), Context::PREVIOUS_INDEX); 938 --context_length; 939 } 940 StoreToFrameField(StandardFrameConstants::kContextOffset, 941 context_register()); 942 } 943 944 __ jmp(current->AsIteration()->continue_label()); 945} 946 947void FullCodeGenerator::VisitContinueStatement(ContinueStatement* stmt) { 948 Comment cmnt(masm_, "[ ContinueStatement"); 949 SetStatementPosition(stmt); 950 EmitContinue(stmt->target()); 951} 952 953void FullCodeGenerator::EmitBreak(Statement* target) { 954 NestedStatement* current = nesting_stack_; 955 int stack_depth = 0; 956 int context_length = 0; 957 // When breaking, we clobber the unpredictable value in the accumulator 958 // with one that's safe for GC. If we hit an exit from the try block of 959 // try...finally on our way out, we will unconditionally preserve the 960 // accumulator on the stack. 961 ClearAccumulator(); 962 while (!current->IsBreakTarget(target)) { 963 if (current->IsTryFinally()) { 964 Comment cmnt(masm(), "[ Deferred break through finally"); 965 current->Exit(&stack_depth, &context_length); 966 DCHECK_EQ(0, stack_depth); 967 DCHECK_EQ(0, context_length); 968 current->AsTryFinally()->deferred_commands()->RecordBreak(target); 969 return; 970 } 971 current = current->Exit(&stack_depth, &context_length); 972 } 973 __ Drop(stack_depth); 974 if (context_length > 0) { 975 while (context_length > 0) { 976 LoadContextField(context_register(), Context::PREVIOUS_INDEX); 977 --context_length; 978 } 979 StoreToFrameField(StandardFrameConstants::kContextOffset, 980 context_register()); 981 } 982 983 __ jmp(current->AsBreakable()->break_label()); 984} 985 986void FullCodeGenerator::VisitBreakStatement(BreakStatement* stmt) { 987 Comment cmnt(masm_, "[ BreakStatement"); 988 SetStatementPosition(stmt); 989 EmitBreak(stmt->target()); 990} 991 992void FullCodeGenerator::EmitUnwindAndReturn() { 993 NestedStatement* current = nesting_stack_; 994 int stack_depth = 0; 995 int context_length = 0; 996 while (current != NULL) { 997 if (current->IsTryFinally()) { 998 Comment cmnt(masm(), "[ Deferred return through finally"); 999 current->Exit(&stack_depth, &context_length); 1000 DCHECK_EQ(0, stack_depth); 1001 DCHECK_EQ(0, context_length); 1002 current->AsTryFinally()->deferred_commands()->RecordReturn(); 1003 return; 1004 } 1005 current = current->Exit(&stack_depth, &context_length); 1006 } 1007 __ Drop(stack_depth); 1008 EmitReturnSequence(); 1009} 1010 1011void FullCodeGenerator::EmitNamedSuperPropertyLoad(Property* prop) { 1012 // Stack: receiver, home_object 1013 SetExpressionPosition(prop); 1014 Literal* key = prop->key()->AsLiteral(); 1015 DCHECK(!key->value()->IsSmi()); 1016 DCHECK(prop->IsSuperAccess()); 1017 1018 PushOperand(key->value()); 1019 CallRuntimeWithOperands(Runtime::kLoadFromSuper); 1020} 1021 1022void FullCodeGenerator::EmitKeyedPropertyLoad(Property* prop) { 1023 SetExpressionPosition(prop); 1024 Handle<Code> ic = CodeFactory::KeyedLoadIC(isolate()).code(); 1025 __ Move(LoadDescriptor::SlotRegister(), 1026 SmiFromSlot(prop->PropertyFeedbackSlot())); 1027 CallIC(ic); 1028} 1029 1030void FullCodeGenerator::EmitKeyedSuperPropertyLoad(Property* prop) { 1031 // Stack: receiver, home_object, key. 1032 SetExpressionPosition(prop); 1033 CallRuntimeWithOperands(Runtime::kLoadKeyedFromSuper); 1034} 1035 1036void FullCodeGenerator::EmitPropertyKey(ObjectLiteralProperty* property, 1037 BailoutId bailout_id) { 1038 VisitForStackValue(property->key()); 1039 CallRuntimeWithOperands(Runtime::kToName); 1040 PrepareForBailoutForId(bailout_id, NO_REGISTERS); 1041 PushOperand(result_register()); 1042} 1043 1044 1045void FullCodeGenerator::VisitReturnStatement(ReturnStatement* stmt) { 1046 Comment cmnt(masm_, "[ ReturnStatement"); 1047 SetStatementPosition(stmt); 1048 Expression* expr = stmt->expression(); 1049 VisitForAccumulatorValue(expr); 1050 EmitUnwindAndReturn(); 1051} 1052 1053 1054void FullCodeGenerator::VisitWithStatement(WithStatement* stmt) { 1055 Comment cmnt(masm_, "[ WithStatement"); 1056 SetStatementPosition(stmt); 1057 1058 VisitForAccumulatorValue(stmt->expression()); 1059 Callable callable = CodeFactory::ToObject(isolate()); 1060 __ Move(callable.descriptor().GetRegisterParameter(0), result_register()); 1061 __ Call(callable.code(), RelocInfo::CODE_TARGET); 1062 PrepareForBailoutForId(stmt->ToObjectId(), NO_REGISTERS); 1063 PushOperand(result_register()); 1064 PushFunctionArgumentForContextAllocation(); 1065 CallRuntimeWithOperands(Runtime::kPushWithContext); 1066 StoreToFrameField(StandardFrameConstants::kContextOffset, context_register()); 1067 PrepareForBailoutForId(stmt->EntryId(), NO_REGISTERS); 1068 1069 Scope* saved_scope = scope(); 1070 scope_ = stmt->scope(); 1071 { WithOrCatch body(this); 1072 Visit(stmt->statement()); 1073 } 1074 scope_ = saved_scope; 1075 1076 // Pop context. 1077 LoadContextField(context_register(), Context::PREVIOUS_INDEX); 1078 // Update local stack frame context field. 1079 StoreToFrameField(StandardFrameConstants::kContextOffset, context_register()); 1080} 1081 1082 1083void FullCodeGenerator::VisitDoWhileStatement(DoWhileStatement* stmt) { 1084 Comment cmnt(masm_, "[ DoWhileStatement"); 1085 // Do not insert break location as we do that below. 1086 SetStatementPosition(stmt, SKIP_BREAK); 1087 1088 Label body, book_keeping; 1089 1090 Iteration loop_statement(this, stmt); 1091 increment_loop_depth(); 1092 1093 __ bind(&body); 1094 Visit(stmt->body()); 1095 1096 // Record the position of the do while condition and make sure it is 1097 // possible to break on the condition. 1098 __ bind(loop_statement.continue_label()); 1099 PrepareForBailoutForId(stmt->ContinueId(), NO_REGISTERS); 1100 1101 // Here is the actual 'while' keyword. 1102 SetExpressionAsStatementPosition(stmt->cond()); 1103 VisitForControl(stmt->cond(), 1104 &book_keeping, 1105 loop_statement.break_label(), 1106 &book_keeping); 1107 1108 // Check stack before looping. 1109 PrepareForBailoutForId(stmt->BackEdgeId(), NO_REGISTERS); 1110 __ bind(&book_keeping); 1111 EmitBackEdgeBookkeeping(stmt, &body); 1112 __ jmp(&body); 1113 1114 PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS); 1115 __ bind(loop_statement.break_label()); 1116 decrement_loop_depth(); 1117} 1118 1119 1120void FullCodeGenerator::VisitWhileStatement(WhileStatement* stmt) { 1121 Comment cmnt(masm_, "[ WhileStatement"); 1122 Label loop, body; 1123 1124 Iteration loop_statement(this, stmt); 1125 increment_loop_depth(); 1126 1127 __ bind(&loop); 1128 1129 SetExpressionAsStatementPosition(stmt->cond()); 1130 VisitForControl(stmt->cond(), 1131 &body, 1132 loop_statement.break_label(), 1133 &body); 1134 1135 PrepareForBailoutForId(stmt->BodyId(), NO_REGISTERS); 1136 __ bind(&body); 1137 Visit(stmt->body()); 1138 1139 __ bind(loop_statement.continue_label()); 1140 1141 // Check stack before looping. 1142 EmitBackEdgeBookkeeping(stmt, &loop); 1143 __ jmp(&loop); 1144 1145 PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS); 1146 __ bind(loop_statement.break_label()); 1147 decrement_loop_depth(); 1148} 1149 1150 1151void FullCodeGenerator::VisitForStatement(ForStatement* stmt) { 1152 Comment cmnt(masm_, "[ ForStatement"); 1153 // Do not insert break location as we do it below. 1154 SetStatementPosition(stmt, SKIP_BREAK); 1155 1156 Label test, body; 1157 1158 Iteration loop_statement(this, stmt); 1159 1160 if (stmt->init() != NULL) { 1161 SetStatementPosition(stmt->init()); 1162 Visit(stmt->init()); 1163 } 1164 1165 increment_loop_depth(); 1166 // Emit the test at the bottom of the loop (even if empty). 1167 __ jmp(&test); 1168 1169 PrepareForBailoutForId(stmt->BodyId(), NO_REGISTERS); 1170 __ bind(&body); 1171 Visit(stmt->body()); 1172 1173 PrepareForBailoutForId(stmt->ContinueId(), NO_REGISTERS); 1174 __ bind(loop_statement.continue_label()); 1175 if (stmt->next() != NULL) { 1176 SetStatementPosition(stmt->next()); 1177 Visit(stmt->next()); 1178 } 1179 1180 // Check stack before looping. 1181 EmitBackEdgeBookkeeping(stmt, &body); 1182 1183 __ bind(&test); 1184 if (stmt->cond() != NULL) { 1185 SetExpressionAsStatementPosition(stmt->cond()); 1186 VisitForControl(stmt->cond(), 1187 &body, 1188 loop_statement.break_label(), 1189 loop_statement.break_label()); 1190 } else { 1191 __ jmp(&body); 1192 } 1193 1194 PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS); 1195 __ bind(loop_statement.break_label()); 1196 decrement_loop_depth(); 1197} 1198 1199 1200void FullCodeGenerator::VisitForOfStatement(ForOfStatement* stmt) { 1201 Comment cmnt(masm_, "[ ForOfStatement"); 1202 1203 Iteration loop_statement(this, stmt); 1204 increment_loop_depth(); 1205 1206 // var iterator = iterable[Symbol.iterator](); 1207 VisitForEffect(stmt->assign_iterator()); 1208 1209 // Loop entry. 1210 __ bind(loop_statement.continue_label()); 1211 1212 // result = iterator.next() 1213 SetExpressionAsStatementPosition(stmt->next_result()); 1214 VisitForEffect(stmt->next_result()); 1215 1216 // if (result.done) break; 1217 Label result_not_done; 1218 VisitForControl(stmt->result_done(), loop_statement.break_label(), 1219 &result_not_done, &result_not_done); 1220 __ bind(&result_not_done); 1221 1222 // each = result.value 1223 VisitForEffect(stmt->assign_each()); 1224 1225 // Generate code for the body of the loop. 1226 Visit(stmt->body()); 1227 1228 // Check stack before looping. 1229 PrepareForBailoutForId(stmt->BackEdgeId(), NO_REGISTERS); 1230 EmitBackEdgeBookkeeping(stmt, loop_statement.continue_label()); 1231 __ jmp(loop_statement.continue_label()); 1232 1233 // Exit and decrement the loop depth. 1234 PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS); 1235 __ bind(loop_statement.break_label()); 1236 decrement_loop_depth(); 1237} 1238 1239 1240void FullCodeGenerator::VisitTryCatchStatement(TryCatchStatement* stmt) { 1241 Comment cmnt(masm_, "[ TryCatchStatement"); 1242 SetStatementPosition(stmt, SKIP_BREAK); 1243 1244 // The try block adds a handler to the exception handler chain before 1245 // entering, and removes it again when exiting normally. If an exception 1246 // is thrown during execution of the try block, the handler is consumed 1247 // and control is passed to the catch block with the exception in the 1248 // result register. 1249 1250 Label try_entry, handler_entry, exit; 1251 __ jmp(&try_entry); 1252 __ bind(&handler_entry); 1253 ClearPendingMessage(); 1254 1255 // Exception handler code, the exception is in the result register. 1256 // Extend the context before executing the catch block. 1257 { Comment cmnt(masm_, "[ Extend catch context"); 1258 PushOperand(stmt->variable()->name()); 1259 PushOperand(result_register()); 1260 PushFunctionArgumentForContextAllocation(); 1261 CallRuntimeWithOperands(Runtime::kPushCatchContext); 1262 StoreToFrameField(StandardFrameConstants::kContextOffset, 1263 context_register()); 1264 } 1265 1266 Scope* saved_scope = scope(); 1267 scope_ = stmt->scope(); 1268 DCHECK(scope_->declarations()->is_empty()); 1269 { WithOrCatch catch_body(this); 1270 Visit(stmt->catch_block()); 1271 } 1272 // Restore the context. 1273 LoadContextField(context_register(), Context::PREVIOUS_INDEX); 1274 StoreToFrameField(StandardFrameConstants::kContextOffset, context_register()); 1275 scope_ = saved_scope; 1276 __ jmp(&exit); 1277 1278 // Try block code. Sets up the exception handler chain. 1279 __ bind(&try_entry); 1280 1281 try_catch_depth_++; 1282 int handler_index = NewHandlerTableEntry(); 1283 EnterTryBlock(handler_index, &handler_entry); 1284 { TryCatch try_body(this); 1285 Visit(stmt->try_block()); 1286 } 1287 ExitTryBlock(handler_index); 1288 try_catch_depth_--; 1289 __ bind(&exit); 1290} 1291 1292 1293void FullCodeGenerator::VisitTryFinallyStatement(TryFinallyStatement* stmt) { 1294 Comment cmnt(masm_, "[ TryFinallyStatement"); 1295 SetStatementPosition(stmt, SKIP_BREAK); 1296 1297 // Try finally is compiled by setting up a try-handler on the stack while 1298 // executing the try body, and removing it again afterwards. 1299 // 1300 // The try-finally construct can enter the finally block in three ways: 1301 // 1. By exiting the try-block normally. This exits the try block, 1302 // pushes the continuation token and falls through to the finally 1303 // block. 1304 // 2. By exiting the try-block with a function-local control flow transfer 1305 // (break/continue/return). The site of the, e.g., break exits the 1306 // try block, pushes the continuation token and jumps to the 1307 // finally block. After the finally block executes, the execution 1308 // continues based on the continuation token to a block that 1309 // continues with the control flow transfer. 1310 // 3. By exiting the try-block with a thrown exception. In the handler, 1311 // we push the exception and continuation token and jump to the 1312 // finally block (which will again dispatch based on the token once 1313 // it is finished). 1314 1315 Label try_entry, handler_entry, finally_entry; 1316 DeferredCommands deferred(this, &finally_entry); 1317 1318 // Jump to try-handler setup and try-block code. 1319 __ jmp(&try_entry); 1320 __ bind(&handler_entry); 1321 1322 // Exception handler code. This code is only executed when an exception 1323 // is thrown. Record the continuation and jump to the finally block. 1324 { 1325 Comment cmt_handler(masm(), "[ Finally handler"); 1326 deferred.RecordThrow(); 1327 } 1328 1329 // Set up try handler. 1330 __ bind(&try_entry); 1331 int handler_index = NewHandlerTableEntry(); 1332 EnterTryBlock(handler_index, &handler_entry); 1333 { 1334 TryFinally try_body(this, &deferred); 1335 Visit(stmt->try_block()); 1336 } 1337 ExitTryBlock(handler_index); 1338 // Execute the finally block on the way out. Clobber the unpredictable 1339 // value in the result register with one that's safe for GC because the 1340 // finally block will unconditionally preserve the result register on the 1341 // stack. 1342 ClearAccumulator(); 1343 deferred.EmitFallThrough(); 1344 // Fall through to the finally block. 1345 1346 // Finally block implementation. 1347 __ bind(&finally_entry); 1348 Comment cmnt_finally(masm(), "[ Finally block"); 1349 OperandStackDepthIncrement(2); // Token and accumulator are on stack. 1350 EnterFinallyBlock(); 1351 { 1352 Finally finally_body(this); 1353 Visit(stmt->finally_block()); 1354 } 1355 ExitFinallyBlock(); 1356 OperandStackDepthDecrement(2); // Token and accumulator were on stack. 1357 1358 { 1359 Comment cmnt_deferred(masm(), "[ Post-finally dispatch"); 1360 deferred.EmitCommands(); // Return to the calling code. 1361 } 1362} 1363 1364 1365void FullCodeGenerator::VisitDebuggerStatement(DebuggerStatement* stmt) { 1366 Comment cmnt(masm_, "[ DebuggerStatement"); 1367 SetStatementPosition(stmt); 1368 1369 __ DebugBreak(); 1370 // Ignore the return value. 1371 1372 PrepareForBailoutForId(stmt->DebugBreakId(), NO_REGISTERS); 1373} 1374 1375 1376void FullCodeGenerator::VisitCaseClause(CaseClause* clause) { 1377 UNREACHABLE(); 1378} 1379 1380 1381void FullCodeGenerator::VisitConditional(Conditional* expr) { 1382 Comment cmnt(masm_, "[ Conditional"); 1383 Label true_case, false_case, done; 1384 VisitForControl(expr->condition(), &true_case, &false_case, &true_case); 1385 1386 int original_stack_depth = operand_stack_depth_; 1387 PrepareForBailoutForId(expr->ThenId(), NO_REGISTERS); 1388 __ bind(&true_case); 1389 SetExpressionPosition(expr->then_expression()); 1390 if (context()->IsTest()) { 1391 const TestContext* for_test = TestContext::cast(context()); 1392 VisitForControl(expr->then_expression(), 1393 for_test->true_label(), 1394 for_test->false_label(), 1395 NULL); 1396 } else { 1397 VisitInDuplicateContext(expr->then_expression()); 1398 __ jmp(&done); 1399 } 1400 1401 operand_stack_depth_ = original_stack_depth; 1402 PrepareForBailoutForId(expr->ElseId(), NO_REGISTERS); 1403 __ bind(&false_case); 1404 SetExpressionPosition(expr->else_expression()); 1405 VisitInDuplicateContext(expr->else_expression()); 1406 // If control flow falls through Visit, merge it with true case here. 1407 if (!context()->IsTest()) { 1408 __ bind(&done); 1409 } 1410} 1411 1412 1413void FullCodeGenerator::VisitLiteral(Literal* expr) { 1414 Comment cmnt(masm_, "[ Literal"); 1415 context()->Plug(expr->value()); 1416} 1417 1418 1419void FullCodeGenerator::VisitFunctionLiteral(FunctionLiteral* expr) { 1420 Comment cmnt(masm_, "[ FunctionLiteral"); 1421 1422 // Build the function boilerplate and instantiate it. 1423 Handle<SharedFunctionInfo> function_info = 1424 Compiler::GetSharedFunctionInfo(expr, script(), info_); 1425 if (function_info.is_null()) { 1426 SetStackOverflow(); 1427 return; 1428 } 1429 EmitNewClosure(function_info, expr->pretenure()); 1430} 1431 1432 1433void FullCodeGenerator::VisitClassLiteral(ClassLiteral* lit) { 1434 Comment cmnt(masm_, "[ ClassLiteral"); 1435 1436 { 1437 EnterBlockScopeIfNeeded block_scope_state( 1438 this, lit->scope(), lit->EntryId(), lit->DeclsId(), lit->ExitId()); 1439 1440 if (lit->extends() != NULL) { 1441 VisitForStackValue(lit->extends()); 1442 } else { 1443 PushOperand(isolate()->factory()->the_hole_value()); 1444 } 1445 1446 VisitForStackValue(lit->constructor()); 1447 1448 PushOperand(Smi::FromInt(lit->start_position())); 1449 PushOperand(Smi::FromInt(lit->end_position())); 1450 1451 CallRuntimeWithOperands(Runtime::kDefineClass); 1452 PrepareForBailoutForId(lit->CreateLiteralId(), TOS_REG); 1453 PushOperand(result_register()); 1454 1455 // Load the "prototype" from the constructor. 1456 __ Move(LoadDescriptor::ReceiverRegister(), result_register()); 1457 __ LoadRoot(LoadDescriptor::NameRegister(), 1458 Heap::kprototype_stringRootIndex); 1459 __ Move(LoadDescriptor::SlotRegister(), SmiFromSlot(lit->PrototypeSlot())); 1460 CallLoadIC(NOT_INSIDE_TYPEOF); 1461 PrepareForBailoutForId(lit->PrototypeId(), TOS_REG); 1462 PushOperand(result_register()); 1463 1464 EmitClassDefineProperties(lit); 1465 1466 // Set both the prototype and constructor to have fast properties, and also 1467 // freeze them in strong mode. 1468 CallRuntimeWithOperands(Runtime::kFinalizeClassDefinition); 1469 1470 if (lit->class_variable_proxy() != nullptr) { 1471 EmitVariableAssignment(lit->class_variable_proxy()->var(), Token::INIT, 1472 lit->ProxySlot()); 1473 } 1474 } 1475 1476 context()->Plug(result_register()); 1477} 1478 1479 1480void FullCodeGenerator::VisitNativeFunctionLiteral( 1481 NativeFunctionLiteral* expr) { 1482 Comment cmnt(masm_, "[ NativeFunctionLiteral"); 1483 Handle<SharedFunctionInfo> shared = 1484 Compiler::GetSharedFunctionInfoForNative(expr->extension(), expr->name()); 1485 EmitNewClosure(shared, false); 1486} 1487 1488 1489void FullCodeGenerator::VisitThrow(Throw* expr) { 1490 Comment cmnt(masm_, "[ Throw"); 1491 VisitForStackValue(expr->exception()); 1492 SetExpressionPosition(expr); 1493 CallRuntimeWithOperands(Runtime::kThrow); 1494 // Never returns here. 1495 1496 // Even though this expression doesn't produce a value, we need to simulate 1497 // plugging of the value context to ensure stack depth tracking is in sync. 1498 if (context()->IsStackValue()) OperandStackDepthIncrement(1); 1499} 1500 1501 1502void FullCodeGenerator::EnterTryBlock(int handler_index, Label* handler) { 1503 HandlerTableEntry* entry = &handler_table_[handler_index]; 1504 entry->range_start = masm()->pc_offset(); 1505 entry->handler_offset = handler->pos(); 1506 entry->try_catch_depth = try_catch_depth_; 1507 entry->stack_depth = operand_stack_depth_; 1508 1509 // We are using the operand stack depth, check for accuracy. 1510 EmitOperandStackDepthCheck(); 1511 1512 // Push context onto operand stack. 1513 STATIC_ASSERT(TryBlockConstant::kElementCount == 1); 1514 PushOperand(context_register()); 1515} 1516 1517 1518void FullCodeGenerator::ExitTryBlock(int handler_index) { 1519 HandlerTableEntry* entry = &handler_table_[handler_index]; 1520 entry->range_end = masm()->pc_offset(); 1521 1522 // Drop context from operand stack. 1523 DropOperands(TryBlockConstant::kElementCount); 1524} 1525 1526 1527void FullCodeGenerator::VisitCall(Call* expr) { 1528#ifdef DEBUG 1529 // We want to verify that RecordJSReturnSite gets called on all paths 1530 // through this function. Avoid early returns. 1531 expr->return_is_recorded_ = false; 1532#endif 1533 1534 Comment cmnt(masm_, (expr->tail_call_mode() == TailCallMode::kAllow) 1535 ? "[ TailCall" 1536 : "[ Call"); 1537 Expression* callee = expr->expression(); 1538 Call::CallType call_type = expr->GetCallType(isolate()); 1539 1540 switch (call_type) { 1541 case Call::POSSIBLY_EVAL_CALL: 1542 EmitPossiblyEvalCall(expr); 1543 break; 1544 case Call::GLOBAL_CALL: 1545 EmitCallWithLoadIC(expr); 1546 break; 1547 case Call::LOOKUP_SLOT_CALL: 1548 // Call to a lookup slot (dynamically introduced variable). 1549 PushCalleeAndWithBaseObject(expr); 1550 EmitCall(expr); 1551 break; 1552 case Call::NAMED_PROPERTY_CALL: { 1553 Property* property = callee->AsProperty(); 1554 VisitForStackValue(property->obj()); 1555 EmitCallWithLoadIC(expr); 1556 break; 1557 } 1558 case Call::KEYED_PROPERTY_CALL: { 1559 Property* property = callee->AsProperty(); 1560 VisitForStackValue(property->obj()); 1561 EmitKeyedCallWithLoadIC(expr, property->key()); 1562 break; 1563 } 1564 case Call::NAMED_SUPER_PROPERTY_CALL: 1565 EmitSuperCallWithLoadIC(expr); 1566 break; 1567 case Call::KEYED_SUPER_PROPERTY_CALL: 1568 EmitKeyedSuperCallWithLoadIC(expr); 1569 break; 1570 case Call::SUPER_CALL: 1571 EmitSuperConstructorCall(expr); 1572 break; 1573 case Call::OTHER_CALL: 1574 // Call to an arbitrary expression not handled specially above. 1575 VisitForStackValue(callee); 1576 OperandStackDepthIncrement(1); 1577 __ PushRoot(Heap::kUndefinedValueRootIndex); 1578 // Emit function call. 1579 EmitCall(expr); 1580 break; 1581 } 1582 1583#ifdef DEBUG 1584 // RecordJSReturnSite should have been called. 1585 DCHECK(expr->return_is_recorded_); 1586#endif 1587} 1588 1589 1590void FullCodeGenerator::VisitSpread(Spread* expr) { UNREACHABLE(); } 1591 1592 1593void FullCodeGenerator::VisitEmptyParentheses(EmptyParentheses* expr) { 1594 UNREACHABLE(); 1595} 1596 1597 1598void FullCodeGenerator::VisitRewritableExpression(RewritableExpression* expr) { 1599 Visit(expr->expression()); 1600} 1601 1602 1603FullCodeGenerator::NestedStatement* FullCodeGenerator::TryFinally::Exit( 1604 int* stack_depth, int* context_length) { 1605 // The macros used here must preserve the result register. 1606 1607 // Because the handler block contains the context of the finally 1608 // code, we can restore it directly from there for the finally code 1609 // rather than iteratively unwinding contexts via their previous 1610 // links. 1611 if (*context_length > 0) { 1612 __ Drop(*stack_depth); // Down to the handler block. 1613 // Restore the context to its dedicated register and the stack. 1614 STATIC_ASSERT(TryFinally::kElementCount == 1); 1615 __ Pop(codegen_->context_register()); 1616 codegen_->StoreToFrameField(StandardFrameConstants::kContextOffset, 1617 codegen_->context_register()); 1618 } else { 1619 // Down to the handler block and also drop context. 1620 __ Drop(*stack_depth + kElementCount); 1621 } 1622 *stack_depth = 0; 1623 *context_length = 0; 1624 return previous_; 1625} 1626 1627void FullCodeGenerator::DeferredCommands::RecordBreak(Statement* target) { 1628 TokenId token = dispenser_.GetBreakContinueToken(); 1629 commands_.push_back({kBreak, token, target}); 1630 EmitJumpToFinally(token); 1631} 1632 1633void FullCodeGenerator::DeferredCommands::RecordContinue(Statement* target) { 1634 TokenId token = dispenser_.GetBreakContinueToken(); 1635 commands_.push_back({kContinue, token, target}); 1636 EmitJumpToFinally(token); 1637} 1638 1639void FullCodeGenerator::DeferredCommands::RecordReturn() { 1640 if (return_token_ == TokenDispenserForFinally::kInvalidToken) { 1641 return_token_ = TokenDispenserForFinally::kReturnToken; 1642 commands_.push_back({kReturn, return_token_, nullptr}); 1643 } 1644 EmitJumpToFinally(return_token_); 1645} 1646 1647void FullCodeGenerator::DeferredCommands::RecordThrow() { 1648 if (throw_token_ == TokenDispenserForFinally::kInvalidToken) { 1649 throw_token_ = TokenDispenserForFinally::kThrowToken; 1650 commands_.push_back({kThrow, throw_token_, nullptr}); 1651 } 1652 EmitJumpToFinally(throw_token_); 1653} 1654 1655void FullCodeGenerator::DeferredCommands::EmitFallThrough() { 1656 __ Push(Smi::FromInt(TokenDispenserForFinally::kFallThroughToken)); 1657 __ Push(result_register()); 1658} 1659 1660void FullCodeGenerator::DeferredCommands::EmitJumpToFinally(TokenId token) { 1661 __ Push(Smi::FromInt(token)); 1662 __ Push(result_register()); 1663 __ jmp(finally_entry_); 1664} 1665 1666bool FullCodeGenerator::TryLiteralCompare(CompareOperation* expr) { 1667 Expression* sub_expr; 1668 Handle<String> check; 1669 if (expr->IsLiteralCompareTypeof(&sub_expr, &check)) { 1670 EmitLiteralCompareTypeof(expr, sub_expr, check); 1671 return true; 1672 } 1673 1674 if (expr->IsLiteralCompareUndefined(&sub_expr, isolate())) { 1675 EmitLiteralCompareNil(expr, sub_expr, kUndefinedValue); 1676 return true; 1677 } 1678 1679 if (expr->IsLiteralCompareNull(&sub_expr)) { 1680 EmitLiteralCompareNil(expr, sub_expr, kNullValue); 1681 return true; 1682 } 1683 1684 return false; 1685} 1686 1687 1688void BackEdgeTable::Patch(Isolate* isolate, Code* unoptimized) { 1689 DisallowHeapAllocation no_gc; 1690 Code* patch = isolate->builtins()->builtin(Builtins::kOnStackReplacement); 1691 1692 // Increment loop nesting level by one and iterate over the back edge table 1693 // to find the matching loops to patch the interrupt 1694 // call to an unconditional call to the replacement code. 1695 int loop_nesting_level = unoptimized->allow_osr_at_loop_nesting_level() + 1; 1696 if (loop_nesting_level > Code::kMaxLoopNestingMarker) return; 1697 1698 BackEdgeTable back_edges(unoptimized, &no_gc); 1699 for (uint32_t i = 0; i < back_edges.length(); i++) { 1700 if (static_cast<int>(back_edges.loop_depth(i)) == loop_nesting_level) { 1701 DCHECK_EQ(INTERRUPT, GetBackEdgeState(isolate, 1702 unoptimized, 1703 back_edges.pc(i))); 1704 PatchAt(unoptimized, back_edges.pc(i), ON_STACK_REPLACEMENT, patch); 1705 } 1706 } 1707 1708 unoptimized->set_allow_osr_at_loop_nesting_level(loop_nesting_level); 1709 DCHECK(Verify(isolate, unoptimized)); 1710} 1711 1712 1713void BackEdgeTable::Revert(Isolate* isolate, Code* unoptimized) { 1714 DisallowHeapAllocation no_gc; 1715 Code* patch = isolate->builtins()->builtin(Builtins::kInterruptCheck); 1716 1717 // Iterate over the back edge table and revert the patched interrupt calls. 1718 int loop_nesting_level = unoptimized->allow_osr_at_loop_nesting_level(); 1719 1720 BackEdgeTable back_edges(unoptimized, &no_gc); 1721 for (uint32_t i = 0; i < back_edges.length(); i++) { 1722 if (static_cast<int>(back_edges.loop_depth(i)) <= loop_nesting_level) { 1723 DCHECK_NE(INTERRUPT, GetBackEdgeState(isolate, 1724 unoptimized, 1725 back_edges.pc(i))); 1726 PatchAt(unoptimized, back_edges.pc(i), INTERRUPT, patch); 1727 } 1728 } 1729 1730 unoptimized->set_allow_osr_at_loop_nesting_level(0); 1731 // Assert that none of the back edges are patched anymore. 1732 DCHECK(Verify(isolate, unoptimized)); 1733} 1734 1735 1736void BackEdgeTable::AddStackCheck(Handle<Code> code, uint32_t pc_offset) { 1737 DisallowHeapAllocation no_gc; 1738 Isolate* isolate = code->GetIsolate(); 1739 Address pc = code->instruction_start() + pc_offset; 1740 Code* patch = isolate->builtins()->builtin(Builtins::kOsrAfterStackCheck); 1741 PatchAt(*code, pc, OSR_AFTER_STACK_CHECK, patch); 1742} 1743 1744 1745void BackEdgeTable::RemoveStackCheck(Handle<Code> code, uint32_t pc_offset) { 1746 DisallowHeapAllocation no_gc; 1747 Isolate* isolate = code->GetIsolate(); 1748 Address pc = code->instruction_start() + pc_offset; 1749 1750 if (OSR_AFTER_STACK_CHECK == GetBackEdgeState(isolate, *code, pc)) { 1751 Code* patch = isolate->builtins()->builtin(Builtins::kOnStackReplacement); 1752 PatchAt(*code, pc, ON_STACK_REPLACEMENT, patch); 1753 } 1754} 1755 1756 1757#ifdef DEBUG 1758bool BackEdgeTable::Verify(Isolate* isolate, Code* unoptimized) { 1759 DisallowHeapAllocation no_gc; 1760 int loop_nesting_level = unoptimized->allow_osr_at_loop_nesting_level(); 1761 BackEdgeTable back_edges(unoptimized, &no_gc); 1762 for (uint32_t i = 0; i < back_edges.length(); i++) { 1763 uint32_t loop_depth = back_edges.loop_depth(i); 1764 CHECK_LE(static_cast<int>(loop_depth), Code::kMaxLoopNestingMarker); 1765 // Assert that all back edges for shallower loops (and only those) 1766 // have already been patched. 1767 CHECK_EQ((static_cast<int>(loop_depth) <= loop_nesting_level), 1768 GetBackEdgeState(isolate, 1769 unoptimized, 1770 back_edges.pc(i)) != INTERRUPT); 1771 } 1772 return true; 1773} 1774#endif // DEBUG 1775 1776 1777FullCodeGenerator::EnterBlockScopeIfNeeded::EnterBlockScopeIfNeeded( 1778 FullCodeGenerator* codegen, Scope* scope, BailoutId entry_id, 1779 BailoutId declarations_id, BailoutId exit_id) 1780 : codegen_(codegen), exit_id_(exit_id) { 1781 saved_scope_ = codegen_->scope(); 1782 1783 if (scope == NULL) { 1784 codegen_->PrepareForBailoutForId(entry_id, NO_REGISTERS); 1785 needs_block_context_ = false; 1786 } else { 1787 needs_block_context_ = scope->NeedsContext(); 1788 codegen_->scope_ = scope; 1789 { 1790 if (needs_block_context_) { 1791 Comment cmnt(masm(), "[ Extend block context"); 1792 codegen_->PushOperand(scope->GetScopeInfo(codegen->isolate())); 1793 codegen_->PushFunctionArgumentForContextAllocation(); 1794 codegen_->CallRuntimeWithOperands(Runtime::kPushBlockContext); 1795 1796 // Replace the context stored in the frame. 1797 codegen_->StoreToFrameField(StandardFrameConstants::kContextOffset, 1798 codegen_->context_register()); 1799 } 1800 CHECK_EQ(0, scope->num_stack_slots()); 1801 codegen_->PrepareForBailoutForId(entry_id, NO_REGISTERS); 1802 } 1803 { 1804 Comment cmnt(masm(), "[ Declarations"); 1805 codegen_->VisitDeclarations(scope->declarations()); 1806 codegen_->PrepareForBailoutForId(declarations_id, NO_REGISTERS); 1807 } 1808 } 1809} 1810 1811 1812FullCodeGenerator::EnterBlockScopeIfNeeded::~EnterBlockScopeIfNeeded() { 1813 if (needs_block_context_) { 1814 codegen_->LoadContextField(codegen_->context_register(), 1815 Context::PREVIOUS_INDEX); 1816 // Update local stack frame context field. 1817 codegen_->StoreToFrameField(StandardFrameConstants::kContextOffset, 1818 codegen_->context_register()); 1819 } 1820 codegen_->PrepareForBailoutForId(exit_id_, NO_REGISTERS); 1821 codegen_->scope_ = saved_scope_; 1822} 1823 1824 1825bool FullCodeGenerator::NeedsHoleCheckForLoad(VariableProxy* proxy) { 1826 Variable* var = proxy->var(); 1827 1828 if (!var->binding_needs_init()) { 1829 return false; 1830 } 1831 1832 // var->scope() may be NULL when the proxy is located in eval code and 1833 // refers to a potential outside binding. Currently those bindings are 1834 // always looked up dynamically, i.e. in that case 1835 // var->location() == LOOKUP. 1836 // always holds. 1837 DCHECK(var->scope() != NULL); 1838 DCHECK(var->location() == VariableLocation::PARAMETER || 1839 var->location() == VariableLocation::LOCAL || 1840 var->location() == VariableLocation::CONTEXT); 1841 1842 // Check if the binding really needs an initialization check. The check 1843 // can be skipped in the following situation: we have a LET or CONST 1844 // binding in harmony mode, both the Variable and the VariableProxy have 1845 // the same declaration scope (i.e. they are both in global code, in the 1846 // same function or in the same eval code), the VariableProxy is in 1847 // the source physically located after the initializer of the variable, 1848 // and that the initializer cannot be skipped due to a nonlinear scope. 1849 // 1850 // We cannot skip any initialization checks for CONST in non-harmony 1851 // mode because const variables may be declared but never initialized: 1852 // if (false) { const x; }; var y = x; 1853 // 1854 // The condition on the declaration scopes is a conservative check for 1855 // nested functions that access a binding and are called before the 1856 // binding is initialized: 1857 // function() { f(); let x = 1; function f() { x = 2; } } 1858 // 1859 // The check cannot be skipped on non-linear scopes, namely switch 1860 // scopes, to ensure tests are done in cases like the following: 1861 // switch (1) { case 0: let x = 2; case 1: f(x); } 1862 // The scope of the variable needs to be checked, in case the use is 1863 // in a sub-block which may be linear. 1864 if (var->scope()->DeclarationScope() != scope()->DeclarationScope()) { 1865 return true; 1866 } 1867 1868 if (var->is_this()) { 1869 DCHECK(literal() != nullptr && 1870 (literal()->kind() & kSubclassConstructor) != 0); 1871 // TODO(littledan): implement 'this' hole check elimination. 1872 return true; 1873 } 1874 1875 // Check that we always have valid source position. 1876 DCHECK(var->initializer_position() != RelocInfo::kNoPosition); 1877 DCHECK(proxy->position() != RelocInfo::kNoPosition); 1878 1879 return var->mode() == CONST_LEGACY || var->scope()->is_nonlinear() || 1880 var->initializer_position() >= proxy->position(); 1881} 1882 1883 1884#undef __ 1885 1886 1887} // namespace internal 1888} // namespace v8 1889