| OLD | NEW |
| 1 // Copyright 2006-2008 the V8 project authors. All rights reserved. | 1 // Copyright 2006-2008 the V8 project authors. All rights reserved. |
| 2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
| 3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
| 4 // met: | 4 // met: |
| 5 // | 5 // |
| 6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
| 7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
| 8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
| 9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
| 10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
| (...skipping 12 matching lines...) Expand all Loading... |
| 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 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. | 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 27 | 27 |
| 28 #include "v8.h" | 28 #include "v8.h" |
| 29 | 29 |
| 30 #include "bootstrapper.h" | 30 #include "bootstrapper.h" |
| 31 #include "codegen-inl.h" | 31 #include "codegen-inl.h" |
| 32 #include "debug.h" | 32 #include "debug.h" |
| 33 #include "prettyprinter.h" | |
| 34 #include "scopeinfo.h" | |
| 35 #include "scopes.h" | 33 #include "scopes.h" |
| 36 #include "runtime.h" | 34 #include "runtime.h" |
| 37 | 35 |
| 38 namespace v8 { namespace internal { | 36 namespace v8 { namespace internal { |
| 39 | 37 |
| 40 class ArmCodeGenerator; | |
| 41 | |
| 42 | |
| 43 // ----------------------------------------------------------------------------- | |
| 44 // Reference support | |
| 45 | |
| 46 // A reference is a C++ stack-allocated object that keeps an ECMA | |
| 47 // reference on the execution stack while in scope. For variables | |
| 48 // the reference is empty, indicating that it isn't necessary to | |
| 49 // store state on the stack for keeping track of references to those. | |
| 50 // For properties, we keep either one (named) or two (indexed) values | |
| 51 // on the execution stack to represent the reference. | |
| 52 | |
| 53 enum InitState { CONST_INIT, NOT_CONST_INIT }; | |
| 54 enum TypeofState { INSIDE_TYPEOF, NOT_INSIDE_TYPEOF }; | |
| 55 | |
| 56 class Reference BASE_EMBEDDED { | |
| 57 public: | |
| 58 // The values of the types is important, see size(). | |
| 59 enum Type { ILLEGAL = -1, SLOT = 0, NAMED = 1, KEYED = 2 }; | |
| 60 Reference(ArmCodeGenerator* cgen, Expression* expression); | |
| 61 ~Reference(); | |
| 62 | |
| 63 Expression* expression() const { return expression_; } | |
| 64 Type type() const { return type_; } | |
| 65 void set_type(Type value) { | |
| 66 ASSERT(type_ == ILLEGAL); | |
| 67 type_ = value; | |
| 68 } | |
| 69 // The size of the reference or -1 if the reference is illegal. | |
| 70 int size() const { return type_; } | |
| 71 | |
| 72 bool is_illegal() const { return type_ == ILLEGAL; } | |
| 73 bool is_slot() const { return type_ == SLOT; } | |
| 74 bool is_property() const { return type_ == NAMED || type_ == KEYED; } | |
| 75 | |
| 76 // Return the name. Only valid for named property references. | |
| 77 Handle<String> GetName(); | |
| 78 | |
| 79 // Generate code to push the value of the reference on top of the | |
| 80 // expression stack. The reference is expected to be already on top of | |
| 81 // the expression stack, and it is left in place with its value above it. | |
| 82 void GetValue(TypeofState typeof_state); | |
| 83 | |
| 84 // Generate code to store the value on top of the expression stack in the | |
| 85 // reference. The reference is expected to be immediately below the value | |
| 86 // on the expression stack. The stored value is left in place (with the | |
| 87 // reference intact below it) to support chained assignments. | |
| 88 void SetValue(InitState init_state); | |
| 89 | |
| 90 private: | |
| 91 ArmCodeGenerator* cgen_; | |
| 92 Expression* expression_; | |
| 93 Type type_; | |
| 94 }; | |
| 95 | |
| 96 | |
| 97 // ------------------------------------------------------------------------- | |
| 98 // Code generation state | |
| 99 | |
| 100 // The state is passed down the AST by the code generator (and back up, in | |
| 101 // the form of the state of the label pair). It is threaded through the | |
| 102 // call stack. Constructing a state implicitly pushes it on the owning code | |
| 103 // generator's stack of states, and destroying one implicitly pops it. | |
| 104 | |
| 105 class CodeGenState BASE_EMBEDDED { | |
| 106 public: | |
| 107 // Create an initial code generator state. Destroying the initial state | |
| 108 // leaves the code generator with a NULL state. | |
| 109 explicit CodeGenState(ArmCodeGenerator* owner); | |
| 110 | |
| 111 // Create a code generator state based on a code generator's current | |
| 112 // state. The new state has its own typeof state and pair of branch | |
| 113 // labels. | |
| 114 CodeGenState(ArmCodeGenerator* owner, | |
| 115 TypeofState typeof_state, | |
| 116 Label* true_target, | |
| 117 Label* false_target); | |
| 118 | |
| 119 // Destroy a code generator state and restore the owning code generator's | |
| 120 // previous state. | |
| 121 ~CodeGenState(); | |
| 122 | |
| 123 TypeofState typeof_state() const { return typeof_state_; } | |
| 124 Label* true_target() const { return true_target_; } | |
| 125 Label* false_target() const { return false_target_; } | |
| 126 | |
| 127 private: | |
| 128 ArmCodeGenerator* owner_; | |
| 129 TypeofState typeof_state_; | |
| 130 Label* true_target_; | |
| 131 Label* false_target_; | |
| 132 CodeGenState* previous_; | |
| 133 }; | |
| 134 | |
| 135 | |
| 136 // ----------------------------------------------------------------------------- | |
| 137 // ArmCodeGenerator | |
| 138 | |
| 139 class ArmCodeGenerator: public CodeGenerator { | |
| 140 public: | |
| 141 static Handle<Code> MakeCode(FunctionLiteral* fun, | |
| 142 Handle<Script> script, | |
| 143 bool is_eval); | |
| 144 | |
| 145 MacroAssembler* masm() { return masm_; } | |
| 146 | |
| 147 Scope* scope() const { return scope_; } | |
| 148 | |
| 149 CodeGenState* state() { return state_; } | |
| 150 void set_state(CodeGenState* state) { state_ = state; } | |
| 151 | |
| 152 private: | |
| 153 // Assembler | |
| 154 MacroAssembler* masm_; // to generate code | |
| 155 | |
| 156 // Code generation state | |
| 157 Scope* scope_; | |
| 158 Condition cc_reg_; | |
| 159 CodeGenState* state_; | |
| 160 int break_stack_height_; | |
| 161 | |
| 162 // Labels | |
| 163 Label function_return_; | |
| 164 | |
| 165 // Construction/destruction | |
| 166 ArmCodeGenerator(int buffer_size, | |
| 167 Handle<Script> script, | |
| 168 bool is_eval); | |
| 169 | |
| 170 virtual ~ArmCodeGenerator() { delete masm_; } | |
| 171 | |
| 172 // Main code generation function | |
| 173 void GenCode(FunctionLiteral* fun); | |
| 174 | |
| 175 // The following are used by class Reference. | |
| 176 void LoadReference(Reference* ref); | |
| 177 void UnloadReference(Reference* ref); | |
| 178 | |
| 179 // State | |
| 180 bool has_cc() const { return cc_reg_ != al; } | |
| 181 TypeofState typeof_state() const { return state_->typeof_state(); } | |
| 182 Label* true_target() const { return state_->true_target(); } | |
| 183 Label* false_target() const { return state_->false_target(); } | |
| 184 | |
| 185 | |
| 186 // Expressions | |
| 187 MemOperand GlobalObject() const { | |
| 188 return ContextOperand(cp, Context::GLOBAL_INDEX); | |
| 189 } | |
| 190 | |
| 191 MemOperand ContextOperand(Register context, int index) const { | |
| 192 return MemOperand(context, Context::SlotOffset(index)); | |
| 193 } | |
| 194 | |
| 195 MemOperand ParameterOperand(int index) const { | |
| 196 int num_parameters = scope()->num_parameters(); | |
| 197 // index -2 corresponds to the activated closure, -1 corresponds | |
| 198 // to the receiver | |
| 199 ASSERT(-2 <= index && index < num_parameters); | |
| 200 int offset = (1 + num_parameters - index) * kPointerSize; | |
| 201 return MemOperand(fp, offset); | |
| 202 } | |
| 203 | |
| 204 MemOperand FunctionOperand() const { | |
| 205 return MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset); | |
| 206 } | |
| 207 | |
| 208 MemOperand SlotOperand(Slot* slot, Register tmp); | |
| 209 | |
| 210 void LoadCondition(Expression* x, | |
| 211 TypeofState typeof_state, | |
| 212 Label* true_target, | |
| 213 Label* false_target, | |
| 214 bool force_cc); | |
| 215 void Load(Expression* x, TypeofState typeof_state = NOT_INSIDE_TYPEOF); | |
| 216 void LoadGlobal(); | |
| 217 | |
| 218 // Read a value from a slot and leave it on top of the expression stack. | |
| 219 void LoadFromSlot(Slot* slot, TypeofState typeof_state); | |
| 220 | |
| 221 // Special code for typeof expressions: Unfortunately, we must | |
| 222 // be careful when loading the expression in 'typeof' | |
| 223 // expressions. We are not allowed to throw reference errors for | |
| 224 // non-existing properties of the global object, so we must make it | |
| 225 // look like an explicit property access, instead of an access | |
| 226 // through the context chain. | |
| 227 void LoadTypeofExpression(Expression* x); | |
| 228 | |
| 229 void ToBoolean(Label* true_target, Label* false_target); | |
| 230 | |
| 231 void GenericBinaryOperation(Token::Value op); | |
| 232 void Comparison(Condition cc, bool strict = false); | |
| 233 | |
| 234 void SmiOperation(Token::Value op, Handle<Object> value, bool reversed); | |
| 235 | |
| 236 void CallWithArguments(ZoneList<Expression*>* arguments, int position); | |
| 237 | |
| 238 // Declare global variables and functions in the given array of | |
| 239 // name/value pairs. | |
| 240 virtual void DeclareGlobals(Handle<FixedArray> pairs); | |
| 241 | |
| 242 // Instantiate the function boilerplate. | |
| 243 void InstantiateBoilerplate(Handle<JSFunction> boilerplate); | |
| 244 | |
| 245 // Control flow | |
| 246 void Branch(bool if_true, Label* L); | |
| 247 void CheckStack(); | |
| 248 void CleanStack(int num_bytes); | |
| 249 | |
| 250 // Node visitors | |
| 251 #define DEF_VISIT(type) \ | |
| 252 virtual void Visit##type(type* node); | |
| 253 NODE_LIST(DEF_VISIT) | |
| 254 #undef DEF_VISIT | |
| 255 | |
| 256 // Fast-case switch | |
| 257 static const int kFastCaseSwitchMaxOverheadFactor = 10; | |
| 258 static const int kFastCaseSwitchMinCaseCount = 5; | |
| 259 virtual int FastCaseSwitchMaxOverheadFactor(); | |
| 260 virtual int FastCaseSwitchMinCaseCount(); | |
| 261 virtual void GenerateFastCaseSwitchJumpTable( | |
| 262 SwitchStatement* node, int min_index, int range, Label *fail_label, | |
| 263 SmartPointer<Label*> &case_targets, SmartPointer<Label> &case_labels); | |
| 264 | |
| 265 void RecordStatementPosition(Node* node); | |
| 266 | |
| 267 // Activation frames | |
| 268 void EnterJSFrame(); | |
| 269 void ExitJSFrame(); | |
| 270 | |
| 271 virtual void GenerateIsSmi(ZoneList<Expression*>* args); | |
| 272 virtual void GenerateIsNonNegativeSmi(ZoneList<Expression*>* args); | |
| 273 virtual void GenerateIsArray(ZoneList<Expression*>* args); | |
| 274 | |
| 275 virtual void GenerateArgumentsLength(ZoneList<Expression*>* args); | |
| 276 virtual void GenerateArgumentsAccess(ZoneList<Expression*>* args); | |
| 277 | |
| 278 virtual void GenerateValueOf(ZoneList<Expression*>* args); | |
| 279 virtual void GenerateSetValueOf(ZoneList<Expression*>* args); | |
| 280 | |
| 281 virtual void GenerateFastCharCodeAt(ZoneList<Expression*>* args); | |
| 282 | |
| 283 virtual void GenerateObjectEquals(ZoneList<Expression*>* args); | |
| 284 | |
| 285 friend class Reference; | |
| 286 friend class Property; | |
| 287 friend class VariableProxy; | |
| 288 friend class Slot; | |
| 289 }; | |
| 290 | |
| 291 | |
| 292 // ------------------------------------------------------------------------- | 38 // ------------------------------------------------------------------------- |
| 293 // CodeGenState implementation. | 39 // CodeGenState implementation. |
| 294 | 40 |
| 295 CodeGenState::CodeGenState(ArmCodeGenerator* owner) | 41 CodeGenState::CodeGenState(CodeGenerator* owner) |
| 296 : owner_(owner), | 42 : owner_(owner), |
| 297 typeof_state_(NOT_INSIDE_TYPEOF), | 43 typeof_state_(NOT_INSIDE_TYPEOF), |
| 298 true_target_(NULL), | 44 true_target_(NULL), |
| 299 false_target_(NULL), | 45 false_target_(NULL), |
| 300 previous_(NULL) { | 46 previous_(NULL) { |
| 301 owner_->set_state(this); | 47 owner_->set_state(this); |
| 302 } | 48 } |
| 303 | 49 |
| 304 | 50 |
| 305 CodeGenState::CodeGenState(ArmCodeGenerator* owner, | 51 CodeGenState::CodeGenState(CodeGenerator* owner, |
| 306 TypeofState typeof_state, | 52 TypeofState typeof_state, |
| 307 Label* true_target, | 53 Label* true_target, |
| 308 Label* false_target) | 54 Label* false_target) |
| 309 : owner_(owner), | 55 : owner_(owner), |
| 310 typeof_state_(typeof_state), | 56 typeof_state_(typeof_state), |
| 311 true_target_(true_target), | 57 true_target_(true_target), |
| 312 false_target_(false_target), | 58 false_target_(false_target), |
| 313 previous_(owner->state()) { | 59 previous_(owner->state()) { |
| 314 owner_->set_state(this); | 60 owner_->set_state(this); |
| 315 } | 61 } |
| 316 | 62 |
| 317 | 63 |
| 318 CodeGenState::~CodeGenState() { | 64 CodeGenState::~CodeGenState() { |
| 319 ASSERT(owner_->state() == this); | 65 ASSERT(owner_->state() == this); |
| 320 owner_->set_state(previous_); | 66 owner_->set_state(previous_); |
| 321 } | 67 } |
| 322 | 68 |
| 323 | 69 |
| 324 // ----------------------------------------------------------------------------- | 70 // ----------------------------------------------------------------------------- |
| 325 // ArmCodeGenerator implementation | 71 // CodeGenerator implementation |
| 326 | 72 |
| 327 #define __ masm_-> | 73 #define __ masm_-> |
| 328 | 74 |
| 329 Handle<Code> ArmCodeGenerator::MakeCode(FunctionLiteral* flit, | 75 CodeGenerator::CodeGenerator(int buffer_size, Handle<Script> script, |
| 330 Handle<Script> script, | 76 bool is_eval) |
| 331 bool is_eval) { | 77 : is_eval_(is_eval), |
| 332 #ifdef ENABLE_DISASSEMBLER | 78 script_(script), |
| 333 bool print_code = FLAG_print_code && !Bootstrapper::IsActive(); | 79 deferred_(8), |
| 334 #endif // ENABLE_DISASSEMBLER | |
| 335 | |
| 336 #ifdef DEBUG | |
| 337 bool print_source = false; | |
| 338 bool print_ast = false; | |
| 339 const char* ftype; | |
| 340 | |
| 341 if (Bootstrapper::IsActive()) { | |
| 342 print_source = FLAG_print_builtin_source; | |
| 343 print_ast = FLAG_print_builtin_ast; | |
| 344 print_code = FLAG_print_builtin_code; | |
| 345 ftype = "builtin"; | |
| 346 } else { | |
| 347 print_source = FLAG_print_source; | |
| 348 print_ast = FLAG_print_ast; | |
| 349 ftype = "user-defined"; | |
| 350 } | |
| 351 | |
| 352 if (FLAG_trace_codegen || print_source || print_ast) { | |
| 353 PrintF("*** Generate code for %s function: ", ftype); | |
| 354 flit->name()->ShortPrint(); | |
| 355 PrintF(" ***\n"); | |
| 356 } | |
| 357 | |
| 358 if (print_source) { | |
| 359 PrintF("--- Source from AST ---\n%s\n", PrettyPrinter().PrintProgram(flit)); | |
| 360 } | |
| 361 | |
| 362 if (print_ast) { | |
| 363 PrintF("--- AST ---\n%s\n", AstPrinter().PrintProgram(flit)); | |
| 364 } | |
| 365 #endif // DEBUG | |
| 366 | |
| 367 // Generate code. | |
| 368 const int initial_buffer_size = 4 * KB; | |
| 369 ArmCodeGenerator cgen(initial_buffer_size, script, is_eval); | |
| 370 cgen.GenCode(flit); | |
| 371 if (cgen.HasStackOverflow()) { | |
| 372 ASSERT(!Top::has_pending_exception()); | |
| 373 return Handle<Code>::null(); | |
| 374 } | |
| 375 | |
| 376 // Process any deferred code. | |
| 377 cgen.ProcessDeferred(); | |
| 378 | |
| 379 // Allocate and install the code. | |
| 380 CodeDesc desc; | |
| 381 cgen.masm()->GetCode(&desc); | |
| 382 ScopeInfo<> sinfo(flit->scope()); | |
| 383 Code::Flags flags = Code::ComputeFlags(Code::FUNCTION); | |
| 384 Handle<Code> code = Factory::NewCode(desc, &sinfo, flags); | |
| 385 | |
| 386 // Add unresolved entries in the code to the fixup list. | |
| 387 Bootstrapper::AddFixup(*code, cgen.masm()); | |
| 388 | |
| 389 #ifdef ENABLE_DISASSEMBLER | |
| 390 if (print_code) { | |
| 391 // Print the source code if available. | |
| 392 if (!script->IsUndefined() && !script->source()->IsUndefined()) { | |
| 393 PrintF("--- Raw source ---\n"); | |
| 394 StringInputBuffer stream(String::cast(script->source())); | |
| 395 stream.Seek(flit->start_position()); | |
| 396 // flit->end_position() points to the last character in the stream. We | |
| 397 // need to compensate by adding one to calculate the length. | |
| 398 int source_len = flit->end_position() - flit->start_position() + 1; | |
| 399 for (int i = 0; i < source_len; i++) { | |
| 400 if (stream.has_more()) PrintF("%c", stream.GetNext()); | |
| 401 } | |
| 402 PrintF("\n\n"); | |
| 403 } | |
| 404 PrintF("--- Code ---\n"); | |
| 405 code->Disassemble(); | |
| 406 } | |
| 407 #endif // ENABLE_DISASSEMBLER | |
| 408 | |
| 409 return code; | |
| 410 } | |
| 411 | |
| 412 | |
| 413 ArmCodeGenerator::ArmCodeGenerator(int buffer_size, | |
| 414 Handle<Script> script, | |
| 415 bool is_eval) | |
| 416 : CodeGenerator(is_eval, script), | |
| 417 masm_(new MacroAssembler(NULL, buffer_size)), | 80 masm_(new MacroAssembler(NULL, buffer_size)), |
| 418 scope_(NULL), | 81 scope_(NULL), |
| 419 cc_reg_(al), | 82 cc_reg_(al), |
| 420 state_(NULL), | 83 state_(NULL), |
| 421 break_stack_height_(0) { | 84 break_stack_height_(0) { |
| 422 } | 85 } |
| 423 | 86 |
| 424 | 87 |
| 425 // Calling conventions: | 88 // Calling conventions: |
| 426 | 89 |
| 427 // r0: the number of arguments | 90 // r0: the number of arguments |
| 428 // fp: frame pointer | 91 // fp: frame pointer |
| 429 // sp: stack pointer | 92 // sp: stack pointer |
| 430 // pp: caller's parameter pointer | 93 // pp: caller's parameter pointer |
| 431 // cp: callee's context | 94 // cp: callee's context |
| 432 | 95 |
| 433 void ArmCodeGenerator::GenCode(FunctionLiteral* fun) { | 96 void CodeGenerator::GenCode(FunctionLiteral* fun) { |
| 434 Scope* scope = fun->scope(); | 97 Scope* scope = fun->scope(); |
| 435 ZoneList<Statement*>* body = fun->body(); | 98 ZoneList<Statement*>* body = fun->body(); |
| 436 | 99 |
| 437 // Initialize state. | 100 // Initialize state. |
| 438 { CodeGenState state(this); | 101 { CodeGenState state(this); |
| 439 scope_ = scope; | 102 scope_ = scope; |
| 440 cc_reg_ = al; | 103 cc_reg_ = al; |
| 441 | 104 |
| 442 // Entry | 105 // Entry |
| 443 // stack: function, receiver, arguments, return address | 106 // stack: function, receiver, arguments, return address |
| (...skipping 169 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 613 __ add(sp, sp, Operand((scope_->num_parameters() + 1) * kPointerSize)); | 276 __ add(sp, sp, Operand((scope_->num_parameters() + 1) * kPointerSize)); |
| 614 __ mov(pc, lr); | 277 __ mov(pc, lr); |
| 615 | 278 |
| 616 // Code generation state must be reset. | 279 // Code generation state must be reset. |
| 617 scope_ = NULL; | 280 scope_ = NULL; |
| 618 ASSERT(!has_cc()); | 281 ASSERT(!has_cc()); |
| 619 ASSERT(state_ == NULL); | 282 ASSERT(state_ == NULL); |
| 620 } | 283 } |
| 621 | 284 |
| 622 | 285 |
| 623 MemOperand ArmCodeGenerator::SlotOperand(Slot* slot, Register tmp) { | 286 MemOperand CodeGenerator::SlotOperand(Slot* slot, Register tmp) { |
| 624 // Currently, this assertion will fail if we try to assign to | 287 // Currently, this assertion will fail if we try to assign to |
| 625 // a constant variable that is constant because it is read-only | 288 // a constant variable that is constant because it is read-only |
| 626 // (such as the variable referring to a named function expression). | 289 // (such as the variable referring to a named function expression). |
| 627 // We need to implement assignments to read-only variables. | 290 // We need to implement assignments to read-only variables. |
| 628 // Ideally, we should do this during AST generation (by converting | 291 // Ideally, we should do this during AST generation (by converting |
| 629 // such assignments into expression statements); however, in general | 292 // such assignments into expression statements); however, in general |
| 630 // we may not be able to make the decision until past AST generation, | 293 // we may not be able to make the decision until past AST generation, |
| 631 // that is when the entire program is known. | 294 // that is when the entire program is known. |
| 632 ASSERT(slot != NULL); | 295 ASSERT(slot != NULL); |
| 633 int index = slot->index(); | 296 int index = slot->index(); |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 672 return MemOperand(r0, 0); | 335 return MemOperand(r0, 0); |
| 673 } | 336 } |
| 674 } | 337 } |
| 675 | 338 |
| 676 | 339 |
| 677 // Loads a value on the stack. If it is a boolean value, the result may have | 340 // Loads a value on the stack. If it is a boolean value, the result may have |
| 678 // been (partially) translated into branches, or it may have set the condition | 341 // been (partially) translated into branches, or it may have set the condition |
| 679 // code register. If force_cc is set, the value is forced to set the condition | 342 // code register. If force_cc is set, the value is forced to set the condition |
| 680 // code register and no value is pushed. If the condition code register was set, | 343 // code register and no value is pushed. If the condition code register was set, |
| 681 // has_cc() is true and cc_reg_ contains the condition to test for 'true'. | 344 // has_cc() is true and cc_reg_ contains the condition to test for 'true'. |
| 682 void ArmCodeGenerator::LoadCondition(Expression* x, | 345 void CodeGenerator::LoadCondition(Expression* x, |
| 683 TypeofState typeof_state, | 346 TypeofState typeof_state, |
| 684 Label* true_target, | 347 Label* true_target, |
| 685 Label* false_target, | 348 Label* false_target, |
| 686 bool force_cc) { | 349 bool force_cc) { |
| 687 ASSERT(!has_cc()); | 350 ASSERT(!has_cc()); |
| 688 | 351 |
| 689 { CodeGenState new_state(this, typeof_state, true_target, false_target); | 352 { CodeGenState new_state(this, typeof_state, true_target, false_target); |
| 690 Visit(x); | 353 Visit(x); |
| 691 } | 354 } |
| 692 if (force_cc && !has_cc()) { | 355 if (force_cc && !has_cc()) { |
| 693 // Convert the TOS value to a boolean in the condition code register. | 356 // Convert the TOS value to a boolean in the condition code register. |
| 694 ToBoolean(true_target, false_target); | 357 ToBoolean(true_target, false_target); |
| 695 } | 358 } |
| 696 ASSERT(has_cc() || !force_cc); | 359 ASSERT(has_cc() || !force_cc); |
| 697 } | 360 } |
| 698 | 361 |
| 699 | 362 |
| 700 void ArmCodeGenerator::Load(Expression* x, TypeofState typeof_state) { | 363 void CodeGenerator::Load(Expression* x, TypeofState typeof_state) { |
| 701 Label true_target; | 364 Label true_target; |
| 702 Label false_target; | 365 Label false_target; |
| 703 LoadCondition(x, typeof_state, &true_target, &false_target, false); | 366 LoadCondition(x, typeof_state, &true_target, &false_target, false); |
| 704 | 367 |
| 705 if (has_cc()) { | 368 if (has_cc()) { |
| 706 // convert cc_reg_ into a bool | 369 // convert cc_reg_ into a bool |
| 707 Label loaded, materialize_true; | 370 Label loaded, materialize_true; |
| 708 __ b(cc_reg_, &materialize_true); | 371 __ b(cc_reg_, &materialize_true); |
| 709 __ mov(r0, Operand(Factory::false_value())); | 372 __ mov(r0, Operand(Factory::false_value())); |
| 710 __ push(r0); | 373 __ push(r0); |
| (...skipping 28 matching lines...) Expand all Loading... |
| 739 __ mov(r0, Operand(Factory::false_value())); | 402 __ mov(r0, Operand(Factory::false_value())); |
| 740 __ push(r0); | 403 __ push(r0); |
| 741 } | 404 } |
| 742 // everything is loaded at this point | 405 // everything is loaded at this point |
| 743 __ bind(&loaded); | 406 __ bind(&loaded); |
| 744 } | 407 } |
| 745 ASSERT(!has_cc()); | 408 ASSERT(!has_cc()); |
| 746 } | 409 } |
| 747 | 410 |
| 748 | 411 |
| 749 void ArmCodeGenerator::LoadGlobal() { | 412 void CodeGenerator::LoadGlobal() { |
| 750 __ ldr(r0, GlobalObject()); | 413 __ ldr(r0, GlobalObject()); |
| 751 __ push(r0); | 414 __ push(r0); |
| 752 } | 415 } |
| 753 | 416 |
| 754 | 417 |
| 755 // TODO(1241834): Get rid of this function in favor of just using Load, now | 418 // TODO(1241834): Get rid of this function in favor of just using Load, now |
| 756 // that we have the INSIDE_TYPEOF typeof state. => Need to handle global | 419 // that we have the INSIDE_TYPEOF typeof state. => Need to handle global |
| 757 // variables w/o reference errors elsewhere. | 420 // variables w/o reference errors elsewhere. |
| 758 void ArmCodeGenerator::LoadTypeofExpression(Expression* x) { | 421 void CodeGenerator::LoadTypeofExpression(Expression* x) { |
| 759 Variable* variable = x->AsVariableProxy()->AsVariable(); | 422 Variable* variable = x->AsVariableProxy()->AsVariable(); |
| 760 if (variable != NULL && !variable->is_this() && variable->is_global()) { | 423 if (variable != NULL && !variable->is_this() && variable->is_global()) { |
| 761 // NOTE: This is somewhat nasty. We force the compiler to load | 424 // NOTE: This is somewhat nasty. We force the compiler to load |
| 762 // the variable as if through '<global>.<variable>' to make sure we | 425 // the variable as if through '<global>.<variable>' to make sure we |
| 763 // do not get reference errors. | 426 // do not get reference errors. |
| 764 Slot global(variable, Slot::CONTEXT, Context::GLOBAL_INDEX); | 427 Slot global(variable, Slot::CONTEXT, Context::GLOBAL_INDEX); |
| 765 Literal key(variable->name()); | 428 Literal key(variable->name()); |
| 766 // TODO(1241834): Fetch the position from the variable instead of using | 429 // TODO(1241834): Fetch the position from the variable instead of using |
| 767 // no position. | 430 // no position. |
| 768 Property property(&global, &key, RelocInfo::kNoPosition); | 431 Property property(&global, &key, RelocInfo::kNoPosition); |
| 769 Load(&property); | 432 Load(&property); |
| 770 } else { | 433 } else { |
| 771 Load(x, INSIDE_TYPEOF); | 434 Load(x, INSIDE_TYPEOF); |
| 772 } | 435 } |
| 773 } | 436 } |
| 774 | 437 |
| 775 | 438 |
| 776 Reference::Reference(ArmCodeGenerator* cgen, Expression* expression) | 439 Reference::Reference(CodeGenerator* cgen, Expression* expression) |
| 777 : cgen_(cgen), expression_(expression), type_(ILLEGAL) { | 440 : cgen_(cgen), expression_(expression), type_(ILLEGAL) { |
| 778 cgen->LoadReference(this); | 441 cgen->LoadReference(this); |
| 779 } | 442 } |
| 780 | 443 |
| 781 | 444 |
| 782 Reference::~Reference() { | 445 Reference::~Reference() { |
| 783 cgen_->UnloadReference(this); | 446 cgen_->UnloadReference(this); |
| 784 } | 447 } |
| 785 | 448 |
| 786 | 449 |
| 787 void ArmCodeGenerator::LoadReference(Reference* ref) { | 450 void CodeGenerator::LoadReference(Reference* ref) { |
| 788 Comment cmnt(masm_, "[ LoadReference"); | 451 Comment cmnt(masm_, "[ LoadReference"); |
| 452 |
| 789 Expression* e = ref->expression(); | 453 Expression* e = ref->expression(); |
| 790 Property* property = e->AsProperty(); | 454 Property* property = e->AsProperty(); |
| 791 Variable* var = e->AsVariableProxy()->AsVariable(); | 455 Variable* var = e->AsVariableProxy()->AsVariable(); |
| 792 | 456 |
| 793 if (property != NULL) { | 457 if (property != NULL) { |
| 794 // The expression is either a property or a variable proxy that rewrites | 458 // The expression is either a property or a variable proxy that rewrites |
| 795 // to a property. | 459 // to a property. |
| 796 Load(property->obj()); | 460 Load(property->obj()); |
| 797 // We use a named reference if the key is a literal symbol, unless it is | 461 // We use a named reference if the key is a literal symbol, unless it is |
| 798 // a string that can be legally parsed as an integer. This is because | 462 // a string that can be legally parsed as an integer. This is because |
| (...skipping 20 matching lines...) Expand all Loading... |
| 819 ref->set_type(Reference::SLOT); | 483 ref->set_type(Reference::SLOT); |
| 820 } | 484 } |
| 821 } else { | 485 } else { |
| 822 // Anything else is a runtime error. | 486 // Anything else is a runtime error. |
| 823 Load(e); | 487 Load(e); |
| 824 __ CallRuntime(Runtime::kThrowReferenceError, 1); | 488 __ CallRuntime(Runtime::kThrowReferenceError, 1); |
| 825 } | 489 } |
| 826 } | 490 } |
| 827 | 491 |
| 828 | 492 |
| 829 void ArmCodeGenerator::UnloadReference(Reference* ref) { | 493 void CodeGenerator::UnloadReference(Reference* ref) { |
| 830 Comment cmnt(masm_, "[ UnloadReference"); | 494 Comment cmnt(masm_, "[ UnloadReference"); |
| 495 |
| 831 int size = ref->size(); | 496 int size = ref->size(); |
| 832 if (size <= 0) { | 497 if (size <= 0) { |
| 833 // Do nothing. No popping is necessary. | 498 // Do nothing. No popping is necessary. |
| 834 } else { | 499 } else { |
| 835 __ pop(r0); | 500 __ pop(r0); |
| 836 __ add(sp, sp, Operand(size * kPointerSize)); | 501 __ add(sp, sp, Operand(size * kPointerSize)); |
| 837 __ push(r0); | 502 __ push(r0); |
| 838 } | 503 } |
| 839 } | 504 } |
| 840 | 505 |
| 841 | 506 |
| 842 // ECMA-262, section 9.2, page 30: ToBoolean(). Convert the given | 507 // ECMA-262, section 9.2, page 30: ToBoolean(). Convert the given |
| 843 // register to a boolean in the condition code register. The code | 508 // register to a boolean in the condition code register. The code |
| 844 // may jump to 'false_target' in case the register converts to 'false'. | 509 // may jump to 'false_target' in case the register converts to 'false'. |
| 845 void ArmCodeGenerator::ToBoolean(Label* true_target, | 510 void CodeGenerator::ToBoolean(Label* true_target, |
| 846 Label* false_target) { | 511 Label* false_target) { |
| 847 // Note: The generated code snippet does not change stack variables. | 512 // Note: The generated code snippet does not change stack variables. |
| 848 // Only the condition code should be set. | 513 // Only the condition code should be set. |
| 849 __ pop(r0); | 514 __ pop(r0); |
| 850 | 515 |
| 851 // Fast case checks | 516 // Fast case checks |
| 852 | 517 |
| 853 // Check if the value is 'false'. | 518 // Check if the value is 'false'. |
| 854 __ cmp(r0, Operand(Factory::false_value())); | 519 __ cmp(r0, Operand(Factory::false_value())); |
| 855 __ b(eq, false_target); | 520 __ b(eq, false_target); |
| (...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 950 #ifdef DEBUG | 615 #ifdef DEBUG |
| 951 void Print() { | 616 void Print() { |
| 952 PrintF("InvokeBuiltinStub (kind %d, argc, %d)\n", | 617 PrintF("InvokeBuiltinStub (kind %d, argc, %d)\n", |
| 953 static_cast<int>(kind_), | 618 static_cast<int>(kind_), |
| 954 argc_); | 619 argc_); |
| 955 } | 620 } |
| 956 #endif | 621 #endif |
| 957 }; | 622 }; |
| 958 | 623 |
| 959 | 624 |
| 960 void ArmCodeGenerator::GenericBinaryOperation(Token::Value op) { | 625 void CodeGenerator::GenericBinaryOperation(Token::Value op) { |
| 961 // sp[0] : y | 626 // sp[0] : y |
| 962 // sp[1] : x | 627 // sp[1] : x |
| 963 // result : r0 | 628 // result : r0 |
| 964 | 629 |
| 965 // Stub is entered with a call: 'return address' is in lr. | 630 // Stub is entered with a call: 'return address' is in lr. |
| 966 switch (op) { | 631 switch (op) { |
| 967 case Token::ADD: // fall through. | 632 case Token::ADD: // fall through. |
| 968 case Token::SUB: // fall through. | 633 case Token::SUB: // fall through. |
| 969 case Token::MUL: | 634 case Token::MUL: |
| 970 case Token::BIT_OR: | 635 case Token::BIT_OR: |
| (...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1075 __ CallStub(&igostub); | 740 __ CallStub(&igostub); |
| 1076 } | 741 } |
| 1077 | 742 |
| 1078 private: | 743 private: |
| 1079 Token::Value op_; | 744 Token::Value op_; |
| 1080 int value_; | 745 int value_; |
| 1081 bool reversed_; | 746 bool reversed_; |
| 1082 }; | 747 }; |
| 1083 | 748 |
| 1084 | 749 |
| 1085 void ArmCodeGenerator::SmiOperation(Token::Value op, | 750 void CodeGenerator::SmiOperation(Token::Value op, |
| 1086 Handle<Object> value, | 751 Handle<Object> value, |
| 1087 bool reversed) { | 752 bool reversed) { |
| 1088 // NOTE: This is an attempt to inline (a bit) more of the code for | 753 // NOTE: This is an attempt to inline (a bit) more of the code for |
| 1089 // some possible smi operations (like + and -) when (at least) one | 754 // some possible smi operations (like + and -) when (at least) one |
| 1090 // of the operands is a literal smi. With this optimization, the | 755 // of the operands is a literal smi. With this optimization, the |
| 1091 // performance of the system is increased by ~15%, and the generated | 756 // performance of the system is increased by ~15%, and the generated |
| 1092 // code size is increased by ~1% (measured on a combination of | 757 // code size is increased by ~1% (measured on a combination of |
| 1093 // different benchmarks). | 758 // different benchmarks). |
| 1094 | 759 |
| 1095 // sp[0] : operand | 760 // sp[0] : operand |
| (...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1210 __ push(r0); | 875 __ push(r0); |
| 1211 } | 876 } |
| 1212 GenericBinaryOperation(op); | 877 GenericBinaryOperation(op); |
| 1213 break; | 878 break; |
| 1214 } | 879 } |
| 1215 | 880 |
| 1216 __ bind(&exit); | 881 __ bind(&exit); |
| 1217 } | 882 } |
| 1218 | 883 |
| 1219 | 884 |
| 1220 void ArmCodeGenerator::Comparison(Condition cc, bool strict) { | 885 void CodeGenerator::Comparison(Condition cc, bool strict) { |
| 1221 // sp[0] : y | 886 // sp[0] : y |
| 1222 // sp[1] : x | 887 // sp[1] : x |
| 1223 // result : cc register | 888 // result : cc register |
| 1224 | 889 |
| 1225 // Strict only makes sense for equality comparisons. | 890 // Strict only makes sense for equality comparisons. |
| 1226 ASSERT(!strict || cc == eq); | 891 ASSERT(!strict || cc == eq); |
| 1227 | 892 |
| 1228 Label exit, smi; | 893 Label exit, smi; |
| 1229 // Implement '>' and '<=' by reversal to obtain ECMA-262 conversion order. | 894 // Implement '>' and '<=' by reversal to obtain ECMA-262 conversion order. |
| 1230 if (cc == gt || cc == le) { | 895 if (cc == gt || cc == le) { |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1291 #if defined(DEBUG) | 956 #if defined(DEBUG) |
| 1292 void Print() { PrintF("CallFunctionStub (argc %d)\n", argc_); } | 957 void Print() { PrintF("CallFunctionStub (argc %d)\n", argc_); } |
| 1293 #endif // defined(DEBUG) | 958 #endif // defined(DEBUG) |
| 1294 | 959 |
| 1295 Major MajorKey() { return CallFunction; } | 960 Major MajorKey() { return CallFunction; } |
| 1296 int MinorKey() { return argc_; } | 961 int MinorKey() { return argc_; } |
| 1297 }; | 962 }; |
| 1298 | 963 |
| 1299 | 964 |
| 1300 // Call the function on the stack with the given arguments. | 965 // Call the function on the stack with the given arguments. |
| 1301 void ArmCodeGenerator::CallWithArguments(ZoneList<Expression*>* args, | 966 void CodeGenerator::CallWithArguments(ZoneList<Expression*>* args, |
| 1302 int position) { | 967 int position) { |
| 1303 // Push the arguments ("left-to-right") on the stack. | 968 // Push the arguments ("left-to-right") on the stack. |
| 1304 for (int i = 0; i < args->length(); i++) { | 969 for (int i = 0; i < args->length(); i++) { |
| 1305 Load(args->at(i)); | 970 Load(args->at(i)); |
| 1306 } | 971 } |
| 1307 | 972 |
| 1308 // Record the position for debugging purposes. | 973 // Record the position for debugging purposes. |
| 1309 __ RecordPosition(position); | 974 __ RecordPosition(position); |
| 1310 | 975 |
| 1311 // Use the shared code stub to call the function. | 976 // Use the shared code stub to call the function. |
| 1312 CallFunctionStub call_function(args->length()); | 977 CallFunctionStub call_function(args->length()); |
| 1313 __ CallStub(&call_function); | 978 __ CallStub(&call_function); |
| 1314 | 979 |
| 1315 // Restore context and pop function from the stack. | 980 // Restore context and pop function from the stack. |
| 1316 __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); | 981 __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); |
| 1317 __ pop(); // discard the TOS | 982 __ pop(); // discard the TOS |
| 1318 } | 983 } |
| 1319 | 984 |
| 1320 | 985 |
| 1321 void ArmCodeGenerator::Branch(bool if_true, Label* L) { | 986 void CodeGenerator::Branch(bool if_true, Label* L) { |
| 1322 ASSERT(has_cc()); | 987 ASSERT(has_cc()); |
| 1323 Condition cc = if_true ? cc_reg_ : NegateCondition(cc_reg_); | 988 Condition cc = if_true ? cc_reg_ : NegateCondition(cc_reg_); |
| 1324 __ b(cc, L); | 989 __ b(cc, L); |
| 1325 cc_reg_ = al; | 990 cc_reg_ = al; |
| 1326 } | 991 } |
| 1327 | 992 |
| 1328 | 993 |
| 1329 void ArmCodeGenerator::CheckStack() { | 994 void CodeGenerator::CheckStack() { |
| 1330 if (FLAG_check_stack) { | 995 if (FLAG_check_stack) { |
| 1331 Comment cmnt(masm_, "[ check stack"); | 996 Comment cmnt(masm_, "[ check stack"); |
| 1332 StackCheckStub stub; | 997 StackCheckStub stub; |
| 1333 __ CallStub(&stub); | 998 __ CallStub(&stub); |
| 1334 } | 999 } |
| 1335 } | 1000 } |
| 1336 | 1001 |
| 1337 | 1002 |
| 1338 void ArmCodeGenerator::VisitBlock(Block* node) { | 1003 void CodeGenerator::VisitBlock(Block* node) { |
| 1339 Comment cmnt(masm_, "[ Block"); | 1004 Comment cmnt(masm_, "[ Block"); |
| 1340 if (FLAG_debug_info) RecordStatementPosition(node); | 1005 if (FLAG_debug_info) RecordStatementPosition(node); |
| 1341 node->set_break_stack_height(break_stack_height_); | 1006 node->set_break_stack_height(break_stack_height_); |
| 1342 VisitStatements(node->statements()); | 1007 VisitStatements(node->statements()); |
| 1343 __ bind(node->break_target()); | 1008 __ bind(node->break_target()); |
| 1344 } | 1009 } |
| 1345 | 1010 |
| 1346 | 1011 |
| 1347 void ArmCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) { | 1012 void CodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) { |
| 1348 __ mov(r0, Operand(pairs)); | 1013 __ mov(r0, Operand(pairs)); |
| 1349 __ push(r0); | 1014 __ push(r0); |
| 1350 __ push(cp); | 1015 __ push(cp); |
| 1351 __ mov(r0, Operand(Smi::FromInt(is_eval() ? 1 : 0))); | 1016 __ mov(r0, Operand(Smi::FromInt(is_eval() ? 1 : 0))); |
| 1352 __ push(r0); | 1017 __ push(r0); |
| 1353 __ CallRuntime(Runtime::kDeclareGlobals, 3); | 1018 __ CallRuntime(Runtime::kDeclareGlobals, 3); |
| 1354 // The result is discarded. | 1019 // The result is discarded. |
| 1355 } | 1020 } |
| 1356 | 1021 |
| 1357 | 1022 |
| 1358 void ArmCodeGenerator::VisitDeclaration(Declaration* node) { | 1023 void CodeGenerator::VisitDeclaration(Declaration* node) { |
| 1359 Comment cmnt(masm_, "[ Declaration"); | 1024 Comment cmnt(masm_, "[ Declaration"); |
| 1360 Variable* var = node->proxy()->var(); | 1025 Variable* var = node->proxy()->var(); |
| 1361 ASSERT(var != NULL); // must have been resolved | 1026 ASSERT(var != NULL); // must have been resolved |
| 1362 Slot* slot = var->slot(); | 1027 Slot* slot = var->slot(); |
| 1363 | 1028 |
| 1364 // If it was not possible to allocate the variable at compile time, | 1029 // If it was not possible to allocate the variable at compile time, |
| 1365 // we need to "declare" it at runtime to make sure it actually | 1030 // we need to "declare" it at runtime to make sure it actually |
| 1366 // exists in the local context. | 1031 // exists in the local context. |
| 1367 if (slot != NULL && slot->type() == Slot::LOOKUP) { | 1032 if (slot != NULL && slot->type() == Slot::LOOKUP) { |
| 1368 // Variables with a "LOOKUP" slot were introduced as non-locals | 1033 // Variables with a "LOOKUP" slot were introduced as non-locals |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1413 target.SetValue(NOT_CONST_INIT); | 1078 target.SetValue(NOT_CONST_INIT); |
| 1414 // Get rid of the assigned value (declarations are statements). It's | 1079 // Get rid of the assigned value (declarations are statements). It's |
| 1415 // safe to pop the value lying on top of the reference before unloading | 1080 // safe to pop the value lying on top of the reference before unloading |
| 1416 // the reference itself (which preserves the top of stack) because we | 1081 // the reference itself (which preserves the top of stack) because we |
| 1417 // know it is a zero-sized reference. | 1082 // know it is a zero-sized reference. |
| 1418 __ pop(); | 1083 __ pop(); |
| 1419 } | 1084 } |
| 1420 } | 1085 } |
| 1421 | 1086 |
| 1422 | 1087 |
| 1423 void ArmCodeGenerator::VisitExpressionStatement(ExpressionStatement* node) { | 1088 void CodeGenerator::VisitExpressionStatement(ExpressionStatement* node) { |
| 1424 Comment cmnt(masm_, "[ ExpressionStatement"); | 1089 Comment cmnt(masm_, "[ ExpressionStatement"); |
| 1425 if (FLAG_debug_info) RecordStatementPosition(node); | 1090 if (FLAG_debug_info) RecordStatementPosition(node); |
| 1426 Expression* expression = node->expression(); | 1091 Expression* expression = node->expression(); |
| 1427 expression->MarkAsStatement(); | 1092 expression->MarkAsStatement(); |
| 1428 Load(expression); | 1093 Load(expression); |
| 1429 __ pop(); | 1094 __ pop(); |
| 1430 } | 1095 } |
| 1431 | 1096 |
| 1432 | 1097 |
| 1433 void ArmCodeGenerator::VisitEmptyStatement(EmptyStatement* node) { | 1098 void CodeGenerator::VisitEmptyStatement(EmptyStatement* node) { |
| 1434 Comment cmnt(masm_, "// EmptyStatement"); | 1099 Comment cmnt(masm_, "// EmptyStatement"); |
| 1435 // nothing to do | 1100 // nothing to do |
| 1436 } | 1101 } |
| 1437 | 1102 |
| 1438 | 1103 |
| 1439 void ArmCodeGenerator::VisitIfStatement(IfStatement* node) { | 1104 void CodeGenerator::VisitIfStatement(IfStatement* node) { |
| 1440 Comment cmnt(masm_, "[ IfStatement"); | 1105 Comment cmnt(masm_, "[ IfStatement"); |
| 1441 // Generate different code depending on which | 1106 // Generate different code depending on which |
| 1442 // parts of the if statement are present or not. | 1107 // parts of the if statement are present or not. |
| 1443 bool has_then_stm = node->HasThenStatement(); | 1108 bool has_then_stm = node->HasThenStatement(); |
| 1444 bool has_else_stm = node->HasElseStatement(); | 1109 bool has_else_stm = node->HasElseStatement(); |
| 1445 | 1110 |
| 1446 if (FLAG_debug_info) RecordStatementPosition(node); | 1111 if (FLAG_debug_info) RecordStatementPosition(node); |
| 1447 | 1112 |
| 1448 Label exit; | 1113 Label exit; |
| 1449 if (has_then_stm && has_else_stm) { | 1114 if (has_then_stm && has_else_stm) { |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1493 } else { | 1158 } else { |
| 1494 __ pop(r0); // __ Pop(no_reg) | 1159 __ pop(r0); // __ Pop(no_reg) |
| 1495 } | 1160 } |
| 1496 } | 1161 } |
| 1497 | 1162 |
| 1498 // end | 1163 // end |
| 1499 __ bind(&exit); | 1164 __ bind(&exit); |
| 1500 } | 1165 } |
| 1501 | 1166 |
| 1502 | 1167 |
| 1503 void ArmCodeGenerator::CleanStack(int num_bytes) { | 1168 void CodeGenerator::CleanStack(int num_bytes) { |
| 1504 ASSERT(num_bytes >= 0); | 1169 ASSERT(num_bytes >= 0); |
| 1505 if (num_bytes > 0) { | 1170 if (num_bytes > 0) { |
| 1506 __ add(sp, sp, Operand(num_bytes)); | 1171 __ add(sp, sp, Operand(num_bytes)); |
| 1507 } | 1172 } |
| 1508 } | 1173 } |
| 1509 | 1174 |
| 1510 | 1175 |
| 1511 void ArmCodeGenerator::VisitContinueStatement(ContinueStatement* node) { | 1176 void CodeGenerator::VisitContinueStatement(ContinueStatement* node) { |
| 1512 Comment cmnt(masm_, "[ ContinueStatement"); | 1177 Comment cmnt(masm_, "[ ContinueStatement"); |
| 1513 if (FLAG_debug_info) RecordStatementPosition(node); | 1178 if (FLAG_debug_info) RecordStatementPosition(node); |
| 1514 CleanStack(break_stack_height_ - node->target()->break_stack_height()); | 1179 CleanStack(break_stack_height_ - node->target()->break_stack_height()); |
| 1515 __ b(node->target()->continue_target()); | 1180 __ b(node->target()->continue_target()); |
| 1516 } | 1181 } |
| 1517 | 1182 |
| 1518 | 1183 |
| 1519 void ArmCodeGenerator::VisitBreakStatement(BreakStatement* node) { | 1184 void CodeGenerator::VisitBreakStatement(BreakStatement* node) { |
| 1520 Comment cmnt(masm_, "[ BreakStatement"); | 1185 Comment cmnt(masm_, "[ BreakStatement"); |
| 1521 if (FLAG_debug_info) RecordStatementPosition(node); | 1186 if (FLAG_debug_info) RecordStatementPosition(node); |
| 1522 CleanStack(break_stack_height_ - node->target()->break_stack_height()); | 1187 CleanStack(break_stack_height_ - node->target()->break_stack_height()); |
| 1523 __ b(node->target()->break_target()); | 1188 __ b(node->target()->break_target()); |
| 1524 } | 1189 } |
| 1525 | 1190 |
| 1526 | 1191 |
| 1527 void ArmCodeGenerator::VisitReturnStatement(ReturnStatement* node) { | 1192 void CodeGenerator::VisitReturnStatement(ReturnStatement* node) { |
| 1528 Comment cmnt(masm_, "[ ReturnStatement"); | 1193 Comment cmnt(masm_, "[ ReturnStatement"); |
| 1529 if (FLAG_debug_info) RecordStatementPosition(node); | 1194 if (FLAG_debug_info) RecordStatementPosition(node); |
| 1530 Load(node->expression()); | 1195 Load(node->expression()); |
| 1531 // Move the function result into r0. | 1196 // Move the function result into r0. |
| 1532 __ pop(r0); | 1197 __ pop(r0); |
| 1533 | 1198 |
| 1534 __ b(&function_return_); | 1199 __ b(&function_return_); |
| 1535 } | 1200 } |
| 1536 | 1201 |
| 1537 | 1202 |
| 1538 void ArmCodeGenerator::VisitWithEnterStatement(WithEnterStatement* node) { | 1203 void CodeGenerator::VisitWithEnterStatement(WithEnterStatement* node) { |
| 1539 Comment cmnt(masm_, "[ WithEnterStatement"); | 1204 Comment cmnt(masm_, "[ WithEnterStatement"); |
| 1540 if (FLAG_debug_info) RecordStatementPosition(node); | 1205 if (FLAG_debug_info) RecordStatementPosition(node); |
| 1541 Load(node->expression()); | 1206 Load(node->expression()); |
| 1542 __ CallRuntime(Runtime::kPushContext, 1); | 1207 __ CallRuntime(Runtime::kPushContext, 1); |
| 1543 if (kDebug) { | 1208 if (kDebug) { |
| 1544 Label verified_true; | 1209 Label verified_true; |
| 1545 __ cmp(r0, Operand(cp)); | 1210 __ cmp(r0, Operand(cp)); |
| 1546 __ b(eq, &verified_true); | 1211 __ b(eq, &verified_true); |
| 1547 __ stop("PushContext: r0 is expected to be the same as cp"); | 1212 __ stop("PushContext: r0 is expected to be the same as cp"); |
| 1548 __ bind(&verified_true); | 1213 __ bind(&verified_true); |
| 1549 } | 1214 } |
| 1550 // Update context local. | 1215 // Update context local. |
| 1551 __ str(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); | 1216 __ str(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); |
| 1552 } | 1217 } |
| 1553 | 1218 |
| 1554 | 1219 |
| 1555 void ArmCodeGenerator::VisitWithExitStatement(WithExitStatement* node) { | 1220 void CodeGenerator::VisitWithExitStatement(WithExitStatement* node) { |
| 1556 Comment cmnt(masm_, "[ WithExitStatement"); | 1221 Comment cmnt(masm_, "[ WithExitStatement"); |
| 1557 // Pop context. | 1222 // Pop context. |
| 1558 __ ldr(cp, ContextOperand(cp, Context::PREVIOUS_INDEX)); | 1223 __ ldr(cp, ContextOperand(cp, Context::PREVIOUS_INDEX)); |
| 1559 // Update context local. | 1224 // Update context local. |
| 1560 __ str(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); | 1225 __ str(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); |
| 1561 } | 1226 } |
| 1562 | 1227 |
| 1563 | 1228 |
| 1564 int ArmCodeGenerator::FastCaseSwitchMaxOverheadFactor() { | 1229 int CodeGenerator::FastCaseSwitchMaxOverheadFactor() { |
| 1565 return kFastCaseSwitchMaxOverheadFactor; | 1230 return kFastSwitchMaxOverheadFactor; |
| 1566 } | 1231 } |
| 1567 | 1232 |
| 1568 int ArmCodeGenerator::FastCaseSwitchMinCaseCount() { | 1233 int CodeGenerator::FastCaseSwitchMinCaseCount() { |
| 1569 return kFastCaseSwitchMinCaseCount; | 1234 return kFastSwitchMinCaseCount; |
| 1570 } | 1235 } |
| 1571 | 1236 |
| 1572 | 1237 |
| 1573 void ArmCodeGenerator::GenerateFastCaseSwitchJumpTable( | 1238 void CodeGenerator::GenerateFastCaseSwitchJumpTable( |
| 1574 SwitchStatement* node, int min_index, int range, Label *fail_label, | 1239 SwitchStatement* node, int min_index, int range, Label *fail_label, |
| 1575 SmartPointer<Label*> &case_targets, SmartPointer<Label> &case_labels) { | 1240 SmartPointer<Label*> &case_targets, SmartPointer<Label> &case_labels) { |
| 1576 | 1241 |
| 1577 ASSERT(kSmiTag == 0 && kSmiTagSize <= 2); | 1242 ASSERT(kSmiTag == 0 && kSmiTagSize <= 2); |
| 1578 | 1243 |
| 1579 __ pop(r0); | 1244 __ pop(r0); |
| 1580 if (min_index != 0) { | 1245 if (min_index != 0) { |
| 1581 // small positive numbers can be immediate operands. | 1246 // small positive numbers can be immediate operands. |
| 1582 if (min_index < 0) { | 1247 if (min_index < 0) { |
| 1583 __ add(r0, r0, Operand(Smi::FromInt(-min_index))); | 1248 __ add(r0, r0, Operand(Smi::FromInt(-min_index))); |
| (...skipping 12 matching lines...) Expand all Loading... |
| 1596 | 1261 |
| 1597 // table containing branch operations. | 1262 // table containing branch operations. |
| 1598 for (int i = 0; i < range; i++) { | 1263 for (int i = 0; i < range; i++) { |
| 1599 __ b(case_targets[i]); | 1264 __ b(case_targets[i]); |
| 1600 } | 1265 } |
| 1601 | 1266 |
| 1602 GenerateFastCaseSwitchCases(node, case_labels); | 1267 GenerateFastCaseSwitchCases(node, case_labels); |
| 1603 } | 1268 } |
| 1604 | 1269 |
| 1605 | 1270 |
| 1606 void ArmCodeGenerator::VisitSwitchStatement(SwitchStatement* node) { | 1271 void CodeGenerator::VisitSwitchStatement(SwitchStatement* node) { |
| 1607 Comment cmnt(masm_, "[ SwitchStatement"); | 1272 Comment cmnt(masm_, "[ SwitchStatement"); |
| 1608 if (FLAG_debug_info) RecordStatementPosition(node); | 1273 if (FLAG_debug_info) RecordStatementPosition(node); |
| 1609 node->set_break_stack_height(break_stack_height_); | 1274 node->set_break_stack_height(break_stack_height_); |
| 1610 | 1275 |
| 1611 Load(node->tag()); | 1276 Load(node->tag()); |
| 1612 | 1277 |
| 1613 if (TryGenerateFastCaseSwitchStatement(node)) { | 1278 if (TryGenerateFastCaseSwitchStatement(node)) { |
| 1614 return; | 1279 return; |
| 1615 } | 1280 } |
| 1616 | 1281 |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1664 } else { | 1329 } else { |
| 1665 // Remove the switch value from the stack. | 1330 // Remove the switch value from the stack. |
| 1666 __ pop(r0); | 1331 __ pop(r0); |
| 1667 } | 1332 } |
| 1668 | 1333 |
| 1669 __ bind(&fall_through); | 1334 __ bind(&fall_through); |
| 1670 __ bind(node->break_target()); | 1335 __ bind(node->break_target()); |
| 1671 } | 1336 } |
| 1672 | 1337 |
| 1673 | 1338 |
| 1674 void ArmCodeGenerator::VisitLoopStatement(LoopStatement* node) { | 1339 void CodeGenerator::VisitLoopStatement(LoopStatement* node) { |
| 1675 Comment cmnt(masm_, "[ LoopStatement"); | 1340 Comment cmnt(masm_, "[ LoopStatement"); |
| 1676 if (FLAG_debug_info) RecordStatementPosition(node); | 1341 if (FLAG_debug_info) RecordStatementPosition(node); |
| 1677 node->set_break_stack_height(break_stack_height_); | 1342 node->set_break_stack_height(break_stack_height_); |
| 1678 | 1343 |
| 1679 // simple condition analysis | 1344 // simple condition analysis |
| 1680 enum { ALWAYS_TRUE, ALWAYS_FALSE, DONT_KNOW } info = DONT_KNOW; | 1345 enum { ALWAYS_TRUE, ALWAYS_FALSE, DONT_KNOW } info = DONT_KNOW; |
| 1681 if (node->cond() == NULL) { | 1346 if (node->cond() == NULL) { |
| 1682 ASSERT(node->type() == LoopStatement::FOR_LOOP); | 1347 ASSERT(node->type() == LoopStatement::FOR_LOOP); |
| 1683 info = ALWAYS_TRUE; | 1348 info = ALWAYS_TRUE; |
| 1684 } else { | 1349 } else { |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1736 true); | 1401 true); |
| 1737 Branch(true, &loop); | 1402 Branch(true, &loop); |
| 1738 break; | 1403 break; |
| 1739 } | 1404 } |
| 1740 | 1405 |
| 1741 // exit | 1406 // exit |
| 1742 __ bind(node->break_target()); | 1407 __ bind(node->break_target()); |
| 1743 } | 1408 } |
| 1744 | 1409 |
| 1745 | 1410 |
| 1746 void ArmCodeGenerator::VisitForInStatement(ForInStatement* node) { | 1411 void CodeGenerator::VisitForInStatement(ForInStatement* node) { |
| 1747 Comment cmnt(masm_, "[ ForInStatement"); | 1412 Comment cmnt(masm_, "[ ForInStatement"); |
| 1748 if (FLAG_debug_info) RecordStatementPosition(node); | 1413 if (FLAG_debug_info) RecordStatementPosition(node); |
| 1749 | 1414 |
| 1750 // We keep stuff on the stack while the body is executing. | 1415 // We keep stuff on the stack while the body is executing. |
| 1751 // Record it, so that a break/continue crossing this statement | 1416 // Record it, so that a break/continue crossing this statement |
| 1752 // can restore the stack. | 1417 // can restore the stack. |
| 1753 const int kForInStackSize = 5 * kPointerSize; | 1418 const int kForInStackSize = 5 * kPointerSize; |
| 1754 break_stack_height_ += kForInStackSize; | 1419 break_stack_height_ += kForInStackSize; |
| 1755 node->set_break_stack_height(break_stack_height_); | 1420 node->set_break_stack_height(break_stack_height_); |
| 1756 | 1421 |
| (...skipping 167 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1924 __ bind(node->break_target()); | 1589 __ bind(node->break_target()); |
| 1925 __ add(sp, sp, Operand(5 * kPointerSize)); | 1590 __ add(sp, sp, Operand(5 * kPointerSize)); |
| 1926 | 1591 |
| 1927 // Exit. | 1592 // Exit. |
| 1928 __ bind(&exit); | 1593 __ bind(&exit); |
| 1929 | 1594 |
| 1930 break_stack_height_ -= kForInStackSize; | 1595 break_stack_height_ -= kForInStackSize; |
| 1931 } | 1596 } |
| 1932 | 1597 |
| 1933 | 1598 |
| 1934 void ArmCodeGenerator::VisitTryCatch(TryCatch* node) { | 1599 void CodeGenerator::VisitTryCatch(TryCatch* node) { |
| 1935 Comment cmnt(masm_, "[ TryCatch"); | 1600 Comment cmnt(masm_, "[ TryCatch"); |
| 1936 | 1601 |
| 1937 Label try_block, exit; | 1602 Label try_block, exit; |
| 1938 | 1603 |
| 1939 __ bl(&try_block); | 1604 __ bl(&try_block); |
| 1940 | 1605 |
| 1941 // --- Catch block --- | 1606 // --- Catch block --- |
| 1942 | 1607 |
| 1943 // Store the caught exception in the catch variable. | 1608 // Store the caught exception in the catch variable. |
| 1944 __ push(r0); | 1609 __ push(r0); |
| (...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2013 // Code slot popped. | 1678 // Code slot popped. |
| 2014 | 1679 |
| 2015 __ b(shadows[i]->shadowed()); | 1680 __ b(shadows[i]->shadowed()); |
| 2016 } | 1681 } |
| 2017 } | 1682 } |
| 2018 | 1683 |
| 2019 __ bind(&exit); | 1684 __ bind(&exit); |
| 2020 } | 1685 } |
| 2021 | 1686 |
| 2022 | 1687 |
| 2023 void ArmCodeGenerator::VisitTryFinally(TryFinally* node) { | 1688 void CodeGenerator::VisitTryFinally(TryFinally* node) { |
| 2024 Comment cmnt(masm_, "[ TryFinally"); | 1689 Comment cmnt(masm_, "[ TryFinally"); |
| 2025 | 1690 |
| 2026 // State: Used to keep track of reason for entering the finally | 1691 // State: Used to keep track of reason for entering the finally |
| 2027 // block. Should probably be extended to hold information for | 1692 // block. Should probably be extended to hold information for |
| 2028 // break/continue from within the try block. | 1693 // break/continue from within the try block. |
| 2029 enum { FALLING, THROWING, JUMPING }; | 1694 enum { FALLING, THROWING, JUMPING }; |
| 2030 | 1695 |
| 2031 Label exit, unlink, try_block, finally_block; | 1696 Label exit, unlink, try_block, finally_block; |
| 2032 | 1697 |
| 2033 __ bl(&try_block); | 1698 __ bl(&try_block); |
| (...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2146 | 1811 |
| 2147 // Rethrow exception. | 1812 // Rethrow exception. |
| 2148 __ push(r0); | 1813 __ push(r0); |
| 2149 __ CallRuntime(Runtime::kReThrow, 1); | 1814 __ CallRuntime(Runtime::kReThrow, 1); |
| 2150 | 1815 |
| 2151 // Done. | 1816 // Done. |
| 2152 __ bind(&exit); | 1817 __ bind(&exit); |
| 2153 } | 1818 } |
| 2154 | 1819 |
| 2155 | 1820 |
| 2156 void ArmCodeGenerator::VisitDebuggerStatement(DebuggerStatement* node) { | 1821 void CodeGenerator::VisitDebuggerStatement(DebuggerStatement* node) { |
| 2157 Comment cmnt(masm_, "[ DebuggerStatament"); | 1822 Comment cmnt(masm_, "[ DebuggerStatament"); |
| 2158 if (FLAG_debug_info) RecordStatementPosition(node); | 1823 if (FLAG_debug_info) RecordStatementPosition(node); |
| 2159 __ CallRuntime(Runtime::kDebugBreak, 1); | 1824 __ CallRuntime(Runtime::kDebugBreak, 1); |
| 2160 __ push(r0); | 1825 __ push(r0); |
| 2161 } | 1826 } |
| 2162 | 1827 |
| 2163 | 1828 |
| 2164 void ArmCodeGenerator::InstantiateBoilerplate(Handle<JSFunction> boilerplate) { | 1829 void CodeGenerator::InstantiateBoilerplate(Handle<JSFunction> boilerplate) { |
| 2165 ASSERT(boilerplate->IsBoilerplate()); | 1830 ASSERT(boilerplate->IsBoilerplate()); |
| 2166 | 1831 |
| 2167 // Push the boilerplate on the stack. | 1832 // Push the boilerplate on the stack. |
| 2168 __ mov(r0, Operand(boilerplate)); | 1833 __ mov(r0, Operand(boilerplate)); |
| 2169 __ push(r0); | 1834 __ push(r0); |
| 2170 | 1835 |
| 2171 // Create a new closure. | 1836 // Create a new closure. |
| 2172 __ push(cp); | 1837 __ push(cp); |
| 2173 __ CallRuntime(Runtime::kNewClosure, 2); | 1838 __ CallRuntime(Runtime::kNewClosure, 2); |
| 2174 __ push(r0); | 1839 __ push(r0); |
| 2175 } | 1840 } |
| 2176 | 1841 |
| 2177 | 1842 |
| 2178 void ArmCodeGenerator::VisitFunctionLiteral(FunctionLiteral* node) { | 1843 void CodeGenerator::VisitFunctionLiteral(FunctionLiteral* node) { |
| 2179 Comment cmnt(masm_, "[ FunctionLiteral"); | 1844 Comment cmnt(masm_, "[ FunctionLiteral"); |
| 2180 | 1845 |
| 2181 // Build the function boilerplate and instantiate it. | 1846 // Build the function boilerplate and instantiate it. |
| 2182 Handle<JSFunction> boilerplate = BuildBoilerplate(node); | 1847 Handle<JSFunction> boilerplate = BuildBoilerplate(node); |
| 2183 // Check for stack-overflow exception. | 1848 // Check for stack-overflow exception. |
| 2184 if (HasStackOverflow()) return; | 1849 if (HasStackOverflow()) return; |
| 2185 InstantiateBoilerplate(boilerplate); | 1850 InstantiateBoilerplate(boilerplate); |
| 2186 } | 1851 } |
| 2187 | 1852 |
| 2188 | 1853 |
| 2189 void ArmCodeGenerator::VisitFunctionBoilerplateLiteral( | 1854 void CodeGenerator::VisitFunctionBoilerplateLiteral( |
| 2190 FunctionBoilerplateLiteral* node) { | 1855 FunctionBoilerplateLiteral* node) { |
| 2191 Comment cmnt(masm_, "[ FunctionBoilerplateLiteral"); | 1856 Comment cmnt(masm_, "[ FunctionBoilerplateLiteral"); |
| 2192 InstantiateBoilerplate(node->boilerplate()); | 1857 InstantiateBoilerplate(node->boilerplate()); |
| 2193 } | 1858 } |
| 2194 | 1859 |
| 2195 | 1860 |
| 2196 void ArmCodeGenerator::VisitConditional(Conditional* node) { | 1861 void CodeGenerator::VisitConditional(Conditional* node) { |
| 2197 Comment cmnt(masm_, "[ Conditional"); | 1862 Comment cmnt(masm_, "[ Conditional"); |
| 2198 Label then, else_, exit; | 1863 Label then, else_, exit; |
| 2199 LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &then, &else_, true); | 1864 LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &then, &else_, true); |
| 2200 Branch(false, &else_); | 1865 Branch(false, &else_); |
| 2201 __ bind(&then); | 1866 __ bind(&then); |
| 2202 Load(node->then_expression(), typeof_state()); | 1867 Load(node->then_expression(), typeof_state()); |
| 2203 __ b(&exit); | 1868 __ b(&exit); |
| 2204 __ bind(&else_); | 1869 __ bind(&else_); |
| 2205 Load(node->else_expression(), typeof_state()); | 1870 Load(node->else_expression(), typeof_state()); |
| 2206 __ bind(&exit); | 1871 __ bind(&exit); |
| 2207 } | 1872 } |
| 2208 | 1873 |
| 2209 | 1874 |
| 2210 void ArmCodeGenerator::LoadFromSlot(Slot* slot, TypeofState typeof_state) { | 1875 void CodeGenerator::LoadFromSlot(Slot* slot, TypeofState typeof_state) { |
| 2211 if (slot->type() == Slot::LOOKUP) { | 1876 if (slot->type() == Slot::LOOKUP) { |
| 2212 ASSERT(slot->var()->mode() == Variable::DYNAMIC); | 1877 ASSERT(slot->var()->mode() == Variable::DYNAMIC); |
| 2213 | 1878 |
| 2214 // For now, just do a runtime call. | 1879 // For now, just do a runtime call. |
| 2215 __ push(cp); | 1880 __ push(cp); |
| 2216 __ mov(r0, Operand(slot->var()->name())); | 1881 __ mov(r0, Operand(slot->var()->name())); |
| 2217 __ push(r0); | 1882 __ push(r0); |
| 2218 | 1883 |
| 2219 if (typeof_state == INSIDE_TYPEOF) { | 1884 if (typeof_state == INSIDE_TYPEOF) { |
| 2220 __ CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2); | 1885 __ CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2); |
| (...skipping 17 matching lines...) Expand all Loading... |
| 2238 Comment cmnt(masm_, "[ Unhole const"); | 1903 Comment cmnt(masm_, "[ Unhole const"); |
| 2239 __ pop(r0); | 1904 __ pop(r0); |
| 2240 __ cmp(r0, Operand(Factory::the_hole_value())); | 1905 __ cmp(r0, Operand(Factory::the_hole_value())); |
| 2241 __ mov(r0, Operand(Factory::undefined_value()), LeaveCC, eq); | 1906 __ mov(r0, Operand(Factory::undefined_value()), LeaveCC, eq); |
| 2242 __ push(r0); | 1907 __ push(r0); |
| 2243 } | 1908 } |
| 2244 } | 1909 } |
| 2245 } | 1910 } |
| 2246 | 1911 |
| 2247 | 1912 |
| 2248 void ArmCodeGenerator::VisitSlot(Slot* node) { | 1913 void CodeGenerator::VisitSlot(Slot* node) { |
| 2249 Comment cmnt(masm_, "[ Slot"); | 1914 Comment cmnt(masm_, "[ Slot"); |
| 2250 LoadFromSlot(node, typeof_state()); | 1915 LoadFromSlot(node, typeof_state()); |
| 2251 } | 1916 } |
| 2252 | 1917 |
| 2253 | 1918 |
| 2254 void ArmCodeGenerator::VisitVariableProxy(VariableProxy* node) { | 1919 void CodeGenerator::VisitVariableProxy(VariableProxy* node) { |
| 2255 Comment cmnt(masm_, "[ VariableProxy"); | 1920 Comment cmnt(masm_, "[ VariableProxy"); |
| 1921 |
| 2256 Variable* var = node->var(); | 1922 Variable* var = node->var(); |
| 2257 Expression* expr = var->rewrite(); | 1923 Expression* expr = var->rewrite(); |
| 2258 if (expr != NULL) { | 1924 if (expr != NULL) { |
| 2259 Visit(expr); | 1925 Visit(expr); |
| 2260 } else { | 1926 } else { |
| 2261 ASSERT(var->is_global()); | 1927 ASSERT(var->is_global()); |
| 2262 Reference ref(this, node); | 1928 Reference ref(this, node); |
| 2263 ref.GetValue(typeof_state()); | 1929 ref.GetValue(typeof_state()); |
| 2264 } | 1930 } |
| 2265 } | 1931 } |
| 2266 | 1932 |
| 2267 | 1933 |
| 2268 void ArmCodeGenerator::VisitLiteral(Literal* node) { | 1934 void CodeGenerator::VisitLiteral(Literal* node) { |
| 2269 Comment cmnt(masm_, "[ Literal"); | 1935 Comment cmnt(masm_, "[ Literal"); |
| 2270 __ mov(r0, Operand(node->handle())); | 1936 __ mov(r0, Operand(node->handle())); |
| 2271 __ push(r0); | 1937 __ push(r0); |
| 2272 } | 1938 } |
| 2273 | 1939 |
| 2274 | 1940 |
| 2275 void ArmCodeGenerator::VisitRegExpLiteral(RegExpLiteral* node) { | 1941 void CodeGenerator::VisitRegExpLiteral(RegExpLiteral* node) { |
| 2276 Comment cmnt(masm_, "[ RexExp Literal"); | 1942 Comment cmnt(masm_, "[ RexExp Literal"); |
| 2277 | 1943 |
| 2278 // Retrieve the literal array and check the allocated entry. | 1944 // Retrieve the literal array and check the allocated entry. |
| 2279 | 1945 |
| 2280 // Load the function of this activation. | 1946 // Load the function of this activation. |
| 2281 __ ldr(r1, FunctionOperand()); | 1947 __ ldr(r1, FunctionOperand()); |
| 2282 | 1948 |
| 2283 // Load the literals array of the function. | 1949 // Load the literals array of the function. |
| 2284 __ ldr(r1, FieldMemOperand(r1, JSFunction::kLiteralsOffset)); | 1950 __ ldr(r1, FieldMemOperand(r1, JSFunction::kLiteralsOffset)); |
| 2285 | 1951 |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2336 __ mov(r0, Operand(Smi::FromInt(node_->literal_index()))); | 2002 __ mov(r0, Operand(Smi::FromInt(node_->literal_index()))); |
| 2337 __ push(r0); | 2003 __ push(r0); |
| 2338 // Constant properties (2). | 2004 // Constant properties (2). |
| 2339 __ mov(r0, Operand(node_->constant_properties())); | 2005 __ mov(r0, Operand(node_->constant_properties())); |
| 2340 __ push(r0); | 2006 __ push(r0); |
| 2341 __ CallRuntime(Runtime::kCreateObjectLiteralBoilerplate, 3); | 2007 __ CallRuntime(Runtime::kCreateObjectLiteralBoilerplate, 3); |
| 2342 __ mov(r2, Operand(r0)); | 2008 __ mov(r2, Operand(r0)); |
| 2343 } | 2009 } |
| 2344 | 2010 |
| 2345 | 2011 |
| 2346 void ArmCodeGenerator::VisitObjectLiteral(ObjectLiteral* node) { | 2012 void CodeGenerator::VisitObjectLiteral(ObjectLiteral* node) { |
| 2347 Comment cmnt(masm_, "[ ObjectLiteral"); | 2013 Comment cmnt(masm_, "[ ObjectLiteral"); |
| 2348 | 2014 |
| 2349 ObjectLiteralDeferred* deferred = new ObjectLiteralDeferred(this, node); | 2015 ObjectLiteralDeferred* deferred = new ObjectLiteralDeferred(this, node); |
| 2350 | 2016 |
| 2351 // Retrieve the literal array and check the allocated entry. | 2017 // Retrieve the literal array and check the allocated entry. |
| 2352 | 2018 |
| 2353 // Load the function of this activation. | 2019 // Load the function of this activation. |
| 2354 __ ldr(r1, FunctionOperand()); | 2020 __ ldr(r1, FunctionOperand()); |
| 2355 | 2021 |
| 2356 // Load the literals array of the function. | 2022 // Load the literals array of the function. |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2409 Load(value); | 2075 Load(value); |
| 2410 __ CallRuntime(Runtime::kDefineAccessor, 4); | 2076 __ CallRuntime(Runtime::kDefineAccessor, 4); |
| 2411 __ ldr(r0, MemOperand(sp, 0)); | 2077 __ ldr(r0, MemOperand(sp, 0)); |
| 2412 break; | 2078 break; |
| 2413 } | 2079 } |
| 2414 } | 2080 } |
| 2415 } | 2081 } |
| 2416 } | 2082 } |
| 2417 | 2083 |
| 2418 | 2084 |
| 2419 void ArmCodeGenerator::VisitArrayLiteral(ArrayLiteral* node) { | 2085 void CodeGenerator::VisitArrayLiteral(ArrayLiteral* node) { |
| 2420 Comment cmnt(masm_, "[ ArrayLiteral"); | 2086 Comment cmnt(masm_, "[ ArrayLiteral"); |
| 2421 | 2087 |
| 2422 // Call runtime to create the array literal. | 2088 // Call runtime to create the array literal. |
| 2423 __ mov(r0, Operand(node->literals())); | 2089 __ mov(r0, Operand(node->literals())); |
| 2424 __ push(r0); | 2090 __ push(r0); |
| 2425 // Load the function of this frame. | 2091 // Load the function of this frame. |
| 2426 __ ldr(r0, FunctionOperand()); | 2092 __ ldr(r0, FunctionOperand()); |
| 2427 __ ldr(r0, FieldMemOperand(r0, JSFunction::kLiteralsOffset)); | 2093 __ ldr(r0, FieldMemOperand(r0, JSFunction::kLiteralsOffset)); |
| 2428 __ push(r0); | 2094 __ push(r0); |
| 2429 __ CallRuntime(Runtime::kCreateArrayLiteral, 2); | 2095 __ CallRuntime(Runtime::kCreateArrayLiteral, 2); |
| (...skipping 23 matching lines...) Expand all Loading... |
| 2453 __ str(r0, FieldMemOperand(r1, offset)); | 2119 __ str(r0, FieldMemOperand(r1, offset)); |
| 2454 | 2120 |
| 2455 // Update the write barrier for the array address. | 2121 // Update the write barrier for the array address. |
| 2456 __ mov(r3, Operand(offset)); | 2122 __ mov(r3, Operand(offset)); |
| 2457 __ RecordWrite(r1, r3, r2); | 2123 __ RecordWrite(r1, r3, r2); |
| 2458 } | 2124 } |
| 2459 } | 2125 } |
| 2460 } | 2126 } |
| 2461 | 2127 |
| 2462 | 2128 |
| 2463 void ArmCodeGenerator::VisitAssignment(Assignment* node) { | 2129 void CodeGenerator::VisitAssignment(Assignment* node) { |
| 2464 Comment cmnt(masm_, "[ Assignment"); | 2130 Comment cmnt(masm_, "[ Assignment"); |
| 2465 if (FLAG_debug_info) RecordStatementPosition(node); | 2131 if (FLAG_debug_info) RecordStatementPosition(node); |
| 2466 | 2132 |
| 2467 Reference target(this, node->target()); | 2133 Reference target(this, node->target()); |
| 2468 if (target.is_illegal()) return; | 2134 if (target.is_illegal()) return; |
| 2469 | 2135 |
| 2470 if (node->op() == Token::ASSIGN || | 2136 if (node->op() == Token::ASSIGN || |
| 2471 node->op() == Token::INIT_VAR || | 2137 node->op() == Token::INIT_VAR || |
| 2472 node->op() == Token::INIT_CONST) { | 2138 node->op() == Token::INIT_CONST) { |
| 2473 Load(node->value()); | 2139 Load(node->value()); |
| (...skipping 25 matching lines...) Expand all Loading... |
| 2499 // and initialize the actual constant declared. Dynamic variable | 2165 // and initialize the actual constant declared. Dynamic variable |
| 2500 // initializations are simply assignments and use SetValue. | 2166 // initializations are simply assignments and use SetValue. |
| 2501 target.SetValue(CONST_INIT); | 2167 target.SetValue(CONST_INIT); |
| 2502 } else { | 2168 } else { |
| 2503 target.SetValue(NOT_CONST_INIT); | 2169 target.SetValue(NOT_CONST_INIT); |
| 2504 } | 2170 } |
| 2505 } | 2171 } |
| 2506 } | 2172 } |
| 2507 | 2173 |
| 2508 | 2174 |
| 2509 void ArmCodeGenerator::VisitThrow(Throw* node) { | 2175 void CodeGenerator::VisitThrow(Throw* node) { |
| 2510 Comment cmnt(masm_, "[ Throw"); | 2176 Comment cmnt(masm_, "[ Throw"); |
| 2511 | 2177 |
| 2512 Load(node->exception()); | 2178 Load(node->exception()); |
| 2513 __ RecordPosition(node->position()); | 2179 __ RecordPosition(node->position()); |
| 2514 __ CallRuntime(Runtime::kThrow, 1); | 2180 __ CallRuntime(Runtime::kThrow, 1); |
| 2515 __ push(r0); | 2181 __ push(r0); |
| 2516 } | 2182 } |
| 2517 | 2183 |
| 2518 | 2184 |
| 2519 void ArmCodeGenerator::VisitProperty(Property* node) { | 2185 void CodeGenerator::VisitProperty(Property* node) { |
| 2520 Comment cmnt(masm_, "[ Property"); | 2186 Comment cmnt(masm_, "[ Property"); |
| 2187 |
| 2521 Reference property(this, node); | 2188 Reference property(this, node); |
| 2522 property.GetValue(typeof_state()); | 2189 property.GetValue(typeof_state()); |
| 2523 } | 2190 } |
| 2524 | 2191 |
| 2525 | 2192 |
| 2526 void ArmCodeGenerator::VisitCall(Call* node) { | 2193 void CodeGenerator::VisitCall(Call* node) { |
| 2527 Comment cmnt(masm_, "[ Call"); | 2194 Comment cmnt(masm_, "[ Call"); |
| 2528 | 2195 |
| 2529 ZoneList<Expression*>* args = node->arguments(); | 2196 ZoneList<Expression*>* args = node->arguments(); |
| 2530 | 2197 |
| 2531 if (FLAG_debug_info) RecordStatementPosition(node); | 2198 if (FLAG_debug_info) RecordStatementPosition(node); |
| 2532 // Standard function call. | 2199 // Standard function call. |
| 2533 | 2200 |
| 2534 // Check if the function is a variable or a property. | 2201 // Check if the function is a variable or a property. |
| 2535 Expression* function = node->expression(); | 2202 Expression* function = node->expression(); |
| 2536 Variable* var = function->AsVariableProxy()->AsVariable(); | 2203 Variable* var = function->AsVariableProxy()->AsVariable(); |
| (...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2642 Load(function); | 2309 Load(function); |
| 2643 // Pass the global object as the receiver. | 2310 // Pass the global object as the receiver. |
| 2644 LoadGlobal(); | 2311 LoadGlobal(); |
| 2645 // Call the function. | 2312 // Call the function. |
| 2646 CallWithArguments(args, node->position()); | 2313 CallWithArguments(args, node->position()); |
| 2647 __ push(r0); | 2314 __ push(r0); |
| 2648 } | 2315 } |
| 2649 } | 2316 } |
| 2650 | 2317 |
| 2651 | 2318 |
| 2652 void ArmCodeGenerator::VisitCallNew(CallNew* node) { | 2319 void CodeGenerator::VisitCallNew(CallNew* node) { |
| 2653 Comment cmnt(masm_, "[ CallNew"); | 2320 Comment cmnt(masm_, "[ CallNew"); |
| 2654 | 2321 |
| 2655 // According to ECMA-262, section 11.2.2, page 44, the function | 2322 // According to ECMA-262, section 11.2.2, page 44, the function |
| 2656 // expression in new calls must be evaluated before the | 2323 // expression in new calls must be evaluated before the |
| 2657 // arguments. This is different from ordinary calls, where the | 2324 // arguments. This is different from ordinary calls, where the |
| 2658 // actual function to call is resolved after the arguments have been | 2325 // actual function to call is resolved after the arguments have been |
| 2659 // evaluated. | 2326 // evaluated. |
| 2660 | 2327 |
| 2661 // Compute function to call and use the global object as the | 2328 // Compute function to call and use the global object as the |
| 2662 // receiver. | 2329 // receiver. |
| (...skipping 14 matching lines...) Expand all Loading... |
| 2677 // constructor invocation. | 2344 // constructor invocation. |
| 2678 __ RecordPosition(RelocInfo::POSITION); | 2345 __ RecordPosition(RelocInfo::POSITION); |
| 2679 __ Call(Handle<Code>(Builtins::builtin(Builtins::JSConstructCall)), | 2346 __ Call(Handle<Code>(Builtins::builtin(Builtins::JSConstructCall)), |
| 2680 RelocInfo::CONSTRUCT_CALL); | 2347 RelocInfo::CONSTRUCT_CALL); |
| 2681 | 2348 |
| 2682 // Discard old TOS value and push r0 on the stack (same as Pop(), push(r0)). | 2349 // Discard old TOS value and push r0 on the stack (same as Pop(), push(r0)). |
| 2683 __ str(r0, MemOperand(sp, 0 * kPointerSize)); | 2350 __ str(r0, MemOperand(sp, 0 * kPointerSize)); |
| 2684 } | 2351 } |
| 2685 | 2352 |
| 2686 | 2353 |
| 2687 void ArmCodeGenerator::GenerateValueOf(ZoneList<Expression*>* args) { | 2354 void CodeGenerator::GenerateValueOf(ZoneList<Expression*>* args) { |
| 2688 ASSERT(args->length() == 1); | 2355 ASSERT(args->length() == 1); |
| 2689 Label leave; | 2356 Label leave; |
| 2690 Load(args->at(0)); | 2357 Load(args->at(0)); |
| 2691 __ pop(r0); // r0 contains object. | 2358 __ pop(r0); // r0 contains object. |
| 2692 // if (object->IsSmi()) return the object. | 2359 // if (object->IsSmi()) return the object. |
| 2693 __ tst(r0, Operand(kSmiTagMask)); | 2360 __ tst(r0, Operand(kSmiTagMask)); |
| 2694 __ b(eq, &leave); | 2361 __ b(eq, &leave); |
| 2695 // It is a heap object - get map. | 2362 // It is a heap object - get map. |
| 2696 __ ldr(r1, FieldMemOperand(r0, HeapObject::kMapOffset)); | 2363 __ ldr(r1, FieldMemOperand(r0, HeapObject::kMapOffset)); |
| 2697 __ ldrb(r1, FieldMemOperand(r1, Map::kInstanceTypeOffset)); | 2364 __ ldrb(r1, FieldMemOperand(r1, Map::kInstanceTypeOffset)); |
| 2698 // if (!object->IsJSValue()) return the object. | 2365 // if (!object->IsJSValue()) return the object. |
| 2699 __ cmp(r1, Operand(JS_VALUE_TYPE)); | 2366 __ cmp(r1, Operand(JS_VALUE_TYPE)); |
| 2700 __ b(ne, &leave); | 2367 __ b(ne, &leave); |
| 2701 // Load the value. | 2368 // Load the value. |
| 2702 __ ldr(r0, FieldMemOperand(r0, JSValue::kValueOffset)); | 2369 __ ldr(r0, FieldMemOperand(r0, JSValue::kValueOffset)); |
| 2703 __ bind(&leave); | 2370 __ bind(&leave); |
| 2704 __ push(r0); | 2371 __ push(r0); |
| 2705 } | 2372 } |
| 2706 | 2373 |
| 2707 | 2374 |
| 2708 void ArmCodeGenerator::GenerateSetValueOf(ZoneList<Expression*>* args) { | 2375 void CodeGenerator::GenerateSetValueOf(ZoneList<Expression*>* args) { |
| 2709 ASSERT(args->length() == 2); | 2376 ASSERT(args->length() == 2); |
| 2710 Label leave; | 2377 Label leave; |
| 2711 Load(args->at(0)); // Load the object. | 2378 Load(args->at(0)); // Load the object. |
| 2712 Load(args->at(1)); // Load the value. | 2379 Load(args->at(1)); // Load the value. |
| 2713 __ pop(r0); // r0 contains value | 2380 __ pop(r0); // r0 contains value |
| 2714 __ pop(r1); // r1 contains object | 2381 __ pop(r1); // r1 contains object |
| 2715 // if (object->IsSmi()) return object. | 2382 // if (object->IsSmi()) return object. |
| 2716 __ tst(r1, Operand(kSmiTagMask)); | 2383 __ tst(r1, Operand(kSmiTagMask)); |
| 2717 __ b(eq, &leave); | 2384 __ b(eq, &leave); |
| 2718 // It is a heap object - get map. | 2385 // It is a heap object - get map. |
| 2719 __ ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset)); | 2386 __ ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset)); |
| 2720 __ ldrb(r2, FieldMemOperand(r2, Map::kInstanceTypeOffset)); | 2387 __ ldrb(r2, FieldMemOperand(r2, Map::kInstanceTypeOffset)); |
| 2721 // if (!object->IsJSValue()) return object. | 2388 // if (!object->IsJSValue()) return object. |
| 2722 __ cmp(r2, Operand(JS_VALUE_TYPE)); | 2389 __ cmp(r2, Operand(JS_VALUE_TYPE)); |
| 2723 __ b(ne, &leave); | 2390 __ b(ne, &leave); |
| 2724 // Store the value. | 2391 // Store the value. |
| 2725 __ str(r0, FieldMemOperand(r1, JSValue::kValueOffset)); | 2392 __ str(r0, FieldMemOperand(r1, JSValue::kValueOffset)); |
| 2726 // Update the write barrier. | 2393 // Update the write barrier. |
| 2727 __ mov(r2, Operand(JSValue::kValueOffset - kHeapObjectTag)); | 2394 __ mov(r2, Operand(JSValue::kValueOffset - kHeapObjectTag)); |
| 2728 __ RecordWrite(r1, r2, r3); | 2395 __ RecordWrite(r1, r2, r3); |
| 2729 // Leave. | 2396 // Leave. |
| 2730 __ bind(&leave); | 2397 __ bind(&leave); |
| 2731 __ push(r0); | 2398 __ push(r0); |
| 2732 } | 2399 } |
| 2733 | 2400 |
| 2734 | 2401 |
| 2735 void ArmCodeGenerator::GenerateIsSmi(ZoneList<Expression*>* args) { | 2402 void CodeGenerator::GenerateIsSmi(ZoneList<Expression*>* args) { |
| 2736 ASSERT(args->length() == 1); | 2403 ASSERT(args->length() == 1); |
| 2737 Load(args->at(0)); | 2404 Load(args->at(0)); |
| 2738 __ pop(r0); | 2405 __ pop(r0); |
| 2739 __ tst(r0, Operand(kSmiTagMask)); | 2406 __ tst(r0, Operand(kSmiTagMask)); |
| 2740 cc_reg_ = eq; | 2407 cc_reg_ = eq; |
| 2741 } | 2408 } |
| 2742 | 2409 |
| 2743 | 2410 |
| 2744 void ArmCodeGenerator::GenerateIsNonNegativeSmi(ZoneList<Expression*>* args) { | 2411 void CodeGenerator::GenerateIsNonNegativeSmi(ZoneList<Expression*>* args) { |
| 2745 ASSERT(args->length() == 1); | 2412 ASSERT(args->length() == 1); |
| 2746 Load(args->at(0)); | 2413 Load(args->at(0)); |
| 2747 __ pop(r0); | 2414 __ pop(r0); |
| 2748 __ tst(r0, Operand(kSmiTagMask | 0x80000000)); | 2415 __ tst(r0, Operand(kSmiTagMask | 0x80000000)); |
| 2749 cc_reg_ = eq; | 2416 cc_reg_ = eq; |
| 2750 } | 2417 } |
| 2751 | 2418 |
| 2752 | 2419 |
| 2753 // This should generate code that performs a charCodeAt() call or returns | 2420 // This should generate code that performs a charCodeAt() call or returns |
| 2754 // undefined in order to trigger the slow case, Runtime_StringCharCodeAt. | 2421 // undefined in order to trigger the slow case, Runtime_StringCharCodeAt. |
| 2755 // It is not yet implemented on ARM, so it always goes to the slow case. | 2422 // It is not yet implemented on ARM, so it always goes to the slow case. |
| 2756 void ArmCodeGenerator::GenerateFastCharCodeAt(ZoneList<Expression*>* args) { | 2423 void CodeGenerator::GenerateFastCharCodeAt(ZoneList<Expression*>* args) { |
| 2757 ASSERT(args->length() == 2); | 2424 ASSERT(args->length() == 2); |
| 2758 __ mov(r0, Operand(Factory::undefined_value())); | 2425 __ mov(r0, Operand(Factory::undefined_value())); |
| 2759 __ push(r0); | 2426 __ push(r0); |
| 2760 } | 2427 } |
| 2761 | 2428 |
| 2762 | 2429 |
| 2763 void ArmCodeGenerator::GenerateIsArray(ZoneList<Expression*>* args) { | 2430 void CodeGenerator::GenerateIsArray(ZoneList<Expression*>* args) { |
| 2764 ASSERT(args->length() == 1); | 2431 ASSERT(args->length() == 1); |
| 2765 Load(args->at(0)); | 2432 Load(args->at(0)); |
| 2766 Label answer; | 2433 Label answer; |
| 2767 // We need the CC bits to come out as not_equal in the case where the | 2434 // We need the CC bits to come out as not_equal in the case where the |
| 2768 // object is a smi. This can't be done with the usual test opcode so | 2435 // object is a smi. This can't be done with the usual test opcode so |
| 2769 // we use XOR to get the right CC bits. | 2436 // we use XOR to get the right CC bits. |
| 2770 __ pop(r0); | 2437 __ pop(r0); |
| 2771 __ and_(r1, r0, Operand(kSmiTagMask)); | 2438 __ and_(r1, r0, Operand(kSmiTagMask)); |
| 2772 __ eor(r1, r1, Operand(kSmiTagMask), SetCC); | 2439 __ eor(r1, r1, Operand(kSmiTagMask), SetCC); |
| 2773 __ b(ne, &answer); | 2440 __ b(ne, &answer); |
| 2774 // It is a heap object - get the map. | 2441 // It is a heap object - get the map. |
| 2775 __ ldr(r1, FieldMemOperand(r0, HeapObject::kMapOffset)); | 2442 __ ldr(r1, FieldMemOperand(r0, HeapObject::kMapOffset)); |
| 2776 __ ldrb(r1, FieldMemOperand(r1, Map::kInstanceTypeOffset)); | 2443 __ ldrb(r1, FieldMemOperand(r1, Map::kInstanceTypeOffset)); |
| 2777 // Check if the object is a JS array or not. | 2444 // Check if the object is a JS array or not. |
| 2778 __ cmp(r1, Operand(JS_ARRAY_TYPE)); | 2445 __ cmp(r1, Operand(JS_ARRAY_TYPE)); |
| 2779 __ bind(&answer); | 2446 __ bind(&answer); |
| 2780 cc_reg_ = eq; | 2447 cc_reg_ = eq; |
| 2781 } | 2448 } |
| 2782 | 2449 |
| 2783 | 2450 |
| 2784 void ArmCodeGenerator::GenerateArgumentsLength(ZoneList<Expression*>* args) { | 2451 void CodeGenerator::GenerateArgumentsLength(ZoneList<Expression*>* args) { |
| 2785 ASSERT(args->length() == 0); | 2452 ASSERT(args->length() == 0); |
| 2786 | 2453 |
| 2787 // Seed the result with the formal parameters count, which will be used | 2454 // Seed the result with the formal parameters count, which will be used |
| 2788 // in case no arguments adaptor frame is found below the current frame. | 2455 // in case no arguments adaptor frame is found below the current frame. |
| 2789 __ mov(r0, Operand(Smi::FromInt(scope_->num_parameters()))); | 2456 __ mov(r0, Operand(Smi::FromInt(scope_->num_parameters()))); |
| 2790 | 2457 |
| 2791 // Call the shared stub to get to the arguments.length. | 2458 // Call the shared stub to get to the arguments.length. |
| 2792 ArgumentsAccessStub stub(ArgumentsAccessStub::READ_LENGTH); | 2459 ArgumentsAccessStub stub(ArgumentsAccessStub::READ_LENGTH); |
| 2793 __ CallStub(&stub); | 2460 __ CallStub(&stub); |
| 2794 __ push(r0); | 2461 __ push(r0); |
| 2795 } | 2462 } |
| 2796 | 2463 |
| 2797 | 2464 |
| 2798 void ArmCodeGenerator::GenerateArgumentsAccess(ZoneList<Expression*>* args) { | 2465 void CodeGenerator::GenerateArgumentsAccess(ZoneList<Expression*>* args) { |
| 2799 ASSERT(args->length() == 1); | 2466 ASSERT(args->length() == 1); |
| 2800 | 2467 |
| 2801 // Satisfy contract with ArgumentsAccessStub: | 2468 // Satisfy contract with ArgumentsAccessStub: |
| 2802 // Load the key into r1 and the formal parameters count into r0. | 2469 // Load the key into r1 and the formal parameters count into r0. |
| 2803 Load(args->at(0)); | 2470 Load(args->at(0)); |
| 2804 __ pop(r1); | 2471 __ pop(r1); |
| 2805 __ mov(r0, Operand(Smi::FromInt(scope_->num_parameters()))); | 2472 __ mov(r0, Operand(Smi::FromInt(scope_->num_parameters()))); |
| 2806 | 2473 |
| 2807 // Call the shared stub to get to arguments[key]. | 2474 // Call the shared stub to get to arguments[key]. |
| 2808 ArgumentsAccessStub stub(ArgumentsAccessStub::READ_ELEMENT); | 2475 ArgumentsAccessStub stub(ArgumentsAccessStub::READ_ELEMENT); |
| 2809 __ CallStub(&stub); | 2476 __ CallStub(&stub); |
| 2810 __ push(r0); | 2477 __ push(r0); |
| 2811 } | 2478 } |
| 2812 | 2479 |
| 2813 | 2480 |
| 2814 void ArmCodeGenerator::GenerateObjectEquals(ZoneList<Expression*>* args) { | 2481 void CodeGenerator::GenerateObjectEquals(ZoneList<Expression*>* args) { |
| 2815 ASSERT(args->length() == 2); | 2482 ASSERT(args->length() == 2); |
| 2816 | 2483 |
| 2817 // Load the two objects into registers and perform the comparison. | 2484 // Load the two objects into registers and perform the comparison. |
| 2818 Load(args->at(0)); | 2485 Load(args->at(0)); |
| 2819 Load(args->at(1)); | 2486 Load(args->at(1)); |
| 2820 __ pop(r0); | 2487 __ pop(r0); |
| 2821 __ pop(r1); | 2488 __ pop(r1); |
| 2822 __ cmp(r0, Operand(r1)); | 2489 __ cmp(r0, Operand(r1)); |
| 2823 cc_reg_ = eq; | 2490 cc_reg_ = eq; |
| 2824 } | 2491 } |
| 2825 | 2492 |
| 2826 | 2493 |
| 2827 void ArmCodeGenerator::VisitCallRuntime(CallRuntime* node) { | 2494 void CodeGenerator::VisitCallRuntime(CallRuntime* node) { |
| 2828 if (CheckForInlineRuntimeCall(node)) return; | 2495 if (CheckForInlineRuntimeCall(node)) return; |
| 2829 | 2496 |
| 2830 ZoneList<Expression*>* args = node->arguments(); | 2497 ZoneList<Expression*>* args = node->arguments(); |
| 2831 Comment cmnt(masm_, "[ CallRuntime"); | 2498 Comment cmnt(masm_, "[ CallRuntime"); |
| 2832 Runtime::Function* function = node->function(); | 2499 Runtime::Function* function = node->function(); |
| 2833 | 2500 |
| 2834 if (function != NULL) { | 2501 if (function != NULL) { |
| 2835 // Push the arguments ("left-to-right"). | 2502 // Push the arguments ("left-to-right"). |
| 2836 for (int i = 0; i < args->length(); i++) Load(args->at(i)); | 2503 for (int i = 0; i < args->length(); i++) Load(args->at(i)); |
| 2837 | 2504 |
| (...skipping 15 matching lines...) Expand all Loading... |
| 2853 // Call the JS runtime function. | 2520 // Call the JS runtime function. |
| 2854 Handle<Code> stub = ComputeCallInitialize(args->length()); | 2521 Handle<Code> stub = ComputeCallInitialize(args->length()); |
| 2855 __ Call(stub, RelocInfo::CODE_TARGET); | 2522 __ Call(stub, RelocInfo::CODE_TARGET); |
| 2856 __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); | 2523 __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); |
| 2857 __ pop(); | 2524 __ pop(); |
| 2858 __ push(r0); | 2525 __ push(r0); |
| 2859 } | 2526 } |
| 2860 } | 2527 } |
| 2861 | 2528 |
| 2862 | 2529 |
| 2863 void ArmCodeGenerator::VisitUnaryOperation(UnaryOperation* node) { | 2530 void CodeGenerator::VisitUnaryOperation(UnaryOperation* node) { |
| 2864 Comment cmnt(masm_, "[ UnaryOperation"); | 2531 Comment cmnt(masm_, "[ UnaryOperation"); |
| 2865 | 2532 |
| 2866 Token::Value op = node->op(); | 2533 Token::Value op = node->op(); |
| 2867 | 2534 |
| 2868 if (op == Token::NOT) { | 2535 if (op == Token::NOT) { |
| 2869 LoadCondition(node->expression(), | 2536 LoadCondition(node->expression(), |
| 2870 NOT_INSIDE_TYPEOF, | 2537 NOT_INSIDE_TYPEOF, |
| 2871 false_target(), | 2538 false_target(), |
| 2872 true_target(), | 2539 true_target(), |
| 2873 true); | 2540 true); |
| (...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2978 break; | 2645 break; |
| 2979 } | 2646 } |
| 2980 default: | 2647 default: |
| 2981 UNREACHABLE(); | 2648 UNREACHABLE(); |
| 2982 } | 2649 } |
| 2983 __ push(r0); // r0 has result | 2650 __ push(r0); // r0 has result |
| 2984 } | 2651 } |
| 2985 } | 2652 } |
| 2986 | 2653 |
| 2987 | 2654 |
| 2988 void ArmCodeGenerator::VisitCountOperation(CountOperation* node) { | 2655 void CodeGenerator::VisitCountOperation(CountOperation* node) { |
| 2989 Comment cmnt(masm_, "[ CountOperation"); | 2656 Comment cmnt(masm_, "[ CountOperation"); |
| 2990 | 2657 |
| 2991 bool is_postfix = node->is_postfix(); | 2658 bool is_postfix = node->is_postfix(); |
| 2992 bool is_increment = node->op() == Token::INC; | 2659 bool is_increment = node->op() == Token::INC; |
| 2993 | 2660 |
| 2994 Variable* var = node->expression()->AsVariableProxy()->AsVariable(); | 2661 Variable* var = node->expression()->AsVariableProxy()->AsVariable(); |
| 2995 bool is_const = (var != NULL && var->mode() == Variable::CONST); | 2662 bool is_const = (var != NULL && var->mode() == Variable::CONST); |
| 2996 | 2663 |
| 2997 // Postfix: Make room for the result. | 2664 // Postfix: Make room for the result. |
| 2998 if (is_postfix) { | 2665 if (is_postfix) { |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3058 __ bind(&exit); | 2725 __ bind(&exit); |
| 3059 __ push(r0); | 2726 __ push(r0); |
| 3060 if (!is_const) target.SetValue(NOT_CONST_INIT); | 2727 if (!is_const) target.SetValue(NOT_CONST_INIT); |
| 3061 } | 2728 } |
| 3062 | 2729 |
| 3063 // Postfix: Discard the new value and use the old. | 2730 // Postfix: Discard the new value and use the old. |
| 3064 if (is_postfix) __ pop(r0); | 2731 if (is_postfix) __ pop(r0); |
| 3065 } | 2732 } |
| 3066 | 2733 |
| 3067 | 2734 |
| 3068 void ArmCodeGenerator::VisitBinaryOperation(BinaryOperation* node) { | 2735 void CodeGenerator::VisitBinaryOperation(BinaryOperation* node) { |
| 3069 Comment cmnt(masm_, "[ BinaryOperation"); | 2736 Comment cmnt(masm_, "[ BinaryOperation"); |
| 3070 Token::Value op = node->op(); | 2737 Token::Value op = node->op(); |
| 3071 | 2738 |
| 3072 // According to ECMA-262 section 11.11, page 58, the binary logical | 2739 // According to ECMA-262 section 11.11, page 58, the binary logical |
| 3073 // operators must yield the result of one of the two expressions | 2740 // operators must yield the result of one of the two expressions |
| 3074 // before any ToBoolean() conversions. This means that the value | 2741 // before any ToBoolean() conversions. This means that the value |
| 3075 // produced by a && or || operator is not necessarily a boolean. | 2742 // produced by a && or || operator is not necessarily a boolean. |
| 3076 | 2743 |
| 3077 // NOTE: If the left hand side produces a materialized value (not in | 2744 // NOTE: If the left hand side produces a materialized value (not in |
| 3078 // the CC register), we force the right hand side to do the | 2745 // the CC register), we force the right hand side to do the |
| (...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3180 } else { | 2847 } else { |
| 3181 Load(node->left()); | 2848 Load(node->left()); |
| 3182 Load(node->right()); | 2849 Load(node->right()); |
| 3183 GenericBinaryOperation(node->op()); | 2850 GenericBinaryOperation(node->op()); |
| 3184 } | 2851 } |
| 3185 __ push(r0); | 2852 __ push(r0); |
| 3186 } | 2853 } |
| 3187 } | 2854 } |
| 3188 | 2855 |
| 3189 | 2856 |
| 3190 void ArmCodeGenerator::VisitThisFunction(ThisFunction* node) { | 2857 void CodeGenerator::VisitThisFunction(ThisFunction* node) { |
| 3191 __ ldr(r0, FunctionOperand()); | 2858 __ ldr(r0, FunctionOperand()); |
| 3192 __ push(r0); | 2859 __ push(r0); |
| 3193 } | 2860 } |
| 3194 | 2861 |
| 3195 | 2862 |
| 3196 void ArmCodeGenerator::VisitCompareOperation(CompareOperation* node) { | 2863 void CodeGenerator::VisitCompareOperation(CompareOperation* node) { |
| 3197 Comment cmnt(masm_, "[ CompareOperation"); | 2864 Comment cmnt(masm_, "[ CompareOperation"); |
| 3198 | 2865 |
| 3199 // Get the expressions from the node. | 2866 // Get the expressions from the node. |
| 3200 Expression* left = node->left(); | 2867 Expression* left = node->left(); |
| 3201 Expression* right = node->right(); | 2868 Expression* right = node->right(); |
| 3202 Token::Value op = node->op(); | 2869 Token::Value op = node->op(); |
| 3203 | 2870 |
| 3204 // NOTE: To make null checks efficient, we check if either left or | 2871 // NOTE: To make null checks efficient, we check if either left or |
| 3205 // right is the literal 'null'. If so, we optimize the code by | 2872 // right is the literal 'null'. If so, we optimize the code by |
| 3206 // inlining a null check instead of calling the (very) general | 2873 // inlining a null check instead of calling the (very) general |
| (...skipping 174 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3381 __ tst(r0, Operand(r0)); | 3048 __ tst(r0, Operand(r0)); |
| 3382 cc_reg_ = eq; | 3049 cc_reg_ = eq; |
| 3383 break; | 3050 break; |
| 3384 | 3051 |
| 3385 default: | 3052 default: |
| 3386 UNREACHABLE(); | 3053 UNREACHABLE(); |
| 3387 } | 3054 } |
| 3388 } | 3055 } |
| 3389 | 3056 |
| 3390 | 3057 |
| 3391 void ArmCodeGenerator::RecordStatementPosition(Node* node) { | 3058 void CodeGenerator::RecordStatementPosition(Node* node) { |
| 3392 if (FLAG_debug_info) { | 3059 if (FLAG_debug_info) { |
| 3393 int statement_pos = node->statement_pos(); | 3060 int statement_pos = node->statement_pos(); |
| 3394 if (statement_pos == RelocInfo::kNoPosition) return; | 3061 if (statement_pos == RelocInfo::kNoPosition) return; |
| 3395 __ RecordStatementPosition(statement_pos); | 3062 __ RecordStatementPosition(statement_pos); |
| 3396 } | 3063 } |
| 3397 } | 3064 } |
| 3398 | 3065 |
| 3399 | 3066 |
| 3400 void ArmCodeGenerator::EnterJSFrame() { | 3067 void CodeGenerator::EnterJSFrame() { |
| 3401 #if defined(DEBUG) | 3068 #if defined(DEBUG) |
| 3402 { Label done, fail; | 3069 { Label done, fail; |
| 3403 __ tst(r1, Operand(kSmiTagMask)); | 3070 __ tst(r1, Operand(kSmiTagMask)); |
| 3404 __ b(eq, &fail); | 3071 __ b(eq, &fail); |
| 3405 __ ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset)); | 3072 __ ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset)); |
| 3406 __ ldrb(r2, FieldMemOperand(r2, Map::kInstanceTypeOffset)); | 3073 __ ldrb(r2, FieldMemOperand(r2, Map::kInstanceTypeOffset)); |
| 3407 __ cmp(r2, Operand(JS_FUNCTION_TYPE)); | 3074 __ cmp(r2, Operand(JS_FUNCTION_TYPE)); |
| 3408 __ b(eq, &done); | 3075 __ b(eq, &done); |
| 3409 __ bind(&fail); | 3076 __ bind(&fail); |
| 3410 __ stop("ArmCodeGenerator::EnterJSFrame - r1 not a function"); | 3077 __ stop("CodeGenerator::EnterJSFrame - r1 not a function"); |
| 3411 __ bind(&done); | 3078 __ bind(&done); |
| 3412 } | 3079 } |
| 3413 #endif // DEBUG | 3080 #endif // DEBUG |
| 3414 | 3081 |
| 3415 __ stm(db_w, sp, r1.bit() | cp.bit() | fp.bit() | lr.bit()); | 3082 __ stm(db_w, sp, r1.bit() | cp.bit() | fp.bit() | lr.bit()); |
| 3416 __ add(fp, sp, Operand(2 * kPointerSize)); // Adjust FP to point to saved FP. | 3083 __ add(fp, sp, Operand(2 * kPointerSize)); // Adjust FP to point to saved FP. |
| 3417 } | 3084 } |
| 3418 | 3085 |
| 3419 | 3086 |
| 3420 void ArmCodeGenerator::ExitJSFrame() { | 3087 void CodeGenerator::ExitJSFrame() { |
| 3421 // Drop the execution stack down to the frame pointer and restore the caller | 3088 // Drop the execution stack down to the frame pointer and restore the caller |
| 3422 // frame pointer and return address. | 3089 // frame pointer and return address. |
| 3423 __ mov(sp, fp); | 3090 __ mov(sp, fp); |
| 3424 __ ldm(ia_w, sp, fp.bit() | lr.bit()); | 3091 __ ldm(ia_w, sp, fp.bit() | lr.bit()); |
| 3425 } | 3092 } |
| 3426 | 3093 |
| 3427 | 3094 |
| 3428 #undef __ | 3095 #undef __ |
| 3429 #define __ masm-> | 3096 #define __ masm-> |
| 3430 | 3097 |
| (...skipping 1061 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4492 | 4159 |
| 4493 // Slow-case: Non-function called. | 4160 // Slow-case: Non-function called. |
| 4494 __ bind(&slow); | 4161 __ bind(&slow); |
| 4495 __ mov(r0, Operand(argc_)); // Setup the number of arguments. | 4162 __ mov(r0, Operand(argc_)); // Setup the number of arguments. |
| 4496 __ InvokeBuiltin(Builtins::CALL_NON_FUNCTION, JUMP_JS); | 4163 __ InvokeBuiltin(Builtins::CALL_NON_FUNCTION, JUMP_JS); |
| 4497 } | 4164 } |
| 4498 | 4165 |
| 4499 | 4166 |
| 4500 #undef __ | 4167 #undef __ |
| 4501 | 4168 |
| 4502 // ----------------------------------------------------------------------------- | |
| 4503 // CodeGenerator interface | |
| 4504 | |
| 4505 // MakeCode() is just a wrapper for CodeGenerator::MakeCode() | |
| 4506 // so we don't have to expose the entire CodeGenerator class in | |
| 4507 // the .h file. | |
| 4508 Handle<Code> CodeGenerator::MakeCode(FunctionLiteral* fun, | |
| 4509 Handle<Script> script, | |
| 4510 bool is_eval) { | |
| 4511 Handle<Code> code = ArmCodeGenerator::MakeCode(fun, script, is_eval); | |
| 4512 if (!code.is_null()) { | |
| 4513 Counters::total_compiled_code_size.Increment(code->instruction_size()); | |
| 4514 } | |
| 4515 return code; | |
| 4516 } | |
| 4517 | |
| 4518 | |
| 4519 } } // namespace v8::internal | 4169 } } // namespace v8::internal |
| OLD | NEW |