codegen-arm.h revision 402d937239b0e2fd11bf2f4fe972ad78aa9fd481
1// Copyright 2010 the V8 project authors. All rights reserved. 2// Redistribution and use in source and binary forms, with or without 3// modification, are permitted provided that the following conditions are 4// met: 5// 6// * Redistributions of source code must retain the above copyright 7// notice, this list of conditions and the following disclaimer. 8// * Redistributions in binary form must reproduce the above 9// copyright notice, this list of conditions and the following 10// disclaimer in the documentation and/or other materials provided 11// with the distribution. 12// * Neither the name of Google Inc. nor the names of its 13// contributors may be used to endorse or promote products derived 14// from this software without specific prior written permission. 15// 16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 28#ifndef V8_ARM_CODEGEN_ARM_H_ 29#define V8_ARM_CODEGEN_ARM_H_ 30 31namespace v8 { 32namespace internal { 33 34// Forward declarations 35class CompilationInfo; 36class DeferredCode; 37class RegisterAllocator; 38class RegisterFile; 39 40enum InitState { CONST_INIT, NOT_CONST_INIT }; 41enum TypeofState { INSIDE_TYPEOF, NOT_INSIDE_TYPEOF }; 42 43 44// ------------------------------------------------------------------------- 45// Reference support 46 47// A reference is a C++ stack-allocated object that puts a 48// reference on the virtual frame. The reference may be consumed 49// by GetValue, TakeValue, SetValue, and Codegen::UnloadReference. 50// When the lifetime (scope) of a valid reference ends, it must have 51// been consumed, and be in state UNLOADED. 52class Reference BASE_EMBEDDED { 53 public: 54 // The values of the types is important, see size(). 55 enum Type { UNLOADED = -2, ILLEGAL = -1, SLOT = 0, NAMED = 1, KEYED = 2 }; 56 Reference(CodeGenerator* cgen, 57 Expression* expression, 58 bool persist_after_get = false); 59 ~Reference(); 60 61 Expression* expression() const { return expression_; } 62 Type type() const { return type_; } 63 void set_type(Type value) { 64 ASSERT_EQ(ILLEGAL, type_); 65 type_ = value; 66 } 67 68 void set_unloaded() { 69 ASSERT_NE(ILLEGAL, type_); 70 ASSERT_NE(UNLOADED, type_); 71 type_ = UNLOADED; 72 } 73 // The size the reference takes up on the stack. 74 int size() const { 75 return (type_ < SLOT) ? 0 : type_; 76 } 77 78 bool is_illegal() const { return type_ == ILLEGAL; } 79 bool is_slot() const { return type_ == SLOT; } 80 bool is_property() const { return type_ == NAMED || type_ == KEYED; } 81 bool is_unloaded() const { return type_ == UNLOADED; } 82 83 // Return the name. Only valid for named property references. 84 Handle<String> GetName(); 85 86 // Generate code to push the value of the reference on top of the 87 // expression stack. The reference is expected to be already on top of 88 // the expression stack, and it is consumed by the call unless the 89 // reference is for a compound assignment. 90 // If the reference is not consumed, it is left in place under its value. 91 void GetValue(); 92 93 // Generate code to pop a reference, push the value of the reference, 94 // and then spill the stack frame. 95 inline void GetValueAndSpill(); 96 97 // Generate code to store the value on top of the expression stack in the 98 // reference. The reference is expected to be immediately below the value 99 // on the expression stack. The value is stored in the location specified 100 // by the reference, and is left on top of the stack, after the reference 101 // is popped from beneath it (unloaded). 102 void SetValue(InitState init_state); 103 104 private: 105 CodeGenerator* cgen_; 106 Expression* expression_; 107 Type type_; 108 // Keep the reference on the stack after get, so it can be used by set later. 109 bool persist_after_get_; 110}; 111 112 113// ------------------------------------------------------------------------- 114// Code generation state 115 116// The state is passed down the AST by the code generator (and back up, in 117// the form of the state of the label pair). It is threaded through the 118// call stack. Constructing a state implicitly pushes it on the owning code 119// generator's stack of states, and destroying one implicitly pops it. 120 121class CodeGenState BASE_EMBEDDED { 122 public: 123 // Create an initial code generator state. Destroying the initial state 124 // leaves the code generator with a NULL state. 125 explicit CodeGenState(CodeGenerator* owner); 126 127 // Create a code generator state based on a code generator's current 128 // state. The new state has its own pair of branch labels. 129 CodeGenState(CodeGenerator* owner, 130 JumpTarget* true_target, 131 JumpTarget* false_target); 132 133 // Destroy a code generator state and restore the owning code generator's 134 // previous state. 135 ~CodeGenState(); 136 137 JumpTarget* true_target() const { return true_target_; } 138 JumpTarget* false_target() const { return false_target_; } 139 140 private: 141 CodeGenerator* owner_; 142 JumpTarget* true_target_; 143 JumpTarget* false_target_; 144 CodeGenState* previous_; 145}; 146 147 148// ------------------------------------------------------------------------- 149// CodeGenerator 150 151class CodeGenerator: public AstVisitor { 152 public: 153 // Takes a function literal, generates code for it. This function should only 154 // be called by compiler.cc. 155 static Handle<Code> MakeCode(CompilationInfo* info); 156 157 // Printing of AST, etc. as requested by flags. 158 static void MakeCodePrologue(CompilationInfo* info); 159 160 // Allocate and install the code. 161 static Handle<Code> MakeCodeEpilogue(MacroAssembler* masm, 162 Code::Flags flags, 163 CompilationInfo* info); 164 165#ifdef ENABLE_LOGGING_AND_PROFILING 166 static bool ShouldGenerateLog(Expression* type); 167#endif 168 169 static void SetFunctionInfo(Handle<JSFunction> fun, 170 FunctionLiteral* lit, 171 bool is_toplevel, 172 Handle<Script> script); 173 174 static void RecordPositions(MacroAssembler* masm, int pos); 175 176 // Accessors 177 MacroAssembler* masm() { return masm_; } 178 VirtualFrame* frame() const { return frame_; } 179 inline Handle<Script> script(); 180 181 bool has_valid_frame() const { return frame_ != NULL; } 182 183 // Set the virtual frame to be new_frame, with non-frame register 184 // reference counts given by non_frame_registers. The non-frame 185 // register reference counts of the old frame are returned in 186 // non_frame_registers. 187 void SetFrame(VirtualFrame* new_frame, RegisterFile* non_frame_registers); 188 189 void DeleteFrame(); 190 191 RegisterAllocator* allocator() const { return allocator_; } 192 193 CodeGenState* state() { return state_; } 194 void set_state(CodeGenState* state) { state_ = state; } 195 196 void AddDeferred(DeferredCode* code) { deferred_.Add(code); } 197 198 static const int kUnknownIntValue = -1; 199 200 private: 201 // Construction/Destruction 202 explicit CodeGenerator(MacroAssembler* masm); 203 204 // Accessors 205 inline bool is_eval(); 206 Scope* scope(); 207 208 // Generating deferred code. 209 void ProcessDeferred(); 210 211 // State 212 bool has_cc() const { return cc_reg_ != al; } 213 JumpTarget* true_target() const { return state_->true_target(); } 214 JumpTarget* false_target() const { return state_->false_target(); } 215 216 // We don't track loop nesting level on ARM yet. 217 int loop_nesting() const { return 0; } 218 219 // Node visitors. 220 void VisitStatements(ZoneList<Statement*>* statements); 221 222#define DEF_VISIT(type) \ 223 void Visit##type(type* node); 224 AST_NODE_LIST(DEF_VISIT) 225#undef DEF_VISIT 226 227 // Visit a statement and then spill the virtual frame if control flow can 228 // reach the end of the statement (ie, it does not exit via break, 229 // continue, return, or throw). This function is used temporarily while 230 // the code generator is being transformed. 231 inline void VisitAndSpill(Statement* statement); 232 233 // Visit a list of statements and then spill the virtual frame if control 234 // flow can reach the end of the list. 235 inline void VisitStatementsAndSpill(ZoneList<Statement*>* statements); 236 237 // Main code generation function 238 void Generate(CompilationInfo* info); 239 240 // The following are used by class Reference. 241 void LoadReference(Reference* ref); 242 void UnloadReference(Reference* ref); 243 244 static MemOperand ContextOperand(Register context, int index) { 245 return MemOperand(context, Context::SlotOffset(index)); 246 } 247 248 MemOperand SlotOperand(Slot* slot, Register tmp); 249 250 MemOperand ContextSlotOperandCheckExtensions(Slot* slot, 251 Register tmp, 252 Register tmp2, 253 JumpTarget* slow); 254 255 // Expressions 256 static MemOperand GlobalObject() { 257 return ContextOperand(cp, Context::GLOBAL_INDEX); 258 } 259 260 void LoadCondition(Expression* x, 261 JumpTarget* true_target, 262 JumpTarget* false_target, 263 bool force_cc); 264 void Load(Expression* expr); 265 void LoadGlobal(); 266 void LoadGlobalReceiver(Register scratch); 267 268 // Generate code to push the value of an expression on top of the frame 269 // and then spill the frame fully to memory. This function is used 270 // temporarily while the code generator is being transformed. 271 inline void LoadAndSpill(Expression* expression); 272 273 // Call LoadCondition and then spill the virtual frame unless control flow 274 // cannot reach the end of the expression (ie, by emitting only 275 // unconditional jumps to the control targets). 276 inline void LoadConditionAndSpill(Expression* expression, 277 JumpTarget* true_target, 278 JumpTarget* false_target, 279 bool force_control); 280 281 // Read a value from a slot and leave it on top of the expression stack. 282 void LoadFromSlot(Slot* slot, TypeofState typeof_state); 283 // Store the value on top of the stack to a slot. 284 void StoreToSlot(Slot* slot, InitState init_state); 285 // Load a keyed property, leaving it in r0. The receiver and key are 286 // passed on the stack, and remain there. 287 void EmitKeyedLoad(bool is_global); 288 289 void LoadFromGlobalSlotCheckExtensions(Slot* slot, 290 TypeofState typeof_state, 291 Register tmp, 292 Register tmp2, 293 JumpTarget* slow); 294 295 // Special code for typeof expressions: Unfortunately, we must 296 // be careful when loading the expression in 'typeof' 297 // expressions. We are not allowed to throw reference errors for 298 // non-existing properties of the global object, so we must make it 299 // look like an explicit property access, instead of an access 300 // through the context chain. 301 void LoadTypeofExpression(Expression* x); 302 303 void ToBoolean(JumpTarget* true_target, JumpTarget* false_target); 304 305 void GenericBinaryOperation(Token::Value op, 306 OverwriteMode overwrite_mode, 307 int known_rhs = kUnknownIntValue); 308 void Comparison(Condition cc, 309 Expression* left, 310 Expression* right, 311 bool strict = false); 312 313 void SmiOperation(Token::Value op, 314 Handle<Object> value, 315 bool reversed, 316 OverwriteMode mode); 317 318 void CallWithArguments(ZoneList<Expression*>* arguments, 319 CallFunctionFlags flags, 320 int position); 321 322 // Control flow 323 void Branch(bool if_true, JumpTarget* target); 324 void CheckStack(); 325 326 struct InlineRuntimeLUT { 327 void (CodeGenerator::*method)(ZoneList<Expression*>*); 328 const char* name; 329 }; 330 331 static InlineRuntimeLUT* FindInlineRuntimeLUT(Handle<String> name); 332 bool CheckForInlineRuntimeCall(CallRuntime* node); 333 static bool PatchInlineRuntimeEntry(Handle<String> name, 334 const InlineRuntimeLUT& new_entry, 335 InlineRuntimeLUT* old_entry); 336 337 static Handle<Code> ComputeLazyCompile(int argc); 338 void ProcessDeclarations(ZoneList<Declaration*>* declarations); 339 340 static Handle<Code> ComputeCallInitialize(int argc, InLoopFlag in_loop); 341 342 // Declare global variables and functions in the given array of 343 // name/value pairs. 344 void DeclareGlobals(Handle<FixedArray> pairs); 345 346 // Instantiate the function boilerplate. 347 void InstantiateBoilerplate(Handle<JSFunction> boilerplate); 348 349 // Support for type checks. 350 void GenerateIsSmi(ZoneList<Expression*>* args); 351 void GenerateIsNonNegativeSmi(ZoneList<Expression*>* args); 352 void GenerateIsArray(ZoneList<Expression*>* args); 353 void GenerateIsRegExp(ZoneList<Expression*>* args); 354 void GenerateIsObject(ZoneList<Expression*>* args); 355 void GenerateIsFunction(ZoneList<Expression*>* args); 356 void GenerateIsUndetectableObject(ZoneList<Expression*>* args); 357 358 // Support for construct call checks. 359 void GenerateIsConstructCall(ZoneList<Expression*>* args); 360 361 // Support for arguments.length and arguments[?]. 362 void GenerateArgumentsLength(ZoneList<Expression*>* args); 363 void GenerateArgumentsAccess(ZoneList<Expression*>* args); 364 365 // Support for accessing the class and value fields of an object. 366 void GenerateClassOf(ZoneList<Expression*>* args); 367 void GenerateValueOf(ZoneList<Expression*>* args); 368 void GenerateSetValueOf(ZoneList<Expression*>* args); 369 370 // Fast support for charCodeAt(n). 371 void GenerateFastCharCodeAt(ZoneList<Expression*>* args); 372 373 // Fast support for object equality testing. 374 void GenerateObjectEquals(ZoneList<Expression*>* args); 375 376 void GenerateLog(ZoneList<Expression*>* args); 377 378 // Fast support for Math.random(). 379 void GenerateRandomPositiveSmi(ZoneList<Expression*>* args); 380 381 // Fast support for StringAdd. 382 void GenerateStringAdd(ZoneList<Expression*>* args); 383 384 // Fast support for SubString. 385 void GenerateSubString(ZoneList<Expression*>* args); 386 387 // Fast support for StringCompare. 388 void GenerateStringCompare(ZoneList<Expression*>* args); 389 390 // Support for direct calls from JavaScript to native RegExp code. 391 void GenerateRegExpExec(ZoneList<Expression*>* args); 392 393 // Fast support for number to string. 394 void GenerateNumberToString(ZoneList<Expression*>* args); 395 396 // Fast call to sine function. 397 void GenerateMathSin(ZoneList<Expression*>* args); 398 void GenerateMathCos(ZoneList<Expression*>* args); 399 400 // Simple condition analysis. 401 enum ConditionAnalysis { 402 ALWAYS_TRUE, 403 ALWAYS_FALSE, 404 DONT_KNOW 405 }; 406 ConditionAnalysis AnalyzeCondition(Expression* cond); 407 408 // Methods used to indicate which source code is generated for. Source 409 // positions are collected by the assembler and emitted with the relocation 410 // information. 411 void CodeForFunctionPosition(FunctionLiteral* fun); 412 void CodeForReturnPosition(FunctionLiteral* fun); 413 void CodeForStatementPosition(Statement* node); 414 void CodeForDoWhileConditionPosition(DoWhileStatement* stmt); 415 void CodeForSourcePosition(int pos); 416 417#ifdef DEBUG 418 // True if the registers are valid for entry to a block. 419 bool HasValidEntryRegisters(); 420#endif 421 422 List<DeferredCode*> deferred_; 423 424 // Assembler 425 MacroAssembler* masm_; // to generate code 426 427 CompilationInfo* info_; 428 429 // Code generation state 430 VirtualFrame* frame_; 431 RegisterAllocator* allocator_; 432 Condition cc_reg_; 433 CodeGenState* state_; 434 435 // Jump targets 436 BreakTarget function_return_; 437 438 // True if the function return is shadowed (ie, jumping to the target 439 // function_return_ does not jump to the true function return, but rather 440 // to some unlinking code). 441 bool function_return_is_shadowed_; 442 443 static InlineRuntimeLUT kInlineRuntimeLUT[]; 444 445 friend class VirtualFrame; 446 friend class JumpTarget; 447 friend class Reference; 448 friend class FastCodeGenerator; 449 friend class FullCodeGenerator; 450 friend class FullCodeGenSyntaxChecker; 451 452 DISALLOW_COPY_AND_ASSIGN(CodeGenerator); 453}; 454 455 456class GenericBinaryOpStub : public CodeStub { 457 public: 458 GenericBinaryOpStub(Token::Value op, 459 OverwriteMode mode, 460 int constant_rhs = CodeGenerator::kUnknownIntValue) 461 : op_(op), 462 mode_(mode), 463 constant_rhs_(constant_rhs), 464 specialized_on_rhs_(RhsIsOneWeWantToOptimizeFor(op, constant_rhs)), 465 name_(NULL) { } 466 467 private: 468 Token::Value op_; 469 OverwriteMode mode_; 470 int constant_rhs_; 471 bool specialized_on_rhs_; 472 char* name_; 473 474 static const int kMaxKnownRhs = 0x40000000; 475 476 // Minor key encoding in 16 bits. 477 class ModeBits: public BitField<OverwriteMode, 0, 2> {}; 478 class OpBits: public BitField<Token::Value, 2, 6> {}; 479 class KnownIntBits: public BitField<int, 8, 8> {}; 480 481 Major MajorKey() { return GenericBinaryOp; } 482 int MinorKey() { 483 // Encode the parameters in a unique 16 bit value. 484 return OpBits::encode(op_) 485 | ModeBits::encode(mode_) 486 | KnownIntBits::encode(MinorKeyForKnownInt()); 487 } 488 489 void Generate(MacroAssembler* masm); 490 void HandleNonSmiBitwiseOp(MacroAssembler* masm); 491 492 static bool RhsIsOneWeWantToOptimizeFor(Token::Value op, int constant_rhs) { 493 if (constant_rhs == CodeGenerator::kUnknownIntValue) return false; 494 if (op == Token::DIV) return constant_rhs >= 2 && constant_rhs <= 3; 495 if (op == Token::MOD) { 496 if (constant_rhs <= 1) return false; 497 if (constant_rhs <= 10) return true; 498 if (constant_rhs <= kMaxKnownRhs && IsPowerOf2(constant_rhs)) return true; 499 return false; 500 } 501 return false; 502 } 503 504 int MinorKeyForKnownInt() { 505 if (!specialized_on_rhs_) return 0; 506 if (constant_rhs_ <= 10) return constant_rhs_ + 1; 507 ASSERT(IsPowerOf2(constant_rhs_)); 508 int key = 12; 509 int d = constant_rhs_; 510 while ((d & 1) == 0) { 511 key++; 512 d >>= 1; 513 } 514 return key; 515 } 516 517 const char* GetName(); 518 519#ifdef DEBUG 520 void Print() { 521 if (!specialized_on_rhs_) { 522 PrintF("GenericBinaryOpStub (%s)\n", Token::String(op_)); 523 } else { 524 PrintF("GenericBinaryOpStub (%s by %d)\n", 525 Token::String(op_), 526 constant_rhs_); 527 } 528 } 529#endif 530}; 531 532 533class StringStubBase: public CodeStub { 534 public: 535 // Generate code for copying characters using a simple loop. This should only 536 // be used in places where the number of characters is small and the 537 // additional setup and checking in GenerateCopyCharactersLong adds too much 538 // overhead. Copying of overlapping regions is not supported. 539 // Dest register ends at the position after the last character written. 540 void GenerateCopyCharacters(MacroAssembler* masm, 541 Register dest, 542 Register src, 543 Register count, 544 Register scratch, 545 bool ascii); 546 547 // Generate code for copying a large number of characters. This function 548 // is allowed to spend extra time setting up conditions to make copying 549 // faster. Copying of overlapping regions is not supported. 550 // Dest register ends at the position after the last character written. 551 void GenerateCopyCharactersLong(MacroAssembler* masm, 552 Register dest, 553 Register src, 554 Register count, 555 Register scratch1, 556 Register scratch2, 557 Register scratch3, 558 Register scratch4, 559 Register scratch5, 560 int flags); 561}; 562 563 564// Flag that indicates how to generate code for the stub StringAddStub. 565enum StringAddFlags { 566 NO_STRING_ADD_FLAGS = 0, 567 NO_STRING_CHECK_IN_STUB = 1 << 0 // Omit string check in stub. 568}; 569 570 571class StringAddStub: public StringStubBase { 572 public: 573 explicit StringAddStub(StringAddFlags flags) { 574 string_check_ = ((flags & NO_STRING_CHECK_IN_STUB) == 0); 575 } 576 577 private: 578 Major MajorKey() { return StringAdd; } 579 int MinorKey() { return string_check_ ? 0 : 1; } 580 581 void Generate(MacroAssembler* masm); 582 583 // Should the stub check whether arguments are strings? 584 bool string_check_; 585}; 586 587 588class SubStringStub: public StringStubBase { 589 public: 590 SubStringStub() {} 591 592 private: 593 Major MajorKey() { return SubString; } 594 int MinorKey() { return 0; } 595 596 void Generate(MacroAssembler* masm); 597}; 598 599 600 601class StringCompareStub: public CodeStub { 602 public: 603 StringCompareStub() { } 604 605 // Compare two flat ASCII strings and returns result in r0. 606 // Does not use the stack. 607 static void GenerateCompareFlatAsciiStrings(MacroAssembler* masm, 608 Register left, 609 Register right, 610 Register scratch1, 611 Register scratch2, 612 Register scratch3, 613 Register scratch4); 614 615 private: 616 Major MajorKey() { return StringCompare; } 617 int MinorKey() { return 0; } 618 619 void Generate(MacroAssembler* masm); 620}; 621 622 623} } // namespace v8::internal 624 625#endif // V8_ARM_CODEGEN_ARM_H_ 626