📄 codegen-ia32.cc.svn-base
字号:
ref_(NULL), true_target_(NULL), false_target_(NULL), previous_(NULL) { owner_->set_state(this);}CodeGenState::CodeGenState(Ia32CodeGenerator* owner, AccessType access, Label* true_target, Label* false_target) : owner_(owner), access_(access), ref_(NULL), true_target_(true_target), false_target_(false_target), previous_(owner->state()) { owner_->set_state(this);}CodeGenState::CodeGenState(Ia32CodeGenerator* owner, Reference* ref) : owner_(owner), access_(LOAD), ref_(ref), true_target_(owner->state()->true_target_), false_target_(owner->state()->false_target_), previous_(owner->state()) { owner_->set_state(this);}CodeGenState::~CodeGenState() { ASSERT(owner_->state() == this); owner_->set_state(previous_);}// -----------------------------------------------------------------------------// Ia32CodeGenerator implementation#define __ masm_->Handle<Code> Ia32CodeGenerator::MakeCode(FunctionLiteral* flit, Handle<Script> script, bool is_eval) {#ifdef ENABLE_DISASSEMBLER bool print_code = FLAG_print_code && !Bootstrapper::IsActive();#endif#ifdef DEBUG bool print_source = false; bool print_ast = false; const char* ftype; if (Bootstrapper::IsActive()) { print_source = FLAG_print_builtin_source; print_ast = FLAG_print_builtin_ast; print_code = FLAG_print_builtin_code; ftype = "builtin"; } else { print_source = FLAG_print_source; print_ast = FLAG_print_ast; ftype = "user-defined"; } if (FLAG_trace_codegen || print_source || print_ast) { PrintF("*** Generate code for %s function: ", ftype); flit->name()->ShortPrint(); PrintF(" ***\n"); } if (print_source) { PrintF("--- Source from AST ---\n%s\n", PrettyPrinter().PrintProgram(flit)); } if (print_ast) { PrintF("--- AST ---\n%s\n", AstPrinter().PrintProgram(flit)); }#endif // DEBUG // Generate code. const int initial_buffer_size = 4 * KB; Ia32CodeGenerator cgen(initial_buffer_size, script, is_eval); cgen.GenCode(flit); if (cgen.HasStackOverflow()) { ASSERT(!Top::has_pending_exception()); return Handle<Code>::null(); } // Process any deferred code. cgen.ProcessDeferred(); // Allocate and install the code. CodeDesc desc; cgen.masm()->GetCode(&desc); ScopeInfo<> sinfo(flit->scope()); Code::Flags flags = Code::ComputeFlags(Code::FUNCTION); Handle<Code> code = Factory::NewCode(desc, &sinfo, flags); // Add unresolved entries in the code to the fixup list. Bootstrapper::AddFixup(*code, cgen.masm());#ifdef ENABLE_DISASSEMBLER if (print_code) { // Print the source code if available. if (!script->IsUndefined() && !script->source()->IsUndefined()) { PrintF("--- Raw source ---\n"); StringInputBuffer stream(String::cast(script->source())); stream.Seek(flit->start_position()); // flit->end_position() points to the last character in the stream. We // need to compensate by adding one to calculate the length. int source_len = flit->end_position() - flit->start_position() + 1; for (int i = 0; i < source_len; i++) { if (stream.has_more()) PrintF("%c", stream.GetNext()); } PrintF("\n\n"); } PrintF("--- Code ---\n"); code->Disassemble(); }#endif // ENABLE_DISASSEMBLER return code;}Ia32CodeGenerator::Ia32CodeGenerator(int buffer_size, Handle<Script> script, bool is_eval) : CodeGenerator(is_eval, script), masm_(new MacroAssembler(NULL, buffer_size)), scope_(NULL), cc_reg_(no_condition), state_(NULL), is_inside_try_(false), break_stack_height_(0) {}// Calling conventions:// ebp: frame pointer// esp: stack pointer// edi: caller's parameter pointer// esi: callee's contextvoid Ia32CodeGenerator::GenCode(FunctionLiteral* fun) { // Record the position for debugging purposes. __ RecordPosition(fun->start_position()); Scope* scope = fun->scope(); ZoneList<Statement*>* body = fun->body(); // Initialize state. { CodeGenState state(this); scope_ = scope; cc_reg_ = no_condition; // Entry // stack: function, receiver, arguments, return address // esp: stack pointer // ebp: frame pointer // edi: caller's parameter pointer // esi: callee's context { Comment cmnt(masm_, "[ enter JS frame"); EnterJSFrame(); } // tos: code slot#ifdef DEBUG if (strlen(FLAG_stop_at) > 0 && fun->name()->IsEqualTo(CStrVector(FLAG_stop_at))) { __ int3(); }#endif // This section now only allocates and copies the formals into the // arguments object. It saves the address in ecx, which is saved // at any point before either garbage collection or ecx is // overwritten. The flag arguments_array_allocated communicates // with the store into the arguments variable and guards the lazy // pushes of ecx to TOS. The flag arguments_array_saved notes // when the push has happened. bool arguments_object_allocated = false; bool arguments_object_saved = false; // Allocate arguments object. // The arguments object pointer needs to be saved in ecx, since we need // to store arguments into the context. if (scope->arguments() != NULL) { ASSERT(scope->arguments_shadow() != NULL); Comment cmnt(masm_, "[ allocate arguments object"); __ push(FunctionOperand()); __ CallRuntime(Runtime::kNewArguments, 1); __ mov(ecx, Operand(eax)); arguments_object_allocated = true; } // Allocate space for locals and initialize them. if (scope->num_stack_slots() > 0) { Comment cmnt(masm_, "[ allocate space for locals"); __ Set(eax, Immediate(Factory::undefined_value())); for (int i = scope->num_stack_slots(); i-- > 0; ) __ push(eax); } if (scope->num_heap_slots() > 0) { Comment cmnt(masm_, "[ allocate local context"); // Save the arguments object pointer, if any. if (arguments_object_allocated && !arguments_object_saved) { __ push(Operand(ecx)); arguments_object_saved = true; } // Allocate local context. // Get outer context and create a new context based on it. __ push(FunctionOperand()); __ CallRuntime(Runtime::kNewContext, 1); // eax holds the result if (kDebug) { Label verified_true; // Verify eax and esi are the same in debug mode __ cmp(eax, Operand(esi)); __ j(equal, &verified_true); __ int3(); __ bind(&verified_true); } // Update context local. __ mov(Operand(ebp, StandardFrameConstants::kContextOffset), esi); // Restore the arguments array pointer, if any. } // TODO(1241774): Improve this code: // 1) only needed if we have a context // 2) no need to recompute context ptr every single time // 3) don't copy parameter operand code from SlotOperand! { Comment cmnt2(masm_, "[ copy context parameters into .context"); // Note that iteration order is relevant here! If we have the same // parameter twice (e.g., function (x, y, x)), and that parameter // needs to be copied into the context, it must be the last argument // passed to the parameter that needs to be copied. This is a rare // case so we don't check for it, instead we rely on the copying // order: such a parameter is copied repeatedly into the same // context location and thus the last value is what is seen inside // the function. for (int i = 0; i < scope->num_parameters(); i++) { Variable* par = scope->parameter(i); Slot* slot = par->slot(); if (slot != NULL && slot->type() == Slot::CONTEXT) { // Save the arguments object pointer, if any. if (arguments_object_allocated && !arguments_object_saved) { __ push(Operand(ecx)); arguments_object_saved = true; } ASSERT(!scope->is_global_scope()); // no parameters in global scope __ mov(eax, ParameterOperand(i)); // Loads ecx with context; used below in RecordWrite. __ mov(SlotOperand(slot, ecx), eax); int offset = FixedArray::kHeaderSize + slot->index() * kPointerSize; __ RecordWrite(ecx, offset, eax, ebx); } } } // This section stores the pointer to the arguments object that // was allocated and copied into above. If the address was not // saved to TOS, we push ecx onto the stack. // Store the arguments object. // This must happen after context initialization because // the arguments object may be stored in the context if (arguments_object_allocated) { ASSERT(scope->arguments() != NULL); ASSERT(scope->arguments_shadow() != NULL); Comment cmnt(masm_, "[ store arguments object"); { Reference target(this, scope->arguments()); if (!arguments_object_saved) { __ push(Operand(ecx)); } SetValue(&target); } // The value of arguments must also be stored in .arguments. // TODO(1241813): This code can probably be improved by fusing it with // the code that stores the arguments object above. { Reference target(this, scope->arguments_shadow()); Load(scope->arguments()); SetValue(&target); } } // Generate code to 'execute' declarations and initialize // functions (source elements). In case of an illegal // redeclaration we need to handle that instead of processing the // declarations. if (scope->HasIllegalRedeclaration()) { Comment cmnt(masm_, "[ illegal redeclarations"); scope->VisitIllegalRedeclaration(this); } else { Comment cmnt(masm_, "[ declarations"); ProcessDeclarations(scope->declarations()); // Bail out if a stack-overflow exception occurred when // processing declarations. if (HasStackOverflow()) return; } if (FLAG_trace) { __ CallRuntime(Runtime::kTraceEnter, 1); __ push(eax); } CheckStack(); // Compile the body of the function in a vanilla state. Don't // bother compiling all the code if the scope has an illegal // redeclaration. if (!scope->HasIllegalRedeclaration()) { Comment cmnt(masm_, "[ function body");#ifdef DEBUG bool is_builtin = Bootstrapper::IsActive(); bool should_trace = is_builtin ? FLAG_trace_builtin_calls : FLAG_trace_calls; if (should_trace) { __ CallRuntime(Runtime::kDebugTrace, 1); __ push(eax); }#endif VisitStatements(body); // Generate a return statement if necessary. if (body->is_empty() || body->last()->AsReturnStatement() == NULL) { Literal undefined(Factory::undefined_value()); ReturnStatement statement(&undefined); statement.set_statement_pos(fun->end_position()); VisitReturnStatement(&statement); } } } // Code generation state must be reset. scope_ = NULL; ASSERT(!has_cc()); ASSERT(state_ == NULL);}Operand Ia32CodeGenerator::SlotOperand(MacroAssembler* masm, Scope* scope, Slot* slot, Register tmp) { // Currently, this assertion will fail if we try to assign to // a constant variable that is constant because it is read-only // (such as the variable referring to a named function expression). // We need to implement assignments to read-only variables. // Ideally, we should do this during AST generation (by converting // such assignments into expression statements); however, in general // we may not be able to make the decision until past AST generation, // that is when the entire program is known. ASSERT(slot != NULL); int index = slot->index(); switch (slot->type()) { case Slot::PARAMETER: return ParameterOperand(scope, index); case Slot::LOCAL: { ASSERT(0 <= index && index < scope->num_stack_slots()); const int kLocal0Offset = JavaScriptFrameConstants::kLocal0Offset; return Operand(ebp, kLocal0Offset - index * kPointerSize); } case Slot::CONTEXT: { // Follow the context chain if necessary. ASSERT(!tmp.is(esi)); // do not overwrite context register Register context = esi; int chain_length = scope->ContextChainLength(slot->var()->scope()); for (int i = chain_length; i-- > 0;) { // Load the closure. // (All contexts, even 'with' contexts, have a closure, // and it is the same for all contexts inside a function. // There is no need to go to the function context first.)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -