⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 codegen-arm.cc.svn-base

📁 Google浏览器V8内核代码
💻 SVN-BASE
📖 第 1 页 / 共 5 页
字号:
  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;  ArmCodeGenerator 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;}ArmCodeGenerator::ArmCodeGenerator(int buffer_size,                                   Handle<Script> script,                                   bool is_eval)    : CodeGenerator(is_eval, script),      masm_(new MacroAssembler(NULL, buffer_size)),      scope_(NULL),      cc_reg_(al),      state_(NULL),      break_stack_height_(0) {}// Calling conventions:// r0: the number of arguments// fp: frame pointer// sp: stack pointer// pp: caller's parameter pointer// cp: callee's contextvoid ArmCodeGenerator::GenCode(FunctionLiteral* fun) {  Scope* scope = fun->scope();  ZoneList<Statement*>* body = fun->body();  // Initialize state.  { CodeGenState state(this);    scope_ = scope;    cc_reg_ = al;    // Entry    // stack: function, receiver, arguments, return address    // r0: number of arguments    // sp: stack pointer    // fp: frame pointer    // pp: caller's parameter pointer    // cp: 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))) {      __ stop("stop-at");    }#endif    // Allocate space for locals and initialize them.    if (scope->num_stack_slots() > 0) {      Comment cmnt(masm_, "[ allocate space for locals");      // Initialize stack slots with 'undefined' value.      __ mov(ip, Operand(Factory::undefined_value()));      for (int i = 0; i < scope->num_stack_slots(); i++) {        __ push(ip);      }    }    if (scope->num_heap_slots() > 0) {      // Allocate local context.      // Get outer context and create a new context based on it.      __ ldr(r0, FunctionOperand());      __ push(r0);      __ CallRuntime(Runtime::kNewContext, 1);  // r0 holds the result      if (kDebug) {        Label verified_true;        __ cmp(r0, Operand(cp));        __ b(eq, &verified_true);        __ stop("NewContext: r0 is expected to be the same as cp");        __ bind(&verified_true);      }      // Update context local.      __ str(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));    }    // 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) {          ASSERT(!scope->is_global_scope());  // no parameters in global scope          __ ldr(r1, ParameterOperand(i));          // Loads r2 with context; used below in RecordWrite.          __ str(r1, SlotOperand(slot, r2));          // Load the offset into r3.          int slot_offset =              FixedArray::kHeaderSize + slot->index() * kPointerSize;          __ mov(r3, Operand(slot_offset));          __ RecordWrite(r2, r3, r1);        }      }    }    // Store the arguments object.    // This must happen after context initialization because    // the arguments array may be stored in the context!    if (scope->arguments() != NULL) {      ASSERT(scope->arguments_shadow() != NULL);      Comment cmnt(masm_, "[ allocate arguments object");      {        Reference target(this, scope->arguments());        __ ldr(r0, FunctionOperand());        __ push(r0);        __ CallRuntime(Runtime::kNewArguments, 1);        __ push(r0);        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 calls DeclareGlobals indirectly      ProcessDeclarations(scope->declarations());      // Bail out if a stack-overflow exception occurred when      // processing declarations.      if (HasStackOverflow()) return;    }    if (FLAG_trace) {      // Push a valid value as the parameter. The runtime call only uses      // it as the return value to indicate non-failure.      __ mov(r0, Operand(Smi::FromInt(0)));      __ push(r0);      __ CallRuntime(Runtime::kTraceEnter, 1);    }    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) {        // Push a valid value as the parameter. The runtime call only uses        // it as the return value to indicate non-failure.        __ mov(r0, Operand(Smi::FromInt(0)));        __ push(r0);        __ CallRuntime(Runtime::kDebugTrace, 1);      }#endif      VisitStatements(body);    }  }  // exit  // r0: result  // sp: stack pointer  // fp: frame pointer  // pp: parameter pointer  // cp: callee's context  __ mov(r0, Operand(Factory::undefined_value()));  __ bind(&function_return_);  if (FLAG_trace) {    // Push the return value on the stack as the parameter.    // Runtime::TraceExit returns the parameter as it is.    __ push(r0);    __ CallRuntime(Runtime::kTraceExit, 1);  }  // Tear down the frame which will restore the caller's frame pointer and the  // link register.  ExitJSFrame();  __ add(sp, sp, Operand((scope_->num_parameters() + 1) * kPointerSize));  __ mov(pc, lr);  // Code generation state must be reset.  scope_ = NULL;  ASSERT(!has_cc());  ASSERT(state_ == NULL);}MemOperand ArmCodeGenerator::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() &&             index >= 0);      int local_offset = JavaScriptFrameConstants::kLocal0Offset -                         index * kPointerSize;      return MemOperand(fp, local_offset);    }    case Slot::CONTEXT: {      // Follow the context chain if necessary.      ASSERT(!tmp.is(cp));  // do not overwrite context register      Register context = cp;      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.)        masm->ldr(tmp, ContextOperand(context, Context::CLOSURE_INDEX));        // Load the function context (which is the incoming, outer context).        masm->ldr(tmp, FieldMemOperand(tmp, JSFunction::kContextOffset));        context = tmp;      }      // We may have a 'with' context now. Get the function context.      // (In fact this mov may never be the needed, since the scope analysis      // may not permit a direct context access in this case and thus we are      // always at a function context. However it is safe to dereference be-      // cause the function context of a function context is itself. Before      // deleting this mov we should try to create a counter-example first,      // though...)      masm->ldr(tmp, ContextOperand(context, Context::FCONTEXT_INDEX));      return ContextOperand(tmp, index);    }    default:      UNREACHABLE();      return MemOperand(r0, 0);  }}// Loads a value on the stack. If it is a boolean value, the result may have// been (partially) translated into branches, or it may have set the condition// code register. If force_cc is set, the value is forced to set the condition// code register and no value is pushed. If the condition code register was set,// has_cc() is true and cc_reg_ contains the condition to test for 'true'.void ArmCodeGenerator::LoadCondition(Expression* x,                                     CodeGenState::AccessType access,                                     Label* true_target,                                     Label* false_target,                                     bool force_cc) {  ASSERT(access == CodeGenState::LOAD ||         access == CodeGenState::LOAD_TYPEOF_EXPR);  ASSERT(!has_cc() && !is_referenced());  { CodeGenState new_state(this, access, true_target, false_target);    Visit(x);  }  if (force_cc && !has_cc()) {    // Convert the TOS value to a boolean in the condition code register.    ToBoolean(true_target, false_target);  }  ASSERT(has_cc() || !force_cc);}void ArmCodeGenerator::Load(Expression* x, CodeGenState::AccessType access) {  ASSERT(access == CodeGenState::LOAD ||         access == CodeGenState::LOAD_TYPEOF_EXPR);  Label true_target;  Label false_target;  LoadCondition(x, access, &true_target, &false_target, false);  if (has_cc()) {    // convert cc_reg_ into a bool    Label loaded, materialize_true;    __ b(cc_reg_, &materialize_true);    __ mov(r0, Operand(Factory::false_value()));    __ push(r0);    __ b(&loaded);    __ bind(&materialize_true);    __ mov(r0, Operand(Factory::true_value()));

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -