| 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 20 matching lines...) Expand all Loading... |
| 31 #include "codegen-inl.h" | 31 #include "codegen-inl.h" |
| 32 #include "debug.h" | 32 #include "debug.h" |
| 33 #include "scopes.h" | 33 #include "scopes.h" |
| 34 #include "runtime.h" | 34 #include "runtime.h" |
| 35 | 35 |
| 36 namespace v8 { namespace internal { | 36 namespace v8 { namespace internal { |
| 37 | 37 |
| 38 #define __ masm_-> | 38 #define __ masm_-> |
| 39 | 39 |
| 40 // ------------------------------------------------------------------------- | 40 // ------------------------------------------------------------------------- |
| 41 // VirtualFrame implementation. | |
| 42 | |
| 43 VirtualFrame::VirtualFrame(CodeGenerator* cgen) { | |
| 44 ASSERT(cgen->scope() != NULL); | |
| 45 | |
| 46 masm_ = cgen->masm(); | |
| 47 frame_local_count_ = cgen->scope()->num_stack_slots(); | |
| 48 parameter_count_ = cgen->scope()->num_parameters(); | |
| 49 } | |
| 50 | |
| 51 | |
| 52 void VirtualFrame::Enter() { | |
| 53 Comment cmnt(masm_, "[ Enter JS frame"); | |
| 54 __ push(ebp); | |
| 55 __ mov(ebp, Operand(esp)); | |
| 56 | |
| 57 // Store the context and the function in the frame. | |
| 58 __ push(esi); | |
| 59 __ push(edi); | |
| 60 | |
| 61 // Clear the function slot when generating debug code. | |
| 62 if (FLAG_debug_code) { | |
| 63 __ Set(edi, Immediate(reinterpret_cast<int>(kZapValue))); | |
| 64 } | |
| 65 } | |
| 66 | |
| 67 | |
| 68 void VirtualFrame::Exit() { | |
| 69 Comment cmnt(masm_, "[ Exit JS frame"); | |
| 70 // Record the location of the JS exit code for patching when setting | |
| 71 // break point. | |
| 72 __ RecordJSReturn(); | |
| 73 | |
| 74 // Avoid using the leave instruction here, because it is too | |
| 75 // short. We need the return sequence to be a least the size of a | |
| 76 // call instruction to support patching the exit code in the | |
| 77 // debugger. See VisitReturnStatement for the full return sequence. | |
| 78 __ mov(esp, Operand(ebp)); | |
| 79 __ pop(ebp); | |
| 80 } | |
| 81 | |
| 82 | |
| 83 void VirtualFrame::AllocateLocals() { | |
| 84 if (frame_local_count_ > 0) { | |
| 85 Comment cmnt(masm_, "[ Allocate space for locals"); | |
| 86 __ Set(eax, Immediate(Factory::undefined_value())); | |
| 87 for (int i = 0; i < frame_local_count_; i++) { | |
| 88 __ push(eax); | |
| 89 } | |
| 90 } | |
| 91 } | |
| 92 | |
| 93 | |
| 94 void VirtualFrame::Drop(int count) { | |
| 95 ASSERT(count >= 0); | |
| 96 if (count > 0) { | |
| 97 __ add(Operand(esp), Immediate(count * kPointerSize)); | |
| 98 } | |
| 99 } | |
| 100 | |
| 101 | |
| 102 void VirtualFrame::Pop() { | |
| 103 __ add(Operand(esp), Immediate(kPointerSize)); | |
| 104 } | |
| 105 | |
| 106 | |
| 107 void VirtualFrame::Pop(Register reg) { | |
| 108 __ pop(reg); | |
| 109 } | |
| 110 | |
| 111 | |
| 112 void VirtualFrame::Pop(Operand operand) { | |
| 113 __ pop(operand); | |
| 114 } | |
| 115 | |
| 116 | |
| 117 void VirtualFrame::Push(Register reg) { | |
| 118 __ push(reg); | |
| 119 } | |
| 120 | |
| 121 | |
| 122 void VirtualFrame::Push(Operand operand) { | |
| 123 __ push(operand); | |
| 124 } | |
| 125 | |
| 126 | |
| 127 void VirtualFrame::Push(Immediate immediate) { | |
| 128 __ push(immediate); | |
| 129 } | |
| 130 | |
| 131 | |
| 132 // ------------------------------------------------------------------------- | |
| 133 // CodeGenState implementation. | 41 // CodeGenState implementation. |
| 134 | 42 |
| 135 CodeGenState::CodeGenState(CodeGenerator* owner) | 43 CodeGenState::CodeGenState(CodeGenerator* owner) |
| 136 : owner_(owner), | 44 : owner_(owner), |
| 137 typeof_state_(NOT_INSIDE_TYPEOF), | 45 typeof_state_(NOT_INSIDE_TYPEOF), |
| 138 true_target_(NULL), | 46 true_target_(NULL), |
| 139 false_target_(NULL), | 47 false_target_(NULL), |
| 140 previous_(NULL) { | 48 previous_(NULL) { |
| 141 owner_->set_state(this); | 49 owner_->set_state(this); |
| 142 } | 50 } |
| 143 | 51 |
| 144 | 52 |
| 145 CodeGenState::CodeGenState(CodeGenerator* owner, | 53 CodeGenState::CodeGenState(CodeGenerator* owner, |
| 146 TypeofState typeof_state, | 54 TypeofState typeof_state, |
| 147 Label* true_target, | 55 JumpTarget* true_target, |
| 148 Label* false_target) | 56 JumpTarget* false_target) |
| 149 : owner_(owner), | 57 : owner_(owner), |
| 150 typeof_state_(typeof_state), | 58 typeof_state_(typeof_state), |
| 151 true_target_(true_target), | 59 true_target_(true_target), |
| 152 false_target_(false_target), | 60 false_target_(false_target), |
| 153 previous_(owner->state()) { | 61 previous_(owner->state()) { |
| 154 owner_->set_state(this); | 62 owner_->set_state(this); |
| 155 } | 63 } |
| 156 | 64 |
| 157 | 65 |
| 158 CodeGenState::~CodeGenState() { | 66 CodeGenState::~CodeGenState() { |
| (...skipping 10 matching lines...) Expand all Loading... |
| 169 : is_eval_(is_eval), | 77 : is_eval_(is_eval), |
| 170 script_(script), | 78 script_(script), |
| 171 deferred_(8), | 79 deferred_(8), |
| 172 masm_(new MacroAssembler(NULL, buffer_size)), | 80 masm_(new MacroAssembler(NULL, buffer_size)), |
| 173 scope_(NULL), | 81 scope_(NULL), |
| 174 frame_(NULL), | 82 frame_(NULL), |
| 175 cc_reg_(no_condition), | 83 cc_reg_(no_condition), |
| 176 state_(NULL), | 84 state_(NULL), |
| 177 is_inside_try_(false), | 85 is_inside_try_(false), |
| 178 break_stack_height_(0), | 86 break_stack_height_(0), |
| 179 loop_nesting_(0) { | 87 loop_nesting_(0), |
| 88 function_return_is_shadowed_(false) { |
| 180 } | 89 } |
| 181 | 90 |
| 182 | 91 |
| 183 // Calling conventions: | 92 // Calling conventions: |
| 184 // ebp: frame pointer | 93 // ebp: frame pointer |
| 185 // esp: stack pointer | 94 // esp: stack pointer |
| 186 // edi: caller's parameter pointer | 95 // edi: caller's parameter pointer |
| 187 // esi: callee's context | 96 // esi: callee's context |
| 188 | 97 |
| 189 void CodeGenerator::GenCode(FunctionLiteral* fun) { | 98 void CodeGenerator::GenCode(FunctionLiteral* fun) { |
| 190 // Record the position for debugging purposes. | 99 // Record the position for debugging purposes. |
| 191 __ RecordPosition(fun->start_position()); | 100 __ RecordPosition(fun->start_position()); |
| 192 | 101 |
| 193 ZoneList<Statement*>* body = fun->body(); | 102 ZoneList<Statement*>* body = fun->body(); |
| 194 | 103 |
| 195 // Initialize state. | 104 // Initialize state. |
| 196 ASSERT(scope_ == NULL); | 105 ASSERT(scope_ == NULL); |
| 197 scope_ = fun->scope(); | 106 scope_ = fun->scope(); |
| 198 ASSERT(frame_ == NULL); | 107 ASSERT(frame_ == NULL); |
| 199 VirtualFrame virtual_frame(this); | 108 set_frame(new VirtualFrame(this)); |
| 200 frame_ = &virtual_frame; | |
| 201 cc_reg_ = no_condition; | 109 cc_reg_ = no_condition; |
| 110 function_return_.set_code_generator(this); |
| 111 function_return_is_shadowed_ = false; |
| 202 { | 112 { |
| 203 CodeGenState state(this); | 113 CodeGenState state(this); |
| 204 | 114 |
| 205 // Entry | 115 // Entry |
| 206 // stack: function, receiver, arguments, return address | 116 // stack: function, receiver, arguments, return address |
| 207 // esp: stack pointer | 117 // esp: stack pointer |
| 208 // ebp: frame pointer | 118 // ebp: frame pointer |
| 209 // edi: caller's parameter pointer | 119 // edi: caller's parameter pointer |
| 210 // esi: callee's context | 120 // esi: callee's context |
| 211 | 121 |
| (...skipping 20 matching lines...) Expand all Loading... |
| 232 // The arguments object pointer needs to be saved in ecx, since we need | 142 // The arguments object pointer needs to be saved in ecx, since we need |
| 233 // to store arguments into the context. | 143 // to store arguments into the context. |
| 234 if (scope_->arguments() != NULL) { | 144 if (scope_->arguments() != NULL) { |
| 235 ASSERT(scope_->arguments_shadow() != NULL); | 145 ASSERT(scope_->arguments_shadow() != NULL); |
| 236 Comment cmnt(masm_, "[ allocate arguments object"); | 146 Comment cmnt(masm_, "[ allocate arguments object"); |
| 237 ArgumentsAccessStub stub(ArgumentsAccessStub::NEW_OBJECT); | 147 ArgumentsAccessStub stub(ArgumentsAccessStub::NEW_OBJECT); |
| 238 __ lea(eax, frame_->Receiver()); | 148 __ lea(eax, frame_->Receiver()); |
| 239 frame_->Push(frame_->Function()); | 149 frame_->Push(frame_->Function()); |
| 240 frame_->Push(eax); | 150 frame_->Push(eax); |
| 241 frame_->Push(Immediate(Smi::FromInt(scope_->num_parameters()))); | 151 frame_->Push(Immediate(Smi::FromInt(scope_->num_parameters()))); |
| 242 __ CallStub(&stub); | 152 frame_->CallStub(&stub, 3); |
| 243 __ mov(ecx, Operand(eax)); | 153 __ mov(ecx, Operand(eax)); |
| 244 arguments_object_allocated = true; | 154 arguments_object_allocated = true; |
| 245 } | 155 } |
| 246 | 156 |
| 247 // Allocate space for locals and initialize them. | 157 // Allocate space for locals and initialize them. |
| 248 frame_->AllocateLocals(); | 158 frame_->AllocateLocals(); |
| 249 | 159 |
| 250 if (scope_->num_heap_slots() > 0) { | 160 if (scope_->num_heap_slots() > 0) { |
| 251 Comment cmnt(masm_, "[ allocate local context"); | 161 Comment cmnt(masm_, "[ allocate local context"); |
| 252 // Save the arguments object pointer, if any. | 162 // Save the arguments object pointer, if any. |
| 253 if (arguments_object_allocated && !arguments_object_saved) { | 163 if (arguments_object_allocated && !arguments_object_saved) { |
| 254 frame_->Push(ecx); | 164 frame_->Push(ecx); |
| 255 arguments_object_saved = true; | 165 arguments_object_saved = true; |
| 256 } | 166 } |
| 257 // Allocate local context. | 167 // Allocate local context. |
| 258 // Get outer context and create a new context based on it. | 168 // Get outer context and create a new context based on it. |
| 259 frame_->Push(frame_->Function()); | 169 frame_->Push(frame_->Function()); |
| 260 __ CallRuntime(Runtime::kNewContext, 1); // eax holds the result | 170 frame_->CallRuntime(Runtime::kNewContext, 1); // eax holds the result |
| 261 | 171 |
| 262 if (kDebug) { | 172 if (kDebug) { |
| 263 Label verified_true; | 173 JumpTarget verified_true(this); |
| 264 // Verify eax and esi are the same in debug mode | 174 // Verify eax and esi are the same in debug mode |
| 265 __ cmp(eax, Operand(esi)); | 175 __ cmp(eax, Operand(esi)); |
| 266 __ j(equal, &verified_true); | 176 verified_true.Branch(equal); |
| 267 __ int3(); | 177 __ int3(); |
| 268 __ bind(&verified_true); | 178 verified_true.Bind(); |
| 269 } | 179 } |
| 270 | 180 |
| 271 // Update context local. | 181 // Update context local. |
| 272 __ mov(frame_->Context(), esi); | 182 __ mov(frame_->Context(), esi); |
| 273 // Restore the arguments array pointer, if any. | 183 // Restore the arguments array pointer, if any. |
| 274 } | 184 } |
| 275 | 185 |
| 276 // TODO(1241774): Improve this code: | 186 // TODO(1241774): Improve this code: |
| 277 // 1) only needed if we have a context | 187 // 1) only needed if we have a context |
| 278 // 2) no need to recompute context ptr every single time | 188 // 2) no need to recompute context ptr every single time |
| (...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 350 scope_->VisitIllegalRedeclaration(this); | 260 scope_->VisitIllegalRedeclaration(this); |
| 351 } else { | 261 } else { |
| 352 Comment cmnt(masm_, "[ declarations"); | 262 Comment cmnt(masm_, "[ declarations"); |
| 353 ProcessDeclarations(scope_->declarations()); | 263 ProcessDeclarations(scope_->declarations()); |
| 354 // Bail out if a stack-overflow exception occurred when | 264 // Bail out if a stack-overflow exception occurred when |
| 355 // processing declarations. | 265 // processing declarations. |
| 356 if (HasStackOverflow()) return; | 266 if (HasStackOverflow()) return; |
| 357 } | 267 } |
| 358 | 268 |
| 359 if (FLAG_trace) { | 269 if (FLAG_trace) { |
| 360 __ CallRuntime(Runtime::kTraceEnter, 0); | 270 frame_->CallRuntime(Runtime::kTraceEnter, 0); |
| 361 // Ignore the return value. | 271 // Ignore the return value. |
| 362 } | 272 } |
| 363 CheckStack(); | 273 CheckStack(); |
| 364 | 274 |
| 365 // Compile the body of the function in a vanilla state. Don't | 275 // Compile the body of the function in a vanilla state. Don't |
| 366 // bother compiling all the code if the scope has an illegal | 276 // bother compiling all the code if the scope has an illegal |
| 367 // redeclaration. | 277 // redeclaration. |
| 368 if (!scope_->HasIllegalRedeclaration()) { | 278 if (!scope_->HasIllegalRedeclaration()) { |
| 369 Comment cmnt(masm_, "[ function body"); | 279 Comment cmnt(masm_, "[ function body"); |
| 370 #ifdef DEBUG | 280 #ifdef DEBUG |
| 371 bool is_builtin = Bootstrapper::IsActive(); | 281 bool is_builtin = Bootstrapper::IsActive(); |
| 372 bool should_trace = | 282 bool should_trace = |
| 373 is_builtin ? FLAG_trace_builtin_calls : FLAG_trace_calls; | 283 is_builtin ? FLAG_trace_builtin_calls : FLAG_trace_calls; |
| 374 if (should_trace) { | 284 if (should_trace) { |
| 375 __ CallRuntime(Runtime::kDebugTrace, 0); | 285 frame_->CallRuntime(Runtime::kDebugTrace, 0); |
| 376 // Ignore the return value. | 286 // Ignore the return value. |
| 377 } | 287 } |
| 378 #endif | 288 #endif |
| 379 VisitStatements(body); | 289 VisitStatements(body); |
| 380 | 290 |
| 381 // Generate a return statement if necessary. | 291 // Generate a return statement if necessary. A NULL frame indicates |
| 382 if (body->is_empty() || body->last()->AsReturnStatement() == NULL) { | 292 // that control flow leaves the body on all paths and cannot fall |
| 293 // through. |
| 294 if (frame_ != NULL) { |
| 383 Literal undefined(Factory::undefined_value()); | 295 Literal undefined(Factory::undefined_value()); |
| 384 ReturnStatement statement(&undefined); | 296 ReturnStatement statement(&undefined); |
| 385 statement.set_statement_pos(fun->end_position()); | 297 statement.set_statement_pos(fun->end_position()); |
| 386 VisitReturnStatement(&statement); | 298 VisitReturnStatement(&statement); |
| 387 } | 299 } |
| 388 } | 300 } |
| 389 } | 301 } |
| 390 | 302 |
| 391 // Code generation state must be reset. | 303 // Code generation state must be reset. |
| 304 ASSERT(!function_return_is_shadowed_); |
| 305 function_return_.Unuse(); |
| 392 scope_ = NULL; | 306 scope_ = NULL; |
| 393 frame_ = NULL; | 307 delete_frame(); |
| 394 ASSERT(!has_cc()); | 308 ASSERT(!has_cc()); |
| 395 ASSERT(state_ == NULL); | 309 ASSERT(state_ == NULL); |
| 396 } | 310 } |
| 397 | 311 |
| 398 | 312 |
| 399 Operand CodeGenerator::SlotOperand(Slot* slot, Register tmp) { | 313 Operand CodeGenerator::SlotOperand(Slot* slot, Register tmp) { |
| 400 // Currently, this assertion will fail if we try to assign to | 314 // Currently, this assertion will fail if we try to assign to |
| 401 // a constant variable that is constant because it is read-only | 315 // a constant variable that is constant because it is read-only |
| 402 // (such as the variable referring to a named function expression). | 316 // (such as the variable referring to a named function expression). |
| 403 // We need to implement assignments to read-only variables. | 317 // We need to implement assignments to read-only variables. |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 447 } | 361 } |
| 448 | 362 |
| 449 | 363 |
| 450 // Loads a value on TOS. If it is a boolean value, the result may have been | 364 // Loads a value on TOS. If it is a boolean value, the result may have been |
| 451 // (partially) translated into branches, or it may have set the condition code | 365 // (partially) translated into branches, or it may have set the condition code |
| 452 // register. If force_cc is set, the value is forced to set the condition code | 366 // register. If force_cc is set, the value is forced to set the condition code |
| 453 // register and no value is pushed. If the condition code register was set, | 367 // register and no value is pushed. If the condition code register was set, |
| 454 // has_cc() is true and cc_reg_ contains the condition to test for 'true'. | 368 // has_cc() is true and cc_reg_ contains the condition to test for 'true'. |
| 455 void CodeGenerator::LoadCondition(Expression* x, | 369 void CodeGenerator::LoadCondition(Expression* x, |
| 456 TypeofState typeof_state, | 370 TypeofState typeof_state, |
| 457 Label* true_target, | 371 JumpTarget* true_target, |
| 458 Label* false_target, | 372 JumpTarget* false_target, |
| 459 bool force_cc) { | 373 bool force_cc) { |
| 460 ASSERT(!has_cc()); | 374 ASSERT(!has_cc()); |
| 461 | 375 |
| 462 { CodeGenState new_state(this, typeof_state, true_target, false_target); | 376 { CodeGenState new_state(this, typeof_state, true_target, false_target); |
| 463 Visit(x); | 377 Visit(x); |
| 464 } | 378 } |
| 465 if (force_cc && !has_cc()) { | 379 |
| 380 if (force_cc && frame_ != NULL && !has_cc()) { |
| 466 ToBoolean(true_target, false_target); | 381 ToBoolean(true_target, false_target); |
| 467 } | 382 } |
| 468 ASSERT(has_cc() || !force_cc); | 383 |
| 384 ASSERT(!force_cc || frame_ == NULL || has_cc()); |
| 469 } | 385 } |
| 470 | 386 |
| 471 | 387 |
| 472 void CodeGenerator::Load(Expression* x, TypeofState typeof_state) { | 388 void CodeGenerator::Load(Expression* x, TypeofState typeof_state) { |
| 473 Label true_target; | 389 JumpTarget true_target(this); |
| 474 Label false_target; | 390 JumpTarget false_target(this); |
| 475 LoadCondition(x, typeof_state, &true_target, &false_target, false); | 391 LoadCondition(x, typeof_state, &true_target, &false_target, false); |
| 476 | 392 |
| 477 if (has_cc()) { | 393 if (has_cc()) { |
| 394 ASSERT(frame_ != NULL); |
| 478 // convert cc_reg_ into a bool | 395 // convert cc_reg_ into a bool |
| 479 | 396 |
| 480 Label loaded, materialize_true; | 397 JumpTarget loaded(this); |
| 481 __ j(cc_reg_, &materialize_true); | 398 JumpTarget materialize_true(this); |
| 399 materialize_true.Branch(cc_reg_); |
| 482 frame_->Push(Immediate(Factory::false_value())); | 400 frame_->Push(Immediate(Factory::false_value())); |
| 483 __ jmp(&loaded); | 401 loaded.Jump(); |
| 484 __ bind(&materialize_true); | 402 materialize_true.Bind(); |
| 485 frame_->Push(Immediate(Factory::true_value())); | 403 frame_->Push(Immediate(Factory::true_value())); |
| 486 __ bind(&loaded); | 404 loaded.Bind(); |
| 487 cc_reg_ = no_condition; | 405 cc_reg_ = no_condition; |
| 488 } | 406 } |
| 489 | 407 |
| 490 if (true_target.is_linked() || false_target.is_linked()) { | 408 if (true_target.is_linked() || false_target.is_linked()) { |
| 491 // we have at least one condition value | 409 // we have at least one condition value |
| 492 // that has been "translated" into a branch, | 410 // that has been "translated" into a branch, |
| 493 // thus it needs to be loaded explicitly again | 411 // thus it needs to be loaded explicitly again |
| 494 Label loaded; | 412 JumpTarget loaded(this); |
| 495 __ jmp(&loaded); // don't lose current TOS | 413 if (frame_ != NULL) { |
| 414 loaded.Jump(); // don't lose current TOS |
| 415 } |
| 496 bool both = true_target.is_linked() && false_target.is_linked(); | 416 bool both = true_target.is_linked() && false_target.is_linked(); |
| 497 // reincarnate "true", if necessary | 417 // reincarnate "true", if necessary |
| 498 if (true_target.is_linked()) { | 418 if (true_target.is_linked()) { |
| 499 __ bind(&true_target); | 419 true_target.Bind(); |
| 500 frame_->Push(Immediate(Factory::true_value())); | 420 frame_->Push(Immediate(Factory::true_value())); |
| 501 } | 421 } |
| 502 // if both "true" and "false" need to be reincarnated, | 422 // if both "true" and "false" need to be reincarnated, |
| 503 // jump across code for "false" | 423 // jump across code for "false" |
| 504 if (both) | 424 if (both) { |
| 505 __ jmp(&loaded); | 425 loaded.Jump(); |
| 426 } |
| 506 // reincarnate "false", if necessary | 427 // reincarnate "false", if necessary |
| 507 if (false_target.is_linked()) { | 428 if (false_target.is_linked()) { |
| 508 __ bind(&false_target); | 429 false_target.Bind(); |
| 509 frame_->Push(Immediate(Factory::false_value())); | 430 frame_->Push(Immediate(Factory::false_value())); |
| 510 } | 431 } |
| 511 // everything is loaded at this point | 432 // everything is loaded at this point |
| 512 __ bind(&loaded); | 433 loaded.Bind(); |
| 513 } | 434 } |
| 514 ASSERT(!has_cc()); | 435 ASSERT(!has_cc()); |
| 515 } | 436 } |
| 516 | 437 |
| 517 | 438 |
| 518 void CodeGenerator::LoadGlobal() { | 439 void CodeGenerator::LoadGlobal() { |
| 519 frame_->Push(GlobalObject()); | 440 frame_->Push(GlobalObject()); |
| 520 } | 441 } |
| 521 | 442 |
| 522 | 443 |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 588 if (var->is_global()) { | 509 if (var->is_global()) { |
| 589 LoadGlobal(); | 510 LoadGlobal(); |
| 590 ref->set_type(Reference::NAMED); | 511 ref->set_type(Reference::NAMED); |
| 591 } else { | 512 } else { |
| 592 ASSERT(var->slot() != NULL); | 513 ASSERT(var->slot() != NULL); |
| 593 ref->set_type(Reference::SLOT); | 514 ref->set_type(Reference::SLOT); |
| 594 } | 515 } |
| 595 } else { | 516 } else { |
| 596 // Anything else is a runtime error. | 517 // Anything else is a runtime error. |
| 597 Load(e); | 518 Load(e); |
| 598 __ CallRuntime(Runtime::kThrowReferenceError, 1); | 519 frame_->CallRuntime(Runtime::kThrowReferenceError, 1); |
| 599 } | 520 } |
| 600 } | 521 } |
| 601 | 522 |
| 602 | 523 |
| 603 void CodeGenerator::UnloadReference(Reference* ref) { | 524 void CodeGenerator::UnloadReference(Reference* ref) { |
| 604 // Pop a reference from the stack while preserving TOS. | 525 // Pop a reference from the stack while preserving TOS. |
| 605 Comment cmnt(masm_, "[ UnloadReference"); | 526 Comment cmnt(masm_, "[ UnloadReference"); |
| 606 int size = ref->size(); | 527 int size = ref->size(); |
| 607 if (size <= 0) { | 528 if (size <= 0) { |
| 608 // Do nothing. No popping is necessary. | 529 // Do nothing. No popping is necessary. |
| (...skipping 16 matching lines...) Expand all Loading... |
| 625 | 546 |
| 626 private: | 547 private: |
| 627 Major MajorKey() { return ToBoolean; } | 548 Major MajorKey() { return ToBoolean; } |
| 628 int MinorKey() { return 0; } | 549 int MinorKey() { return 0; } |
| 629 }; | 550 }; |
| 630 | 551 |
| 631 | 552 |
| 632 // ECMA-262, section 9.2, page 30: ToBoolean(). Pop the top of stack and | 553 // ECMA-262, section 9.2, page 30: ToBoolean(). Pop the top of stack and |
| 633 // convert it to a boolean in the condition code register or jump to | 554 // convert it to a boolean in the condition code register or jump to |
| 634 // 'false_target'/'true_target' as appropriate. | 555 // 'false_target'/'true_target' as appropriate. |
| 635 void CodeGenerator::ToBoolean(Label* true_target, Label* false_target) { | 556 void CodeGenerator::ToBoolean(JumpTarget* true_target, JumpTarget* false_target)
{ |
| 636 Comment cmnt(masm_, "[ ToBoolean"); | 557 Comment cmnt(masm_, "[ ToBoolean"); |
| 637 | 558 |
| 638 // The value to convert should be popped from the stack. | 559 // The value to convert should be popped from the stack. |
| 639 frame_->Pop(eax); | 560 frame_->Pop(eax); |
| 640 | 561 |
| 641 // Fast case checks. | 562 // Fast case checks. |
| 642 | 563 |
| 643 // 'false' => false. | 564 // 'false' => false. |
| 644 __ cmp(eax, Factory::false_value()); | 565 __ cmp(eax, Factory::false_value()); |
| 645 __ j(equal, false_target); | 566 false_target->Branch(equal); |
| 646 | 567 |
| 647 // 'true' => true. | 568 // 'true' => true. |
| 648 __ cmp(eax, Factory::true_value()); | 569 __ cmp(eax, Factory::true_value()); |
| 649 __ j(equal, true_target); | 570 true_target->Branch(equal); |
| 650 | 571 |
| 651 // 'undefined' => false. | 572 // 'undefined' => false. |
| 652 __ cmp(eax, Factory::undefined_value()); | 573 __ cmp(eax, Factory::undefined_value()); |
| 653 __ j(equal, false_target); | 574 false_target->Branch(equal); |
| 654 | 575 |
| 655 // Smi => false iff zero. | 576 // Smi => false iff zero. |
| 656 ASSERT(kSmiTag == 0); | 577 ASSERT(kSmiTag == 0); |
| 657 __ test(eax, Operand(eax)); | 578 __ test(eax, Operand(eax)); |
| 658 __ j(zero, false_target); | 579 false_target->Branch(zero); |
| 659 __ test(eax, Immediate(kSmiTagMask)); | 580 __ test(eax, Immediate(kSmiTagMask)); |
| 660 __ j(zero, true_target); | 581 true_target->Branch(zero); |
| 661 | 582 |
| 662 // Call the stub for all other cases. | 583 // Call the stub for all other cases. |
| 663 frame_->Push(eax); // Undo the pop(eax) from above. | 584 frame_->Push(eax); // Undo the pop(eax) from above. |
| 664 ToBooleanStub stub; | 585 ToBooleanStub stub; |
| 665 __ CallStub(&stub); | 586 frame_->CallStub(&stub, 1); |
| 666 // Convert result (eax) to condition code. | 587 // Convert result (eax) to condition code. |
| 667 __ test(eax, Operand(eax)); | 588 __ test(eax, Operand(eax)); |
| 668 | 589 |
| 669 ASSERT(not_equal == not_zero); | 590 ASSERT(not_equal == not_zero); |
| 670 cc_reg_ = not_equal; | 591 cc_reg_ = not_equal; |
| 671 } | 592 } |
| 672 | 593 |
| 673 | 594 |
| 674 class FloatingPointHelper : public AllStatic { | 595 class FloatingPointHelper : public AllStatic { |
| 675 public: | 596 public: |
| (...skipping 160 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 836 deferred->GenerateInlineCode(); | 757 deferred->GenerateInlineCode(); |
| 837 // Put result back on the stack. It seems somewhat weird to let | 758 // Put result back on the stack. It seems somewhat weird to let |
| 838 // the deferred code jump back before the assignment to the frame | 759 // the deferred code jump back before the assignment to the frame |
| 839 // top, but this is just to let the peephole optimizer get rid of | 760 // top, but this is just to let the peephole optimizer get rid of |
| 840 // more code. | 761 // more code. |
| 841 __ bind(deferred->exit()); | 762 __ bind(deferred->exit()); |
| 842 __ mov(frame_->Top(), eax); | 763 __ mov(frame_->Top(), eax); |
| 843 } else { | 764 } else { |
| 844 // Call the stub and push the result to the stack. | 765 // Call the stub and push the result to the stack. |
| 845 GenericBinaryOpStub stub(op, overwrite_mode, flags); | 766 GenericBinaryOpStub stub(op, overwrite_mode, flags); |
| 846 __ CallStub(&stub); | 767 frame_->CallStub(&stub, 2); |
| 847 frame_->Push(eax); | 768 frame_->Push(eax); |
| 848 } | 769 } |
| 849 } | 770 } |
| 850 | 771 |
| 851 | 772 |
| 852 class DeferredInlinedSmiOperation: public DeferredCode { | 773 class DeferredInlinedSmiOperation: public DeferredCode { |
| 853 public: | 774 public: |
| 854 DeferredInlinedSmiOperation(CodeGenerator* generator, | 775 DeferredInlinedSmiOperation(CodeGenerator* generator, |
| 855 Token::Value op, int value, | 776 Token::Value op, int value, |
| 856 OverwriteMode overwrite_mode) : | 777 OverwriteMode overwrite_mode) : |
| (...skipping 351 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1208 if (cc == greater || cc == less_equal) { | 1129 if (cc == greater || cc == less_equal) { |
| 1209 cc = ReverseCondition(cc); | 1130 cc = ReverseCondition(cc); |
| 1210 frame_->Pop(edx); | 1131 frame_->Pop(edx); |
| 1211 frame_->Pop(eax); | 1132 frame_->Pop(eax); |
| 1212 } else { | 1133 } else { |
| 1213 frame_->Pop(eax); | 1134 frame_->Pop(eax); |
| 1214 frame_->Pop(edx); | 1135 frame_->Pop(edx); |
| 1215 } | 1136 } |
| 1216 | 1137 |
| 1217 // Check for the smi case. | 1138 // Check for the smi case. |
| 1218 Label is_smi, done; | 1139 JumpTarget is_smi(this); |
| 1140 JumpTarget done(this); |
| 1219 __ mov(ecx, Operand(eax)); | 1141 __ mov(ecx, Operand(eax)); |
| 1220 __ or_(ecx, Operand(edx)); | 1142 __ or_(ecx, Operand(edx)); |
| 1221 __ test(ecx, Immediate(kSmiTagMask)); | 1143 __ test(ecx, Immediate(kSmiTagMask)); |
| 1222 __ j(zero, &is_smi, taken); | 1144 is_smi.Branch(zero, taken); |
| 1223 | 1145 |
| 1224 // When non-smi, call out to the compare stub. "parameters" setup by | 1146 // When non-smi, call out to the compare stub. "parameters" setup by |
| 1225 // calling code in edx and eax and "result" is returned in the flags. | 1147 // calling code in edx and eax and "result" is returned in the flags. |
| 1226 CompareStub stub(cc, strict); | 1148 CompareStub stub(cc, strict); |
| 1227 __ CallStub(&stub); | 1149 frame_->CallStub(&stub, 0); |
| 1228 if (cc == equal) { | 1150 if (cc == equal) { |
| 1229 __ test(eax, Operand(eax)); | 1151 __ test(eax, Operand(eax)); |
| 1230 } else { | 1152 } else { |
| 1231 __ cmp(eax, 0); | 1153 __ cmp(eax, 0); |
| 1232 } | 1154 } |
| 1233 __ jmp(&done); | 1155 done.Jump(); |
| 1234 | 1156 |
| 1235 // Test smi equality by pointer comparison. | 1157 // Test smi equality by pointer comparison. |
| 1236 __ bind(&is_smi); | 1158 is_smi.Bind(); |
| 1237 __ cmp(edx, Operand(eax)); | 1159 __ cmp(edx, Operand(eax)); |
| 1238 // Fall through to |done|. | 1160 // Fall through to |done|. |
| 1239 | 1161 |
| 1240 __ bind(&done); | 1162 done.Bind(); |
| 1241 cc_reg_ = cc; | 1163 cc_reg_ = cc; |
| 1242 } | 1164 } |
| 1243 | 1165 |
| 1244 | 1166 |
| 1245 class SmiComparisonDeferred: public DeferredCode { | 1167 class SmiComparisonDeferred: public DeferredCode { |
| 1246 public: | 1168 public: |
| 1247 SmiComparisonDeferred(CodeGenerator* generator, | 1169 SmiComparisonDeferred(CodeGenerator* generator, |
| 1248 Condition cc, | 1170 Condition cc, |
| 1249 bool strict, | 1171 bool strict, |
| 1250 int value) | 1172 int value) |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1317 // Push the arguments ("left-to-right") on the stack. | 1239 // Push the arguments ("left-to-right") on the stack. |
| 1318 for (int i = 0; i < args->length(); i++) { | 1240 for (int i = 0; i < args->length(); i++) { |
| 1319 Load(args->at(i)); | 1241 Load(args->at(i)); |
| 1320 } | 1242 } |
| 1321 | 1243 |
| 1322 // Record the position for debugging purposes. | 1244 // Record the position for debugging purposes. |
| 1323 __ RecordPosition(position); | 1245 __ RecordPosition(position); |
| 1324 | 1246 |
| 1325 // Use the shared code stub to call the function. | 1247 // Use the shared code stub to call the function. |
| 1326 CallFunctionStub call_function(args->length()); | 1248 CallFunctionStub call_function(args->length()); |
| 1327 __ CallStub(&call_function); | 1249 frame_->CallStub(&call_function, args->length() + 1); |
| 1328 | 1250 |
| 1329 // Restore context and pop function from the stack. | 1251 // Restore context and pop function from the stack. |
| 1330 __ mov(esi, frame_->Context()); | 1252 __ mov(esi, frame_->Context()); |
| 1331 __ mov(frame_->Top(), eax); | 1253 __ mov(frame_->Top(), eax); |
| 1332 } | 1254 } |
| 1333 | 1255 |
| 1334 | 1256 |
| 1335 void CodeGenerator::Branch(bool if_true, Label* L) { | 1257 void CodeGenerator::Branch(bool if_true, JumpTarget* target) { |
| 1336 ASSERT(has_cc()); | 1258 ASSERT(has_cc()); |
| 1337 Condition cc = if_true ? cc_reg_ : NegateCondition(cc_reg_); | 1259 Condition cc = if_true ? cc_reg_ : NegateCondition(cc_reg_); |
| 1338 __ j(cc, L); | 1260 target->Branch(cc); |
| 1339 cc_reg_ = no_condition; | 1261 cc_reg_ = no_condition; |
| 1340 } | 1262 } |
| 1341 | 1263 |
| 1342 | 1264 |
| 1343 void CodeGenerator::CheckStack() { | 1265 void CodeGenerator::CheckStack() { |
| 1344 if (FLAG_check_stack) { | 1266 if (FLAG_check_stack) { |
| 1345 Label stack_is_ok; | 1267 JumpTarget stack_is_ok(this); |
| 1346 StackCheckStub stub; | 1268 StackCheckStub stub; |
| 1347 ExternalReference stack_guard_limit = | 1269 ExternalReference stack_guard_limit = |
| 1348 ExternalReference::address_of_stack_guard_limit(); | 1270 ExternalReference::address_of_stack_guard_limit(); |
| 1349 __ cmp(esp, Operand::StaticVariable(stack_guard_limit)); | 1271 __ cmp(esp, Operand::StaticVariable(stack_guard_limit)); |
| 1350 __ j(above_equal, &stack_is_ok, taken); | 1272 stack_is_ok.Branch(above_equal, taken); |
| 1351 __ CallStub(&stub); | 1273 frame_->CallStub(&stub, 0); |
| 1352 __ bind(&stack_is_ok); | 1274 stack_is_ok.Bind(); |
| 1275 } |
| 1276 } |
| 1277 |
| 1278 |
| 1279 void CodeGenerator::VisitStatements(ZoneList<Statement*>* statements) { |
| 1280 for (int i = 0; frame_ != NULL && i < statements->length(); i++) { |
| 1281 Visit(statements->at(i)); |
| 1353 } | 1282 } |
| 1354 } | 1283 } |
| 1355 | 1284 |
| 1356 | 1285 |
| 1357 void CodeGenerator::VisitBlock(Block* node) { | 1286 void CodeGenerator::VisitBlock(Block* node) { |
| 1358 Comment cmnt(masm_, "[ Block"); | 1287 Comment cmnt(masm_, "[ Block"); |
| 1359 RecordStatementPosition(node); | 1288 RecordStatementPosition(node); |
| 1360 node->set_break_stack_height(break_stack_height_); | 1289 node->set_break_stack_height(break_stack_height_); |
| 1290 node->break_target()->set_code_generator(this); |
| 1361 VisitStatements(node->statements()); | 1291 VisitStatements(node->statements()); |
| 1362 __ bind(node->break_target()); | 1292 if (node->break_target()->is_linked()) { |
| 1293 node->break_target()->Bind(); |
| 1294 } |
| 1363 } | 1295 } |
| 1364 | 1296 |
| 1365 | 1297 |
| 1366 void CodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) { | 1298 void CodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) { |
| 1367 frame_->Push(Immediate(pairs)); | 1299 frame_->Push(Immediate(pairs)); |
| 1368 frame_->Push(esi); | 1300 frame_->Push(esi); |
| 1369 frame_->Push(Immediate(Smi::FromInt(is_eval() ? 1 : 0))); | 1301 frame_->Push(Immediate(Smi::FromInt(is_eval() ? 1 : 0))); |
| 1370 __ CallRuntime(Runtime::kDeclareGlobals, 3); | 1302 frame_->CallRuntime(Runtime::kDeclareGlobals, 3); |
| 1371 // Return value is ignored. | 1303 // Return value is ignored. |
| 1372 } | 1304 } |
| 1373 | 1305 |
| 1374 | 1306 |
| 1375 void CodeGenerator::VisitDeclaration(Declaration* node) { | 1307 void CodeGenerator::VisitDeclaration(Declaration* node) { |
| 1376 Comment cmnt(masm_, "[ Declaration"); | 1308 Comment cmnt(masm_, "[ Declaration"); |
| 1377 Variable* var = node->proxy()->var(); | 1309 Variable* var = node->proxy()->var(); |
| 1378 ASSERT(var != NULL); // must have been resolved | 1310 ASSERT(var != NULL); // must have been resolved |
| 1379 Slot* slot = var->slot(); | 1311 Slot* slot = var->slot(); |
| 1380 | 1312 |
| (...skipping 15 matching lines...) Expand all Loading... |
| 1396 // Note: For variables we must not push an initial value (such as | 1328 // Note: For variables we must not push an initial value (such as |
| 1397 // 'undefined') because we may have a (legal) redeclaration and we | 1329 // 'undefined') because we may have a (legal) redeclaration and we |
| 1398 // must not destroy the current value. | 1330 // must not destroy the current value. |
| 1399 if (node->mode() == Variable::CONST) { | 1331 if (node->mode() == Variable::CONST) { |
| 1400 frame_->Push(Immediate(Factory::the_hole_value())); | 1332 frame_->Push(Immediate(Factory::the_hole_value())); |
| 1401 } else if (node->fun() != NULL) { | 1333 } else if (node->fun() != NULL) { |
| 1402 Load(node->fun()); | 1334 Load(node->fun()); |
| 1403 } else { | 1335 } else { |
| 1404 frame_->Push(Immediate(0)); // no initial value! | 1336 frame_->Push(Immediate(0)); // no initial value! |
| 1405 } | 1337 } |
| 1406 __ CallRuntime(Runtime::kDeclareContextSlot, 4); | 1338 frame_->CallRuntime(Runtime::kDeclareContextSlot, 4); |
| 1407 // Ignore the return value (declarations are statements). | 1339 // Ignore the return value (declarations are statements). |
| 1408 return; | 1340 return; |
| 1409 } | 1341 } |
| 1410 | 1342 |
| 1411 ASSERT(!var->is_global()); | 1343 ASSERT(!var->is_global()); |
| 1412 | 1344 |
| 1413 // If we have a function or a constant, we need to initialize the variable. | 1345 // If we have a function or a constant, we need to initialize the variable. |
| 1414 Expression* val = NULL; | 1346 Expression* val = NULL; |
| 1415 if (node->mode() == Variable::CONST) { | 1347 if (node->mode() == Variable::CONST) { |
| 1416 val = new Literal(Factory::the_hole_value()); | 1348 val = new Literal(Factory::the_hole_value()); |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1451 | 1383 |
| 1452 | 1384 |
| 1453 void CodeGenerator::VisitIfStatement(IfStatement* node) { | 1385 void CodeGenerator::VisitIfStatement(IfStatement* node) { |
| 1454 Comment cmnt(masm_, "[ IfStatement"); | 1386 Comment cmnt(masm_, "[ IfStatement"); |
| 1455 // Generate different code depending on which | 1387 // Generate different code depending on which |
| 1456 // parts of the if statement are present or not. | 1388 // parts of the if statement are present or not. |
| 1457 bool has_then_stm = node->HasThenStatement(); | 1389 bool has_then_stm = node->HasThenStatement(); |
| 1458 bool has_else_stm = node->HasElseStatement(); | 1390 bool has_else_stm = node->HasElseStatement(); |
| 1459 | 1391 |
| 1460 RecordStatementPosition(node); | 1392 RecordStatementPosition(node); |
| 1461 Label exit; | 1393 JumpTarget exit(this); |
| 1462 if (has_then_stm && has_else_stm) { | 1394 if (has_then_stm && has_else_stm) { |
| 1463 Label then; | 1395 JumpTarget then(this); |
| 1464 Label else_; | 1396 JumpTarget else_(this); |
| 1465 // if (cond) | 1397 // if (cond) |
| 1466 LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &then, &else_, true); | 1398 LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &then, &else_, true); |
| 1467 Branch(false, &else_); | 1399 if (frame_ != NULL) { |
| 1400 // A NULL frame here indicates that the code for the condition cannot |
| 1401 // fall-through, i.e. it causes unconditional branchs to targets. |
| 1402 Branch(false, &else_); |
| 1403 } |
| 1468 // then | 1404 // then |
| 1469 __ bind(&then); | 1405 if (frame_ != NULL || then.is_linked()) { |
| 1470 Visit(node->then_statement()); | 1406 // If control flow can reach the then part via fall-through from the |
| 1471 __ jmp(&exit); | 1407 // test or a branch to the target, compile it. |
| 1408 then.Bind(); |
| 1409 Visit(node->then_statement()); |
| 1410 } |
| 1411 if (frame_ != NULL) { |
| 1412 // A NULL frame here indicates that control did not fall out of the |
| 1413 // then statement, it escaped on all branches. In that case, a jump |
| 1414 // to the exit label would be dead code (and impossible, because we |
| 1415 // don't have a current virtual frame to set at the exit label). |
| 1416 exit.Jump(); |
| 1417 } |
| 1472 // else | 1418 // else |
| 1473 __ bind(&else_); | 1419 if (else_.is_linked()) { |
| 1474 Visit(node->else_statement()); | 1420 // Control flow for if-then-else does not fall-through to the else |
| 1421 // part, it can only reach here via jump if at all. |
| 1422 else_.Bind(); |
| 1423 Visit(node->else_statement()); |
| 1424 } |
| 1475 | 1425 |
| 1476 } else if (has_then_stm) { | 1426 } else if (has_then_stm) { |
| 1477 ASSERT(!has_else_stm); | 1427 ASSERT(!has_else_stm); |
| 1478 Label then; | 1428 JumpTarget then(this); |
| 1479 // if (cond) | 1429 // if (cond) |
| 1480 LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &then, &exit, true); | 1430 LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &then, &exit, true); |
| 1481 Branch(false, &exit); | 1431 if (frame_ != NULL) { |
| 1432 Branch(false, &exit); |
| 1433 } |
| 1482 // then | 1434 // then |
| 1483 __ bind(&then); | 1435 if (frame_ != NULL || then.is_linked()) { |
| 1484 Visit(node->then_statement()); | 1436 then.Bind(); |
| 1437 Visit(node->then_statement()); |
| 1438 } |
| 1485 | 1439 |
| 1486 } else if (has_else_stm) { | 1440 } else if (has_else_stm) { |
| 1487 ASSERT(!has_then_stm); | 1441 ASSERT(!has_then_stm); |
| 1488 Label else_; | 1442 JumpTarget else_(this); |
| 1489 // if (!cond) | 1443 // if (!cond) |
| 1490 LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &exit, &else_, true); | 1444 LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &exit, &else_, true); |
| 1491 Branch(true, &exit); | 1445 if (frame_ != NULL) { |
| 1446 Branch(true, &exit); |
| 1447 } |
| 1492 // else | 1448 // else |
| 1493 __ bind(&else_); | 1449 if (frame_ != NULL || else_.is_linked()) { |
| 1494 Visit(node->else_statement()); | 1450 else_.Bind(); |
| 1451 Visit(node->else_statement()); |
| 1452 } |
| 1495 | 1453 |
| 1496 } else { | 1454 } else { |
| 1497 ASSERT(!has_then_stm && !has_else_stm); | 1455 ASSERT(!has_then_stm && !has_else_stm); |
| 1498 // if (cond) | 1456 // if (cond) |
| 1499 LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &exit, &exit, false); | 1457 LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &exit, &exit, false); |
| 1500 if (has_cc()) { | 1458 if (frame_ != NULL) { |
| 1501 cc_reg_ = no_condition; | 1459 if (has_cc()) { |
| 1502 } else { | 1460 cc_reg_ = no_condition; |
| 1503 // No cc value set up, that means the boolean was pushed. | 1461 } else { |
| 1504 // Pop it again, since it is not going to be used. | 1462 // No cc value set up, that means the boolean was pushed. |
| 1505 frame_->Pop(); | 1463 // Pop it again, since it is not going to be used. |
| 1464 frame_->Pop(); |
| 1465 } |
| 1506 } | 1466 } |
| 1507 } | 1467 } |
| 1508 | 1468 |
| 1509 // end | 1469 // end |
| 1510 __ bind(&exit); | 1470 if (exit.is_linked()) { |
| 1471 exit.Bind(); |
| 1472 } |
| 1511 } | 1473 } |
| 1512 | 1474 |
| 1513 | 1475 |
| 1514 void CodeGenerator::CleanStack(int num_bytes) { | 1476 void CodeGenerator::CleanStack(int num_bytes) { |
| 1515 ASSERT(num_bytes % kPointerSize == 0); | 1477 ASSERT(num_bytes % kPointerSize == 0); |
| 1516 frame_->Drop(num_bytes / kPointerSize); | 1478 frame_->Drop(num_bytes / kPointerSize); |
| 1517 } | 1479 } |
| 1518 | 1480 |
| 1519 | 1481 |
| 1520 void CodeGenerator::VisitContinueStatement(ContinueStatement* node) { | 1482 void CodeGenerator::VisitContinueStatement(ContinueStatement* node) { |
| 1521 Comment cmnt(masm_, "[ ContinueStatement"); | 1483 Comment cmnt(masm_, "[ ContinueStatement"); |
| 1522 RecordStatementPosition(node); | 1484 RecordStatementPosition(node); |
| 1523 CleanStack(break_stack_height_ - node->target()->break_stack_height()); | 1485 CleanStack(break_stack_height_ - node->target()->break_stack_height()); |
| 1524 __ jmp(node->target()->continue_target()); | 1486 node->target()->continue_target()->Jump(); |
| 1525 } | 1487 } |
| 1526 | 1488 |
| 1527 | 1489 |
| 1528 void CodeGenerator::VisitBreakStatement(BreakStatement* node) { | 1490 void CodeGenerator::VisitBreakStatement(BreakStatement* node) { |
| 1529 Comment cmnt(masm_, "[ BreakStatement"); | 1491 Comment cmnt(masm_, "[ BreakStatement"); |
| 1530 RecordStatementPosition(node); | 1492 RecordStatementPosition(node); |
| 1531 CleanStack(break_stack_height_ - node->target()->break_stack_height()); | 1493 CleanStack(break_stack_height_ - node->target()->break_stack_height()); |
| 1532 __ jmp(node->target()->break_target()); | 1494 node->target()->break_target()->Jump(); |
| 1533 } | 1495 } |
| 1534 | 1496 |
| 1535 | 1497 |
| 1536 void CodeGenerator::VisitReturnStatement(ReturnStatement* node) { | 1498 void CodeGenerator::VisitReturnStatement(ReturnStatement* node) { |
| 1537 Comment cmnt(masm_, "[ ReturnStatement"); | 1499 Comment cmnt(masm_, "[ ReturnStatement"); |
| 1538 RecordStatementPosition(node); | 1500 RecordStatementPosition(node); |
| 1539 Load(node->expression()); | 1501 Load(node->expression()); |
| 1540 | 1502 |
| 1541 // Move the function result into eax | 1503 // Move the function result into eax |
| 1542 frame_->Pop(eax); | 1504 frame_->Pop(eax); |
| 1543 | 1505 |
| 1544 // If we're inside a try statement or the return instruction | 1506 // If we're inside a try statement or the return instruction |
| 1545 // sequence has been generated, we just jump to that | 1507 // sequence has been generated, we just jump to that |
| 1546 // point. Otherwise, we generate the return instruction sequence and | 1508 // point. Otherwise, we generate the return instruction sequence and |
| 1547 // bind the function return label. | 1509 // bind the function return label. |
| 1548 if (is_inside_try_ || function_return_.is_bound()) { | 1510 if (is_inside_try_ || function_return_.is_bound()) { |
| 1549 __ jmp(&function_return_); | 1511 function_return_.Jump(); |
| 1550 } else { | 1512 } else { |
| 1551 __ bind(&function_return_); | 1513 function_return_.Bind(); |
| 1552 if (FLAG_trace) { | 1514 if (FLAG_trace) { |
| 1553 frame_->Push(eax); // undo the pop(eax) from above | 1515 frame_->Push(eax); // undo the pop(eax) from above |
| 1554 __ CallRuntime(Runtime::kTraceExit, 1); | 1516 frame_->CallRuntime(Runtime::kTraceExit, 1); |
| 1555 } | 1517 } |
| 1556 | 1518 |
| 1557 // Add a label for checking the size of the code used for returning. | 1519 // Add a label for checking the size of the code used for returning. |
| 1558 Label check_exit_codesize; | 1520 Label check_exit_codesize; |
| 1559 __ bind(&check_exit_codesize); | 1521 __ bind(&check_exit_codesize); |
| 1560 | 1522 |
| 1561 // Leave the frame and return popping the arguments and the | 1523 // Leave the frame and return popping the arguments and the |
| 1562 // receiver. | 1524 // receiver. |
| 1563 frame_->Exit(); | 1525 frame_->Exit(); |
| 1564 __ ret((scope_->num_parameters() + 1) * kPointerSize); | 1526 __ ret((scope_->num_parameters() + 1) * kPointerSize); |
| 1527 delete_frame(); |
| 1565 | 1528 |
| 1566 // Check that the size of the code used for returning matches what is | 1529 // Check that the size of the code used for returning matches what is |
| 1567 // expected by the debugger. | 1530 // expected by the debugger. |
| 1568 ASSERT_EQ(Debug::kIa32JSReturnSequenceLength, | 1531 ASSERT_EQ(Debug::kIa32JSReturnSequenceLength, |
| 1569 __ SizeOfCodeGeneratedSince(&check_exit_codesize)); | 1532 __ SizeOfCodeGeneratedSince(&check_exit_codesize)); |
| 1570 } | 1533 } |
| 1571 } | 1534 } |
| 1572 | 1535 |
| 1573 | 1536 |
| 1574 void CodeGenerator::VisitWithEnterStatement(WithEnterStatement* node) { | 1537 void CodeGenerator::VisitWithEnterStatement(WithEnterStatement* node) { |
| 1575 Comment cmnt(masm_, "[ WithEnterStatement"); | 1538 Comment cmnt(masm_, "[ WithEnterStatement"); |
| 1576 RecordStatementPosition(node); | 1539 RecordStatementPosition(node); |
| 1577 Load(node->expression()); | 1540 Load(node->expression()); |
| 1578 __ CallRuntime(Runtime::kPushContext, 1); | 1541 frame_->CallRuntime(Runtime::kPushContext, 1); |
| 1579 | 1542 |
| 1580 if (kDebug) { | 1543 if (kDebug) { |
| 1581 Label verified_true; | 1544 JumpTarget verified_true(this); |
| 1582 // Verify eax and esi are the same in debug mode | 1545 // Verify eax and esi are the same in debug mode |
| 1583 __ cmp(eax, Operand(esi)); | 1546 __ cmp(eax, Operand(esi)); |
| 1584 __ j(equal, &verified_true); | 1547 verified_true.Branch(equal); |
| 1585 __ int3(); | 1548 __ int3(); |
| 1586 __ bind(&verified_true); | 1549 verified_true.Bind(); |
| 1587 } | 1550 } |
| 1588 | 1551 |
| 1589 // Update context local. | 1552 // Update context local. |
| 1590 __ mov(frame_->Context(), esi); | 1553 __ mov(frame_->Context(), esi); |
| 1591 } | 1554 } |
| 1592 | 1555 |
| 1593 | 1556 |
| 1594 void CodeGenerator::VisitWithExitStatement(WithExitStatement* node) { | 1557 void CodeGenerator::VisitWithExitStatement(WithExitStatement* node) { |
| 1595 Comment cmnt(masm_, "[ WithExitStatement"); | 1558 Comment cmnt(masm_, "[ WithExitStatement"); |
| 1596 // Pop context. | 1559 // Pop context. |
| 1597 __ mov(esi, ContextOperand(esi, Context::PREVIOUS_INDEX)); | 1560 __ mov(esi, ContextOperand(esi, Context::PREVIOUS_INDEX)); |
| 1598 // Update context local. | 1561 // Update context local. |
| 1599 __ mov(frame_->Context(), esi); | 1562 __ mov(frame_->Context(), esi); |
| 1600 } | 1563 } |
| 1601 | 1564 |
| 1565 |
| 1602 int CodeGenerator::FastCaseSwitchMaxOverheadFactor() { | 1566 int CodeGenerator::FastCaseSwitchMaxOverheadFactor() { |
| 1603 return kFastSwitchMaxOverheadFactor; | 1567 return kFastSwitchMaxOverheadFactor; |
| 1604 } | 1568 } |
| 1605 | 1569 |
| 1570 |
| 1606 int CodeGenerator::FastCaseSwitchMinCaseCount() { | 1571 int CodeGenerator::FastCaseSwitchMinCaseCount() { |
| 1607 return kFastSwitchMinCaseCount; | 1572 return kFastSwitchMinCaseCount; |
| 1608 } | 1573 } |
| 1609 | 1574 |
| 1575 |
| 1610 // Generate a computed jump to a switch case. | 1576 // Generate a computed jump to a switch case. |
| 1611 void CodeGenerator::GenerateFastCaseSwitchJumpTable( | 1577 void CodeGenerator::GenerateFastCaseSwitchJumpTable( |
| 1612 SwitchStatement* node, | 1578 SwitchStatement* node, |
| 1613 int min_index, | 1579 int min_index, |
| 1614 int range, | 1580 int range, |
| 1615 Label* fail_label, | 1581 JumpTarget* fail_label, |
| 1616 Vector<Label*> case_targets, | 1582 Vector<JumpTarget*> case_targets, |
| 1617 Vector<Label> case_labels) { | 1583 Vector<JumpTarget> case_labels) { |
| 1618 // Notice: Internal references, used by both the jmp instruction and | 1584 // Notice: Internal references, used by both the jmp instruction and |
| 1619 // the table entries, need to be relocated if the buffer grows. This | 1585 // the table entries, need to be relocated if the buffer grows. This |
| 1620 // prevents the forward use of Labels, since a displacement cannot | 1586 // prevents the forward use of Labels, since a displacement cannot |
| 1621 // survive relocation, and it also cannot safely be distinguished | 1587 // survive relocation, and it also cannot safely be distinguished |
| 1622 // from a real address. Instead we put in zero-values as | 1588 // from a real address. Instead we put in zero-values as |
| 1623 // placeholders, and fill in the addresses after the labels have been | 1589 // placeholders, and fill in the addresses after the labels have been |
| 1624 // bound. | 1590 // bound. |
| 1625 | 1591 |
| 1626 frame_->Pop(eax); // supposed smi | 1592 frame_->Pop(eax); // supposed smi |
| 1627 // check range of value, if outside [0..length-1] jump to default/end label. | 1593 // check range of value, if outside [0..length-1] jump to default/end label. |
| 1628 ASSERT(kSmiTagSize == 1 && kSmiTag == 0); | 1594 ASSERT(kSmiTagSize == 1 && kSmiTag == 0); |
| 1629 if (min_index != 0) { | 1595 if (min_index != 0) { |
| 1630 __ sub(Operand(eax), Immediate(min_index << kSmiTagSize)); | 1596 __ sub(Operand(eax), Immediate(min_index << kSmiTagSize)); |
| 1631 } | 1597 } |
| 1632 __ test(eax, Immediate(0x80000000 | kSmiTagMask)); // negative or not Smi | 1598 __ test(eax, Immediate(0x80000000 | kSmiTagMask)); // negative or not Smi |
| 1633 __ j(not_equal, fail_label, not_taken); | 1599 fail_label->Branch(not_equal, not_taken); |
| 1634 __ cmp(eax, range << kSmiTagSize); | 1600 __ cmp(eax, range << kSmiTagSize); |
| 1635 __ j(greater_equal, fail_label, not_taken); | 1601 fail_label->Branch(greater_equal, not_taken); |
| 1636 | 1602 |
| 1637 // 0 is placeholder. | 1603 // 0 is placeholder. |
| 1638 __ jmp(Operand(eax, times_2, 0x0, RelocInfo::INTERNAL_REFERENCE)); | 1604 __ jmp(Operand(eax, times_2, 0x0, RelocInfo::INTERNAL_REFERENCE)); |
| 1639 // calculate address to overwrite later with actual address of table. | 1605 // calculate address to overwrite later with actual address of table. |
| 1640 int32_t jump_table_ref = __ pc_offset() - sizeof(int32_t); | 1606 int32_t jump_table_ref = __ pc_offset() - sizeof(int32_t); |
| 1641 | 1607 |
| 1642 __ Align(4); | 1608 __ Align(4); |
| 1643 Label table_start; | 1609 JumpTarget table_start(this); |
| 1644 __ bind(&table_start); | 1610 table_start.Bind(); |
| 1645 __ WriteInternalReference(jump_table_ref, table_start); | 1611 __ WriteInternalReference(jump_table_ref, *table_start.label()); |
| 1646 | 1612 |
| 1647 for (int i = 0; i < range; i++) { | 1613 for (int i = 0; i < range; i++) { |
| 1648 // table entry, 0 is placeholder for case address | 1614 // table entry, 0 is placeholder for case address |
| 1649 __ dd(0x0, RelocInfo::INTERNAL_REFERENCE); | 1615 __ dd(0x0, RelocInfo::INTERNAL_REFERENCE); |
| 1650 } | 1616 } |
| 1651 | 1617 |
| 1652 GenerateFastCaseSwitchCases(node, case_labels); | 1618 GenerateFastCaseSwitchCases(node, case_labels, &table_start); |
| 1653 | 1619 |
| 1654 for (int i = 0, entry_pos = table_start.pos(); | 1620 for (int i = 0, entry_pos = table_start.label()->pos(); |
| 1655 i < range; i++, entry_pos += sizeof(uint32_t)) { | 1621 i < range; |
| 1656 __ WriteInternalReference(entry_pos, *case_targets[i]); | 1622 i++, entry_pos += sizeof(uint32_t)) { |
| 1623 __ WriteInternalReference(entry_pos, *case_targets[i]->label()); |
| 1657 } | 1624 } |
| 1658 } | 1625 } |
| 1659 | 1626 |
| 1660 | 1627 |
| 1661 void CodeGenerator::VisitSwitchStatement(SwitchStatement* node) { | 1628 void CodeGenerator::VisitSwitchStatement(SwitchStatement* node) { |
| 1662 Comment cmnt(masm_, "[ SwitchStatement"); | 1629 Comment cmnt(masm_, "[ SwitchStatement"); |
| 1663 RecordStatementPosition(node); | 1630 RecordStatementPosition(node); |
| 1664 node->set_break_stack_height(break_stack_height_); | 1631 node->set_break_stack_height(break_stack_height_); |
| 1632 node->break_target()->set_code_generator(this); |
| 1665 | 1633 |
| 1666 Load(node->tag()); | 1634 Load(node->tag()); |
| 1667 | 1635 |
| 1668 if (TryGenerateFastCaseSwitchStatement(node)) { | 1636 if (TryGenerateFastCaseSwitchStatement(node)) { |
| 1669 return; | 1637 return; |
| 1670 } | 1638 } |
| 1671 | 1639 |
| 1672 Label next, fall_through, default_case; | 1640 JumpTarget next_test(this); |
| 1641 JumpTarget fall_through(this); |
| 1642 JumpTarget default_entry(this); |
| 1643 JumpTarget default_exit(this); |
| 1644 |
| 1673 ZoneList<CaseClause*>* cases = node->cases(); | 1645 ZoneList<CaseClause*>* cases = node->cases(); |
| 1674 int length = cases->length(); | 1646 int length = cases->length(); |
| 1647 CaseClause* default_clause = NULL; |
| 1675 | 1648 |
| 1676 for (int i = 0; i < length; i++) { | 1649 for (int i = 0; i < length; i++) { |
| 1677 CaseClause* clause = cases->at(i); | 1650 CaseClause* clause = cases->at(i); |
| 1678 Comment cmnt(masm_, "[ case clause"); | |
| 1679 | 1651 |
| 1680 if (clause->is_default()) { | 1652 if (clause->is_default()) { |
| 1681 // Continue matching cases. The program will execute the default case's | 1653 default_clause = clause; |
| 1682 // statements if it does not match any of the cases. | 1654 } else { |
| 1683 __ jmp(&next); | 1655 Comment cmnt(masm_, "[ Case clause"); |
| 1684 | 1656 |
| 1685 // Bind the default case label, so we can branch to it when we | 1657 // Compile the test. |
| 1686 // have compared against all other cases. | 1658 next_test.Bind(); |
| 1687 ASSERT(default_case.is_unused()); // at most one default clause | 1659 next_test.Unuse(); |
| 1688 __ bind(&default_case); | 1660 // Duplicate TOS. |
| 1689 } else { | |
| 1690 __ bind(&next); | |
| 1691 next.Unuse(); | |
| 1692 __ mov(eax, frame_->Top()); | 1661 __ mov(eax, frame_->Top()); |
| 1693 frame_->Push(eax); // duplicate TOS | 1662 frame_->Push(eax); |
| 1694 Load(clause->label()); | 1663 Load(clause->label()); |
| 1695 Comparison(equal, true); | 1664 Comparison(equal, true); |
| 1696 Branch(false, &next); | 1665 Branch(false, &next_test); |
| 1666 |
| 1667 // Before entering the body, remove the switch value from the stack. |
| 1668 frame_->Pop(); |
| 1669 |
| 1670 // Label the body so that fall through is enabled. |
| 1671 if (i > 0 && cases->at(i - 1)->is_default()) { |
| 1672 default_exit.Bind(); |
| 1673 } else { |
| 1674 fall_through.Bind(); |
| 1675 fall_through.Unuse(); |
| 1676 } |
| 1677 VisitStatements(clause->statements()); |
| 1678 |
| 1679 // If control flow can fall through from the body jump to the |
| 1680 // next body or end of the statement. |
| 1681 if (frame_ != NULL) { |
| 1682 if (i < length - 1 && cases->at(i + 1)->is_default()) { |
| 1683 default_entry.Jump(); |
| 1684 } else { |
| 1685 fall_through.Jump(); |
| 1686 } |
| 1687 } |
| 1697 } | 1688 } |
| 1698 | |
| 1699 // Entering the case statement for the first time. Remove the switch value | |
| 1700 // from the stack. | |
| 1701 frame_->Pop(eax); | |
| 1702 | |
| 1703 // Generate code for the body. | |
| 1704 // This is also the target for the fall through from the previous case's | |
| 1705 // statements which has to skip over the matching code and the popping of | |
| 1706 // the switch value. | |
| 1707 __ bind(&fall_through); | |
| 1708 fall_through.Unuse(); | |
| 1709 VisitStatements(clause->statements()); | |
| 1710 __ jmp(&fall_through); | |
| 1711 } | 1689 } |
| 1712 | 1690 |
| 1713 __ bind(&next); | 1691 // The final test removes the switch value. |
| 1714 // Reached the end of the case statements without matching any of the cases. | 1692 next_test.Bind(); |
| 1715 if (default_case.is_bound()) { | 1693 frame_->Pop(); |
| 1716 // A default case exists -> execute its statements. | 1694 |
| 1717 __ jmp(&default_case); | 1695 // If there is a default clause, compile it. |
| 1718 } else { | 1696 if (default_clause != NULL) { |
| 1719 // Remove the switch value from the stack. | 1697 Comment cmnt(masm_, "[ Default clause"); |
| 1720 frame_->Pop(); | 1698 default_entry.Bind(); |
| 1699 VisitStatements(default_clause->statements()); |
| 1700 // If control flow can fall out of the default and there is a case after |
| 1701 // it, jump to that case's body. |
| 1702 if (frame_ != NULL && default_exit.is_bound()) { |
| 1703 default_exit.Jump(); |
| 1704 } |
| 1721 } | 1705 } |
| 1722 | 1706 |
| 1723 __ bind(&fall_through); | 1707 if (fall_through.is_linked()) { |
| 1724 __ bind(node->break_target()); | 1708 fall_through.Bind(); |
| 1709 } |
| 1710 |
| 1711 if (node->break_target()->is_linked()) { |
| 1712 node->break_target()->Bind(); |
| 1713 } |
| 1725 } | 1714 } |
| 1726 | 1715 |
| 1727 | 1716 |
| 1728 void CodeGenerator::VisitLoopStatement(LoopStatement* node) { | 1717 void CodeGenerator::VisitLoopStatement(LoopStatement* node) { |
| 1729 Comment cmnt(masm_, "[ LoopStatement"); | 1718 Comment cmnt(masm_, "[ LoopStatement"); |
| 1730 RecordStatementPosition(node); | 1719 RecordStatementPosition(node); |
| 1731 node->set_break_stack_height(break_stack_height_); | 1720 node->set_break_stack_height(break_stack_height_); |
| 1721 node->break_target()->set_code_generator(this); |
| 1722 node->continue_target()->set_code_generator(this); |
| 1732 | 1723 |
| 1733 // simple condition analysis | 1724 // Simple condition analysis. ALWAYS_TRUE and ALWAYS_FALSE represent a |
| 1725 // known result for the test expression, with no side effects. |
| 1734 enum { ALWAYS_TRUE, ALWAYS_FALSE, DONT_KNOW } info = DONT_KNOW; | 1726 enum { ALWAYS_TRUE, ALWAYS_FALSE, DONT_KNOW } info = DONT_KNOW; |
| 1735 if (node->cond() == NULL) { | 1727 if (node->cond() == NULL) { |
| 1736 ASSERT(node->type() == LoopStatement::FOR_LOOP); | 1728 ASSERT(node->type() == LoopStatement::FOR_LOOP); |
| 1737 info = ALWAYS_TRUE; | 1729 info = ALWAYS_TRUE; |
| 1738 } else { | 1730 } else { |
| 1739 Literal* lit = node->cond()->AsLiteral(); | 1731 Literal* lit = node->cond()->AsLiteral(); |
| 1740 if (lit != NULL) { | 1732 if (lit != NULL) { |
| 1741 if (lit->IsTrue()) { | 1733 if (lit->IsTrue()) { |
| 1742 info = ALWAYS_TRUE; | 1734 info = ALWAYS_TRUE; |
| 1743 } else if (lit->IsFalse()) { | 1735 } else if (lit->IsFalse()) { |
| 1744 info = ALWAYS_FALSE; | 1736 info = ALWAYS_FALSE; |
| 1745 } | 1737 } |
| 1746 } | 1738 } |
| 1747 } | 1739 } |
| 1748 | 1740 |
| 1749 Label loop, entry; | 1741 switch (node->type()) { |
| 1742 case LoopStatement::DO_LOOP: { |
| 1743 JumpTarget body(this); |
| 1750 | 1744 |
| 1751 // init | 1745 IncrementLoopNesting(); |
| 1752 if (node->init() != NULL) { | 1746 // Label the body. |
| 1753 ASSERT(node->type() == LoopStatement::FOR_LOOP); | 1747 if (info == ALWAYS_TRUE) { |
| 1754 Visit(node->init()); | 1748 node->continue_target()->Bind(); |
| 1755 } | 1749 } else if (info == ALWAYS_FALSE) { |
| 1756 if (node->type() != LoopStatement::DO_LOOP && info != ALWAYS_TRUE) { | 1750 // There is no need, we will never jump back. |
| 1757 __ jmp(&entry); | 1751 } else { |
| 1758 } | 1752 ASSERT(info == DONT_KNOW); |
| 1753 body.Bind(); |
| 1754 } |
| 1755 CheckStack(); // TODO(1222600): ignore if body contains calls. |
| 1756 Visit(node->body()); |
| 1759 | 1757 |
| 1760 IncrementLoopNesting(); | 1758 if (info == ALWAYS_TRUE) { |
| 1759 if (frame_ != NULL) { |
| 1760 // If control flow can fall off the end of the body, jump back to |
| 1761 // the top. |
| 1762 node->continue_target()->Jump(); |
| 1763 } |
| 1764 } else if (info == ALWAYS_FALSE) { |
| 1765 // If we have a continue in the body, we only have to bind its jump |
| 1766 // target. |
| 1767 if (node->continue_target()->is_linked()) { |
| 1768 node->continue_target()->Bind(); |
| 1769 } |
| 1770 } else { |
| 1771 ASSERT(info == DONT_KNOW); |
| 1772 // We have to compile the test expression if we don't know its value |
| 1773 // and it can be reached by control flow falling out of the body or |
| 1774 // via continue. |
| 1775 if (frame_ != NULL || node->continue_target()->is_linked()) { |
| 1776 node->continue_target()->Bind(); |
| 1777 LoadCondition(node->cond(), NOT_INSIDE_TYPEOF, |
| 1778 &body, node->break_target(), true); |
| 1779 if (frame_ != NULL) { |
| 1780 // A NULL frame here indicates that control flow did not fall |
| 1781 // out of the test expression. |
| 1782 Branch(true, &body); |
| 1783 } |
| 1784 } |
| 1785 } |
| 1786 break; |
| 1787 } |
| 1761 | 1788 |
| 1762 // body | 1789 case LoopStatement::WHILE_LOOP: { |
| 1763 __ bind(&loop); | |
| 1764 CheckStack(); // TODO(1222600): ignore if body contains calls. | |
| 1765 Visit(node->body()); | |
| 1766 | 1790 |
| 1767 // next | 1791 JumpTarget body(this); |
| 1768 __ bind(node->continue_target()); | |
| 1769 if (node->next() != NULL) { | |
| 1770 // Record source position of the statement as this code which is after the | |
| 1771 // code for the body actually belongs to the loop statement and not the | |
| 1772 // body. | |
| 1773 RecordStatementPosition(node); | |
| 1774 __ RecordPosition(node->statement_pos()); | |
| 1775 ASSERT(node->type() == LoopStatement::FOR_LOOP); | |
| 1776 Visit(node->next()); | |
| 1777 } | |
| 1778 | 1792 |
| 1779 // cond | 1793 IncrementLoopNesting(); |
| 1780 __ bind(&entry); | 1794 // Generate the loop header. |
| 1781 switch (info) { | 1795 if (info == ALWAYS_TRUE) { |
| 1782 case ALWAYS_TRUE: | 1796 // Merely label the body with the continue target. |
| 1783 __ jmp(&loop); | 1797 node->continue_target()->Bind(); |
| 1798 } else if (info == ALWAYS_FALSE) { |
| 1799 // There is no need to even compile the test or body. |
| 1800 break; |
| 1801 } else { |
| 1802 // Compile the test labeled with the continue target and label the |
| 1803 // body with the body target. |
| 1804 ASSERT(info == DONT_KNOW); |
| 1805 node->continue_target()->Bind(); |
| 1806 LoadCondition(node->cond(), NOT_INSIDE_TYPEOF, |
| 1807 &body, node->break_target(), true); |
| 1808 if (frame_ != NULL) { |
| 1809 // A NULL frame indicates that control did not fall out of the |
| 1810 // test expression. |
| 1811 Branch(false, node->break_target()); |
| 1812 } |
| 1813 if (frame_ != NULL || body.is_linked()) { |
| 1814 body.Bind(); |
| 1815 } |
| 1816 } |
| 1817 if (frame_ != NULL) { |
| 1818 CheckStack(); // TODO(1222600): ignore if body contains calls. |
| 1819 Visit(node->body()); |
| 1820 |
| 1821 // If control flow can fall out of the body, jump back to the top. |
| 1822 if (frame_ != NULL) { |
| 1823 node->continue_target()->Jump(); |
| 1824 } |
| 1825 } |
| 1784 break; | 1826 break; |
| 1785 case ALWAYS_FALSE: | 1827 } |
| 1828 |
| 1829 case LoopStatement::FOR_LOOP: { |
| 1830 JumpTarget loop(this); |
| 1831 JumpTarget body(this); |
| 1832 if (node->init() != NULL) { |
| 1833 Visit(node->init()); |
| 1834 } |
| 1835 |
| 1836 IncrementLoopNesting(); |
| 1837 // There is no need to compile the test or body. |
| 1838 if (info == ALWAYS_FALSE) break; |
| 1839 |
| 1840 // If there is no update statement, label the top of the loop with the |
| 1841 // continue target, otherwise with the loop target. |
| 1842 if (node->next() == NULL) { |
| 1843 node->continue_target()->Bind(); |
| 1844 } else { |
| 1845 loop.Bind(); |
| 1846 } |
| 1847 |
| 1848 // If the test is always true, there is no need to compile it. |
| 1849 if (info == DONT_KNOW) { |
| 1850 LoadCondition(node->cond(), NOT_INSIDE_TYPEOF, |
| 1851 &body, node->break_target(), true); |
| 1852 if (frame_ != NULL) { |
| 1853 Branch(false, node->break_target()); |
| 1854 } |
| 1855 if (frame_ != NULL || body.is_linked()) { |
| 1856 body.Bind(); |
| 1857 } |
| 1858 } |
| 1859 |
| 1860 if (frame_ != NULL) { |
| 1861 CheckStack(); // TODO(1222600): ignore if body contains calls. |
| 1862 Visit(node->body()); |
| 1863 |
| 1864 if (node->next() == NULL) { |
| 1865 // If there is no update statement and control flow can fall out |
| 1866 // of the loop, jump directly to the continue label. |
| 1867 if (frame_ != NULL) { |
| 1868 node->continue_target()->Jump(); |
| 1869 } |
| 1870 } else { |
| 1871 // If there is an update statement and control flow can reach it |
| 1872 // via falling out of the body of the loop or continuing, we |
| 1873 // compile the update statement. |
| 1874 if (frame_ != NULL || node->continue_target()->is_linked()) { |
| 1875 node->continue_target()->Bind(); |
| 1876 // Record source position of the statement as this code which is |
| 1877 // after the code for the body actually belongs to the loop |
| 1878 // statement and not the body. |
| 1879 RecordStatementPosition(node); |
| 1880 __ RecordPosition(node->statement_pos()); |
| 1881 ASSERT(node->type() == LoopStatement::FOR_LOOP); |
| 1882 Visit(node->next()); |
| 1883 loop.Jump(); |
| 1884 } |
| 1885 } |
| 1886 } |
| 1786 break; | 1887 break; |
| 1787 case DONT_KNOW: | 1888 } |
| 1788 LoadCondition(node->cond(), NOT_INSIDE_TYPEOF, &loop, | |
| 1789 node->break_target(), true); | |
| 1790 Branch(true, &loop); | |
| 1791 break; | |
| 1792 } | 1889 } |
| 1793 | 1890 |
| 1794 DecrementLoopNesting(); | 1891 DecrementLoopNesting(); |
| 1795 | 1892 if (node->break_target()->is_linked()) { |
| 1796 // exit | 1893 node->break_target()->Bind(); |
| 1797 __ bind(node->break_target()); | 1894 } |
| 1798 } | 1895 } |
| 1799 | 1896 |
| 1800 | 1897 |
| 1801 void CodeGenerator::VisitForInStatement(ForInStatement* node) { | 1898 void CodeGenerator::VisitForInStatement(ForInStatement* node) { |
| 1802 Comment cmnt(masm_, "[ ForInStatement"); | 1899 Comment cmnt(masm_, "[ ForInStatement"); |
| 1803 RecordStatementPosition(node); | 1900 RecordStatementPosition(node); |
| 1804 | 1901 |
| 1805 // We keep stuff on the stack while the body is executing. | 1902 // We keep stuff on the stack while the body is executing. |
| 1806 // Record it, so that a break/continue crossing this statement | 1903 // Record it, so that a break/continue crossing this statement |
| 1807 // can restore the stack. | 1904 // can restore the stack. |
| 1808 const int kForInStackSize = 5 * kPointerSize; | 1905 const int kForInStackSize = 5 * kPointerSize; |
| 1809 break_stack_height_ += kForInStackSize; | 1906 break_stack_height_ += kForInStackSize; |
| 1810 node->set_break_stack_height(break_stack_height_); | 1907 node->set_break_stack_height(break_stack_height_); |
| 1908 node->break_target()->set_code_generator(this); |
| 1909 node->continue_target()->set_code_generator(this); |
| 1811 | 1910 |
| 1812 Label loop, next, entry, cleanup, exit, primitive, jsobject; | 1911 JumpTarget entry(this); |
| 1813 Label end_del_check, fixed_array; | 1912 JumpTarget cleanup(this); |
| 1913 JumpTarget exit(this); |
| 1914 JumpTarget primitive(this); |
| 1915 JumpTarget jsobject(this); |
| 1916 JumpTarget end_del_check(this); |
| 1917 JumpTarget fixed_array(this); |
| 1814 | 1918 |
| 1815 // Get the object to enumerate over (converted to JSObject). | 1919 // Get the object to enumerate over (converted to JSObject). |
| 1816 Load(node->enumerable()); | 1920 Load(node->enumerable()); |
| 1817 | 1921 |
| 1818 // Both SpiderMonkey and kjs ignore null and undefined in contrast | 1922 // Both SpiderMonkey and kjs ignore null and undefined in contrast |
| 1819 // to the specification. 12.6.4 mandates a call to ToObject. | 1923 // to the specification. 12.6.4 mandates a call to ToObject. |
| 1820 frame_->Pop(eax); | 1924 frame_->Pop(eax); |
| 1821 | 1925 |
| 1822 // eax: value to be iterated over | 1926 // eax: value to be iterated over |
| 1823 __ cmp(eax, Factory::undefined_value()); | 1927 __ cmp(eax, Factory::undefined_value()); |
| 1824 __ j(equal, &exit); | 1928 exit.Branch(equal); |
| 1825 __ cmp(eax, Factory::null_value()); | 1929 __ cmp(eax, Factory::null_value()); |
| 1826 __ j(equal, &exit); | 1930 exit.Branch(equal); |
| 1827 | 1931 |
| 1828 // Stack layout in body: | 1932 // Stack layout in body: |
| 1829 // [iteration counter (smi)] <- slot 0 | 1933 // [iteration counter (smi)] <- slot 0 |
| 1830 // [length of array] <- slot 1 | 1934 // [length of array] <- slot 1 |
| 1831 // [FixedArray] <- slot 2 | 1935 // [FixedArray] <- slot 2 |
| 1832 // [Map or 0] <- slot 3 | 1936 // [Map or 0] <- slot 3 |
| 1833 // [Object] <- slot 4 | 1937 // [Object] <- slot 4 |
| 1834 | 1938 |
| 1835 // Check if enumerable is already a JSObject | 1939 // Check if enumerable is already a JSObject |
| 1836 // eax: value to be iterated over | 1940 // eax: value to be iterated over |
| 1837 __ test(eax, Immediate(kSmiTagMask)); | 1941 __ test(eax, Immediate(kSmiTagMask)); |
| 1838 __ j(zero, &primitive); | 1942 primitive.Branch(zero); |
| 1839 __ mov(ecx, FieldOperand(eax, HeapObject::kMapOffset)); | 1943 __ mov(ecx, FieldOperand(eax, HeapObject::kMapOffset)); |
| 1840 __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset)); | 1944 __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset)); |
| 1841 __ cmp(ecx, FIRST_JS_OBJECT_TYPE); | 1945 __ cmp(ecx, FIRST_JS_OBJECT_TYPE); |
| 1842 __ j(above_equal, &jsobject); | 1946 jsobject.Branch(above_equal); |
| 1843 | 1947 |
| 1844 __ bind(&primitive); | 1948 primitive.Bind(); |
| 1845 frame_->Push(eax); | 1949 frame_->Push(eax); |
| 1846 __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION); | 1950 frame_->InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION, 1); |
| 1847 // function call returns the value in eax, which is where we want it below | 1951 // function call returns the value in eax, which is where we want it below |
| 1848 | 1952 |
| 1849 | 1953 |
| 1850 __ bind(&jsobject); | 1954 jsobject.Bind(); |
| 1851 | 1955 |
| 1852 // Get the set of properties (as a FixedArray or Map). | 1956 // Get the set of properties (as a FixedArray or Map). |
| 1853 // eax: value to be iterated over | 1957 // eax: value to be iterated over |
| 1854 frame_->Push(eax); // push the object being iterated over (slot 4) | 1958 frame_->Push(eax); // push the object being iterated over (slot 4) |
| 1855 | 1959 |
| 1856 frame_->Push(eax); // push the Object (slot 4) for the runtime call | 1960 frame_->Push(eax); // push the Object (slot 4) for the runtime call |
| 1857 __ CallRuntime(Runtime::kGetPropertyNamesFast, 1); | 1961 frame_->CallRuntime(Runtime::kGetPropertyNamesFast, 1); |
| 1858 | 1962 |
| 1859 // If we got a Map, we can do a fast modification check. | 1963 // If we got a Map, we can do a fast modification check. |
| 1860 // Otherwise, we got a FixedArray, and we have to do a slow check. | 1964 // Otherwise, we got a FixedArray, and we have to do a slow check. |
| 1861 // eax: map or fixed array (result from call to | 1965 // eax: map or fixed array (result from call to |
| 1862 // Runtime::kGetPropertyNamesFast) | 1966 // Runtime::kGetPropertyNamesFast) |
| 1863 __ mov(edx, Operand(eax)); | 1967 __ mov(edx, Operand(eax)); |
| 1864 __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset)); | 1968 __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset)); |
| 1865 __ cmp(ecx, Factory::meta_map()); | 1969 __ cmp(ecx, Factory::meta_map()); |
| 1866 __ j(not_equal, &fixed_array); | 1970 fixed_array.Branch(not_equal); |
| 1867 | 1971 |
| 1868 // Get enum cache | 1972 // Get enum cache |
| 1869 // eax: map (result from call to Runtime::kGetPropertyNamesFast) | 1973 // eax: map (result from call to Runtime::kGetPropertyNamesFast) |
| 1870 __ mov(ecx, Operand(eax)); | 1974 __ mov(ecx, Operand(eax)); |
| 1871 __ mov(ecx, FieldOperand(ecx, Map::kInstanceDescriptorsOffset)); | 1975 __ mov(ecx, FieldOperand(ecx, Map::kInstanceDescriptorsOffset)); |
| 1872 // Get the bridge array held in the enumeration index field. | 1976 // Get the bridge array held in the enumeration index field. |
| 1873 __ mov(ecx, FieldOperand(ecx, DescriptorArray::kEnumerationIndexOffset)); | 1977 __ mov(ecx, FieldOperand(ecx, DescriptorArray::kEnumerationIndexOffset)); |
| 1874 // Get the cache from the bridge array. | 1978 // Get the cache from the bridge array. |
| 1875 __ mov(edx, FieldOperand(ecx, DescriptorArray::kEnumCacheBridgeCacheOffset)); | 1979 __ mov(edx, FieldOperand(ecx, DescriptorArray::kEnumCacheBridgeCacheOffset)); |
| 1876 | 1980 |
| 1877 frame_->Push(eax); // <- slot 3 | 1981 frame_->Push(eax); // <- slot 3 |
| 1878 frame_->Push(edx); // <- slot 2 | 1982 frame_->Push(edx); // <- slot 2 |
| 1879 __ mov(eax, FieldOperand(edx, FixedArray::kLengthOffset)); | 1983 __ mov(eax, FieldOperand(edx, FixedArray::kLengthOffset)); |
| 1880 __ shl(eax, kSmiTagSize); | 1984 __ shl(eax, kSmiTagSize); |
| 1881 frame_->Push(eax); // <- slot 1 | 1985 frame_->Push(eax); // <- slot 1 |
| 1882 frame_->Push(Immediate(Smi::FromInt(0))); // <- slot 0 | 1986 frame_->Push(Immediate(Smi::FromInt(0))); // <- slot 0 |
| 1883 __ jmp(&entry); | 1987 entry.Jump(); |
| 1884 | 1988 |
| 1885 | 1989 |
| 1886 __ bind(&fixed_array); | 1990 fixed_array.Bind(); |
| 1887 | 1991 |
| 1888 // eax: fixed array (result from call to Runtime::kGetPropertyNamesFast) | 1992 // eax: fixed array (result from call to Runtime::kGetPropertyNamesFast) |
| 1889 frame_->Push(Immediate(Smi::FromInt(0))); // <- slot 3 | 1993 frame_->Push(Immediate(Smi::FromInt(0))); // <- slot 3 |
| 1890 frame_->Push(eax); // <- slot 2 | 1994 frame_->Push(eax); // <- slot 2 |
| 1891 | 1995 |
| 1892 // Push the length of the array and the initial index onto the stack. | 1996 // Push the length of the array and the initial index onto the stack. |
| 1893 __ mov(eax, FieldOperand(eax, FixedArray::kLengthOffset)); | 1997 __ mov(eax, FieldOperand(eax, FixedArray::kLengthOffset)); |
| 1894 __ shl(eax, kSmiTagSize); | 1998 __ shl(eax, kSmiTagSize); |
| 1895 frame_->Push(eax); // <- slot 1 | 1999 frame_->Push(eax); // <- slot 1 |
| 1896 frame_->Push(Immediate(Smi::FromInt(0))); // <- slot 0 | 2000 frame_->Push(Immediate(Smi::FromInt(0))); // <- slot 0 |
| 1897 __ jmp(&entry); | |
| 1898 | |
| 1899 // Body. | |
| 1900 __ bind(&loop); | |
| 1901 Visit(node->body()); | |
| 1902 | |
| 1903 // Next. | |
| 1904 __ bind(node->continue_target()); | |
| 1905 __ bind(&next); | |
| 1906 frame_->Pop(eax); | |
| 1907 __ add(Operand(eax), Immediate(Smi::FromInt(1))); | |
| 1908 frame_->Push(eax); | |
| 1909 | 2001 |
| 1910 // Condition. | 2002 // Condition. |
| 1911 __ bind(&entry); | 2003 entry.Bind(); |
| 1912 | 2004 |
| 1913 __ mov(eax, frame_->Element(0)); // load the current count | 2005 __ mov(eax, frame_->Element(0)); // load the current count |
| 1914 __ cmp(eax, frame_->Element(1)); // compare to the array length | 2006 __ cmp(eax, frame_->Element(1)); // compare to the array length |
| 1915 __ j(above_equal, &cleanup); | 2007 cleanup.Branch(above_equal); |
| 1916 | 2008 |
| 1917 // Get the i'th entry of the array. | 2009 // Get the i'th entry of the array. |
| 1918 __ mov(edx, frame_->Element(2)); | 2010 __ mov(edx, frame_->Element(2)); |
| 1919 __ mov(ebx, Operand(edx, eax, times_2, | 2011 __ mov(ebx, Operand(edx, eax, times_2, |
| 1920 FixedArray::kHeaderSize - kHeapObjectTag)); | 2012 FixedArray::kHeaderSize - kHeapObjectTag)); |
| 1921 | 2013 |
| 1922 // Get the expected map from the stack or a zero map in the | 2014 // Get the expected map from the stack or a zero map in the |
| 1923 // permanent slow case eax: current iteration count ebx: i'th entry | 2015 // permanent slow case eax: current iteration count ebx: i'th entry |
| 1924 // of the enum cache | 2016 // of the enum cache |
| 1925 __ mov(edx, frame_->Element(3)); | 2017 __ mov(edx, frame_->Element(3)); |
| 1926 // Check if the expected map still matches that of the enumerable. | 2018 // Check if the expected map still matches that of the enumerable. |
| 1927 // If not, we have to filter the key. | 2019 // If not, we have to filter the key. |
| 1928 // eax: current iteration count | 2020 // eax: current iteration count |
| 1929 // ebx: i'th entry of the enum cache | 2021 // ebx: i'th entry of the enum cache |
| 1930 // edx: expected map value | 2022 // edx: expected map value |
| 1931 __ mov(ecx, frame_->Element(4)); | 2023 __ mov(ecx, frame_->Element(4)); |
| 1932 __ mov(ecx, FieldOperand(ecx, HeapObject::kMapOffset)); | 2024 __ mov(ecx, FieldOperand(ecx, HeapObject::kMapOffset)); |
| 1933 __ cmp(ecx, Operand(edx)); | 2025 __ cmp(ecx, Operand(edx)); |
| 1934 __ j(equal, &end_del_check); | 2026 end_del_check.Branch(equal); |
| 1935 | 2027 |
| 1936 // Convert the entry to a string (or null if it isn't a property anymore). | 2028 // Convert the entry to a string (or null if it isn't a property anymore). |
| 1937 frame_->Push(frame_->Element(4)); // push enumerable | 2029 frame_->Push(frame_->Element(4)); // push enumerable |
| 1938 frame_->Push(ebx); // push entry | 2030 frame_->Push(ebx); // push entry |
| 1939 __ InvokeBuiltin(Builtins::FILTER_KEY, CALL_FUNCTION); | 2031 frame_->InvokeBuiltin(Builtins::FILTER_KEY, CALL_FUNCTION, 2); |
| 1940 __ mov(ebx, Operand(eax)); | 2032 __ mov(ebx, Operand(eax)); |
| 1941 | 2033 |
| 1942 // If the property has been removed while iterating, we just skip it. | 2034 // If the property has been removed while iterating, we just skip it. |
| 1943 __ cmp(ebx, Factory::null_value()); | 2035 __ cmp(ebx, Factory::null_value()); |
| 1944 __ j(equal, &next); | 2036 node->continue_target()->Branch(equal); |
| 1945 | 2037 |
| 1946 | 2038 end_del_check.Bind(); |
| 1947 __ bind(&end_del_check); | |
| 1948 | |
| 1949 // Store the entry in the 'each' expression and take another spin in the loop. | 2039 // Store the entry in the 'each' expression and take another spin in the loop. |
| 1950 // edx: i'th entry of the enum cache (or string there of) | 2040 // edx: i'th entry of the enum cache (or string there of) |
| 1951 frame_->Push(ebx); | 2041 frame_->Push(ebx); |
| 1952 { Reference each(this, node->each()); | 2042 { Reference each(this, node->each()); |
| 1953 if (!each.is_illegal()) { | 2043 if (!each.is_illegal()) { |
| 1954 if (each.size() > 0) { | 2044 if (each.size() > 0) { |
| 1955 frame_->Push(frame_->Element(each.size())); | 2045 frame_->Push(frame_->Element(each.size())); |
| 1956 } | 2046 } |
| 1957 // If the reference was to a slot we rely on the convenient property | 2047 // If the reference was to a slot we rely on the convenient property |
| 1958 // that it doesn't matter whether a value (eg, ebx pushed above) is | 2048 // that it doesn't matter whether a value (eg, ebx pushed above) is |
| 1959 // right on top of or right underneath a zero-sized reference. | 2049 // right on top of or right underneath a zero-sized reference. |
| 1960 each.SetValue(NOT_CONST_INIT); | 2050 each.SetValue(NOT_CONST_INIT); |
| 1961 if (each.size() > 0) { | 2051 if (each.size() > 0) { |
| 1962 // It's safe to pop the value lying on top of the reference before | 2052 // It's safe to pop the value lying on top of the reference before |
| 1963 // unloading the reference itself (which preserves the top of stack, | 2053 // unloading the reference itself (which preserves the top of stack, |
| 1964 // ie, now the topmost value of the non-zero sized reference), since | 2054 // ie, now the topmost value of the non-zero sized reference), since |
| 1965 // we will discard the top of stack after unloading the reference | 2055 // we will discard the top of stack after unloading the reference |
| 1966 // anyway. | 2056 // anyway. |
| 1967 frame_->Pop(); | 2057 frame_->Pop(); |
| 1968 } | 2058 } |
| 1969 } | 2059 } |
| 1970 } | 2060 } |
| 1971 // Discard the i'th entry pushed above or else the remainder of the | 2061 // Discard the i'th entry pushed above or else the remainder of the |
| 1972 // reference, whichever is currently on top of the stack. | 2062 // reference, whichever is currently on top of the stack. |
| 1973 frame_->Pop(); | 2063 frame_->Pop(); |
| 2064 |
| 2065 // Body. |
| 1974 CheckStack(); // TODO(1222600): ignore if body contains calls. | 2066 CheckStack(); // TODO(1222600): ignore if body contains calls. |
| 1975 __ jmp(&loop); | 2067 Visit(node->body()); |
| 2068 |
| 2069 // Next. |
| 2070 node->continue_target()->Bind(); |
| 2071 frame_->Pop(eax); |
| 2072 __ add(Operand(eax), Immediate(Smi::FromInt(1))); |
| 2073 frame_->Push(eax); |
| 2074 entry.Jump(); |
| 1976 | 2075 |
| 1977 // Cleanup. | 2076 // Cleanup. |
| 1978 __ bind(&cleanup); | 2077 cleanup.Bind(); |
| 1979 __ bind(node->break_target()); | 2078 node->break_target()->Bind(); |
| 1980 frame_->Drop(5); | 2079 frame_->Drop(5); |
| 1981 | 2080 |
| 1982 // Exit. | 2081 // Exit. |
| 1983 __ bind(&exit); | 2082 exit.Bind(); |
| 1984 | 2083 |
| 1985 break_stack_height_ -= kForInStackSize; | 2084 break_stack_height_ -= kForInStackSize; |
| 1986 } | 2085 } |
| 1987 | 2086 |
| 1988 | 2087 |
| 1989 void CodeGenerator::VisitTryCatch(TryCatch* node) { | 2088 void CodeGenerator::VisitTryCatch(TryCatch* node) { |
| 1990 Comment cmnt(masm_, "[ TryCatch"); | 2089 Comment cmnt(masm_, "[ TryCatch"); |
| 1991 | 2090 |
| 1992 Label try_block, exit; | 2091 JumpTarget try_block(this); |
| 2092 JumpTarget exit(this); |
| 1993 | 2093 |
| 1994 __ call(&try_block); | 2094 try_block.Call(); |
| 1995 // --- Catch block --- | 2095 // --- Catch block --- |
| 1996 frame_->Push(eax); | 2096 frame_->Push(eax); |
| 1997 | 2097 |
| 1998 // Store the caught exception in the catch variable. | 2098 // Store the caught exception in the catch variable. |
| 1999 { Reference ref(this, node->catch_var()); | 2099 { Reference ref(this, node->catch_var()); |
| 2000 ASSERT(ref.is_slot()); | 2100 ASSERT(ref.is_slot()); |
| 2001 // Load the exception to the top of the stack. Here we make use of the | 2101 // Load the exception to the top of the stack. Here we make use of the |
| 2002 // convenient property that it doesn't matter whether a value is | 2102 // convenient property that it doesn't matter whether a value is |
| 2003 // immediately on top of or underneath a zero-sized reference. | 2103 // immediately on top of or underneath a zero-sized reference. |
| 2004 ref.SetValue(NOT_CONST_INIT); | 2104 ref.SetValue(NOT_CONST_INIT); |
| 2005 } | 2105 } |
| 2006 | 2106 |
| 2007 // Remove the exception from the stack. | 2107 // Remove the exception from the stack. |
| 2008 frame_->Pop(); | 2108 frame_->Pop(); |
| 2009 | 2109 |
| 2010 VisitStatements(node->catch_block()->statements()); | 2110 VisitStatements(node->catch_block()->statements()); |
| 2011 __ jmp(&exit); | 2111 if (frame_ != NULL) { |
| 2112 exit.Jump(); |
| 2113 } |
| 2012 | 2114 |
| 2013 | 2115 |
| 2014 // --- Try block --- | 2116 // --- Try block --- |
| 2015 __ bind(&try_block); | 2117 try_block.Bind(); |
| 2016 | 2118 |
| 2017 __ PushTryHandler(IN_JAVASCRIPT, TRY_CATCH_HANDLER); | 2119 frame_->PushTryHandler(TRY_CATCH_HANDLER); |
| 2018 // TODO(1222589): remove the reliance of PushTryHandler on a cached TOS | 2120 int handler_height = frame_->height(); |
| 2019 frame_->Push(eax); // | |
| 2020 | 2121 |
| 2021 // Shadow the labels for all escapes from the try block, including | 2122 // Shadow the labels for all escapes from the try block, including |
| 2022 // returns. During shadowing, the original label is hidden as the | 2123 // returns. During shadowing, the original label is hidden as the |
| 2023 // LabelShadow and operations on the original actually affect the | 2124 // LabelShadow and operations on the original actually affect the |
| 2024 // shadowing label. | 2125 // shadowing label. |
| 2025 // | 2126 // |
| 2026 // We should probably try to unify the escaping labels and the return | 2127 // We should probably try to unify the escaping labels and the return |
| 2027 // label. | 2128 // label. |
| 2028 int nof_escapes = node->escaping_labels()->length(); | 2129 int nof_escapes = node->escaping_targets()->length(); |
| 2029 List<LabelShadow*> shadows(1 + nof_escapes); | 2130 List<ShadowTarget*> shadows(1 + nof_escapes); |
| 2030 shadows.Add(new LabelShadow(&function_return_)); | 2131 shadows.Add(new ShadowTarget(&function_return_)); |
| 2031 for (int i = 0; i < nof_escapes; i++) { | 2132 for (int i = 0; i < nof_escapes; i++) { |
| 2032 shadows.Add(new LabelShadow(node->escaping_labels()->at(i))); | 2133 shadows.Add(new ShadowTarget(node->escaping_targets()->at(i))); |
| 2033 } | 2134 } |
| 2135 bool function_return_was_shadowed = function_return_is_shadowed_; |
| 2136 function_return_is_shadowed_ = true; |
| 2034 | 2137 |
| 2035 // Generate code for the statements in the try block. | 2138 // Generate code for the statements in the try block. |
| 2036 bool was_inside_try = is_inside_try_; | 2139 bool was_inside_try = is_inside_try_; |
| 2037 is_inside_try_ = true; | 2140 is_inside_try_ = true; |
| 2038 VisitStatements(node->try_block()->statements()); | 2141 VisitStatements(node->try_block()->statements()); |
| 2039 is_inside_try_ = was_inside_try; | 2142 is_inside_try_ = was_inside_try; |
| 2040 | 2143 |
| 2041 // Stop the introduced shadowing and count the number of required unlinks. | 2144 // Stop the introduced shadowing and count the number of required unlinks. |
| 2042 // After shadowing stops, the original labels are unshadowed and the | 2145 // After shadowing stops, the original labels are unshadowed and the |
| 2043 // LabelShadows represent the formerly shadowing labels. | 2146 // LabelShadows represent the formerly shadowing labels. |
| 2044 int nof_unlinks = 0; | 2147 int nof_unlinks = 0; |
| 2045 for (int i = 0; i <= nof_escapes; i++) { | 2148 for (int i = 0; i <= nof_escapes; i++) { |
| 2046 shadows[i]->StopShadowing(); | 2149 shadows[i]->StopShadowing(); |
| 2047 if (shadows[i]->is_linked()) nof_unlinks++; | 2150 if (shadows[i]->is_linked()) nof_unlinks++; |
| 2048 } | 2151 } |
| 2152 function_return_is_shadowed_ = function_return_was_shadowed; |
| 2049 | 2153 |
| 2050 // Get an external reference to the handler address. | 2154 // Get an external reference to the handler address. |
| 2051 ExternalReference handler_address(Top::k_handler_address); | 2155 ExternalReference handler_address(Top::k_handler_address); |
| 2052 | 2156 |
| 2053 // Make sure that there's nothing left on the stack above the | 2157 // Make sure that there's nothing left on the stack above the |
| 2054 // handler structure. | 2158 // handler structure. |
| 2055 if (FLAG_debug_code) { | 2159 if (FLAG_debug_code) { |
| 2056 __ mov(eax, Operand::StaticVariable(handler_address)); | 2160 __ mov(eax, Operand::StaticVariable(handler_address)); |
| 2057 __ lea(eax, Operand(eax, StackHandlerConstants::kAddressDisplacement)); | 2161 __ lea(eax, Operand(eax, StackHandlerConstants::kAddressDisplacement)); |
| 2058 __ cmp(esp, Operand(eax)); | 2162 __ cmp(esp, Operand(eax)); |
| 2059 __ Assert(equal, "stack pointer should point to top handler"); | 2163 __ Assert(equal, "stack pointer should point to top handler"); |
| 2060 } | 2164 } |
| 2061 | 2165 |
| 2062 // Unlink from try chain. | 2166 // If we can fall off the end of the try block, unlink from try chain. |
| 2063 frame_->Pop(eax); | 2167 if (frame_ != NULL) { |
| 2064 __ mov(Operand::StaticVariable(handler_address), eax); // TOS == next_sp | 2168 frame_->Pop(eax); |
| 2065 frame_->Drop(StackHandlerConstants::kSize / kPointerSize - 1); | 2169 __ mov(Operand::StaticVariable(handler_address), eax); // TOS == next_sp |
| 2066 // next_sp popped. | 2170 frame_->Drop(StackHandlerConstants::kSize / kPointerSize - 1); |
| 2067 if (nof_unlinks > 0) __ jmp(&exit); | 2171 // next_sp popped. |
| 2172 if (nof_unlinks > 0) { |
| 2173 exit.Jump(); |
| 2174 } |
| 2175 } |
| 2068 | 2176 |
| 2069 // Generate unlink code for the (formerly) shadowing labels that have been | 2177 // Generate unlink code for the (formerly) shadowing labels that have been |
| 2070 // jumped to. | 2178 // jumped to. |
| 2071 for (int i = 0; i <= nof_escapes; i++) { | 2179 for (int i = 0; i <= nof_escapes; i++) { |
| 2072 if (shadows[i]->is_linked()) { | 2180 if (shadows[i]->is_linked()) { |
| 2073 // Unlink from try chain; be careful not to destroy the TOS. | 2181 // Unlink from try chain; be careful not to destroy the TOS. |
| 2074 __ bind(shadows[i]); | 2182 shadows[i]->Bind(); |
| 2075 | 2183 |
| 2076 // Reload sp from the top handler, because some statements that we | 2184 // Reload sp from the top handler, because some statements that we |
| 2077 // break from (eg, for...in) may have left stuff on the stack. | 2185 // break from (eg, for...in) may have left stuff on the stack. |
| 2078 __ mov(edx, Operand::StaticVariable(handler_address)); | 2186 __ mov(edx, Operand::StaticVariable(handler_address)); |
| 2079 const int kNextOffset = StackHandlerConstants::kNextOffset + | 2187 const int kNextOffset = StackHandlerConstants::kNextOffset + |
| 2080 StackHandlerConstants::kAddressDisplacement; | 2188 StackHandlerConstants::kAddressDisplacement; |
| 2081 __ lea(esp, Operand(edx, kNextOffset)); | 2189 __ lea(esp, Operand(edx, kNextOffset)); |
| 2190 frame_->Forget(frame_->height() - handler_height); |
| 2082 | 2191 |
| 2083 frame_->Pop(Operand::StaticVariable(handler_address)); | 2192 frame_->Pop(Operand::StaticVariable(handler_address)); |
| 2084 frame_->Drop(StackHandlerConstants::kSize / kPointerSize - 1); | 2193 frame_->Drop(StackHandlerConstants::kSize / kPointerSize - 1); |
| 2085 // next_sp popped. | 2194 // next_sp popped. |
| 2086 __ jmp(shadows[i]->original_label()); | 2195 JumpTarget* original_target = shadows[i]->original_target(); |
| 2196 original_target->Jump(); |
| 2087 } | 2197 } |
| 2088 } | 2198 } |
| 2089 | 2199 |
| 2090 __ bind(&exit); | 2200 exit.Bind(); |
| 2091 } | 2201 } |
| 2092 | 2202 |
| 2093 | 2203 |
| 2094 void CodeGenerator::VisitTryFinally(TryFinally* node) { | 2204 void CodeGenerator::VisitTryFinally(TryFinally* node) { |
| 2095 Comment cmnt(masm_, "[ TryFinally"); | 2205 Comment cmnt(masm_, "[ TryFinally"); |
| 2096 | 2206 |
| 2097 // State: Used to keep track of reason for entering the finally | 2207 // State: Used to keep track of reason for entering the finally |
| 2098 // block. Should probably be extended to hold information for | 2208 // block. Should probably be extended to hold information for |
| 2099 // break/continue from within the try block. | 2209 // break/continue from within the try block. |
| 2100 enum { FALLING, THROWING, JUMPING }; | 2210 enum { FALLING, THROWING, JUMPING }; |
| 2101 | 2211 |
| 2102 Label exit, unlink, try_block, finally_block; | 2212 JumpTarget exit(this); |
| 2213 JumpTarget unlink(this); |
| 2214 JumpTarget try_block(this); |
| 2215 JumpTarget finally_block(this); |
| 2103 | 2216 |
| 2104 __ call(&try_block); | 2217 try_block.Call(); |
| 2105 | 2218 |
| 2106 frame_->Push(eax); | 2219 frame_->Push(eax); |
| 2107 // In case of thrown exceptions, this is where we continue. | 2220 // In case of thrown exceptions, this is where we continue. |
| 2108 __ Set(ecx, Immediate(Smi::FromInt(THROWING))); | 2221 __ Set(ecx, Immediate(Smi::FromInt(THROWING))); |
| 2109 __ jmp(&finally_block); | 2222 finally_block.Jump(); |
| 2110 | 2223 |
| 2111 | 2224 |
| 2112 // --- Try block --- | 2225 // --- Try block --- |
| 2113 __ bind(&try_block); | 2226 try_block.Bind(); |
| 2114 | 2227 |
| 2115 __ PushTryHandler(IN_JAVASCRIPT, TRY_FINALLY_HANDLER); | 2228 frame_->PushTryHandler(TRY_FINALLY_HANDLER); |
| 2116 // TODO(1222589): remove the reliance of PushTryHandler on a cached TOS | 2229 int handler_height = frame_->height(); |
| 2117 frame_->Push(eax); | |
| 2118 | 2230 |
| 2119 // Shadow the labels for all escapes from the try block, including | 2231 // Shadow the labels for all escapes from the try block, including |
| 2120 // returns. During shadowing, the original label is hidden as the | 2232 // returns. During shadowing, the original label is hidden as the |
| 2121 // LabelShadow and operations on the original actually affect the | 2233 // LabelShadow and operations on the original actually affect the |
| 2122 // shadowing label. | 2234 // shadowing label. |
| 2123 // | 2235 // |
| 2124 // We should probably try to unify the escaping labels and the return | 2236 // We should probably try to unify the escaping labels and the return |
| 2125 // label. | 2237 // label. |
| 2126 int nof_escapes = node->escaping_labels()->length(); | 2238 int nof_escapes = node->escaping_targets()->length(); |
| 2127 List<LabelShadow*> shadows(1 + nof_escapes); | 2239 List<ShadowTarget*> shadows(1 + nof_escapes); |
| 2128 shadows.Add(new LabelShadow(&function_return_)); | 2240 shadows.Add(new ShadowTarget(&function_return_)); |
| 2129 for (int i = 0; i < nof_escapes; i++) { | 2241 for (int i = 0; i < nof_escapes; i++) { |
| 2130 shadows.Add(new LabelShadow(node->escaping_labels()->at(i))); | 2242 shadows.Add(new ShadowTarget(node->escaping_targets()->at(i))); |
| 2131 } | 2243 } |
| 2244 bool function_return_was_shadowed = function_return_is_shadowed_; |
| 2245 function_return_is_shadowed_ = true; |
| 2132 | 2246 |
| 2133 // Generate code for the statements in the try block. | 2247 // Generate code for the statements in the try block. |
| 2134 bool was_inside_try = is_inside_try_; | 2248 bool was_inside_try = is_inside_try_; |
| 2135 is_inside_try_ = true; | 2249 is_inside_try_ = true; |
| 2136 VisitStatements(node->try_block()->statements()); | 2250 VisitStatements(node->try_block()->statements()); |
| 2137 is_inside_try_ = was_inside_try; | 2251 is_inside_try_ = was_inside_try; |
| 2138 | 2252 |
| 2139 // Stop the introduced shadowing and count the number of required unlinks. | 2253 // Stop the introduced shadowing and count the number of required unlinks. |
| 2140 // After shadowing stops, the original labels are unshadowed and the | 2254 // After shadowing stops, the original labels are unshadowed and the |
| 2141 // LabelShadows represent the formerly shadowing labels. | 2255 // LabelShadows represent the formerly shadowing labels. |
| 2142 int nof_unlinks = 0; | 2256 int nof_unlinks = 0; |
| 2143 for (int i = 0; i <= nof_escapes; i++) { | 2257 for (int i = 0; i <= nof_escapes; i++) { |
| 2144 shadows[i]->StopShadowing(); | 2258 shadows[i]->StopShadowing(); |
| 2145 if (shadows[i]->is_linked()) nof_unlinks++; | 2259 if (shadows[i]->is_linked()) nof_unlinks++; |
| 2146 } | 2260 } |
| 2261 function_return_is_shadowed_ = function_return_was_shadowed; |
| 2147 | 2262 |
| 2148 // Set the state on the stack to FALLING. | 2263 // If we can fall off the end of the try block, set the state on the stack |
| 2149 frame_->Push(Immediate(Factory::undefined_value())); // fake TOS | 2264 // to FALLING. |
| 2150 __ Set(ecx, Immediate(Smi::FromInt(FALLING))); | 2265 if (frame_ != NULL) { |
| 2151 if (nof_unlinks > 0) __ jmp(&unlink); | 2266 frame_->Push(Immediate(Factory::undefined_value())); // fake TOS |
| 2267 __ Set(ecx, Immediate(Smi::FromInt(FALLING))); |
| 2268 if (nof_unlinks > 0) { |
| 2269 unlink.Jump(); |
| 2270 } |
| 2271 } |
| 2152 | 2272 |
| 2153 // Generate code to set the state for the (formerly) shadowing labels that | 2273 // Generate code to set the state for the (formerly) shadowing labels that |
| 2154 // have been jumped to. | 2274 // have been jumped to. |
| 2155 for (int i = 0; i <= nof_escapes; i++) { | 2275 for (int i = 0; i <= nof_escapes; i++) { |
| 2156 if (shadows[i]->is_linked()) { | 2276 if (shadows[i]->is_linked()) { |
| 2157 __ bind(shadows[i]); | 2277 shadows[i]->Bind(); |
| 2158 if (shadows[i]->original_label() == &function_return_) { | 2278 if (shadows[i]->original_target() == &function_return_) { |
| 2159 // If this label shadowed the function return, materialize the | 2279 // If this label shadowed the function return, materialize the |
| 2160 // return value on the stack. | 2280 // return value on the stack. |
| 2161 frame_->Push(eax); | 2281 frame_->Push(eax); |
| 2162 } else { | 2282 } else { |
| 2163 // Fake TOS for labels that shadowed breaks and continues. | 2283 // Fake TOS for labels that shadowed breaks and continues. |
| 2164 frame_->Push(Immediate(Factory::undefined_value())); | 2284 frame_->Push(Immediate(Factory::undefined_value())); |
| 2165 } | 2285 } |
| 2166 __ Set(ecx, Immediate(Smi::FromInt(JUMPING + i))); | 2286 __ Set(ecx, Immediate(Smi::FromInt(JUMPING + i))); |
| 2167 __ jmp(&unlink); | 2287 unlink.Jump(); |
| 2168 } | 2288 } |
| 2169 } | 2289 } |
| 2170 | 2290 |
| 2171 // Unlink from try chain; be careful not to destroy the TOS. | 2291 // Unlink from try chain; be careful not to destroy the TOS. |
| 2172 __ bind(&unlink); | 2292 unlink.Bind(); |
| 2173 // Reload sp from the top handler, because some statements that we | 2293 // Reload sp from the top handler, because some statements that we |
| 2174 // break from (eg, for...in) may have left stuff on the stack. | 2294 // break from (eg, for...in) may have left stuff on the stack. |
| 2175 // Preserve the TOS in a register across stack manipulation. | 2295 // Preserve the TOS in a register across stack manipulation. |
| 2176 frame_->Pop(eax); | 2296 frame_->Pop(eax); |
| 2177 ExternalReference handler_address(Top::k_handler_address); | 2297 ExternalReference handler_address(Top::k_handler_address); |
| 2178 __ mov(edx, Operand::StaticVariable(handler_address)); | 2298 __ mov(edx, Operand::StaticVariable(handler_address)); |
| 2179 const int kNextOffset = StackHandlerConstants::kNextOffset + | 2299 const int kNextOffset = StackHandlerConstants::kNextOffset + |
| 2180 StackHandlerConstants::kAddressDisplacement; | 2300 StackHandlerConstants::kAddressDisplacement; |
| 2181 __ lea(esp, Operand(edx, kNextOffset)); | 2301 __ lea(esp, Operand(edx, kNextOffset)); |
| 2302 frame_->Forget(frame_->height() - handler_height); |
| 2182 | 2303 |
| 2183 frame_->Pop(Operand::StaticVariable(handler_address)); | 2304 frame_->Pop(Operand::StaticVariable(handler_address)); |
| 2184 frame_->Drop(StackHandlerConstants::kSize / kPointerSize - 1); | 2305 frame_->Drop(StackHandlerConstants::kSize / kPointerSize - 1); |
| 2185 // Next_sp popped. | 2306 // Next_sp popped. |
| 2186 // Preserve the TOS in a register across stack manipulation. | 2307 // Preserve the TOS in a register across stack manipulation. |
| 2187 frame_->Push(eax); | 2308 frame_->Push(eax); |
| 2188 | 2309 |
| 2189 // --- Finally block --- | 2310 // --- Finally block --- |
| 2190 __ bind(&finally_block); | 2311 finally_block.Bind(); |
| 2191 | 2312 |
| 2192 // Push the state on the stack. | 2313 // Push the state on the stack. |
| 2193 frame_->Push(ecx); | 2314 frame_->Push(ecx); |
| 2194 | 2315 |
| 2195 // We keep two elements on the stack - the (possibly faked) result | 2316 // We keep two elements on the stack - the (possibly faked) result |
| 2196 // and the state - while evaluating the finally block. Record it, so | 2317 // and the state - while evaluating the finally block. Record it, so |
| 2197 // that a break/continue crossing this statement can restore the | 2318 // that a break/continue crossing this statement can restore the |
| 2198 // stack. | 2319 // stack. |
| 2199 const int kFinallyStackSize = 2 * kPointerSize; | 2320 const int kFinallyStackSize = 2 * kPointerSize; |
| 2200 break_stack_height_ += kFinallyStackSize; | 2321 break_stack_height_ += kFinallyStackSize; |
| 2201 | 2322 |
| 2202 // Generate code for the statements in the finally block. | 2323 // Generate code for the statements in the finally block. |
| 2203 VisitStatements(node->finally_block()->statements()); | 2324 VisitStatements(node->finally_block()->statements()); |
| 2204 | 2325 |
| 2205 // Restore state and return value or faked TOS. | |
| 2206 frame_->Pop(ecx); | |
| 2207 frame_->Pop(eax); | |
| 2208 break_stack_height_ -= kFinallyStackSize; | 2326 break_stack_height_ -= kFinallyStackSize; |
| 2327 if (frame_ != NULL) { |
| 2328 // Restore state and return value or faked TOS. |
| 2329 frame_->Pop(ecx); |
| 2330 frame_->Pop(eax); |
| 2209 | 2331 |
| 2210 // Generate code to jump to the right destination for all used (formerly) | 2332 // Generate code to jump to the right destination for all used |
| 2211 // shadowing labels. | 2333 // (formerly) shadowing labels. |
| 2212 for (int i = 0; i <= nof_escapes; i++) { | 2334 for (int i = 0; i <= nof_escapes; i++) { |
| 2213 if (shadows[i]->is_bound()) { | 2335 if (shadows[i]->is_bound()) { |
| 2214 __ cmp(Operand(ecx), Immediate(Smi::FromInt(JUMPING + i))); | 2336 __ cmp(Operand(ecx), Immediate(Smi::FromInt(JUMPING + i))); |
| 2215 __ j(equal, shadows[i]->original_label()); | 2337 shadows[i]->original_target()->Branch(equal); |
| 2338 } |
| 2216 } | 2339 } |
| 2340 |
| 2341 // Check if we need to rethrow the exception. |
| 2342 __ cmp(Operand(ecx), Immediate(Smi::FromInt(THROWING))); |
| 2343 exit.Branch(not_equal); |
| 2344 |
| 2345 // Rethrow exception. |
| 2346 frame_->Push(eax); // undo pop from above |
| 2347 frame_->CallRuntime(Runtime::kReThrow, 1); |
| 2348 |
| 2349 // Done. |
| 2350 exit.Bind(); |
| 2217 } | 2351 } |
| 2218 | |
| 2219 // Check if we need to rethrow the exception. | |
| 2220 __ cmp(Operand(ecx), Immediate(Smi::FromInt(THROWING))); | |
| 2221 __ j(not_equal, &exit); | |
| 2222 | |
| 2223 // Rethrow exception. | |
| 2224 frame_->Push(eax); // undo pop from above | |
| 2225 __ CallRuntime(Runtime::kReThrow, 1); | |
| 2226 | |
| 2227 // Done. | |
| 2228 __ bind(&exit); | |
| 2229 } | 2352 } |
| 2230 | 2353 |
| 2231 | 2354 |
| 2232 void CodeGenerator::VisitDebuggerStatement(DebuggerStatement* node) { | 2355 void CodeGenerator::VisitDebuggerStatement(DebuggerStatement* node) { |
| 2233 Comment cmnt(masm_, "[ DebuggerStatement"); | 2356 Comment cmnt(masm_, "[ DebuggerStatement"); |
| 2234 RecordStatementPosition(node); | 2357 RecordStatementPosition(node); |
| 2235 __ CallRuntime(Runtime::kDebugBreak, 0); | 2358 frame_->CallRuntime(Runtime::kDebugBreak, 0); |
| 2236 // Ignore the return value. | 2359 // Ignore the return value. |
| 2237 } | 2360 } |
| 2238 | 2361 |
| 2239 | 2362 |
| 2240 void CodeGenerator::InstantiateBoilerplate(Handle<JSFunction> boilerplate) { | 2363 void CodeGenerator::InstantiateBoilerplate(Handle<JSFunction> boilerplate) { |
| 2241 ASSERT(boilerplate->IsBoilerplate()); | 2364 ASSERT(boilerplate->IsBoilerplate()); |
| 2242 | 2365 |
| 2243 // Push the boilerplate on the stack. | 2366 // Push the boilerplate on the stack. |
| 2244 frame_->Push(Immediate(boilerplate)); | 2367 frame_->Push(Immediate(boilerplate)); |
| 2245 | 2368 |
| 2246 // Create a new closure. | 2369 // Create a new closure. |
| 2247 frame_->Push(esi); | 2370 frame_->Push(esi); |
| 2248 __ CallRuntime(Runtime::kNewClosure, 2); | 2371 frame_->CallRuntime(Runtime::kNewClosure, 2); |
| 2249 frame_->Push(eax); | 2372 frame_->Push(eax); |
| 2250 } | 2373 } |
| 2251 | 2374 |
| 2252 | 2375 |
| 2253 void CodeGenerator::VisitFunctionLiteral(FunctionLiteral* node) { | 2376 void CodeGenerator::VisitFunctionLiteral(FunctionLiteral* node) { |
| 2254 Comment cmnt(masm_, "[ FunctionLiteral"); | 2377 Comment cmnt(masm_, "[ FunctionLiteral"); |
| 2255 | 2378 |
| 2256 // Build the function boilerplate and instantiate it. | 2379 // Build the function boilerplate and instantiate it. |
| 2257 Handle<JSFunction> boilerplate = BuildBoilerplate(node); | 2380 Handle<JSFunction> boilerplate = BuildBoilerplate(node); |
| 2258 // Check for stack-overflow exception. | 2381 // Check for stack-overflow exception. |
| 2259 if (HasStackOverflow()) return; | 2382 if (HasStackOverflow()) return; |
| 2260 InstantiateBoilerplate(boilerplate); | 2383 InstantiateBoilerplate(boilerplate); |
| 2261 } | 2384 } |
| 2262 | 2385 |
| 2263 | 2386 |
| 2264 void CodeGenerator::VisitFunctionBoilerplateLiteral( | 2387 void CodeGenerator::VisitFunctionBoilerplateLiteral( |
| 2265 FunctionBoilerplateLiteral* node) { | 2388 FunctionBoilerplateLiteral* node) { |
| 2266 Comment cmnt(masm_, "[ FunctionBoilerplateLiteral"); | 2389 Comment cmnt(masm_, "[ FunctionBoilerplateLiteral"); |
| 2267 InstantiateBoilerplate(node->boilerplate()); | 2390 InstantiateBoilerplate(node->boilerplate()); |
| 2268 } | 2391 } |
| 2269 | 2392 |
| 2270 | 2393 |
| 2271 void CodeGenerator::VisitConditional(Conditional* node) { | 2394 void CodeGenerator::VisitConditional(Conditional* node) { |
| 2272 Comment cmnt(masm_, "[ Conditional"); | 2395 Comment cmnt(masm_, "[ Conditional"); |
| 2273 Label then, else_, exit; | 2396 JumpTarget then(this); |
| 2397 JumpTarget else_(this); |
| 2398 JumpTarget exit(this); |
| 2274 LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &then, &else_, true); | 2399 LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &then, &else_, true); |
| 2275 Branch(false, &else_); | 2400 if (frame_ != NULL) { |
| 2276 __ bind(&then); | 2401 Branch(false, &else_); |
| 2277 Load(node->then_expression(), typeof_state()); | 2402 } |
| 2278 __ jmp(&exit); | 2403 if (frame_ != NULL || then.is_linked()) { |
| 2279 __ bind(&else_); | 2404 then.Bind(); |
| 2280 Load(node->else_expression(), typeof_state()); | 2405 Load(node->then_expression(), typeof_state()); |
| 2281 __ bind(&exit); | 2406 exit.Jump(); |
| 2407 } |
| 2408 if (else_.is_linked()) { |
| 2409 else_.Bind(); |
| 2410 Load(node->else_expression(), typeof_state()); |
| 2411 } |
| 2412 exit.Bind(); |
| 2282 } | 2413 } |
| 2283 | 2414 |
| 2284 | 2415 |
| 2285 void CodeGenerator::LoadFromSlot(Slot* slot, TypeofState typeof_state) { | 2416 void CodeGenerator::LoadFromSlot(Slot* slot, TypeofState typeof_state) { |
| 2286 if (slot->type() == Slot::LOOKUP) { | 2417 if (slot->type() == Slot::LOOKUP) { |
| 2287 ASSERT(slot->var()->mode() == Variable::DYNAMIC); | 2418 ASSERT(slot->var()->mode() == Variable::DYNAMIC); |
| 2288 | 2419 |
| 2289 // For now, just do a runtime call. | 2420 // For now, just do a runtime call. |
| 2290 frame_->Push(esi); | 2421 frame_->Push(esi); |
| 2291 frame_->Push(Immediate(slot->var()->name())); | 2422 frame_->Push(Immediate(slot->var()->name())); |
| 2292 | 2423 |
| 2293 if (typeof_state == INSIDE_TYPEOF) { | 2424 if (typeof_state == INSIDE_TYPEOF) { |
| 2294 __ CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2); | 2425 frame_->CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2); |
| 2295 } else { | 2426 } else { |
| 2296 __ CallRuntime(Runtime::kLoadContextSlot, 2); | 2427 frame_->CallRuntime(Runtime::kLoadContextSlot, 2); |
| 2297 } | 2428 } |
| 2298 frame_->Push(eax); | 2429 frame_->Push(eax); |
| 2299 | 2430 |
| 2300 } else { | 2431 } else { |
| 2301 // Note: We would like to keep the assert below, but it fires because of | 2432 // Note: We would like to keep the assert below, but it fires because of |
| 2302 // some nasty code in LoadTypeofExpression() which should be removed... | 2433 // some nasty code in LoadTypeofExpression() which should be removed... |
| 2303 // ASSERT(slot->var()->mode() != Variable::DYNAMIC); | 2434 // ASSERT(slot->var()->mode() != Variable::DYNAMIC); |
| 2304 if (slot->var()->mode() == Variable::CONST) { | 2435 if (slot->var()->mode() == Variable::CONST) { |
| 2305 // Const slots may contain 'the hole' value (the constant hasn't been | 2436 // Const slots may contain 'the hole' value (the constant hasn't been |
| 2306 // initialized yet) which needs to be converted into the 'undefined' | 2437 // initialized yet) which needs to be converted into the 'undefined' |
| 2307 // value. | 2438 // value. |
| 2308 Comment cmnt(masm_, "[ Load const"); | 2439 Comment cmnt(masm_, "[ Load const"); |
| 2309 Label exit; | 2440 JumpTarget exit(this); |
| 2310 __ mov(eax, SlotOperand(slot, ecx)); | 2441 __ mov(eax, SlotOperand(slot, ecx)); |
| 2311 __ cmp(eax, Factory::the_hole_value()); | 2442 __ cmp(eax, Factory::the_hole_value()); |
| 2312 __ j(not_equal, &exit); | 2443 exit.Branch(not_equal); |
| 2313 __ mov(eax, Factory::undefined_value()); | 2444 __ mov(eax, Factory::undefined_value()); |
| 2314 __ bind(&exit); | 2445 exit.Bind(); |
| 2315 frame_->Push(eax); | 2446 frame_->Push(eax); |
| 2316 } else { | 2447 } else { |
| 2317 frame_->Push(SlotOperand(slot, ecx)); | 2448 frame_->Push(SlotOperand(slot, ecx)); |
| 2318 } | 2449 } |
| 2319 } | 2450 } |
| 2320 } | 2451 } |
| 2321 | 2452 |
| 2322 | 2453 |
| 2323 void CodeGenerator::VisitSlot(Slot* node) { | 2454 void CodeGenerator::VisitSlot(Slot* node) { |
| 2324 Comment cmnt(masm_, "[ Slot"); | 2455 Comment cmnt(masm_, "[ Slot"); |
| 2325 LoadFromSlot(node, typeof_state()); | 2456 LoadFromSlot(node, typeof_state()); |
| 2326 } | 2457 } |
| 2327 | 2458 |
| 2328 | 2459 |
| 2329 void CodeGenerator::VisitVariableProxy(VariableProxy* node) { | 2460 void CodeGenerator::VisitVariableProxy(VariableProxy* node) { |
| 2330 Comment cmnt(masm_, "[ VariableProxy"); | 2461 Comment cmnt(masm_, "[ VariableProxy"); |
| 2331 Variable* var = node->var(); | 2462 Variable* var = node->var(); |
| 2332 Expression* expr = var->rewrite(); | 2463 Expression* expr = var->rewrite(); |
| 2333 if (expr != NULL) { | 2464 if (expr != NULL) { |
| 2465 // We have to be wary of calling Visit directly on expressions. Because |
| 2466 // of special casing comparisons of the form typeof<expr> === "string", |
| 2467 // we can return from a call from Visit (to a comparison or a unary |
| 2468 // operation) without a virtual frame; which will probably crash if we |
| 2469 // try to emit frame code before reestablishing a frame. Here we're |
| 2470 // safe as long as variable proxies can't rewrite into typeof |
| 2471 // comparisons or unary logical not expressions. |
| 2334 Visit(expr); | 2472 Visit(expr); |
| 2473 ASSERT(frame_ != NULL); |
| 2335 } else { | 2474 } else { |
| 2336 ASSERT(var->is_global()); | 2475 ASSERT(var->is_global()); |
| 2337 Reference ref(this, node); | 2476 Reference ref(this, node); |
| 2338 ref.GetValue(typeof_state()); | 2477 ref.GetValue(typeof_state()); |
| 2339 } | 2478 } |
| 2340 } | 2479 } |
| 2341 | 2480 |
| 2342 | 2481 |
| 2343 void CodeGenerator::VisitLiteral(Literal* node) { | 2482 void CodeGenerator::VisitLiteral(Literal* node) { |
| 2344 Comment cmnt(masm_, "[ Literal"); | 2483 Comment cmnt(masm_, "[ Literal"); |
| (...skipping 16 matching lines...) Expand all Loading... |
| 2361 : DeferredCode(generator), node_(node) { | 2500 : DeferredCode(generator), node_(node) { |
| 2362 set_comment("[ RegExpDeferred"); | 2501 set_comment("[ RegExpDeferred"); |
| 2363 } | 2502 } |
| 2364 virtual void Generate(); | 2503 virtual void Generate(); |
| 2365 private: | 2504 private: |
| 2366 RegExpLiteral* node_; | 2505 RegExpLiteral* node_; |
| 2367 }; | 2506 }; |
| 2368 | 2507 |
| 2369 | 2508 |
| 2370 void RegExpDeferred::Generate() { | 2509 void RegExpDeferred::Generate() { |
| 2371 // If the entry is undefined we call the runtime system to computed | 2510 // If the entry is undefined we call the runtime system to compute the |
| 2372 // the literal. | 2511 // literal. |
| 2373 | 2512 |
| 2374 // Literal array (0). | 2513 // Literal array (0). |
| 2375 __ push(ecx); | 2514 __ push(ecx); |
| 2376 // Literal index (1). | 2515 // Literal index (1). |
| 2377 __ push(Immediate(Smi::FromInt(node_->literal_index()))); | 2516 __ push(Immediate(Smi::FromInt(node_->literal_index()))); |
| 2378 // RegExp pattern (2). | 2517 // RegExp pattern (2). |
| 2379 __ push(Immediate(node_->pattern())); | 2518 __ push(Immediate(node_->pattern())); |
| 2380 // RegExp flags (3). | 2519 // RegExp flags (3). |
| 2381 __ push(Immediate(node_->flags())); | 2520 __ push(Immediate(node_->flags())); |
| 2382 __ CallRuntime(Runtime::kMaterializeRegExpLiteral, 4); | 2521 __ CallRuntime(Runtime::kMaterializeRegExpLiteral, 4); |
| (...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2463 | 2602 |
| 2464 // Check whether we need to materialize the object literal boilerplate. | 2603 // Check whether we need to materialize the object literal boilerplate. |
| 2465 // If so, jump to the deferred code. | 2604 // If so, jump to the deferred code. |
| 2466 __ cmp(ebx, Factory::undefined_value()); | 2605 __ cmp(ebx, Factory::undefined_value()); |
| 2467 __ j(equal, deferred->enter(), not_taken); | 2606 __ j(equal, deferred->enter(), not_taken); |
| 2468 __ bind(deferred->exit()); | 2607 __ bind(deferred->exit()); |
| 2469 | 2608 |
| 2470 // Push the literal. | 2609 // Push the literal. |
| 2471 frame_->Push(ebx); | 2610 frame_->Push(ebx); |
| 2472 // Clone the boilerplate object. | 2611 // Clone the boilerplate object. |
| 2473 __ CallRuntime(Runtime::kCloneObjectLiteralBoilerplate, 1); | 2612 frame_->CallRuntime(Runtime::kCloneObjectLiteralBoilerplate, 1); |
| 2474 // Push the new cloned literal object as the result. | 2613 // Push the new cloned literal object as the result. |
| 2475 frame_->Push(eax); | 2614 frame_->Push(eax); |
| 2476 | 2615 |
| 2477 | 2616 |
| 2478 for (int i = 0; i < node->properties()->length(); i++) { | 2617 for (int i = 0; i < node->properties()->length(); i++) { |
| 2479 ObjectLiteral::Property* property = node->properties()->at(i); | 2618 ObjectLiteral::Property* property = node->properties()->at(i); |
| 2480 switch (property->kind()) { | 2619 switch (property->kind()) { |
| 2481 case ObjectLiteral::Property::CONSTANT: break; | 2620 case ObjectLiteral::Property::CONSTANT: break; |
| 2482 case ObjectLiteral::Property::COMPUTED: { | 2621 case ObjectLiteral::Property::COMPUTED: { |
| 2483 Handle<Object> key(property->key()->handle()); | 2622 Handle<Object> key(property->key()->handle()); |
| 2484 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); | 2623 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); |
| 2485 if (key->IsSymbol()) { | 2624 if (key->IsSymbol()) { |
| 2486 __ mov(eax, frame_->Top()); | 2625 __ mov(eax, frame_->Top()); |
| 2487 frame_->Push(eax); | 2626 frame_->Push(eax); |
| 2488 Load(property->value()); | 2627 Load(property->value()); |
| 2489 frame_->Pop(eax); | 2628 frame_->Pop(eax); |
| 2490 __ Set(ecx, Immediate(key)); | 2629 __ Set(ecx, Immediate(key)); |
| 2491 __ call(ic, RelocInfo::CODE_TARGET); | 2630 frame_->CallCode(ic, RelocInfo::CODE_TARGET, 0); |
| 2492 frame_->Pop(); | 2631 frame_->Pop(); |
| 2493 // Ignore result. | 2632 // Ignore result. |
| 2494 break; | 2633 break; |
| 2495 } | 2634 } |
| 2496 // Fall through | 2635 // Fall through |
| 2497 } | 2636 } |
| 2498 case ObjectLiteral::Property::PROTOTYPE: { | 2637 case ObjectLiteral::Property::PROTOTYPE: { |
| 2499 __ mov(eax, frame_->Top()); | 2638 __ mov(eax, frame_->Top()); |
| 2500 frame_->Push(eax); | 2639 frame_->Push(eax); |
| 2501 Load(property->key()); | 2640 Load(property->key()); |
| 2502 Load(property->value()); | 2641 Load(property->value()); |
| 2503 __ CallRuntime(Runtime::kSetProperty, 3); | 2642 frame_->CallRuntime(Runtime::kSetProperty, 3); |
| 2504 // Ignore result. | 2643 // Ignore result. |
| 2505 break; | 2644 break; |
| 2506 } | 2645 } |
| 2507 case ObjectLiteral::Property::SETTER: { | 2646 case ObjectLiteral::Property::SETTER: { |
| 2508 // Duplicate the resulting object on the stack. The runtime | 2647 // Duplicate the resulting object on the stack. The runtime |
| 2509 // function will pop the three arguments passed in. | 2648 // function will pop the three arguments passed in. |
| 2510 __ mov(eax, frame_->Top()); | 2649 __ mov(eax, frame_->Top()); |
| 2511 frame_->Push(eax); | 2650 frame_->Push(eax); |
| 2512 Load(property->key()); | 2651 Load(property->key()); |
| 2513 frame_->Push(Immediate(Smi::FromInt(1))); | 2652 frame_->Push(Immediate(Smi::FromInt(1))); |
| 2514 Load(property->value()); | 2653 Load(property->value()); |
| 2515 __ CallRuntime(Runtime::kDefineAccessor, 4); | 2654 frame_->CallRuntime(Runtime::kDefineAccessor, 4); |
| 2516 // Ignore result. | 2655 // Ignore result. |
| 2517 break; | 2656 break; |
| 2518 } | 2657 } |
| 2519 case ObjectLiteral::Property::GETTER: { | 2658 case ObjectLiteral::Property::GETTER: { |
| 2520 // Duplicate the resulting object on the stack. The runtime | 2659 // Duplicate the resulting object on the stack. The runtime |
| 2521 // function will pop the three arguments passed in. | 2660 // function will pop the three arguments passed in. |
| 2522 __ mov(eax, frame_->Top()); | 2661 __ mov(eax, frame_->Top()); |
| 2523 frame_->Push(eax); | 2662 frame_->Push(eax); |
| 2524 Load(property->key()); | 2663 Load(property->key()); |
| 2525 frame_->Push(Immediate(Smi::FromInt(0))); | 2664 frame_->Push(Immediate(Smi::FromInt(0))); |
| 2526 Load(property->value()); | 2665 Load(property->value()); |
| 2527 __ CallRuntime(Runtime::kDefineAccessor, 4); | 2666 frame_->CallRuntime(Runtime::kDefineAccessor, 4); |
| 2528 // Ignore result. | 2667 // Ignore result. |
| 2529 break; | 2668 break; |
| 2530 } | 2669 } |
| 2531 default: UNREACHABLE(); | 2670 default: UNREACHABLE(); |
| 2532 } | 2671 } |
| 2533 } | 2672 } |
| 2534 } | 2673 } |
| 2535 | 2674 |
| 2536 | 2675 |
| 2537 void CodeGenerator::VisitArrayLiteral(ArrayLiteral* node) { | 2676 void CodeGenerator::VisitArrayLiteral(ArrayLiteral* node) { |
| 2538 Comment cmnt(masm_, "[ ArrayLiteral"); | 2677 Comment cmnt(masm_, "[ ArrayLiteral"); |
| 2539 | 2678 |
| 2540 // Call runtime to create the array literal. | 2679 // Call runtime to create the array literal. |
| 2541 frame_->Push(Immediate(node->literals())); | 2680 frame_->Push(Immediate(node->literals())); |
| 2542 // Load the function of this frame. | 2681 // Load the function of this frame. |
| 2543 __ mov(ecx, frame_->Function()); | 2682 __ mov(ecx, frame_->Function()); |
| 2544 // Load the literals array of the function. | 2683 // Load the literals array of the function. |
| 2545 __ mov(ecx, FieldOperand(ecx, JSFunction::kLiteralsOffset)); | 2684 __ mov(ecx, FieldOperand(ecx, JSFunction::kLiteralsOffset)); |
| 2546 frame_->Push(ecx); | 2685 frame_->Push(ecx); |
| 2547 __ CallRuntime(Runtime::kCreateArrayLiteral, 2); | 2686 frame_->CallRuntime(Runtime::kCreateArrayLiteral, 2); |
| 2548 | 2687 |
| 2549 // Push the resulting array literal on the stack. | 2688 // Push the resulting array literal on the stack. |
| 2550 frame_->Push(eax); | 2689 frame_->Push(eax); |
| 2551 | 2690 |
| 2552 // Generate code to set the elements in the array that are not | 2691 // Generate code to set the elements in the array that are not |
| 2553 // literals. | 2692 // literals. |
| 2554 for (int i = 0; i < node->values()->length(); i++) { | 2693 for (int i = 0; i < node->values()->length(); i++) { |
| 2555 Expression* value = node->values()->at(i); | 2694 Expression* value = node->values()->at(i); |
| 2556 | 2695 |
| 2557 // If value is literal the property value is already | 2696 // If value is literal the property value is already |
| (...skipping 24 matching lines...) Expand all Loading... |
| 2582 if (literal == NULL || !literal->handle()->IsSmi()) return false; | 2721 if (literal == NULL || !literal->handle()->IsSmi()) return false; |
| 2583 int int_value = Smi::cast(*literal->handle())->value(); | 2722 int int_value = Smi::cast(*literal->handle())->value(); |
| 2584 return is_intn(int_value, kMaxSmiInlinedBits); | 2723 return is_intn(int_value, kMaxSmiInlinedBits); |
| 2585 } | 2724 } |
| 2586 | 2725 |
| 2587 | 2726 |
| 2588 void CodeGenerator::VisitAssignment(Assignment* node) { | 2727 void CodeGenerator::VisitAssignment(Assignment* node) { |
| 2589 Comment cmnt(masm_, "[ Assignment"); | 2728 Comment cmnt(masm_, "[ Assignment"); |
| 2590 | 2729 |
| 2591 RecordStatementPosition(node); | 2730 RecordStatementPosition(node); |
| 2592 Reference target(this, node->target()); | 2731 { Reference target(this, node->target()); |
| 2593 if (target.is_illegal()) return; | 2732 if (target.is_illegal()) { |
| 2733 // Fool the virtual frame into thinking that we left the assignment's |
| 2734 // value on the frame. |
| 2735 frame_->Push(Immediate(Smi::FromInt(0))); |
| 2736 return; |
| 2737 } |
| 2594 | 2738 |
| 2595 if (node->op() == Token::ASSIGN || | 2739 if (node->op() == Token::ASSIGN || |
| 2596 node->op() == Token::INIT_VAR || | 2740 node->op() == Token::INIT_VAR || |
| 2597 node->op() == Token::INIT_CONST) { | 2741 node->op() == Token::INIT_CONST) { |
| 2598 Load(node->value()); | 2742 Load(node->value()); |
| 2599 | 2743 |
| 2744 } else { |
| 2745 target.GetValue(NOT_INSIDE_TYPEOF); |
| 2746 Literal* literal = node->value()->AsLiteral(); |
| 2747 if (IsInlineSmi(literal)) { |
| 2748 SmiOperation(node->binary_op(), node->type(), literal->handle(), false, |
| 2749 NO_OVERWRITE); |
| 2750 } else { |
| 2751 Load(node->value()); |
| 2752 GenericBinaryOperation(node->binary_op(), node->type()); |
| 2753 } |
| 2754 } |
| 2755 |
| 2756 Variable* var = node->target()->AsVariableProxy()->AsVariable(); |
| 2757 if (var != NULL && |
| 2758 var->mode() == Variable::CONST && |
| 2759 node->op() != Token::INIT_VAR && node->op() != Token::INIT_CONST) { |
| 2760 // Assignment ignored - leave the value on the stack. |
| 2600 } else { | 2761 } else { |
| 2601 target.GetValue(NOT_INSIDE_TYPEOF); | 2762 __ RecordPosition(node->position()); |
| 2602 Literal* literal = node->value()->AsLiteral(); | 2763 if (node->op() == Token::INIT_CONST) { |
| 2603 if (IsInlineSmi(literal)) { | 2764 // Dynamic constant initializations must use the function context |
| 2604 SmiOperation(node->binary_op(), node->type(), literal->handle(), false, | 2765 // and initialize the actual constant declared. Dynamic variable |
| 2605 NO_OVERWRITE); | 2766 // initializations are simply assignments and use SetValue. |
| 2606 } else { | 2767 target.SetValue(CONST_INIT); |
| 2607 Load(node->value()); | 2768 } else { |
| 2608 GenericBinaryOperation(node->binary_op(), node->type()); | 2769 target.SetValue(NOT_CONST_INIT); |
| 2609 } | 2770 } |
| 2610 } | |
| 2611 | |
| 2612 Variable* var = node->target()->AsVariableProxy()->AsVariable(); | |
| 2613 if (var != NULL && | |
| 2614 var->mode() == Variable::CONST && | |
| 2615 node->op() != Token::INIT_VAR && node->op() != Token::INIT_CONST) { | |
| 2616 // Assignment ignored - leave the value on the stack. | |
| 2617 } else { | |
| 2618 __ RecordPosition(node->position()); | |
| 2619 if (node->op() == Token::INIT_CONST) { | |
| 2620 // Dynamic constant initializations must use the function context | |
| 2621 // and initialize the actual constant declared. Dynamic variable | |
| 2622 // initializations are simply assignments and use SetValue. | |
| 2623 target.SetValue(CONST_INIT); | |
| 2624 } else { | |
| 2625 target.SetValue(NOT_CONST_INIT); | |
| 2626 } | 2771 } |
| 2627 } | 2772 } |
| 2628 } | 2773 } |
| 2629 | 2774 |
| 2630 | 2775 |
| 2631 void CodeGenerator::VisitThrow(Throw* node) { | 2776 void CodeGenerator::VisitThrow(Throw* node) { |
| 2632 Comment cmnt(masm_, "[ Throw"); | 2777 Comment cmnt(masm_, "[ Throw"); |
| 2633 | 2778 |
| 2634 Load(node->exception()); | 2779 Load(node->exception()); |
| 2635 __ RecordPosition(node->position()); | 2780 __ RecordPosition(node->position()); |
| 2636 __ CallRuntime(Runtime::kThrow, 1); | 2781 frame_->CallRuntime(Runtime::kThrow, 1); |
| 2637 frame_->Push(eax); | 2782 frame_->Push(eax); |
| 2638 } | 2783 } |
| 2639 | 2784 |
| 2640 | 2785 |
| 2641 void CodeGenerator::VisitProperty(Property* node) { | 2786 void CodeGenerator::VisitProperty(Property* node) { |
| 2642 Comment cmnt(masm_, "[ Property"); | 2787 Comment cmnt(masm_, "[ Property"); |
| 2643 | |
| 2644 Reference property(this, node); | 2788 Reference property(this, node); |
| 2645 property.GetValue(typeof_state()); | 2789 property.GetValue(typeof_state()); |
| 2646 } | 2790 } |
| 2647 | 2791 |
| 2648 | 2792 |
| 2649 void CodeGenerator::VisitCall(Call* node) { | 2793 void CodeGenerator::VisitCall(Call* node) { |
| 2650 Comment cmnt(masm_, "[ Call"); | 2794 Comment cmnt(masm_, "[ Call"); |
| 2651 | 2795 |
| 2652 ZoneList<Expression*>* args = node->arguments(); | 2796 ZoneList<Expression*>* args = node->arguments(); |
| 2653 | 2797 |
| (...skipping 27 matching lines...) Expand all Loading... |
| 2681 LoadGlobal(); | 2825 LoadGlobal(); |
| 2682 | 2826 |
| 2683 // Load the arguments. | 2827 // Load the arguments. |
| 2684 for (int i = 0; i < args->length(); i++) { | 2828 for (int i = 0; i < args->length(); i++) { |
| 2685 Load(args->at(i)); | 2829 Load(args->at(i)); |
| 2686 } | 2830 } |
| 2687 | 2831 |
| 2688 // Setup the receiver register and call the IC initialization code. | 2832 // Setup the receiver register and call the IC initialization code. |
| 2689 Handle<Code> stub = ComputeCallInitialize(args->length()); | 2833 Handle<Code> stub = ComputeCallInitialize(args->length()); |
| 2690 __ RecordPosition(node->position()); | 2834 __ RecordPosition(node->position()); |
| 2691 __ call(stub, RelocInfo::CODE_TARGET_CONTEXT); | 2835 frame_->CallCode(stub, RelocInfo::CODE_TARGET_CONTEXT, args->length() + 1); |
| 2692 __ mov(esi, frame_->Context()); | 2836 __ mov(esi, frame_->Context()); |
| 2693 | 2837 |
| 2694 // Overwrite the function on the stack with the result. | 2838 // Overwrite the function on the stack with the result. |
| 2695 __ mov(frame_->Top(), eax); | 2839 __ mov(frame_->Top(), eax); |
| 2696 | 2840 |
| 2697 } else if (var != NULL && var->slot() != NULL && | 2841 } else if (var != NULL && var->slot() != NULL && |
| 2698 var->slot()->type() == Slot::LOOKUP) { | 2842 var->slot()->type() == Slot::LOOKUP) { |
| 2699 // ---------------------------------- | 2843 // ---------------------------------- |
| 2700 // JavaScript example: 'with (obj) foo(1, 2, 3)' // foo is in obj | 2844 // JavaScript example: 'with (obj) foo(1, 2, 3)' // foo is in obj |
| 2701 // ---------------------------------- | 2845 // ---------------------------------- |
| 2702 | 2846 |
| 2703 // Load the function | 2847 // Load the function |
| 2704 frame_->Push(esi); | 2848 frame_->Push(esi); |
| 2705 frame_->Push(Immediate(var->name())); | 2849 frame_->Push(Immediate(var->name())); |
| 2706 __ CallRuntime(Runtime::kLoadContextSlot, 2); | 2850 frame_->CallRuntime(Runtime::kLoadContextSlot, 2); |
| 2707 // eax: slot value; edx: receiver | 2851 // eax: slot value; edx: receiver |
| 2708 | 2852 |
| 2709 // Load the receiver. | 2853 // Load the receiver. |
| 2710 frame_->Push(eax); | 2854 frame_->Push(eax); |
| 2711 frame_->Push(edx); | 2855 frame_->Push(edx); |
| 2712 | 2856 |
| 2713 // Call the function. | 2857 // Call the function. |
| 2714 CallWithArguments(args, node->position()); | 2858 CallWithArguments(args, node->position()); |
| 2715 | 2859 |
| 2716 } else if (property != NULL) { | 2860 } else if (property != NULL) { |
| 2717 // Check if the key is a literal string. | 2861 // Check if the key is a literal string. |
| 2718 Literal* literal = property->key()->AsLiteral(); | 2862 Literal* literal = property->key()->AsLiteral(); |
| 2719 | 2863 |
| 2720 if (literal != NULL && literal->handle()->IsSymbol()) { | 2864 if (literal != NULL && literal->handle()->IsSymbol()) { |
| 2721 // ------------------------------------------------------------------ | 2865 // ------------------------------------------------------------------ |
| 2722 // JavaScript example: 'object.foo(1, 2, 3)' or 'map["key"](1, 2, 3)' | 2866 // JavaScript example: 'object.foo(1, 2, 3)' or 'map["key"](1, 2, 3)' |
| 2723 // ------------------------------------------------------------------ | 2867 // ------------------------------------------------------------------ |
| 2724 | 2868 |
| 2725 // Push the name of the function and the receiver onto the stack. | 2869 // Push the name of the function and the receiver onto the stack. |
| 2726 frame_->Push(Immediate(literal->handle())); | 2870 frame_->Push(Immediate(literal->handle())); |
| 2727 Load(property->obj()); | 2871 Load(property->obj()); |
| 2728 | 2872 |
| 2729 // Load the arguments. | 2873 // Load the arguments. |
| 2730 for (int i = 0; i < args->length(); i++) Load(args->at(i)); | 2874 for (int i = 0; i < args->length(); i++) Load(args->at(i)); |
| 2731 | 2875 |
| 2732 // Call the IC initialization code. | 2876 // Call the IC initialization code. |
| 2733 Handle<Code> stub = ComputeCallInitialize(args->length()); | 2877 Handle<Code> stub = ComputeCallInitialize(args->length()); |
| 2734 __ RecordPosition(node->position()); | 2878 __ RecordPosition(node->position()); |
| 2735 __ call(stub, RelocInfo::CODE_TARGET); | 2879 frame_->CallCode(stub, RelocInfo::CODE_TARGET, args->length() + 1); |
| 2736 __ mov(esi, frame_->Context()); | 2880 __ mov(esi, frame_->Context()); |
| 2737 | 2881 |
| 2738 // Overwrite the function on the stack with the result. | 2882 // Overwrite the function on the stack with the result. |
| 2739 __ mov(frame_->Top(), eax); | 2883 __ mov(frame_->Top(), eax); |
| 2740 | 2884 |
| 2741 } else { | 2885 } else { |
| 2742 // ------------------------------------------- | 2886 // ------------------------------------------- |
| 2743 // JavaScript example: 'array[index](1, 2, 3)' | 2887 // JavaScript example: 'array[index](1, 2, 3)' |
| 2744 // ------------------------------------------- | 2888 // ------------------------------------------- |
| 2745 | 2889 |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2782 // evaluated. | 2926 // evaluated. |
| 2783 | 2927 |
| 2784 // Compute function to call and use the global object as the | 2928 // Compute function to call and use the global object as the |
| 2785 // receiver. There is no need to use the global proxy here because | 2929 // receiver. There is no need to use the global proxy here because |
| 2786 // it will always be replaced with a newly allocated object. | 2930 // it will always be replaced with a newly allocated object. |
| 2787 Load(node->expression()); | 2931 Load(node->expression()); |
| 2788 LoadGlobal(); | 2932 LoadGlobal(); |
| 2789 | 2933 |
| 2790 // Push the arguments ("left-to-right") on the stack. | 2934 // Push the arguments ("left-to-right") on the stack. |
| 2791 ZoneList<Expression*>* args = node->arguments(); | 2935 ZoneList<Expression*>* args = node->arguments(); |
| 2792 for (int i = 0; i < args->length(); i++) Load(args->at(i)); | 2936 for (int i = 0; i < args->length(); i++) { |
| 2937 Load(args->at(i)); |
| 2938 } |
| 2793 | 2939 |
| 2794 // Constructors are called with the number of arguments in register | 2940 // Constructors are called with the number of arguments in register |
| 2795 // eax for now. Another option would be to have separate construct | 2941 // eax for now. Another option would be to have separate construct |
| 2796 // call trampolines per different arguments counts encountered. | 2942 // call trampolines per different arguments counts encountered. |
| 2797 __ Set(eax, Immediate(args->length())); | 2943 __ Set(eax, Immediate(args->length())); |
| 2798 | 2944 |
| 2799 // Load the function into temporary function slot as per calling | 2945 // Load the function into temporary function slot as per calling |
| 2800 // convention. | 2946 // convention. |
| 2801 __ mov(edi, frame_->Element(args->length() + 1)); | 2947 __ mov(edi, frame_->Element(args->length() + 1)); |
| 2802 | 2948 |
| 2803 // Call the construct call builtin that handles allocation and | 2949 // Call the construct call builtin that handles allocation and |
| 2804 // constructor invocation. | 2950 // constructor invocation. |
| 2805 __ RecordPosition(node->position()); | 2951 __ RecordPosition(node->position()); |
| 2806 __ call(Handle<Code>(Builtins::builtin(Builtins::JSConstructCall)), | 2952 Handle<Code> ic(Builtins::builtin(Builtins::JSConstructCall)); |
| 2807 RelocInfo::CONSTRUCT_CALL); | 2953 frame_->CallCode(ic, RelocInfo::CONSTRUCT_CALL, args->length() + 1); |
| 2808 // Discard the function and "push" the newly created object. | 2954 // Discard the function and "push" the newly created object. |
| 2809 __ mov(frame_->Top(), eax); | 2955 __ mov(frame_->Top(), eax); |
| 2810 } | 2956 } |
| 2811 | 2957 |
| 2812 | 2958 |
| 2813 void CodeGenerator::GenerateIsSmi(ZoneList<Expression*>* args) { | 2959 void CodeGenerator::GenerateIsSmi(ZoneList<Expression*>* args) { |
| 2814 ASSERT(args->length() == 1); | 2960 ASSERT(args->length() == 1); |
| 2815 Load(args->at(0)); | 2961 Load(args->at(0)); |
| 2816 frame_->Pop(eax); | 2962 frame_->Pop(eax); |
| 2817 __ test(eax, Immediate(kSmiTagMask)); | 2963 __ test(eax, Immediate(kSmiTagMask)); |
| (...skipping 12 matching lines...) Expand all Loading... |
| 2830 | 2976 |
| 2831 // This generates code that performs a charCodeAt() call or returns | 2977 // This generates code that performs a charCodeAt() call or returns |
| 2832 // undefined in order to trigger the slow case, Runtime_StringCharCodeAt. | 2978 // undefined in order to trigger the slow case, Runtime_StringCharCodeAt. |
| 2833 // It can handle flat and sliced strings, 8 and 16 bit characters and | 2979 // It can handle flat and sliced strings, 8 and 16 bit characters and |
| 2834 // cons strings where the answer is found in the left hand branch of the | 2980 // cons strings where the answer is found in the left hand branch of the |
| 2835 // cons. The slow case will flatten the string, which will ensure that | 2981 // cons. The slow case will flatten the string, which will ensure that |
| 2836 // the answer is in the left hand side the next time around. | 2982 // the answer is in the left hand side the next time around. |
| 2837 void CodeGenerator::GenerateFastCharCodeAt(ZoneList<Expression*>* args) { | 2983 void CodeGenerator::GenerateFastCharCodeAt(ZoneList<Expression*>* args) { |
| 2838 ASSERT(args->length() == 2); | 2984 ASSERT(args->length() == 2); |
| 2839 | 2985 |
| 2840 Label slow_case; | 2986 JumpTarget slow_case(this); |
| 2841 Label end; | 2987 JumpTarget end(this); |
| 2842 Label not_a_flat_string; | 2988 JumpTarget not_a_flat_string(this); |
| 2843 Label not_a_cons_string_either; | 2989 JumpTarget not_a_cons_string_either(this); |
| 2844 Label try_again_with_new_string; | 2990 JumpTarget try_again_with_new_string(this); |
| 2845 Label ascii_string; | 2991 JumpTarget ascii_string(this); |
| 2846 Label got_char_code; | 2992 JumpTarget got_char_code(this); |
| 2847 | 2993 |
| 2848 // Load the string into eax. | 2994 // Load the string into eax. |
| 2849 Load(args->at(0)); | 2995 Load(args->at(0)); |
| 2850 frame_->Pop(eax); | 2996 frame_->Pop(eax); |
| 2851 // If the receiver is a smi return undefined. | 2997 // If the receiver is a smi return undefined. |
| 2852 ASSERT(kSmiTag == 0); | 2998 ASSERT(kSmiTag == 0); |
| 2853 __ test(eax, Immediate(kSmiTagMask)); | 2999 __ test(eax, Immediate(kSmiTagMask)); |
| 2854 __ j(zero, &slow_case, not_taken); | 3000 slow_case.Branch(zero, not_taken); |
| 2855 | 3001 |
| 2856 // Load the index into ebx. | 3002 // Load the index into ebx. |
| 2857 Load(args->at(1)); | 3003 Load(args->at(1)); |
| 2858 frame_->Pop(ebx); | 3004 frame_->Pop(ebx); |
| 2859 | 3005 |
| 2860 // Check for negative or non-smi index. | 3006 // Check for negative or non-smi index. |
| 2861 ASSERT(kSmiTag == 0); | 3007 ASSERT(kSmiTag == 0); |
| 2862 __ test(ebx, Immediate(kSmiTagMask | 0x80000000)); | 3008 __ test(ebx, Immediate(kSmiTagMask | 0x80000000)); |
| 2863 __ j(not_zero, &slow_case, not_taken); | 3009 slow_case.Branch(not_zero, not_taken); |
| 2864 // Get rid of the smi tag on the index. | 3010 // Get rid of the smi tag on the index. |
| 2865 __ sar(ebx, kSmiTagSize); | 3011 __ sar(ebx, kSmiTagSize); |
| 2866 | 3012 |
| 2867 __ bind(&try_again_with_new_string); | 3013 try_again_with_new_string.Bind(); |
| 2868 // Get the type of the heap object into edi. | 3014 // Get the type of the heap object into edi. |
| 2869 __ mov(edx, FieldOperand(eax, HeapObject::kMapOffset)); | 3015 __ mov(edx, FieldOperand(eax, HeapObject::kMapOffset)); |
| 2870 __ movzx_b(edi, FieldOperand(edx, Map::kInstanceTypeOffset)); | 3016 __ movzx_b(edi, FieldOperand(edx, Map::kInstanceTypeOffset)); |
| 2871 // We don't handle non-strings. | 3017 // We don't handle non-strings. |
| 2872 __ test(edi, Immediate(kIsNotStringMask)); | 3018 __ test(edi, Immediate(kIsNotStringMask)); |
| 2873 __ j(not_zero, &slow_case, not_taken); | 3019 slow_case.Branch(not_zero, not_taken); |
| 2874 | 3020 |
| 2875 // Here we make assumptions about the tag values and the shifts needed. | 3021 // Here we make assumptions about the tag values and the shifts needed. |
| 2876 // See the comment in objects.h. | 3022 // See the comment in objects.h. |
| 2877 ASSERT(kLongStringTag == 0); | 3023 ASSERT(kLongStringTag == 0); |
| 2878 ASSERT(kMediumStringTag + String::kLongLengthShift == | 3024 ASSERT(kMediumStringTag + String::kLongLengthShift == |
| 2879 String::kMediumLengthShift); | 3025 String::kMediumLengthShift); |
| 2880 ASSERT(kShortStringTag + String::kLongLengthShift == | 3026 ASSERT(kShortStringTag + String::kLongLengthShift == |
| 2881 String::kShortLengthShift); | 3027 String::kShortLengthShift); |
| 2882 __ mov(ecx, Operand(edi)); | 3028 __ mov(ecx, Operand(edi)); |
| 2883 __ and_(ecx, kStringSizeMask); | 3029 __ and_(ecx, kStringSizeMask); |
| 2884 __ add(Operand(ecx), Immediate(String::kLongLengthShift)); | 3030 __ add(Operand(ecx), Immediate(String::kLongLengthShift)); |
| 2885 // Get the length field. | 3031 // Get the length field. |
| 2886 __ mov(edx, FieldOperand(eax, String::kLengthOffset)); | 3032 __ mov(edx, FieldOperand(eax, String::kLengthOffset)); |
| 2887 __ shr(edx); // ecx is implicit operand. | 3033 __ shr(edx); // ecx is implicit operand. |
| 2888 // edx is now the length of the string. | 3034 // edx is now the length of the string. |
| 2889 | 3035 |
| 2890 // Check for index out of range. | 3036 // Check for index out of range. |
| 2891 __ cmp(ebx, Operand(edx)); | 3037 __ cmp(ebx, Operand(edx)); |
| 2892 __ j(greater_equal, &slow_case, not_taken); | 3038 slow_case.Branch(greater_equal, not_taken); |
| 2893 | 3039 |
| 2894 // We need special handling for non-flat strings. | 3040 // We need special handling for non-flat strings. |
| 2895 ASSERT(kSeqStringTag == 0); | 3041 ASSERT(kSeqStringTag == 0); |
| 2896 __ test(edi, Immediate(kStringRepresentationMask)); | 3042 __ test(edi, Immediate(kStringRepresentationMask)); |
| 2897 __ j(not_zero, ¬_a_flat_string, not_taken); | 3043 not_a_flat_string.Branch(not_zero, not_taken); |
| 2898 | 3044 |
| 2899 // Check for 1-byte or 2-byte string. | 3045 // Check for 1-byte or 2-byte string. |
| 2900 __ test(edi, Immediate(kStringEncodingMask)); | 3046 __ test(edi, Immediate(kStringEncodingMask)); |
| 2901 __ j(not_zero, &ascii_string, taken); | 3047 ascii_string.Branch(not_zero, taken); |
| 2902 | 3048 |
| 2903 // 2-byte string. | 3049 // 2-byte string. |
| 2904 // Load the 2-byte character code. | 3050 // Load the 2-byte character code. |
| 2905 __ movzx_w(eax, | 3051 __ movzx_w(eax, |
| 2906 FieldOperand(eax, ebx, times_2, SeqTwoByteString::kHeaderSize)); | 3052 FieldOperand(eax, ebx, times_2, SeqTwoByteString::kHeaderSize)); |
| 2907 __ jmp(&got_char_code); | 3053 got_char_code.Jump(); |
| 2908 | 3054 |
| 2909 // ASCII string. | 3055 // ASCII string. |
| 2910 __ bind(&ascii_string); | 3056 ascii_string.Bind(); |
| 2911 // Load the byte. | 3057 // Load the byte. |
| 2912 __ movzx_b(eax, FieldOperand(eax, ebx, times_1, SeqAsciiString::kHeaderSize)); | 3058 __ movzx_b(eax, FieldOperand(eax, ebx, times_1, SeqAsciiString::kHeaderSize)); |
| 2913 | 3059 |
| 2914 __ bind(&got_char_code); | 3060 got_char_code.Bind(); |
| 2915 ASSERT(kSmiTag == 0); | 3061 ASSERT(kSmiTag == 0); |
| 2916 __ shl(eax, kSmiTagSize); | 3062 __ shl(eax, kSmiTagSize); |
| 2917 frame_->Push(eax); | 3063 frame_->Push(eax); |
| 2918 __ jmp(&end); | 3064 end.Jump(); |
| 2919 | 3065 |
| 2920 // Handle non-flat strings. | 3066 // Handle non-flat strings. |
| 2921 __ bind(¬_a_flat_string); | 3067 not_a_flat_string.Bind(); |
| 2922 __ and_(edi, kStringRepresentationMask); | 3068 __ and_(edi, kStringRepresentationMask); |
| 2923 __ cmp(edi, kConsStringTag); | 3069 __ cmp(edi, kConsStringTag); |
| 2924 __ j(not_equal, ¬_a_cons_string_either, not_taken); | 3070 not_a_cons_string_either.Branch(not_equal, not_taken); |
| 2925 | 3071 |
| 2926 // ConsString. | 3072 // ConsString. |
| 2927 // Get the first of the two strings. | 3073 // Get the first of the two strings. |
| 2928 __ mov(eax, FieldOperand(eax, ConsString::kFirstOffset)); | 3074 __ mov(eax, FieldOperand(eax, ConsString::kFirstOffset)); |
| 2929 __ jmp(&try_again_with_new_string); | 3075 try_again_with_new_string.Jump(); |
| 2930 | 3076 |
| 2931 __ bind(¬_a_cons_string_either); | 3077 not_a_cons_string_either.Bind(); |
| 2932 __ cmp(edi, kSlicedStringTag); | 3078 __ cmp(edi, kSlicedStringTag); |
| 2933 __ j(not_equal, &slow_case, not_taken); | 3079 slow_case.Branch(not_equal, not_taken); |
| 2934 | 3080 |
| 2935 // SlicedString. | 3081 // SlicedString. |
| 2936 // Add the offset to the index. | 3082 // Add the offset to the index. |
| 2937 __ add(ebx, FieldOperand(eax, SlicedString::kStartOffset)); | 3083 __ add(ebx, FieldOperand(eax, SlicedString::kStartOffset)); |
| 2938 __ j(overflow, &slow_case); | 3084 slow_case.Branch(overflow); |
| 2939 // Get the underlying string. | 3085 // Get the underlying string. |
| 2940 __ mov(eax, FieldOperand(eax, SlicedString::kBufferOffset)); | 3086 __ mov(eax, FieldOperand(eax, SlicedString::kBufferOffset)); |
| 2941 __ jmp(&try_again_with_new_string); | 3087 try_again_with_new_string.Jump(); |
| 2942 | 3088 |
| 2943 __ bind(&slow_case); | 3089 slow_case.Bind(); |
| 2944 frame_->Push(Immediate(Factory::undefined_value())); | 3090 frame_->Push(Immediate(Factory::undefined_value())); |
| 2945 | 3091 |
| 2946 __ bind(&end); | 3092 end.Bind(); |
| 2947 } | 3093 } |
| 2948 | 3094 |
| 2949 | 3095 |
| 2950 void CodeGenerator::GenerateIsArray(ZoneList<Expression*>* args) { | 3096 void CodeGenerator::GenerateIsArray(ZoneList<Expression*>* args) { |
| 2951 ASSERT(args->length() == 1); | 3097 ASSERT(args->length() == 1); |
| 2952 Load(args->at(0)); | 3098 Load(args->at(0)); |
| 2953 Label answer; | 3099 JumpTarget answer(this); |
| 2954 // We need the CC bits to come out as not_equal in the case where the | 3100 // We need the CC bits to come out as not_equal in the case where the |
| 2955 // object is a smi. This can't be done with the usual test opcode so | 3101 // object is a smi. This can't be done with the usual test opcode so |
| 2956 // we copy the object to ecx and do some destructive ops on it that | 3102 // we copy the object to ecx and do some destructive ops on it that |
| 2957 // result in the right CC bits. | 3103 // result in the right CC bits. |
| 2958 frame_->Pop(eax); | 3104 frame_->Pop(eax); |
| 2959 __ mov(ecx, Operand(eax)); | 3105 __ mov(ecx, Operand(eax)); |
| 2960 __ and_(ecx, kSmiTagMask); | 3106 __ and_(ecx, kSmiTagMask); |
| 2961 __ xor_(ecx, kSmiTagMask); | 3107 __ xor_(ecx, kSmiTagMask); |
| 2962 __ j(not_equal, &answer, not_taken); | 3108 answer.Branch(not_equal, not_taken); |
| 2963 // It is a heap object - get map. | 3109 // It is a heap object - get map. |
| 2964 __ mov(eax, FieldOperand(eax, HeapObject::kMapOffset)); | 3110 __ mov(eax, FieldOperand(eax, HeapObject::kMapOffset)); |
| 2965 __ movzx_b(eax, FieldOperand(eax, Map::kInstanceTypeOffset)); | 3111 __ movzx_b(eax, FieldOperand(eax, Map::kInstanceTypeOffset)); |
| 2966 // Check if the object is a JS array or not. | 3112 // Check if the object is a JS array or not. |
| 2967 __ cmp(eax, JS_ARRAY_TYPE); | 3113 __ cmp(eax, JS_ARRAY_TYPE); |
| 2968 __ bind(&answer); | 3114 answer.Bind(); |
| 2969 cc_reg_ = equal; | 3115 cc_reg_ = equal; |
| 2970 } | 3116 } |
| 2971 | 3117 |
| 2972 | 3118 |
| 2973 void CodeGenerator::GenerateArgumentsLength(ZoneList<Expression*>* args) { | 3119 void CodeGenerator::GenerateArgumentsLength(ZoneList<Expression*>* args) { |
| 2974 ASSERT(args->length() == 0); | 3120 ASSERT(args->length() == 0); |
| 2975 | 3121 |
| 2976 // Seed the result with the formal parameters count, which will be | 3122 // Seed the result with the formal parameters count, which will be |
| 2977 // used in case no arguments adaptor frame is found below the | 3123 // used in case no arguments adaptor frame is found below the |
| 2978 // current frame. | 3124 // current frame. |
| 2979 __ Set(eax, Immediate(Smi::FromInt(scope_->num_parameters()))); | 3125 __ Set(eax, Immediate(Smi::FromInt(scope_->num_parameters()))); |
| 2980 | 3126 |
| 2981 // Call the shared stub to get to the arguments.length. | 3127 // Call the shared stub to get to the arguments.length. |
| 2982 ArgumentsAccessStub stub(ArgumentsAccessStub::READ_LENGTH); | 3128 ArgumentsAccessStub stub(ArgumentsAccessStub::READ_LENGTH); |
| 2983 __ CallStub(&stub); | 3129 frame_->CallStub(&stub, 0); |
| 2984 frame_->Push(eax); | 3130 frame_->Push(eax); |
| 2985 } | 3131 } |
| 2986 | 3132 |
| 2987 | 3133 |
| 2988 void CodeGenerator::GenerateValueOf(ZoneList<Expression*>* args) { | 3134 void CodeGenerator::GenerateValueOf(ZoneList<Expression*>* args) { |
| 2989 ASSERT(args->length() == 1); | 3135 ASSERT(args->length() == 1); |
| 2990 Label leave; | 3136 JumpTarget leave(this); |
| 2991 Load(args->at(0)); // Load the object. | 3137 Load(args->at(0)); // Load the object. |
| 2992 __ mov(eax, frame_->Top()); | 3138 __ mov(eax, frame_->Top()); |
| 2993 // if (object->IsSmi()) return object. | 3139 // if (object->IsSmi()) return object. |
| 2994 __ test(eax, Immediate(kSmiTagMask)); | 3140 __ test(eax, Immediate(kSmiTagMask)); |
| 2995 __ j(zero, &leave, taken); | 3141 leave.Branch(zero, taken); |
| 2996 // It is a heap object - get map. | 3142 // It is a heap object - get map. |
| 2997 __ mov(ecx, FieldOperand(eax, HeapObject::kMapOffset)); | 3143 __ mov(ecx, FieldOperand(eax, HeapObject::kMapOffset)); |
| 2998 __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset)); | 3144 __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset)); |
| 2999 // if (!object->IsJSValue()) return object. | 3145 // if (!object->IsJSValue()) return object. |
| 3000 __ cmp(ecx, JS_VALUE_TYPE); | 3146 __ cmp(ecx, JS_VALUE_TYPE); |
| 3001 __ j(not_equal, &leave, not_taken); | 3147 leave.Branch(not_equal, not_taken); |
| 3002 __ mov(eax, FieldOperand(eax, JSValue::kValueOffset)); | 3148 __ mov(eax, FieldOperand(eax, JSValue::kValueOffset)); |
| 3003 __ mov(frame_->Top(), eax); | 3149 __ mov(frame_->Top(), eax); |
| 3004 __ bind(&leave); | 3150 leave.Bind(); |
| 3005 } | 3151 } |
| 3006 | 3152 |
| 3007 | 3153 |
| 3008 void CodeGenerator::GenerateSetValueOf(ZoneList<Expression*>* args) { | 3154 void CodeGenerator::GenerateSetValueOf(ZoneList<Expression*>* args) { |
| 3009 ASSERT(args->length() == 2); | 3155 ASSERT(args->length() == 2); |
| 3010 Label leave; | 3156 JumpTarget leave(this); |
| 3011 Load(args->at(0)); // Load the object. | 3157 Load(args->at(0)); // Load the object. |
| 3012 Load(args->at(1)); // Load the value. | 3158 Load(args->at(1)); // Load the value. |
| 3013 __ mov(eax, frame_->Element(1)); | 3159 __ mov(eax, frame_->Element(1)); |
| 3014 __ mov(ecx, frame_->Top()); | 3160 __ mov(ecx, frame_->Top()); |
| 3015 // if (object->IsSmi()) return object. | 3161 // if (object->IsSmi()) return object. |
| 3016 __ test(eax, Immediate(kSmiTagMask)); | 3162 __ test(eax, Immediate(kSmiTagMask)); |
| 3017 __ j(zero, &leave, taken); | 3163 leave.Branch(zero, taken); |
| 3018 // It is a heap object - get map. | 3164 // It is a heap object - get map. |
| 3019 __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset)); | 3165 __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset)); |
| 3020 __ movzx_b(ebx, FieldOperand(ebx, Map::kInstanceTypeOffset)); | 3166 __ movzx_b(ebx, FieldOperand(ebx, Map::kInstanceTypeOffset)); |
| 3021 // if (!object->IsJSValue()) return object. | 3167 // if (!object->IsJSValue()) return object. |
| 3022 __ cmp(ebx, JS_VALUE_TYPE); | 3168 __ cmp(ebx, JS_VALUE_TYPE); |
| 3023 __ j(not_equal, &leave, not_taken); | 3169 leave.Branch(not_equal, not_taken); |
| 3024 // Store the value. | 3170 // Store the value. |
| 3025 __ mov(FieldOperand(eax, JSValue::kValueOffset), ecx); | 3171 __ mov(FieldOperand(eax, JSValue::kValueOffset), ecx); |
| 3026 // Update the write barrier. | 3172 // Update the write barrier. |
| 3027 __ RecordWrite(eax, JSValue::kValueOffset, ecx, ebx); | 3173 __ RecordWrite(eax, JSValue::kValueOffset, ecx, ebx); |
| 3028 // Leave. | 3174 // Leave. |
| 3029 __ bind(&leave); | 3175 leave.Bind(); |
| 3030 __ mov(ecx, frame_->Top()); | 3176 __ mov(ecx, frame_->Top()); |
| 3031 frame_->Pop(); | 3177 frame_->Pop(); |
| 3032 __ mov(frame_->Top(), ecx); | 3178 __ mov(frame_->Top(), ecx); |
| 3033 } | 3179 } |
| 3034 | 3180 |
| 3035 | 3181 |
| 3036 void CodeGenerator::GenerateArgumentsAccess(ZoneList<Expression*>* args) { | 3182 void CodeGenerator::GenerateArgumentsAccess(ZoneList<Expression*>* args) { |
| 3037 ASSERT(args->length() == 1); | 3183 ASSERT(args->length() == 1); |
| 3038 | 3184 |
| 3039 // Load the key onto the stack and set register eax to the formal | 3185 // Load the key onto the stack and set register eax to the formal |
| 3040 // parameters count for the currently executing function. | 3186 // parameters count for the currently executing function. |
| 3041 Load(args->at(0)); | 3187 Load(args->at(0)); |
| 3042 __ Set(eax, Immediate(Smi::FromInt(scope_->num_parameters()))); | 3188 __ Set(eax, Immediate(Smi::FromInt(scope_->num_parameters()))); |
| 3043 | 3189 |
| 3044 // Call the shared stub to get to arguments[key]. | 3190 // Call the shared stub to get to arguments[key]. |
| 3045 ArgumentsAccessStub stub(ArgumentsAccessStub::READ_ELEMENT); | 3191 ArgumentsAccessStub stub(ArgumentsAccessStub::READ_ELEMENT); |
| 3046 __ CallStub(&stub); | 3192 frame_->CallStub(&stub, 0); |
| 3047 __ mov(frame_->Top(), eax); | 3193 __ mov(frame_->Top(), eax); |
| 3048 } | 3194 } |
| 3049 | 3195 |
| 3050 | 3196 |
| 3051 void CodeGenerator::GenerateObjectEquals(ZoneList<Expression*>* args) { | 3197 void CodeGenerator::GenerateObjectEquals(ZoneList<Expression*>* args) { |
| 3052 ASSERT(args->length() == 2); | 3198 ASSERT(args->length() == 2); |
| 3053 | 3199 |
| 3054 // Load the two objects into registers and perform the comparison. | 3200 // Load the two objects into registers and perform the comparison. |
| 3055 Load(args->at(0)); | 3201 Load(args->at(0)); |
| 3056 Load(args->at(1)); | 3202 Load(args->at(1)); |
| 3057 frame_->Pop(eax); | 3203 frame_->Pop(eax); |
| 3058 frame_->Pop(ecx); | 3204 frame_->Pop(ecx); |
| 3059 __ cmp(eax, Operand(ecx)); | 3205 __ cmp(eax, Operand(ecx)); |
| 3060 cc_reg_ = equal; | 3206 cc_reg_ = equal; |
| 3061 } | 3207 } |
| 3062 | 3208 |
| 3063 | 3209 |
| 3064 void CodeGenerator::VisitCallRuntime(CallRuntime* node) { | 3210 void CodeGenerator::VisitCallRuntime(CallRuntime* node) { |
| 3065 if (CheckForInlineRuntimeCall(node)) return; | 3211 if (CheckForInlineRuntimeCall(node)) { |
| 3212 return; |
| 3213 } |
| 3066 | 3214 |
| 3067 ZoneList<Expression*>* args = node->arguments(); | 3215 ZoneList<Expression*>* args = node->arguments(); |
| 3068 Comment cmnt(masm_, "[ CallRuntime"); | 3216 Comment cmnt(masm_, "[ CallRuntime"); |
| 3069 Runtime::Function* function = node->function(); | 3217 Runtime::Function* function = node->function(); |
| 3070 | 3218 |
| 3071 if (function == NULL) { | 3219 if (function == NULL) { |
| 3072 // Prepare stack for calling JS runtime function. | 3220 // Prepare stack for calling JS runtime function. |
| 3073 frame_->Push(Immediate(node->name())); | 3221 frame_->Push(Immediate(node->name())); |
| 3074 // Push the builtins object found in the current global object. | 3222 // Push the builtins object found in the current global object. |
| 3075 __ mov(edx, GlobalObject()); | 3223 __ mov(edx, GlobalObject()); |
| 3076 frame_->Push(FieldOperand(edx, GlobalObject::kBuiltinsOffset)); | 3224 frame_->Push(FieldOperand(edx, GlobalObject::kBuiltinsOffset)); |
| 3077 } | 3225 } |
| 3078 | 3226 |
| 3079 // Push the arguments ("left-to-right"). | 3227 // Push the arguments ("left-to-right"). |
| 3080 for (int i = 0; i < args->length(); i++) | 3228 for (int i = 0; i < args->length(); i++) { |
| 3081 Load(args->at(i)); | 3229 Load(args->at(i)); |
| 3230 } |
| 3082 | 3231 |
| 3083 if (function != NULL) { | 3232 if (function == NULL) { |
| 3084 // Call the C runtime function. | |
| 3085 __ CallRuntime(function, args->length()); | |
| 3086 frame_->Push(eax); | |
| 3087 } else { | |
| 3088 // Call the JS runtime function. | 3233 // Call the JS runtime function. |
| 3089 Handle<Code> stub = ComputeCallInitialize(args->length()); | 3234 Handle<Code> stub = ComputeCallInitialize(args->length()); |
| 3090 __ Set(eax, Immediate(args->length())); | 3235 __ Set(eax, Immediate(args->length())); |
| 3091 __ call(stub, RelocInfo::CODE_TARGET); | 3236 frame_->CallCode(stub, RelocInfo::CODE_TARGET, args->length() + 1); |
| 3092 __ mov(esi, frame_->Context()); | 3237 __ mov(esi, frame_->Context()); |
| 3093 __ mov(frame_->Top(), eax); | 3238 __ mov(frame_->Top(), eax); |
| 3239 } else { |
| 3240 // Call the C runtime function. |
| 3241 frame_->CallRuntime(function, args->length()); |
| 3242 frame_->Push(eax); |
| 3094 } | 3243 } |
| 3095 } | 3244 } |
| 3096 | 3245 |
| 3097 | 3246 |
| 3098 void CodeGenerator::VisitUnaryOperation(UnaryOperation* node) { | 3247 void CodeGenerator::VisitUnaryOperation(UnaryOperation* node) { |
| 3248 // Note that because of NOT and an optimization in comparison of a typeof |
| 3249 // expression to a literal string, this function can fail to leave a value |
| 3250 // on top of the frame or in the cc register. |
| 3099 Comment cmnt(masm_, "[ UnaryOperation"); | 3251 Comment cmnt(masm_, "[ UnaryOperation"); |
| 3100 | 3252 |
| 3101 Token::Value op = node->op(); | 3253 Token::Value op = node->op(); |
| 3102 | 3254 |
| 3103 if (op == Token::NOT) { | 3255 if (op == Token::NOT) { |
| 3104 LoadCondition(node->expression(), NOT_INSIDE_TYPEOF, | 3256 LoadCondition(node->expression(), NOT_INSIDE_TYPEOF, |
| 3105 false_target(), true_target(), true); | 3257 false_target(), true_target(), true); |
| 3106 cc_reg_ = NegateCondition(cc_reg_); | 3258 cc_reg_ = NegateCondition(cc_reg_); |
| 3107 | 3259 |
| 3108 } else if (op == Token::DELETE) { | 3260 } else if (op == Token::DELETE) { |
| 3109 Property* property = node->expression()->AsProperty(); | 3261 Property* property = node->expression()->AsProperty(); |
| 3110 if (property != NULL) { | 3262 if (property != NULL) { |
| 3111 Load(property->obj()); | 3263 Load(property->obj()); |
| 3112 Load(property->key()); | 3264 Load(property->key()); |
| 3113 __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION); | 3265 frame_->InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION, 2); |
| 3114 frame_->Push(eax); | 3266 frame_->Push(eax); |
| 3115 return; | 3267 return; |
| 3116 } | 3268 } |
| 3117 | 3269 |
| 3118 Variable* variable = node->expression()->AsVariableProxy()->AsVariable(); | 3270 Variable* variable = node->expression()->AsVariableProxy()->AsVariable(); |
| 3119 if (variable != NULL) { | 3271 if (variable != NULL) { |
| 3120 Slot* slot = variable->slot(); | 3272 Slot* slot = variable->slot(); |
| 3121 if (variable->is_global()) { | 3273 if (variable->is_global()) { |
| 3122 LoadGlobal(); | 3274 LoadGlobal(); |
| 3123 frame_->Push(Immediate(variable->name())); | 3275 frame_->Push(Immediate(variable->name())); |
| 3124 __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION); | 3276 frame_->InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION, 2); |
| 3125 frame_->Push(eax); | 3277 frame_->Push(eax); |
| 3126 return; | 3278 return; |
| 3127 | 3279 |
| 3128 } else if (slot != NULL && slot->type() == Slot::LOOKUP) { | 3280 } else if (slot != NULL && slot->type() == Slot::LOOKUP) { |
| 3129 // lookup the context holding the named variable | 3281 // lookup the context holding the named variable |
| 3130 frame_->Push(esi); | 3282 frame_->Push(esi); |
| 3131 frame_->Push(Immediate(variable->name())); | 3283 frame_->Push(Immediate(variable->name())); |
| 3132 __ CallRuntime(Runtime::kLookupContext, 2); | 3284 frame_->CallRuntime(Runtime::kLookupContext, 2); |
| 3133 // eax: context | 3285 // eax: context |
| 3134 frame_->Push(eax); | 3286 frame_->Push(eax); |
| 3135 frame_->Push(Immediate(variable->name())); | 3287 frame_->Push(Immediate(variable->name())); |
| 3136 __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION); | 3288 frame_->InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION, 2); |
| 3137 frame_->Push(eax); | 3289 frame_->Push(eax); |
| 3138 return; | 3290 return; |
| 3139 } | 3291 } |
| 3140 | 3292 |
| 3141 // Default: Result of deleting non-global, not dynamically | 3293 // Default: Result of deleting non-global, not dynamically |
| 3142 // introduced variables is false. | 3294 // introduced variables is false. |
| 3143 frame_->Push(Immediate(Factory::false_value())); | 3295 frame_->Push(Immediate(Factory::false_value())); |
| 3144 | 3296 |
| 3145 } else { | 3297 } else { |
| 3146 // Default: Result of deleting expressions is true. | 3298 // Default: Result of deleting expressions is true. |
| 3147 Load(node->expression()); // may have side-effects | 3299 Load(node->expression()); // may have side-effects |
| 3148 __ Set(frame_->Top(), Immediate(Factory::true_value())); | 3300 __ Set(frame_->Top(), Immediate(Factory::true_value())); |
| 3149 } | 3301 } |
| 3150 | 3302 |
| 3151 } else if (op == Token::TYPEOF) { | 3303 } else if (op == Token::TYPEOF) { |
| 3152 // Special case for loading the typeof expression; see comment on | 3304 // Special case for loading the typeof expression; see comment on |
| 3153 // LoadTypeofExpression(). | 3305 // LoadTypeofExpression(). |
| 3154 LoadTypeofExpression(node->expression()); | 3306 LoadTypeofExpression(node->expression()); |
| 3155 __ CallRuntime(Runtime::kTypeof, 1); | 3307 frame_->CallRuntime(Runtime::kTypeof, 1); |
| 3156 frame_->Push(eax); | 3308 frame_->Push(eax); |
| 3157 | 3309 |
| 3158 } else { | 3310 } else { |
| 3159 Load(node->expression()); | 3311 Load(node->expression()); |
| 3160 switch (op) { | 3312 switch (op) { |
| 3161 case Token::NOT: | 3313 case Token::NOT: |
| 3162 case Token::DELETE: | 3314 case Token::DELETE: |
| 3163 case Token::TYPEOF: | 3315 case Token::TYPEOF: |
| 3164 UNREACHABLE(); // handled above | 3316 UNREACHABLE(); // handled above |
| 3165 break; | 3317 break; |
| 3166 | 3318 |
| 3167 case Token::SUB: { | 3319 case Token::SUB: { |
| 3168 UnarySubStub stub; | 3320 UnarySubStub stub; |
| 3169 // TODO(1222589): remove dependency of TOS being cached inside stub | 3321 // TODO(1222589): remove dependency of TOS being cached inside stub |
| 3170 frame_->Pop(eax); | 3322 frame_->Pop(eax); |
| 3171 __ CallStub(&stub); | 3323 frame_->CallStub(&stub, 0); |
| 3172 frame_->Push(eax); | 3324 frame_->Push(eax); |
| 3173 break; | 3325 break; |
| 3174 } | 3326 } |
| 3175 | 3327 |
| 3176 case Token::BIT_NOT: { | 3328 case Token::BIT_NOT: { |
| 3177 // Smi check. | 3329 // Smi check. |
| 3178 Label smi_label; | 3330 JumpTarget smi_label(this); |
| 3179 Label continue_label; | 3331 JumpTarget continue_label(this); |
| 3180 frame_->Pop(eax); | 3332 frame_->Pop(eax); |
| 3181 __ test(eax, Immediate(kSmiTagMask)); | 3333 __ test(eax, Immediate(kSmiTagMask)); |
| 3182 __ j(zero, &smi_label, taken); | 3334 smi_label.Branch(zero, taken); |
| 3183 | 3335 |
| 3184 frame_->Push(eax); // undo popping of TOS | 3336 frame_->Push(eax); // undo popping of TOS |
| 3185 __ InvokeBuiltin(Builtins::BIT_NOT, CALL_FUNCTION); | 3337 frame_->InvokeBuiltin(Builtins::BIT_NOT, CALL_FUNCTION, 1); |
| 3186 | 3338 |
| 3187 __ jmp(&continue_label); | 3339 continue_label.Jump(); |
| 3188 __ bind(&smi_label); | 3340 smi_label.Bind(); |
| 3189 __ not_(eax); | 3341 __ not_(eax); |
| 3190 __ and_(eax, ~kSmiTagMask); // Remove inverted smi-tag. | 3342 __ and_(eax, ~kSmiTagMask); // Remove inverted smi-tag. |
| 3191 __ bind(&continue_label); | 3343 continue_label.Bind(); |
| 3192 frame_->Push(eax); | 3344 frame_->Push(eax); |
| 3193 break; | 3345 break; |
| 3194 } | 3346 } |
| 3195 | 3347 |
| 3196 case Token::VOID: | 3348 case Token::VOID: |
| 3197 __ mov(frame_->Top(), Factory::undefined_value()); | 3349 __ mov(frame_->Top(), Factory::undefined_value()); |
| 3198 break; | 3350 break; |
| 3199 | 3351 |
| 3200 case Token::ADD: { | 3352 case Token::ADD: { |
| 3201 // Smi check. | 3353 // Smi check. |
| 3202 Label continue_label; | 3354 JumpTarget continue_label(this); |
| 3203 frame_->Pop(eax); | 3355 frame_->Pop(eax); |
| 3204 __ test(eax, Immediate(kSmiTagMask)); | 3356 __ test(eax, Immediate(kSmiTagMask)); |
| 3205 __ j(zero, &continue_label); | 3357 continue_label.Branch(zero); |
| 3206 | 3358 |
| 3207 frame_->Push(eax); | 3359 frame_->Push(eax); |
| 3208 __ InvokeBuiltin(Builtins::TO_NUMBER, CALL_FUNCTION); | 3360 frame_->InvokeBuiltin(Builtins::TO_NUMBER, CALL_FUNCTION, 1); |
| 3209 | 3361 |
| 3210 __ bind(&continue_label); | 3362 continue_label.Bind(); |
| 3211 frame_->Push(eax); | 3363 frame_->Push(eax); |
| 3212 break; | 3364 break; |
| 3213 } | 3365 } |
| 3214 | 3366 |
| 3215 default: | 3367 default: |
| 3216 UNREACHABLE(); | 3368 UNREACHABLE(); |
| 3217 } | 3369 } |
| 3218 } | 3370 } |
| 3219 } | 3371 } |
| 3220 | 3372 |
| (...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3312 | 3464 |
| 3313 Variable* var = node->expression()->AsVariableProxy()->AsVariable(); | 3465 Variable* var = node->expression()->AsVariableProxy()->AsVariable(); |
| 3314 bool is_const = (var != NULL && var->mode() == Variable::CONST); | 3466 bool is_const = (var != NULL && var->mode() == Variable::CONST); |
| 3315 | 3467 |
| 3316 // Postfix: Make room for the result. | 3468 // Postfix: Make room for the result. |
| 3317 if (is_postfix) { | 3469 if (is_postfix) { |
| 3318 frame_->Push(Immediate(0)); | 3470 frame_->Push(Immediate(0)); |
| 3319 } | 3471 } |
| 3320 | 3472 |
| 3321 { Reference target(this, node->expression()); | 3473 { Reference target(this, node->expression()); |
| 3322 if (target.is_illegal()) return; | 3474 if (target.is_illegal()) { |
| 3475 // Spoof the virtual frame to have the expected height (one higher |
| 3476 // than on entry). |
| 3477 if (!is_postfix) { |
| 3478 frame_->Push(Immediate(Smi::FromInt(0))); |
| 3479 } |
| 3480 return; |
| 3481 } |
| 3323 target.GetValue(NOT_INSIDE_TYPEOF); | 3482 target.GetValue(NOT_INSIDE_TYPEOF); |
| 3324 | 3483 |
| 3325 CountOperationDeferred* deferred = | 3484 CountOperationDeferred* deferred = |
| 3326 new CountOperationDeferred(this, is_postfix, is_increment, | 3485 new CountOperationDeferred(this, is_postfix, is_increment, |
| 3327 target.size() * kPointerSize); | 3486 target.size() * kPointerSize); |
| 3328 | 3487 |
| 3329 frame_->Pop(eax); // Load TOS into eax for calculations below | 3488 frame_->Pop(eax); // Load TOS into eax for calculations below |
| 3330 | 3489 |
| 3331 // Postfix: Store the old value as the result. | 3490 // Postfix: Store the old value as the result. |
| 3332 if (is_postfix) { | 3491 if (is_postfix) { |
| (...skipping 21 matching lines...) Expand all Loading... |
| 3354 } | 3513 } |
| 3355 | 3514 |
| 3356 // Postfix: Discard the new value and use the old. | 3515 // Postfix: Discard the new value and use the old. |
| 3357 if (is_postfix) { | 3516 if (is_postfix) { |
| 3358 frame_->Pop(); | 3517 frame_->Pop(); |
| 3359 } | 3518 } |
| 3360 } | 3519 } |
| 3361 | 3520 |
| 3362 | 3521 |
| 3363 void CodeGenerator::VisitBinaryOperation(BinaryOperation* node) { | 3522 void CodeGenerator::VisitBinaryOperation(BinaryOperation* node) { |
| 3523 // Note that due to an optimization in comparison operations (typeof |
| 3524 // compared to a string literal), we can evaluate a binary expression such |
| 3525 // as AND or OR and not leave a value on the frame or in the cc register. |
| 3364 Comment cmnt(masm_, "[ BinaryOperation"); | 3526 Comment cmnt(masm_, "[ BinaryOperation"); |
| 3365 Token::Value op = node->op(); | 3527 Token::Value op = node->op(); |
| 3366 | 3528 |
| 3367 // According to ECMA-262 section 11.11, page 58, the binary logical | 3529 // According to ECMA-262 section 11.11, page 58, the binary logical |
| 3368 // operators must yield the result of one of the two expressions | 3530 // operators must yield the result of one of the two expressions |
| 3369 // before any ToBoolean() conversions. This means that the value | 3531 // before any ToBoolean() conversions. This means that the value |
| 3370 // produced by a && or || operator is not necessarily a boolean. | 3532 // produced by a && or || operator is not necessarily a boolean. |
| 3371 | 3533 |
| 3372 // NOTE: If the left hand side produces a materialized value (not in | 3534 // NOTE: If the left hand side produces a materialized value (not in |
| 3373 // the CC register), we force the right hand side to do the | 3535 // the CC register), we force the right hand side to do the |
| 3374 // same. This is necessary because we may have to branch to the exit | 3536 // same. This is necessary because we may have to branch to the exit |
| 3375 // after evaluating the left hand side (due to the shortcut | 3537 // after evaluating the left hand side (due to the shortcut |
| 3376 // semantics), but the compiler must (statically) know if the result | 3538 // semantics), but the compiler must (statically) know if the result |
| 3377 // of compiling the binary operation is materialized or not. | 3539 // of compiling the binary operation is materialized or not. |
| 3378 | 3540 |
| 3379 if (op == Token::AND) { | 3541 if (op == Token::AND) { |
| 3380 Label is_true; | 3542 JumpTarget is_true(this); |
| 3381 LoadCondition(node->left(), NOT_INSIDE_TYPEOF, &is_true, | 3543 LoadCondition(node->left(), NOT_INSIDE_TYPEOF, &is_true, |
| 3382 false_target(), false); | 3544 false_target(), false); |
| 3383 if (has_cc()) { | 3545 if (has_cc() || frame_ == NULL) { |
| 3384 Branch(false, false_target()); | 3546 if (has_cc()) { |
| 3547 ASSERT(frame_ != NULL); |
| 3548 Branch(false, false_target()); |
| 3549 } |
| 3385 | 3550 |
| 3386 // Evaluate right side expression. | 3551 if (frame_ != NULL || is_true.is_linked()) { |
| 3387 __ bind(&is_true); | 3552 // Evaluate right side expression. |
| 3388 LoadCondition(node->right(), NOT_INSIDE_TYPEOF, true_target(), | 3553 is_true.Bind(); |
| 3389 false_target(), false); | 3554 LoadCondition(node->right(), NOT_INSIDE_TYPEOF, true_target(), |
| 3390 | 3555 false_target(), false); |
| 3556 } |
| 3391 } else { | 3557 } else { |
| 3392 Label pop_and_continue, exit; | 3558 // We have a materialized value on the frame. |
| 3559 JumpTarget pop_and_continue(this); |
| 3560 JumpTarget exit(this); |
| 3393 | 3561 |
| 3394 // Avoid popping the result if it converts to 'false' using the | 3562 // Avoid popping the result if it converts to 'false' using the |
| 3395 // standard ToBoolean() conversion as described in ECMA-262, | 3563 // standard ToBoolean() conversion as described in ECMA-262, section |
| 3396 // section 9.2, page 30. | 3564 // 9.2, page 30. |
| 3397 // Duplicate the TOS value. The duplicate will be popped by ToBoolean. | 3565 // |
| 3566 // Duplicate the TOS value. The duplicate will be popped by ToBoolean. |
| 3398 __ mov(eax, frame_->Top()); | 3567 __ mov(eax, frame_->Top()); |
| 3399 frame_->Push(eax); | 3568 frame_->Push(eax); |
| 3400 ToBoolean(&pop_and_continue, &exit); | 3569 ToBoolean(&pop_and_continue, &exit); |
| 3401 Branch(false, &exit); | 3570 Branch(false, &exit); |
| 3402 | 3571 |
| 3403 // Pop the result of evaluating the first part. | 3572 // Pop the result of evaluating the first part. |
| 3404 __ bind(&pop_and_continue); | 3573 pop_and_continue.Bind(); |
| 3405 frame_->Pop(); | 3574 frame_->Pop(); |
| 3406 | 3575 |
| 3407 // Evaluate right side expression. | 3576 // Evaluate right side expression. |
| 3408 __ bind(&is_true); | 3577 is_true.Bind(); |
| 3409 Load(node->right()); | 3578 Load(node->right()); |
| 3410 | 3579 |
| 3411 // Exit (always with a materialized value). | 3580 // Exit (always with a materialized value). |
| 3412 __ bind(&exit); | 3581 exit.Bind(); |
| 3413 } | 3582 } |
| 3414 | 3583 |
| 3415 } else if (op == Token::OR) { | 3584 } else if (op == Token::OR) { |
| 3416 Label is_false; | 3585 JumpTarget is_false(this); |
| 3417 LoadCondition(node->left(), NOT_INSIDE_TYPEOF, true_target(), | 3586 LoadCondition(node->left(), NOT_INSIDE_TYPEOF, true_target(), |
| 3418 &is_false, false); | 3587 &is_false, false); |
| 3419 if (has_cc()) { | 3588 if (has_cc() || frame_ == NULL) { |
| 3420 Branch(true, true_target()); | 3589 if (has_cc()) { |
| 3590 ASSERT(frame_ != NULL); |
| 3591 Branch(true, true_target()); |
| 3592 } |
| 3421 | 3593 |
| 3422 // Evaluate right side expression. | 3594 if (frame_ != NULL || is_false.is_linked()) { |
| 3423 __ bind(&is_false); | 3595 // Evaluate right side expression. |
| 3424 LoadCondition(node->right(), NOT_INSIDE_TYPEOF, true_target(), | 3596 is_false.Bind(); |
| 3425 false_target(), false); | 3597 LoadCondition(node->right(), NOT_INSIDE_TYPEOF, true_target(), |
| 3598 false_target(), false); |
| 3599 } |
| 3426 | 3600 |
| 3427 } else { | 3601 } else { |
| 3428 Label pop_and_continue, exit; | 3602 // We have a materialized value on the frame. |
| 3603 JumpTarget pop_and_continue(this); |
| 3604 JumpTarget exit(this); |
| 3429 | 3605 |
| 3430 // Avoid popping the result if it converts to 'true' using the | 3606 // Avoid popping the result if it converts to 'true' using the |
| 3431 // standard ToBoolean() conversion as described in ECMA-262, | 3607 // standard ToBoolean() conversion as described in ECMA-262, |
| 3432 // section 9.2, page 30. | 3608 // section 9.2, page 30. |
| 3433 // Duplicate the TOS value. The duplicate will be popped by ToBoolean. | 3609 // Duplicate the TOS value. The duplicate will be popped by ToBoolean. |
| 3434 __ mov(eax, frame_->Top()); | 3610 __ mov(eax, frame_->Top()); |
| 3435 frame_->Push(eax); | 3611 frame_->Push(eax); |
| 3436 ToBoolean(&exit, &pop_and_continue); | 3612 ToBoolean(&exit, &pop_and_continue); |
| 3437 Branch(true, &exit); | 3613 Branch(true, &exit); |
| 3438 | 3614 |
| 3439 // Pop the result of evaluating the first part. | 3615 // Pop the result of evaluating the first part. |
| 3440 __ bind(&pop_and_continue); | 3616 pop_and_continue.Bind(); |
| 3441 frame_->Pop(); | 3617 frame_->Pop(); |
| 3442 | 3618 |
| 3443 // Evaluate right side expression. | 3619 // Evaluate right side expression. |
| 3444 __ bind(&is_false); | 3620 is_false.Bind(); |
| 3445 Load(node->right()); | 3621 Load(node->right()); |
| 3446 | 3622 |
| 3447 // Exit (always with a materialized value). | 3623 // Exit (always with a materialized value). |
| 3448 __ bind(&exit); | 3624 exit.Bind(); |
| 3449 } | 3625 } |
| 3450 | 3626 |
| 3451 } else { | 3627 } else { |
| 3452 // NOTE: The code below assumes that the slow cases (calls to runtime) | 3628 // NOTE: The code below assumes that the slow cases (calls to runtime) |
| 3453 // never return a constant/immutable object. | 3629 // never return a constant/immutable object. |
| 3454 OverwriteMode overwrite_mode = NO_OVERWRITE; | 3630 OverwriteMode overwrite_mode = NO_OVERWRITE; |
| 3455 if (node->left()->AsBinaryOperation() != NULL && | 3631 if (node->left()->AsBinaryOperation() != NULL && |
| 3456 node->left()->AsBinaryOperation()->ResultOverwriteAllowed()) { | 3632 node->left()->AsBinaryOperation()->ResultOverwriteAllowed()) { |
| 3457 overwrite_mode = OVERWRITE_LEFT; | 3633 overwrite_mode = OVERWRITE_LEFT; |
| 3458 } else if (node->right()->AsBinaryOperation() != NULL && | 3634 } else if (node->right()->AsBinaryOperation() != NULL && |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3513 // runtime routine for checking equality. | 3689 // runtime routine for checking equality. |
| 3514 | 3690 |
| 3515 if (op == Token::EQ || op == Token::EQ_STRICT) { | 3691 if (op == Token::EQ || op == Token::EQ_STRICT) { |
| 3516 bool left_is_null = | 3692 bool left_is_null = |
| 3517 left->AsLiteral() != NULL && left->AsLiteral()->IsNull(); | 3693 left->AsLiteral() != NULL && left->AsLiteral()->IsNull(); |
| 3518 bool right_is_null = | 3694 bool right_is_null = |
| 3519 right->AsLiteral() != NULL && right->AsLiteral()->IsNull(); | 3695 right->AsLiteral() != NULL && right->AsLiteral()->IsNull(); |
| 3520 // The 'null' value is only equal to 'null' or 'undefined'. | 3696 // The 'null' value is only equal to 'null' or 'undefined'. |
| 3521 if (left_is_null || right_is_null) { | 3697 if (left_is_null || right_is_null) { |
| 3522 Load(left_is_null ? right : left); | 3698 Load(left_is_null ? right : left); |
| 3523 Label exit, undetectable; | 3699 JumpTarget exit(this); |
| 3700 JumpTarget undetectable(this); |
| 3524 frame_->Pop(eax); | 3701 frame_->Pop(eax); |
| 3525 __ cmp(eax, Factory::null_value()); | 3702 __ cmp(eax, Factory::null_value()); |
| 3526 | 3703 |
| 3527 // The 'null' value is only equal to 'undefined' if using | 3704 // The 'null' value is only equal to 'undefined' if using |
| 3528 // non-strict comparisons. | 3705 // non-strict comparisons. |
| 3529 if (op != Token::EQ_STRICT) { | 3706 if (op != Token::EQ_STRICT) { |
| 3530 __ j(equal, &exit); | 3707 exit.Branch(equal); |
| 3531 __ cmp(eax, Factory::undefined_value()); | 3708 __ cmp(eax, Factory::undefined_value()); |
| 3532 | 3709 |
| 3533 // NOTE: it can be an undetectable object. | 3710 // NOTE: it can be an undetectable object. |
| 3534 __ j(equal, &exit); | 3711 exit.Branch(equal); |
| 3535 __ test(eax, Immediate(kSmiTagMask)); | 3712 __ test(eax, Immediate(kSmiTagMask)); |
| 3536 | 3713 |
| 3537 __ j(not_equal, &undetectable); | 3714 undetectable.Branch(not_equal); |
| 3538 __ jmp(false_target()); | 3715 false_target()->Jump(); |
| 3539 | 3716 |
| 3540 __ bind(&undetectable); | 3717 undetectable.Bind(); |
| 3541 __ mov(edx, FieldOperand(eax, HeapObject::kMapOffset)); | 3718 __ mov(edx, FieldOperand(eax, HeapObject::kMapOffset)); |
| 3542 __ movzx_b(ecx, FieldOperand(edx, Map::kBitFieldOffset)); | 3719 __ movzx_b(ecx, FieldOperand(edx, Map::kBitFieldOffset)); |
| 3543 __ and_(ecx, 1 << Map::kIsUndetectable); | 3720 __ and_(ecx, 1 << Map::kIsUndetectable); |
| 3544 __ cmp(ecx, 1 << Map::kIsUndetectable); | 3721 __ cmp(ecx, 1 << Map::kIsUndetectable); |
| 3545 } | 3722 } |
| 3546 | 3723 |
| 3547 __ bind(&exit); | 3724 exit.Bind(); |
| 3548 | 3725 |
| 3549 cc_reg_ = equal; | 3726 cc_reg_ = equal; |
| 3550 return; | 3727 return; |
| 3551 } | 3728 } |
| 3552 } | 3729 } |
| 3553 | 3730 |
| 3554 // NOTE: To make typeof testing for natives implemented in | 3731 // NOTE: To make typeof testing for natives implemented in |
| 3555 // JavaScript really efficient, we generate special code for | 3732 // JavaScript really efficient, we generate special code for |
| 3556 // expressions of the form: 'typeof <expression> == <string>'. | 3733 // expressions of the form: 'typeof <expression> == <string>'. |
| 3557 | 3734 |
| 3558 UnaryOperation* operation = left->AsUnaryOperation(); | 3735 UnaryOperation* operation = left->AsUnaryOperation(); |
| 3559 if ((op == Token::EQ || op == Token::EQ_STRICT) && | 3736 if ((op == Token::EQ || op == Token::EQ_STRICT) && |
| 3560 (operation != NULL && operation->op() == Token::TYPEOF) && | 3737 (operation != NULL && operation->op() == Token::TYPEOF) && |
| 3561 (right->AsLiteral() != NULL && | 3738 (right->AsLiteral() != NULL && |
| 3562 right->AsLiteral()->handle()->IsString())) { | 3739 right->AsLiteral()->handle()->IsString())) { |
| 3563 Handle<String> check(String::cast(*right->AsLiteral()->handle())); | 3740 Handle<String> check(String::cast(*right->AsLiteral()->handle())); |
| 3564 | 3741 |
| 3565 // Load the operand, move it to register edx, and restore TOS. | 3742 // Load the operand, move it to register edx, and restore TOS. |
| 3566 LoadTypeofExpression(operation->expression()); | 3743 LoadTypeofExpression(operation->expression()); |
| 3567 frame_->Pop(edx); | 3744 frame_->Pop(edx); |
| 3568 | 3745 |
| 3569 if (check->Equals(Heap::number_symbol())) { | 3746 if (check->Equals(Heap::number_symbol())) { |
| 3570 __ test(edx, Immediate(kSmiTagMask)); | 3747 __ test(edx, Immediate(kSmiTagMask)); |
| 3571 __ j(zero, true_target()); | 3748 true_target()->Branch(zero); |
| 3572 __ mov(edx, FieldOperand(edx, HeapObject::kMapOffset)); | 3749 __ mov(edx, FieldOperand(edx, HeapObject::kMapOffset)); |
| 3573 __ cmp(edx, Factory::heap_number_map()); | 3750 __ cmp(edx, Factory::heap_number_map()); |
| 3574 cc_reg_ = equal; | 3751 cc_reg_ = equal; |
| 3575 | 3752 |
| 3576 } else if (check->Equals(Heap::string_symbol())) { | 3753 } else if (check->Equals(Heap::string_symbol())) { |
| 3577 __ test(edx, Immediate(kSmiTagMask)); | 3754 __ test(edx, Immediate(kSmiTagMask)); |
| 3578 __ j(zero, false_target()); | 3755 false_target()->Branch(zero); |
| 3579 | 3756 |
| 3580 __ mov(edx, FieldOperand(edx, HeapObject::kMapOffset)); | 3757 __ mov(edx, FieldOperand(edx, HeapObject::kMapOffset)); |
| 3581 | 3758 |
| 3582 // NOTE: it might be an undetectable string object | 3759 // NOTE: it might be an undetectable string object |
| 3583 __ movzx_b(ecx, FieldOperand(edx, Map::kBitFieldOffset)); | 3760 __ movzx_b(ecx, FieldOperand(edx, Map::kBitFieldOffset)); |
| 3584 __ and_(ecx, 1 << Map::kIsUndetectable); | 3761 __ and_(ecx, 1 << Map::kIsUndetectable); |
| 3585 __ cmp(ecx, 1 << Map::kIsUndetectable); | 3762 __ cmp(ecx, 1 << Map::kIsUndetectable); |
| 3586 __ j(equal, false_target()); | 3763 false_target()->Branch(equal); |
| 3587 | 3764 |
| 3588 __ movzx_b(ecx, FieldOperand(edx, Map::kInstanceTypeOffset)); | 3765 __ movzx_b(ecx, FieldOperand(edx, Map::kInstanceTypeOffset)); |
| 3589 __ cmp(ecx, FIRST_NONSTRING_TYPE); | 3766 __ cmp(ecx, FIRST_NONSTRING_TYPE); |
| 3590 cc_reg_ = less; | 3767 cc_reg_ = less; |
| 3591 | 3768 |
| 3592 } else if (check->Equals(Heap::boolean_symbol())) { | 3769 } else if (check->Equals(Heap::boolean_symbol())) { |
| 3593 __ cmp(edx, Factory::true_value()); | 3770 __ cmp(edx, Factory::true_value()); |
| 3594 __ j(equal, true_target()); | 3771 true_target()->Branch(equal); |
| 3595 __ cmp(edx, Factory::false_value()); | 3772 __ cmp(edx, Factory::false_value()); |
| 3596 cc_reg_ = equal; | 3773 cc_reg_ = equal; |
| 3597 | 3774 |
| 3598 } else if (check->Equals(Heap::undefined_symbol())) { | 3775 } else if (check->Equals(Heap::undefined_symbol())) { |
| 3599 __ cmp(edx, Factory::undefined_value()); | 3776 __ cmp(edx, Factory::undefined_value()); |
| 3600 __ j(equal, true_target()); | 3777 true_target()->Branch(equal); |
| 3601 | 3778 |
| 3602 __ test(edx, Immediate(kSmiTagMask)); | 3779 __ test(edx, Immediate(kSmiTagMask)); |
| 3603 __ j(zero, false_target()); | 3780 false_target()->Branch(zero); |
| 3604 | 3781 |
| 3605 // NOTE: it can be an undetectable object. | 3782 // NOTE: it can be an undetectable object. |
| 3606 __ mov(edx, FieldOperand(edx, HeapObject::kMapOffset)); | 3783 __ mov(edx, FieldOperand(edx, HeapObject::kMapOffset)); |
| 3607 __ movzx_b(ecx, FieldOperand(edx, Map::kBitFieldOffset)); | 3784 __ movzx_b(ecx, FieldOperand(edx, Map::kBitFieldOffset)); |
| 3608 __ and_(ecx, 1 << Map::kIsUndetectable); | 3785 __ and_(ecx, 1 << Map::kIsUndetectable); |
| 3609 __ cmp(ecx, 1 << Map::kIsUndetectable); | 3786 __ cmp(ecx, 1 << Map::kIsUndetectable); |
| 3610 | 3787 |
| 3611 cc_reg_ = equal; | 3788 cc_reg_ = equal; |
| 3612 | 3789 |
| 3613 } else if (check->Equals(Heap::function_symbol())) { | 3790 } else if (check->Equals(Heap::function_symbol())) { |
| 3614 __ test(edx, Immediate(kSmiTagMask)); | 3791 __ test(edx, Immediate(kSmiTagMask)); |
| 3615 __ j(zero, false_target()); | 3792 false_target()->Branch(zero); |
| 3616 __ mov(edx, FieldOperand(edx, HeapObject::kMapOffset)); | 3793 __ mov(edx, FieldOperand(edx, HeapObject::kMapOffset)); |
| 3617 __ movzx_b(edx, FieldOperand(edx, Map::kInstanceTypeOffset)); | 3794 __ movzx_b(edx, FieldOperand(edx, Map::kInstanceTypeOffset)); |
| 3618 __ cmp(edx, JS_FUNCTION_TYPE); | 3795 __ cmp(edx, JS_FUNCTION_TYPE); |
| 3619 cc_reg_ = equal; | 3796 cc_reg_ = equal; |
| 3620 | 3797 |
| 3621 } else if (check->Equals(Heap::object_symbol())) { | 3798 } else if (check->Equals(Heap::object_symbol())) { |
| 3622 __ test(edx, Immediate(kSmiTagMask)); | 3799 __ test(edx, Immediate(kSmiTagMask)); |
| 3623 __ j(zero, false_target()); | 3800 false_target()->Branch(zero); |
| 3624 | 3801 |
| 3625 __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset)); | 3802 __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset)); |
| 3626 __ cmp(edx, Factory::null_value()); | 3803 __ cmp(edx, Factory::null_value()); |
| 3627 __ j(equal, true_target()); | 3804 true_target()->Branch(equal); |
| 3628 | 3805 |
| 3629 // NOTE: it might be an undetectable object | 3806 // NOTE: it might be an undetectable object |
| 3630 __ movzx_b(edx, FieldOperand(ecx, Map::kBitFieldOffset)); | 3807 __ movzx_b(edx, FieldOperand(ecx, Map::kBitFieldOffset)); |
| 3631 __ and_(edx, 1 << Map::kIsUndetectable); | 3808 __ and_(edx, 1 << Map::kIsUndetectable); |
| 3632 __ cmp(edx, 1 << Map::kIsUndetectable); | 3809 __ cmp(edx, 1 << Map::kIsUndetectable); |
| 3633 __ j(equal, false_target()); | 3810 false_target()->Branch(equal); |
| 3634 | 3811 |
| 3635 __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset)); | 3812 __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset)); |
| 3636 __ cmp(ecx, FIRST_JS_OBJECT_TYPE); | 3813 __ cmp(ecx, FIRST_JS_OBJECT_TYPE); |
| 3637 __ j(less, false_target()); | 3814 false_target()->Branch(less); |
| 3638 __ cmp(ecx, LAST_JS_OBJECT_TYPE); | 3815 __ cmp(ecx, LAST_JS_OBJECT_TYPE); |
| 3639 cc_reg_ = less_equal; | 3816 cc_reg_ = less_equal; |
| 3640 | 3817 |
| 3641 } else { | 3818 } else { |
| 3642 // Uncommon case: Typeof testing against a string literal that | 3819 // Uncommon case: Typeof testing against a string literal that |
| 3643 // is never returned from the typeof operator. | 3820 // is never returned from the typeof operator. |
| 3644 __ jmp(false_target()); | 3821 false_target()->Jump(); |
| 3822 // TODO(): Can this cause a problem because it is an expression that |
| 3823 // exits without a virtual frame in place? |
| 3645 } | 3824 } |
| 3646 return; | 3825 return; |
| 3647 } | 3826 } |
| 3648 | 3827 |
| 3649 Condition cc = no_condition; | 3828 Condition cc = no_condition; |
| 3650 bool strict = false; | 3829 bool strict = false; |
| 3651 switch (op) { | 3830 switch (op) { |
| 3652 case Token::EQ_STRICT: | 3831 case Token::EQ_STRICT: |
| 3653 strict = true; | 3832 strict = true; |
| 3654 // Fall through | 3833 // Fall through |
| 3655 case Token::EQ: | 3834 case Token::EQ: |
| 3656 cc = equal; | 3835 cc = equal; |
| 3657 break; | 3836 break; |
| 3658 case Token::LT: | 3837 case Token::LT: |
| 3659 cc = less; | 3838 cc = less; |
| 3660 break; | 3839 break; |
| 3661 case Token::GT: | 3840 case Token::GT: |
| 3662 cc = greater; | 3841 cc = greater; |
| 3663 break; | 3842 break; |
| 3664 case Token::LTE: | 3843 case Token::LTE: |
| 3665 cc = less_equal; | 3844 cc = less_equal; |
| 3666 break; | 3845 break; |
| 3667 case Token::GTE: | 3846 case Token::GTE: |
| 3668 cc = greater_equal; | 3847 cc = greater_equal; |
| 3669 break; | 3848 break; |
| 3670 case Token::IN: { | 3849 case Token::IN: { |
| 3671 Load(left); | 3850 Load(left); |
| 3672 Load(right); | 3851 Load(right); |
| 3673 __ InvokeBuiltin(Builtins::IN, CALL_FUNCTION); | 3852 frame_->InvokeBuiltin(Builtins::IN, CALL_FUNCTION, 2); |
| 3674 frame_->Push(eax); // push the result | 3853 frame_->Push(eax); // push the result |
| 3675 return; | 3854 return; |
| 3676 } | 3855 } |
| 3677 case Token::INSTANCEOF: { | 3856 case Token::INSTANCEOF: { |
| 3678 Load(left); | 3857 Load(left); |
| 3679 Load(right); | 3858 Load(right); |
| 3680 InstanceofStub stub; | 3859 InstanceofStub stub; |
| 3681 __ CallStub(&stub); | 3860 frame_->CallStub(&stub, 2); |
| 3682 __ test(eax, Operand(eax)); | 3861 __ test(eax, Operand(eax)); |
| 3683 cc_reg_ = zero; | 3862 cc_reg_ = zero; |
| 3684 return; | 3863 return; |
| 3685 } | 3864 } |
| 3686 default: | 3865 default: |
| 3687 UNREACHABLE(); | 3866 UNREACHABLE(); |
| 3688 } | 3867 } |
| 3689 | 3868 |
| 3690 // Optimize for the case where (at least) one of the expressions | 3869 // Optimize for the case where (at least) one of the expressions |
| 3691 // is a literal small integer. | 3870 // is a literal small integer. |
| (...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3760 // loads must not throw a reference error). | 3939 // loads must not throw a reference error). |
| 3761 Comment cmnt(masm, "[ Load from named Property"); | 3940 Comment cmnt(masm, "[ Load from named Property"); |
| 3762 Handle<String> name(GetName()); | 3941 Handle<String> name(GetName()); |
| 3763 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize)); | 3942 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize)); |
| 3764 // Setup the name register. | 3943 // Setup the name register. |
| 3765 __ mov(ecx, name); | 3944 __ mov(ecx, name); |
| 3766 | 3945 |
| 3767 Variable* var = expression_->AsVariableProxy()->AsVariable(); | 3946 Variable* var = expression_->AsVariableProxy()->AsVariable(); |
| 3768 if (var != NULL) { | 3947 if (var != NULL) { |
| 3769 ASSERT(var->is_global()); | 3948 ASSERT(var->is_global()); |
| 3770 __ call(ic, RelocInfo::CODE_TARGET_CONTEXT); | 3949 frame->CallCode(ic, RelocInfo::CODE_TARGET_CONTEXT, 0); |
| 3771 } else { | 3950 } else { |
| 3772 __ call(ic, RelocInfo::CODE_TARGET); | 3951 frame->CallCode(ic, RelocInfo::CODE_TARGET, 0); |
| 3773 } | 3952 } |
| 3774 frame->Push(eax); // IC call leaves result in eax, push it out | 3953 frame->Push(eax); // IC call leaves result in eax, push it out |
| 3775 break; | 3954 break; |
| 3776 } | 3955 } |
| 3777 | 3956 |
| 3778 case KEYED: { | 3957 case KEYED: { |
| 3779 // TODO(1241834): Make sure that this it is safe to ignore the | 3958 // TODO(1241834): Make sure that this it is safe to ignore the |
| 3780 // distinction between expressions in a typeof and not in a typeof. | 3959 // distinction between expressions in a typeof and not in a typeof. |
| 3781 Comment cmnt(masm, "[ Load from keyed Property"); | 3960 Comment cmnt(masm, "[ Load from keyed Property"); |
| 3782 Property* property = expression_->AsProperty(); | 3961 Property* property = expression_->AsProperty(); |
| 3783 ASSERT(property != NULL); | 3962 ASSERT(property != NULL); |
| 3784 __ RecordPosition(property->position()); | 3963 __ RecordPosition(property->position()); |
| 3785 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize)); | 3964 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize)); |
| 3786 | 3965 |
| 3787 Variable* var = expression_->AsVariableProxy()->AsVariable(); | 3966 Variable* var = expression_->AsVariableProxy()->AsVariable(); |
| 3788 if (var != NULL) { | 3967 if (var != NULL) { |
| 3789 ASSERT(var->is_global()); | 3968 ASSERT(var->is_global()); |
| 3790 __ call(ic, RelocInfo::CODE_TARGET_CONTEXT); | 3969 frame->CallCode(ic, RelocInfo::CODE_TARGET_CONTEXT, 0); |
| 3791 } else { | 3970 } else { |
| 3792 __ call(ic, RelocInfo::CODE_TARGET); | 3971 frame->CallCode(ic, RelocInfo::CODE_TARGET, 0); |
| 3793 } | 3972 } |
| 3794 frame->Push(eax); // IC call leaves result in eax, push it out | 3973 frame->Push(eax); // IC call leaves result in eax, push it out |
| 3795 break; | 3974 break; |
| 3796 } | 3975 } |
| 3797 | 3976 |
| 3798 default: | 3977 default: |
| 3799 UNREACHABLE(); | 3978 UNREACHABLE(); |
| 3800 } | 3979 } |
| 3801 } | 3980 } |
| 3802 | 3981 |
| (...skipping 24 matching lines...) Expand all Loading... |
| 3827 // | 4006 // |
| 3828 // Note that we must declare the foo upon entry of eval(), via a | 4007 // Note that we must declare the foo upon entry of eval(), via a |
| 3829 // context slot declaration, but we cannot initialize it at the | 4008 // context slot declaration, but we cannot initialize it at the |
| 3830 // same time, because the const declaration may be at the end of | 4009 // same time, because the const declaration may be at the end of |
| 3831 // the eval code (sigh...) and the const variable may have been | 4010 // the eval code (sigh...) and the const variable may have been |
| 3832 // used before (where its value is 'undefined'). Thus, we can only | 4011 // used before (where its value is 'undefined'). Thus, we can only |
| 3833 // do the initialization when we actually encounter the expression | 4012 // do the initialization when we actually encounter the expression |
| 3834 // and when the expression operands are defined and valid, and | 4013 // and when the expression operands are defined and valid, and |
| 3835 // thus we need the split into 2 operations: declaration of the | 4014 // thus we need the split into 2 operations: declaration of the |
| 3836 // context slot followed by initialization. | 4015 // context slot followed by initialization. |
| 3837 __ CallRuntime(Runtime::kInitializeConstContextSlot, 3); | 4016 frame->CallRuntime(Runtime::kInitializeConstContextSlot, 3); |
| 3838 } else { | 4017 } else { |
| 3839 __ CallRuntime(Runtime::kStoreContextSlot, 3); | 4018 frame->CallRuntime(Runtime::kStoreContextSlot, 3); |
| 3840 } | 4019 } |
| 3841 // Storing a variable must keep the (new) value on the expression | 4020 // Storing a variable must keep the (new) value on the expression |
| 3842 // stack. This is necessary for compiling chained assignment | 4021 // stack. This is necessary for compiling chained assignment |
| 3843 // expressions. | 4022 // expressions. |
| 3844 frame->Push(eax); | 4023 frame->Push(eax); |
| 3845 | 4024 |
| 3846 } else { | 4025 } else { |
| 3847 ASSERT(slot->var()->mode() != Variable::DYNAMIC); | 4026 ASSERT(slot->var()->mode() != Variable::DYNAMIC); |
| 3848 | 4027 |
| 3849 Label exit; | 4028 JumpTarget exit(cgen_); |
| 3850 if (init_state == CONST_INIT) { | 4029 if (init_state == CONST_INIT) { |
| 3851 ASSERT(slot->var()->mode() == Variable::CONST); | 4030 ASSERT(slot->var()->mode() == Variable::CONST); |
| 3852 // Only the first const initialization must be executed (the slot | 4031 // Only the first const initialization must be executed (the slot |
| 3853 // still contains 'the hole' value). When the assignment is | 4032 // still contains 'the hole' value). When the assignment is |
| 3854 // executed, the code is identical to a normal store (see below). | 4033 // executed, the code is identical to a normal store (see below). |
| 3855 Comment cmnt(masm, "[ Init const"); | 4034 Comment cmnt(masm, "[ Init const"); |
| 3856 __ mov(eax, cgen_->SlotOperand(slot, ecx)); | 4035 __ mov(eax, cgen_->SlotOperand(slot, ecx)); |
| 3857 __ cmp(eax, Factory::the_hole_value()); | 4036 __ cmp(eax, Factory::the_hole_value()); |
| 3858 __ j(not_equal, &exit); | 4037 exit.Branch(not_equal); |
| 3859 } | 4038 } |
| 3860 | 4039 |
| 3861 // We must execute the store. Storing a variable must keep the | 4040 // We must execute the store. Storing a variable must keep the |
| 3862 // (new) value on the stack. This is necessary for compiling | 4041 // (new) value on the stack. This is necessary for compiling |
| 3863 // assignment expressions. | 4042 // assignment expressions. |
| 3864 // | 4043 // |
| 3865 // Note: We will reach here even with slot->var()->mode() == | 4044 // Note: We will reach here even with slot->var()->mode() == |
| 3866 // Variable::CONST because of const declarations which will | 4045 // Variable::CONST because of const declarations which will |
| 3867 // initialize consts to 'the hole' value and by doing so, end up | 4046 // initialize consts to 'the hole' value and by doing so, end up |
| 3868 // calling this code. | 4047 // calling this code. |
| 3869 frame->Pop(eax); | 4048 frame->Pop(eax); |
| 3870 __ mov(cgen_->SlotOperand(slot, ecx), eax); | 4049 __ mov(cgen_->SlotOperand(slot, ecx), eax); |
| 3871 frame->Push(eax); // RecordWrite may destroy the value in eax. | 4050 frame->Push(eax); // RecordWrite may destroy the value in eax. |
| 3872 if (slot->type() == Slot::CONTEXT) { | 4051 if (slot->type() == Slot::CONTEXT) { |
| 3873 // ecx is loaded with context when calling SlotOperand above. | 4052 // ecx is loaded with context when calling SlotOperand above. |
| 3874 int offset = FixedArray::kHeaderSize + slot->index() * kPointerSize; | 4053 int offset = FixedArray::kHeaderSize + slot->index() * kPointerSize; |
| 3875 __ RecordWrite(ecx, offset, eax, ebx); | 4054 __ RecordWrite(ecx, offset, eax, ebx); |
| 3876 } | 4055 } |
| 3877 // If we definitely did not jump over the assignment, we do not need | 4056 // If we definitely did not jump over the assignment, we do not need |
| 3878 // to bind the exit label. Doing so can defeat peephole | 4057 // to bind the exit label. Doing so can defeat peephole |
| 3879 // optimization. | 4058 // optimization. |
| 3880 if (init_state == CONST_INIT) __ bind(&exit); | 4059 if (init_state == CONST_INIT) { |
| 4060 exit.Bind(); |
| 4061 } |
| 3881 } | 4062 } |
| 3882 break; | 4063 break; |
| 3883 } | 4064 } |
| 3884 | 4065 |
| 3885 case NAMED: { | 4066 case NAMED: { |
| 3886 Comment cmnt(masm, "[ Store to named Property"); | 4067 Comment cmnt(masm, "[ Store to named Property"); |
| 3887 // Call the appropriate IC code. | 4068 // Call the appropriate IC code. |
| 3888 Handle<String> name(GetName()); | 4069 Handle<String> name(GetName()); |
| 3889 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); | 4070 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); |
| 3890 // TODO(1222589): Make the IC grab the values from the stack. | 4071 // TODO(1222589): Make the IC grab the values from the stack. |
| 3891 frame->Pop(eax); | 4072 frame->Pop(eax); |
| 3892 // Setup the name register. | 4073 // Setup the name register. |
| 3893 __ mov(ecx, name); | 4074 __ mov(ecx, name); |
| 3894 __ call(ic, RelocInfo::CODE_TARGET); | 4075 frame->CallCode(ic, RelocInfo::CODE_TARGET, 0); |
| 3895 frame->Push(eax); // IC call leaves result in eax, push it out | 4076 frame->Push(eax); // IC call leaves result in eax, push it out |
| 3896 break; | 4077 break; |
| 3897 } | 4078 } |
| 3898 | 4079 |
| 3899 case KEYED: { | 4080 case KEYED: { |
| 3900 Comment cmnt(masm, "[ Store to keyed Property"); | 4081 Comment cmnt(masm, "[ Store to keyed Property"); |
| 3901 Property* property = expression_->AsProperty(); | 4082 Property* property = expression_->AsProperty(); |
| 3902 ASSERT(property != NULL); | 4083 ASSERT(property != NULL); |
| 3903 __ RecordPosition(property->position()); | 4084 __ RecordPosition(property->position()); |
| 3904 // Call IC code. | 4085 // Call IC code. |
| 3905 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize)); | 4086 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize)); |
| 3906 // TODO(1222589): Make the IC grab the values from the stack. | 4087 // TODO(1222589): Make the IC grab the values from the stack. |
| 3907 frame->Pop(eax); | 4088 frame->Pop(eax); |
| 3908 __ call(ic, RelocInfo::CODE_TARGET); | 4089 frame->CallCode(ic, RelocInfo::CODE_TARGET, 0); |
| 3909 frame->Push(eax); // IC call leaves result in eax, push it out | 4090 frame->Push(eax); // IC call leaves result in eax, push it out |
| 3910 break; | 4091 break; |
| 3911 } | 4092 } |
| 3912 | 4093 |
| 3913 default: | 4094 default: |
| 3914 UNREACHABLE(); | 4095 UNREACHABLE(); |
| 3915 } | 4096 } |
| 3916 } | 4097 } |
| 3917 | 4098 |
| 3918 | 4099 |
| (...skipping 1215 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5134 | 5315 |
| 5135 // Slow-case: Go through the JavaScript implementation. | 5316 // Slow-case: Go through the JavaScript implementation. |
| 5136 __ bind(&slow); | 5317 __ bind(&slow); |
| 5137 __ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION); | 5318 __ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION); |
| 5138 } | 5319 } |
| 5139 | 5320 |
| 5140 | 5321 |
| 5141 #undef __ | 5322 #undef __ |
| 5142 | 5323 |
| 5143 } } // namespace v8::internal | 5324 } } // namespace v8::internal |
| OLD | NEW |