| OLD | NEW |
| 1 // Copyright 2006-2008 the V8 project authors. All rights reserved. | 1 // Copyright 2006-2008 the V8 project authors. All rights reserved. |
| 2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
| 3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
| 4 // met: | 4 // met: |
| 5 // | 5 // |
| 6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
| 7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
| 8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
| 9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
| 10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
| (...skipping 12 matching lines...) Expand all Loading... |
| 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 27 | 27 |
| 28 #include "v8.h" | 28 #include "v8.h" |
| 29 | 29 |
| 30 #include "bootstrapper.h" | 30 #include "bootstrapper.h" |
| 31 #include "codegen-inl.h" | 31 #include "codegen-inl.h" |
| 32 #include "debug.h" | 32 #include "debug.h" |
| 33 #include "prettyprinter.h" | |
| 34 #include "scopeinfo.h" | |
| 35 #include "scopes.h" | 33 #include "scopes.h" |
| 36 #include "runtime.h" | 34 #include "runtime.h" |
| 37 | 35 |
| 38 namespace v8 { namespace internal { | 36 namespace v8 { namespace internal { |
| 39 | 37 |
| 40 #define TOS (Operand(esp, 0)) | 38 #define TOS (Operand(esp, 0)) |
| 41 | 39 |
| 42 | 40 |
| 43 class Ia32CodeGenerator; | |
| 44 | |
| 45 // Mode to overwrite BinaryExpression values. | |
| 46 enum OverwriteMode { NO_OVERWRITE, OVERWRITE_LEFT, OVERWRITE_RIGHT }; | |
| 47 | |
| 48 | |
| 49 // ----------------------------------------------------------------------------- | |
| 50 // Reference support | |
| 51 | |
| 52 // A reference is a C++ stack-allocated object that keeps an ECMA | |
| 53 // reference on the execution stack while in scope. For variables | |
| 54 // the reference is empty, indicating that it isn't necessary to | |
| 55 // store state on the stack for keeping track of references to those. | |
| 56 // For properties, we keep either one (named) or two (indexed) values | |
| 57 // on the execution stack to represent the reference. | |
| 58 | |
| 59 enum InitState { CONST_INIT, NOT_CONST_INIT }; | |
| 60 enum TypeofState { INSIDE_TYPEOF, NOT_INSIDE_TYPEOF }; | |
| 61 | |
| 62 class Reference BASE_EMBEDDED { | |
| 63 public: | |
| 64 // The values of the types is important, see size(). | |
| 65 enum Type { ILLEGAL = -1, SLOT = 0, NAMED = 1, KEYED = 2 }; | |
| 66 Reference(Ia32CodeGenerator* cgen, Expression* expression); | |
| 67 ~Reference(); | |
| 68 | |
| 69 Expression* expression() const { return expression_; } | |
| 70 Type type() const { return type_; } | |
| 71 void set_type(Type value) { | |
| 72 ASSERT(type_ == ILLEGAL); | |
| 73 type_ = value; | |
| 74 } | |
| 75 | |
| 76 // The size of the reference or -1 if the reference is illegal. | |
| 77 int size() const { return type_; } | |
| 78 | |
| 79 bool is_illegal() const { return type_ == ILLEGAL; } | |
| 80 bool is_slot() const { return type_ == SLOT; } | |
| 81 bool is_property() const { return type_ == NAMED || type_ == KEYED; } | |
| 82 | |
| 83 // Return the name. Only valid for named property references. | |
| 84 Handle<String> GetName(); | |
| 85 | |
| 86 // Generate code to push the value of the reference on top of the | |
| 87 // expression stack. The reference is expected to be already on top of | |
| 88 // the expression stack, and it is left in place with its value above it. | |
| 89 void GetValue(TypeofState typeof_state); | |
| 90 | |
| 91 // Generate code to store the value on top of the expression stack in the | |
| 92 // reference. The reference is expected to be immediately below the value | |
| 93 // on the expression stack. The stored value is left in place (with the | |
| 94 // reference intact below it) to support chained assignments. | |
| 95 void SetValue(InitState init_state); | |
| 96 | |
| 97 private: | |
| 98 Ia32CodeGenerator* cgen_; | |
| 99 Expression* expression_; | |
| 100 Type type_; | |
| 101 }; | |
| 102 | |
| 103 | |
| 104 // ------------------------------------------------------------------------- | |
| 105 // Code generation state | |
| 106 | |
| 107 // The state is passed down the AST by the code generator (and back up, in | |
| 108 // the form of the state of the label pair). It is threaded through the | |
| 109 // call stack. Constructing a state implicitly pushes it on the owning code | |
| 110 // generator's stack of states, and destroying one implicitly pops it. | |
| 111 | |
| 112 class CodeGenState BASE_EMBEDDED { | |
| 113 public: | |
| 114 // Create an initial code generator state. Destroying the initial state | |
| 115 // leaves the code generator with a NULL state. | |
| 116 explicit CodeGenState(Ia32CodeGenerator* owner); | |
| 117 | |
| 118 // Create a code generator state based on a code generator's current | |
| 119 // state. The new state has its own typeof state and pair of branch | |
| 120 // labels. | |
| 121 CodeGenState(Ia32CodeGenerator* owner, | |
| 122 TypeofState typeof_state, | |
| 123 Label* true_target, | |
| 124 Label* false_target); | |
| 125 | |
| 126 // Destroy a code generator state and restore the owning code generator's | |
| 127 // previous state. | |
| 128 ~CodeGenState(); | |
| 129 | |
| 130 TypeofState typeof_state() const { return typeof_state_; } | |
| 131 Label* true_target() const { return true_target_; } | |
| 132 Label* false_target() const { return false_target_; } | |
| 133 | |
| 134 private: | |
| 135 Ia32CodeGenerator* owner_; | |
| 136 TypeofState typeof_state_; | |
| 137 Label* true_target_; | |
| 138 Label* false_target_; | |
| 139 CodeGenState* previous_; | |
| 140 }; | |
| 141 | |
| 142 | |
| 143 // ----------------------------------------------------------------------------- | |
| 144 // Ia32CodeGenerator | |
| 145 | |
| 146 class Ia32CodeGenerator: public CodeGenerator { | |
| 147 public: | |
| 148 static Handle<Code> MakeCode(FunctionLiteral* fun, | |
| 149 Handle<Script> script, | |
| 150 bool is_eval); | |
| 151 | |
| 152 MacroAssembler* masm() { return masm_; } | |
| 153 | |
| 154 Scope* scope() const { return scope_; } | |
| 155 | |
| 156 CodeGenState* state() { return state_; } | |
| 157 void set_state(CodeGenState* state) { state_ = state; } | |
| 158 | |
| 159 private: | |
| 160 // Assembler | |
| 161 MacroAssembler* masm_; // to generate code | |
| 162 | |
| 163 // Code generation state | |
| 164 Scope* scope_; | |
| 165 Condition cc_reg_; | |
| 166 CodeGenState* state_; | |
| 167 bool is_inside_try_; | |
| 168 int break_stack_height_; | |
| 169 | |
| 170 // Labels | |
| 171 Label function_return_; | |
| 172 | |
| 173 // Construction/destruction | |
| 174 Ia32CodeGenerator(int buffer_size, | |
| 175 Handle<Script> script, | |
| 176 bool is_eval); | |
| 177 virtual ~Ia32CodeGenerator() { delete masm_; } | |
| 178 | |
| 179 // Main code generation function | |
| 180 void GenCode(FunctionLiteral* fun); | |
| 181 | |
| 182 // The following are used by class Reference. | |
| 183 void LoadReference(Reference* ref); | |
| 184 void UnloadReference(Reference* ref); | |
| 185 | |
| 186 // State | |
| 187 bool has_cc() const { return cc_reg_ >= 0; } | |
| 188 TypeofState typeof_state() const { return state_->typeof_state(); } | |
| 189 Label* true_target() const { return state_->true_target(); } | |
| 190 Label* false_target() const { return state_->false_target(); } | |
| 191 | |
| 192 // Expressions | |
| 193 Operand GlobalObject() const { | |
| 194 return ContextOperand(esi, Context::GLOBAL_INDEX); | |
| 195 } | |
| 196 | |
| 197 // Support functions for accessing parameters. | |
| 198 Operand ParameterOperand(int index) const { | |
| 199 int num_parameters = scope()->num_parameters(); | |
| 200 ASSERT(-2 <= index && index < num_parameters); | |
| 201 return Operand(ebp, (1 + num_parameters - index) * kPointerSize); | |
| 202 } | |
| 203 | |
| 204 Operand ReceiverOperand() const { return ParameterOperand(-1); } | |
| 205 | |
| 206 Operand FunctionOperand() const { | |
| 207 return Operand(ebp, JavaScriptFrameConstants::kFunctionOffset); | |
| 208 } | |
| 209 | |
| 210 Operand ContextOperand(Register context, int index) const { | |
| 211 return Operand(context, Context::SlotOffset(index)); | |
| 212 } | |
| 213 | |
| 214 Operand SlotOperand(Slot* slot, Register tmp); | |
| 215 | |
| 216 void LoadCondition(Expression* x, | |
| 217 TypeofState typeof_state, | |
| 218 Label* true_target, | |
| 219 Label* false_target, | |
| 220 bool force_cc); | |
| 221 void Load(Expression* x, TypeofState typeof_state = NOT_INSIDE_TYPEOF); | |
| 222 void LoadGlobal(); | |
| 223 | |
| 224 // Read a value from a slot and leave it on top of the expression stack. | |
| 225 void LoadFromSlot(Slot* slot, TypeofState typeof_state); | |
| 226 | |
| 227 // Special code for typeof expressions: Unfortunately, we must | |
| 228 // be careful when loading the expression in 'typeof' | |
| 229 // expressions. We are not allowed to throw reference errors for | |
| 230 // non-existing properties of the global object, so we must make it | |
| 231 // look like an explicit property access, instead of an access | |
| 232 // through the context chain. | |
| 233 void LoadTypeofExpression(Expression* x); | |
| 234 | |
| 235 void ToBoolean(Label* true_target, Label* false_target); | |
| 236 | |
| 237 void GenericBinaryOperation( | |
| 238 Token::Value op, | |
| 239 const OverwriteMode overwrite_mode = NO_OVERWRITE); | |
| 240 void Comparison(Condition cc, bool strict = false); | |
| 241 | |
| 242 // Inline small integer literals. To prevent long attacker-controlled byte | |
| 243 // sequences, we only inline small Smi:s. | |
| 244 static const int kMaxSmiInlinedBits = 16; | |
| 245 bool IsInlineSmi(Literal* literal); | |
| 246 void SmiComparison(Condition cc, Handle<Object> value, bool strict = false); | |
| 247 void SmiOperation(Token::Value op, | |
| 248 Handle<Object> value, | |
| 249 bool reversed, | |
| 250 OverwriteMode overwrite_mode); | |
| 251 | |
| 252 void CallWithArguments(ZoneList<Expression*>* arguments, int position); | |
| 253 | |
| 254 // Declare global variables and functions in the given array of | |
| 255 // name/value pairs. | |
| 256 virtual void DeclareGlobals(Handle<FixedArray> pairs); | |
| 257 | |
| 258 // Instantiate the function boilerplate. | |
| 259 void InstantiateBoilerplate(Handle<JSFunction> boilerplate); | |
| 260 | |
| 261 // Control flow | |
| 262 void Branch(bool if_true, Label* L); | |
| 263 void CheckStack(); | |
| 264 void CleanStack(int num_bytes); | |
| 265 | |
| 266 // Node visitors | |
| 267 #define DEF_VISIT(type) \ | |
| 268 virtual void Visit##type(type* node); | |
| 269 NODE_LIST(DEF_VISIT) | |
| 270 #undef DEF_VISIT | |
| 271 | |
| 272 // Only allow fast-case switch if the range of labels is at most | |
| 273 // this factor times the number of case labels. | |
| 274 // Value is derived from comparing the size of code generated by the normal | |
| 275 // switch code for Smi-labels to the size of a single pointer. If code | |
| 276 // quality increases this number should be decreased to match. | |
| 277 static const int kFastSwitchMaxOverheadFactor = 5; | |
| 278 | |
| 279 // Minimal number of switch cases required before we allow jump-table | |
| 280 // optimization. | |
| 281 static const int kFastSwitchMinCaseCount = 5; | |
| 282 | |
| 283 virtual int FastCaseSwitchMaxOverheadFactor(); | |
| 284 virtual int FastCaseSwitchMinCaseCount(); | |
| 285 | |
| 286 // Generate a computed jump with an empty jump table. | |
| 287 // Binds a label to the start of the jump table. This table must | |
| 288 // be populated later when the addresses of the targets are known. | |
| 289 // Used by GenerateFastCaseSwitchStatement. | |
| 290 virtual void GenerateFastCaseSwitchJumpTable( | |
| 291 SwitchStatement* node, int min_index, int range, Label *fail_label, | |
| 292 SmartPointer<Label*> &case_targets, SmartPointer<Label> &case_labels); | |
| 293 | |
| 294 void RecordStatementPosition(Node* node); | |
| 295 | |
| 296 // Activation frames. | |
| 297 void EnterJSFrame(); | |
| 298 void ExitJSFrame(); | |
| 299 | |
| 300 virtual void GenerateIsSmi(ZoneList<Expression*>* args); | |
| 301 virtual void GenerateIsNonNegativeSmi(ZoneList<Expression*>* args); | |
| 302 virtual void GenerateIsArray(ZoneList<Expression*>* args); | |
| 303 | |
| 304 virtual void GenerateArgumentsLength(ZoneList<Expression*>* args); | |
| 305 virtual void GenerateArgumentsAccess(ZoneList<Expression*>* args); | |
| 306 | |
| 307 virtual void GenerateValueOf(ZoneList<Expression*>* args); | |
| 308 virtual void GenerateSetValueOf(ZoneList<Expression*>* args); | |
| 309 | |
| 310 virtual void GenerateFastCharCodeAt(ZoneList<Expression*>* args); | |
| 311 | |
| 312 virtual void GenerateObjectEquals(ZoneList<Expression*>* args); | |
| 313 | |
| 314 friend class Reference; | |
| 315 friend class Property; | |
| 316 friend class VariableProxy; | |
| 317 friend class Slot; | |
| 318 }; | |
| 319 | |
| 320 | |
| 321 // ------------------------------------------------------------------------- | 41 // ------------------------------------------------------------------------- |
| 322 // CodeGenState implementation. | 42 // CodeGenState implementation. |
| 323 | 43 |
| 324 CodeGenState::CodeGenState(Ia32CodeGenerator* owner) | 44 CodeGenState::CodeGenState(CodeGenerator* owner) |
| 325 : owner_(owner), | 45 : owner_(owner), |
| 326 typeof_state_(NOT_INSIDE_TYPEOF), | 46 typeof_state_(NOT_INSIDE_TYPEOF), |
| 327 true_target_(NULL), | 47 true_target_(NULL), |
| 328 false_target_(NULL), | 48 false_target_(NULL), |
| 329 previous_(NULL) { | 49 previous_(NULL) { |
| 330 owner_->set_state(this); | 50 owner_->set_state(this); |
| 331 } | 51 } |
| 332 | 52 |
| 333 | 53 |
| 334 CodeGenState::CodeGenState(Ia32CodeGenerator* owner, | 54 CodeGenState::CodeGenState(CodeGenerator* owner, |
| 335 TypeofState typeof_state, | 55 TypeofState typeof_state, |
| 336 Label* true_target, | 56 Label* true_target, |
| 337 Label* false_target) | 57 Label* false_target) |
| 338 : owner_(owner), | 58 : owner_(owner), |
| 339 typeof_state_(typeof_state), | 59 typeof_state_(typeof_state), |
| 340 true_target_(true_target), | 60 true_target_(true_target), |
| 341 false_target_(false_target), | 61 false_target_(false_target), |
| 342 previous_(owner->state()) { | 62 previous_(owner->state()) { |
| 343 owner_->set_state(this); | 63 owner_->set_state(this); |
| 344 } | 64 } |
| 345 | 65 |
| 346 | 66 |
| 347 CodeGenState::~CodeGenState() { | 67 CodeGenState::~CodeGenState() { |
| 348 ASSERT(owner_->state() == this); | 68 ASSERT(owner_->state() == this); |
| 349 owner_->set_state(previous_); | 69 owner_->set_state(previous_); |
| 350 } | 70 } |
| 351 | 71 |
| 352 | 72 |
| 353 // ----------------------------------------------------------------------------- | 73 // ----------------------------------------------------------------------------- |
| 354 // Ia32CodeGenerator implementation | 74 // CodeGenerator implementation |
| 355 | 75 |
| 356 #define __ masm_-> | 76 #define __ masm_-> |
| 357 | 77 |
| 358 Handle<Code> Ia32CodeGenerator::MakeCode(FunctionLiteral* flit, | 78 CodeGenerator::CodeGenerator(int buffer_size, Handle<Script> script, |
| 359 Handle<Script> script, | 79 bool is_eval) |
| 360 bool is_eval) { | 80 : is_eval_(is_eval), |
| 361 #ifdef ENABLE_DISASSEMBLER | 81 script_(script), |
| 362 bool print_code = FLAG_print_code && !Bootstrapper::IsActive(); | 82 deferred_(8), |
| 363 #endif | |
| 364 | |
| 365 #ifdef DEBUG | |
| 366 bool print_source = false; | |
| 367 bool print_ast = false; | |
| 368 const char* ftype; | |
| 369 | |
| 370 if (Bootstrapper::IsActive()) { | |
| 371 print_source = FLAG_print_builtin_source; | |
| 372 print_ast = FLAG_print_builtin_ast; | |
| 373 print_code = FLAG_print_builtin_code; | |
| 374 ftype = "builtin"; | |
| 375 } else { | |
| 376 print_source = FLAG_print_source; | |
| 377 print_ast = FLAG_print_ast; | |
| 378 ftype = "user-defined"; | |
| 379 } | |
| 380 | |
| 381 if (FLAG_trace_codegen || print_source || print_ast) { | |
| 382 PrintF("*** Generate code for %s function: ", ftype); | |
| 383 flit->name()->ShortPrint(); | |
| 384 PrintF(" ***\n"); | |
| 385 } | |
| 386 | |
| 387 if (print_source) { | |
| 388 PrintF("--- Source from AST ---\n%s\n", PrettyPrinter().PrintProgram(flit)); | |
| 389 } | |
| 390 | |
| 391 if (print_ast) { | |
| 392 PrintF("--- AST ---\n%s\n", AstPrinter().PrintProgram(flit)); | |
| 393 } | |
| 394 #endif // DEBUG | |
| 395 | |
| 396 // Generate code. | |
| 397 const int initial_buffer_size = 4 * KB; | |
| 398 Ia32CodeGenerator cgen(initial_buffer_size, script, is_eval); | |
| 399 cgen.GenCode(flit); | |
| 400 if (cgen.HasStackOverflow()) { | |
| 401 ASSERT(!Top::has_pending_exception()); | |
| 402 return Handle<Code>::null(); | |
| 403 } | |
| 404 | |
| 405 // Process any deferred code. | |
| 406 cgen.ProcessDeferred(); | |
| 407 | |
| 408 // Allocate and install the code. | |
| 409 CodeDesc desc; | |
| 410 cgen.masm()->GetCode(&desc); | |
| 411 ScopeInfo<> sinfo(flit->scope()); | |
| 412 Code::Flags flags = Code::ComputeFlags(Code::FUNCTION); | |
| 413 Handle<Code> code = Factory::NewCode(desc, &sinfo, flags); | |
| 414 | |
| 415 // Add unresolved entries in the code to the fixup list. | |
| 416 Bootstrapper::AddFixup(*code, cgen.masm()); | |
| 417 | |
| 418 #ifdef ENABLE_DISASSEMBLER | |
| 419 if (print_code) { | |
| 420 // Print the source code if available. | |
| 421 if (!script->IsUndefined() && !script->source()->IsUndefined()) { | |
| 422 PrintF("--- Raw source ---\n"); | |
| 423 StringInputBuffer stream(String::cast(script->source())); | |
| 424 stream.Seek(flit->start_position()); | |
| 425 // flit->end_position() points to the last character in the stream. We | |
| 426 // need to compensate by adding one to calculate the length. | |
| 427 int source_len = flit->end_position() - flit->start_position() + 1; | |
| 428 for (int i = 0; i < source_len; i++) { | |
| 429 if (stream.has_more()) PrintF("%c", stream.GetNext()); | |
| 430 } | |
| 431 PrintF("\n\n"); | |
| 432 } | |
| 433 PrintF("--- Code ---\n"); | |
| 434 code->Disassemble(); | |
| 435 } | |
| 436 #endif // ENABLE_DISASSEMBLER | |
| 437 | |
| 438 return code; | |
| 439 } | |
| 440 | |
| 441 | |
| 442 Ia32CodeGenerator::Ia32CodeGenerator(int buffer_size, | |
| 443 Handle<Script> script, | |
| 444 bool is_eval) | |
| 445 : CodeGenerator(is_eval, script), | |
| 446 masm_(new MacroAssembler(NULL, buffer_size)), | 83 masm_(new MacroAssembler(NULL, buffer_size)), |
| 447 scope_(NULL), | 84 scope_(NULL), |
| 448 cc_reg_(no_condition), | 85 cc_reg_(no_condition), |
| 449 state_(NULL), | 86 state_(NULL), |
| 450 is_inside_try_(false), | 87 is_inside_try_(false), |
| 451 break_stack_height_(0) { | 88 break_stack_height_(0) { |
| 452 } | 89 } |
| 453 | 90 |
| 454 | 91 |
| 455 // Calling conventions: | 92 // Calling conventions: |
| 456 // ebp: frame pointer | 93 // ebp: frame pointer |
| 457 // esp: stack pointer | 94 // esp: stack pointer |
| 458 // edi: caller's parameter pointer | 95 // edi: caller's parameter pointer |
| 459 // esi: callee's context | 96 // esi: callee's context |
| 460 | 97 |
| 461 void Ia32CodeGenerator::GenCode(FunctionLiteral* fun) { | 98 void CodeGenerator::GenCode(FunctionLiteral* fun) { |
| 462 // Record the position for debugging purposes. | 99 // Record the position for debugging purposes. |
| 463 __ RecordPosition(fun->start_position()); | 100 __ RecordPosition(fun->start_position()); |
| 464 | 101 |
| 465 Scope* scope = fun->scope(); | 102 Scope* scope = fun->scope(); |
| 466 ZoneList<Statement*>* body = fun->body(); | 103 ZoneList<Statement*>* body = fun->body(); |
| 467 | 104 |
| 468 // Initialize state. | 105 // Initialize state. |
| 469 { CodeGenState state(this); | 106 { CodeGenState state(this); |
| 470 scope_ = scope; | 107 scope_ = scope; |
| 471 cc_reg_ = no_condition; | 108 cc_reg_ = no_condition; |
| (...skipping 190 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 662 } | 299 } |
| 663 } | 300 } |
| 664 | 301 |
| 665 // Code generation state must be reset. | 302 // Code generation state must be reset. |
| 666 scope_ = NULL; | 303 scope_ = NULL; |
| 667 ASSERT(!has_cc()); | 304 ASSERT(!has_cc()); |
| 668 ASSERT(state_ == NULL); | 305 ASSERT(state_ == NULL); |
| 669 } | 306 } |
| 670 | 307 |
| 671 | 308 |
| 672 Operand Ia32CodeGenerator::SlotOperand(Slot* slot, Register tmp) { | 309 Operand CodeGenerator::SlotOperand(Slot* slot, Register tmp) { |
| 673 // Currently, this assertion will fail if we try to assign to | 310 // Currently, this assertion will fail if we try to assign to |
| 674 // a constant variable that is constant because it is read-only | 311 // a constant variable that is constant because it is read-only |
| 675 // (such as the variable referring to a named function expression). | 312 // (such as the variable referring to a named function expression). |
| 676 // We need to implement assignments to read-only variables. | 313 // We need to implement assignments to read-only variables. |
| 677 // Ideally, we should do this during AST generation (by converting | 314 // Ideally, we should do this during AST generation (by converting |
| 678 // such assignments into expression statements); however, in general | 315 // such assignments into expression statements); however, in general |
| 679 // we may not be able to make the decision until past AST generation, | 316 // we may not be able to make the decision until past AST generation, |
| 680 // that is when the entire program is known. | 317 // that is when the entire program is known. |
| 681 ASSERT(slot != NULL); | 318 ASSERT(slot != NULL); |
| 682 int index = slot->index(); | 319 int index = slot->index(); |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 721 return Operand(eax); | 358 return Operand(eax); |
| 722 } | 359 } |
| 723 } | 360 } |
| 724 | 361 |
| 725 | 362 |
| 726 // Loads a value on TOS. If it is a boolean value, the result may have been | 363 // Loads a value on TOS. If it is a boolean value, the result may have been |
| 727 // (partially) translated into branches, or it may have set the condition code | 364 // (partially) translated into branches, or it may have set the condition code |
| 728 // register. If force_cc is set, the value is forced to set the condition code | 365 // register. If force_cc is set, the value is forced to set the condition code |
| 729 // register and no value is pushed. If the condition code register was set, | 366 // register and no value is pushed. If the condition code register was set, |
| 730 // has_cc() is true and cc_reg_ contains the condition to test for 'true'. | 367 // has_cc() is true and cc_reg_ contains the condition to test for 'true'. |
| 731 void Ia32CodeGenerator::LoadCondition(Expression* x, | 368 void CodeGenerator::LoadCondition(Expression* x, |
| 732 TypeofState typeof_state, | 369 TypeofState typeof_state, |
| 733 Label* true_target, | 370 Label* true_target, |
| 734 Label* false_target, | 371 Label* false_target, |
| 735 bool force_cc) { | 372 bool force_cc) { |
| 736 ASSERT(!has_cc()); | 373 ASSERT(!has_cc()); |
| 737 | 374 |
| 738 { CodeGenState new_state(this, typeof_state, true_target, false_target); | 375 { CodeGenState new_state(this, typeof_state, true_target, false_target); |
| 739 Visit(x); | 376 Visit(x); |
| 740 } | 377 } |
| 741 if (force_cc && !has_cc()) { | 378 if (force_cc && !has_cc()) { |
| 742 ToBoolean(true_target, false_target); | 379 ToBoolean(true_target, false_target); |
| 743 } | 380 } |
| 744 ASSERT(has_cc() || !force_cc); | 381 ASSERT(has_cc() || !force_cc); |
| 745 } | 382 } |
| 746 | 383 |
| 747 | 384 |
| 748 void Ia32CodeGenerator::Load(Expression* x, TypeofState typeof_state) { | 385 void CodeGenerator::Load(Expression* x, TypeofState typeof_state) { |
| 749 Label true_target; | 386 Label true_target; |
| 750 Label false_target; | 387 Label false_target; |
| 751 LoadCondition(x, typeof_state, &true_target, &false_target, false); | 388 LoadCondition(x, typeof_state, &true_target, &false_target, false); |
| 752 | 389 |
| 753 if (has_cc()) { | 390 if (has_cc()) { |
| 754 // convert cc_reg_ into a bool | 391 // convert cc_reg_ into a bool |
| 755 | 392 |
| 756 Label loaded, materialize_true; | 393 Label loaded, materialize_true; |
| 757 __ j(cc_reg_, &materialize_true); | 394 __ j(cc_reg_, &materialize_true); |
| 758 __ push(Immediate(Factory::false_value())); | 395 __ push(Immediate(Factory::false_value())); |
| (...skipping 25 matching lines...) Expand all Loading... |
| 784 __ bind(&false_target); | 421 __ bind(&false_target); |
| 785 __ push(Immediate(Factory::false_value())); | 422 __ push(Immediate(Factory::false_value())); |
| 786 } | 423 } |
| 787 // everything is loaded at this point | 424 // everything is loaded at this point |
| 788 __ bind(&loaded); | 425 __ bind(&loaded); |
| 789 } | 426 } |
| 790 ASSERT(!has_cc()); | 427 ASSERT(!has_cc()); |
| 791 } | 428 } |
| 792 | 429 |
| 793 | 430 |
| 794 void Ia32CodeGenerator::LoadGlobal() { | 431 void CodeGenerator::LoadGlobal() { |
| 795 __ push(GlobalObject()); | 432 __ push(GlobalObject()); |
| 796 } | 433 } |
| 797 | 434 |
| 798 | 435 |
| 799 // TODO(1241834): Get rid of this function in favor of just using Load, now | 436 // TODO(1241834): Get rid of this function in favor of just using Load, now |
| 800 // that we have the INSIDE_TYPEOF typeof state. => Need to handle global | 437 // that we have the INSIDE_TYPEOF typeof state. => Need to handle global |
| 801 // variables w/o reference errors elsewhere. | 438 // variables w/o reference errors elsewhere. |
| 802 void Ia32CodeGenerator::LoadTypeofExpression(Expression* x) { | 439 void CodeGenerator::LoadTypeofExpression(Expression* x) { |
| 803 Variable* variable = x->AsVariableProxy()->AsVariable(); | 440 Variable* variable = x->AsVariableProxy()->AsVariable(); |
| 804 if (variable != NULL && !variable->is_this() && variable->is_global()) { | 441 if (variable != NULL && !variable->is_this() && variable->is_global()) { |
| 805 // NOTE: This is somewhat nasty. We force the compiler to load | 442 // NOTE: This is somewhat nasty. We force the compiler to load |
| 806 // the variable as if through '<global>.<variable>' to make sure we | 443 // the variable as if through '<global>.<variable>' to make sure we |
| 807 // do not get reference errors. | 444 // do not get reference errors. |
| 808 Slot global(variable, Slot::CONTEXT, Context::GLOBAL_INDEX); | 445 Slot global(variable, Slot::CONTEXT, Context::GLOBAL_INDEX); |
| 809 Literal key(variable->name()); | 446 Literal key(variable->name()); |
| 810 // TODO(1241834): Fetch the position from the variable instead of using | 447 // TODO(1241834): Fetch the position from the variable instead of using |
| 811 // no position. | 448 // no position. |
| 812 Property property(&global, &key, RelocInfo::kNoPosition); | 449 Property property(&global, &key, RelocInfo::kNoPosition); |
| 813 Load(&property); | 450 Load(&property); |
| 814 } else { | 451 } else { |
| 815 Load(x, INSIDE_TYPEOF); | 452 Load(x, INSIDE_TYPEOF); |
| 816 } | 453 } |
| 817 } | 454 } |
| 818 | 455 |
| 819 | 456 |
| 820 Reference::Reference(Ia32CodeGenerator* cgen, Expression* expression) | 457 Reference::Reference(CodeGenerator* cgen, Expression* expression) |
| 821 : cgen_(cgen), expression_(expression), type_(ILLEGAL) { | 458 : cgen_(cgen), expression_(expression), type_(ILLEGAL) { |
| 822 cgen->LoadReference(this); | 459 cgen->LoadReference(this); |
| 823 } | 460 } |
| 824 | 461 |
| 825 | 462 |
| 826 Reference::~Reference() { | 463 Reference::~Reference() { |
| 827 cgen_->UnloadReference(this); | 464 cgen_->UnloadReference(this); |
| 828 } | 465 } |
| 829 | 466 |
| 830 | 467 |
| 831 void Ia32CodeGenerator::LoadReference(Reference* ref) { | 468 void CodeGenerator::LoadReference(Reference* ref) { |
| 832 Comment cmnt(masm_, "[ LoadReference"); | 469 Comment cmnt(masm_, "[ LoadReference"); |
| 833 Expression* e = ref->expression(); | 470 Expression* e = ref->expression(); |
| 834 Property* property = e->AsProperty(); | 471 Property* property = e->AsProperty(); |
| 835 Variable* var = e->AsVariableProxy()->AsVariable(); | 472 Variable* var = e->AsVariableProxy()->AsVariable(); |
| 836 | 473 |
| 837 if (property != NULL) { | 474 if (property != NULL) { |
| 838 // The expression is either a property or a variable proxy that rewrites | 475 // The expression is either a property or a variable proxy that rewrites |
| 839 // to a property. | 476 // to a property. |
| 840 Load(property->obj()); | 477 Load(property->obj()); |
| 841 // We use a named reference if the key is a literal symbol, unless it is | 478 // We use a named reference if the key is a literal symbol, unless it is |
| (...skipping 21 matching lines...) Expand all Loading... |
| 863 ref->set_type(Reference::SLOT); | 500 ref->set_type(Reference::SLOT); |
| 864 } | 501 } |
| 865 } else { | 502 } else { |
| 866 // Anything else is a runtime error. | 503 // Anything else is a runtime error. |
| 867 Load(e); | 504 Load(e); |
| 868 __ CallRuntime(Runtime::kThrowReferenceError, 1); | 505 __ CallRuntime(Runtime::kThrowReferenceError, 1); |
| 869 } | 506 } |
| 870 } | 507 } |
| 871 | 508 |
| 872 | 509 |
| 873 void Ia32CodeGenerator::UnloadReference(Reference* ref) { | 510 void CodeGenerator::UnloadReference(Reference* ref) { |
| 874 // Pop a reference from the stack while preserving TOS. | 511 // Pop a reference from the stack while preserving TOS. |
| 875 Comment cmnt(masm_, "[ UnloadReference"); | 512 Comment cmnt(masm_, "[ UnloadReference"); |
| 876 int size = ref->size(); | 513 int size = ref->size(); |
| 877 if (size <= 0) { | 514 if (size <= 0) { |
| 878 // Do nothing. No popping is necessary. | 515 // Do nothing. No popping is necessary. |
| 879 } else if (size == 1) { | 516 } else if (size == 1) { |
| 880 __ pop(eax); | 517 __ pop(eax); |
| 881 __ mov(TOS, eax); | 518 __ mov(TOS, eax); |
| 882 } else { | 519 } else { |
| 883 __ pop(eax); | 520 __ pop(eax); |
| (...skipping 11 matching lines...) Expand all Loading... |
| 895 | 532 |
| 896 private: | 533 private: |
| 897 Major MajorKey() { return ToBoolean; } | 534 Major MajorKey() { return ToBoolean; } |
| 898 int MinorKey() { return 0; } | 535 int MinorKey() { return 0; } |
| 899 }; | 536 }; |
| 900 | 537 |
| 901 | 538 |
| 902 // ECMA-262, section 9.2, page 30: ToBoolean(). Pop the top of stack and | 539 // ECMA-262, section 9.2, page 30: ToBoolean(). Pop the top of stack and |
| 903 // convert it to a boolean in the condition code register or jump to | 540 // convert it to a boolean in the condition code register or jump to |
| 904 // 'false_target'/'true_target' as appropriate. | 541 // 'false_target'/'true_target' as appropriate. |
| 905 void Ia32CodeGenerator::ToBoolean(Label* true_target, Label* false_target) { | 542 void CodeGenerator::ToBoolean(Label* true_target, Label* false_target) { |
| 906 Comment cmnt(masm_, "[ ToBoolean"); | 543 Comment cmnt(masm_, "[ ToBoolean"); |
| 907 | 544 |
| 908 // The value to convert should be popped from the stack. | 545 // The value to convert should be popped from the stack. |
| 909 __ pop(eax); | 546 __ pop(eax); |
| 910 | 547 |
| 911 // Fast case checks. | 548 // Fast case checks. |
| 912 | 549 |
| 913 // 'false' => false. | 550 // 'false' => false. |
| 914 __ cmp(eax, Factory::false_value()); | 551 __ cmp(eax, Factory::false_value()); |
| 915 __ j(equal, false_target); | 552 __ j(equal, false_target); |
| (...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1006 case Token::BIT_AND: return "GenericBinaryOpStub_BIT_AND"; | 643 case Token::BIT_AND: return "GenericBinaryOpStub_BIT_AND"; |
| 1007 case Token::BIT_XOR: return "GenericBinaryOpStub_BIT_XOR"; | 644 case Token::BIT_XOR: return "GenericBinaryOpStub_BIT_XOR"; |
| 1008 case Token::SAR: return "GenericBinaryOpStub_SAR"; | 645 case Token::SAR: return "GenericBinaryOpStub_SAR"; |
| 1009 case Token::SHL: return "GenericBinaryOpStub_SHL"; | 646 case Token::SHL: return "GenericBinaryOpStub_SHL"; |
| 1010 case Token::SHR: return "GenericBinaryOpStub_SHR"; | 647 case Token::SHR: return "GenericBinaryOpStub_SHR"; |
| 1011 default: return "GenericBinaryOpStub"; | 648 default: return "GenericBinaryOpStub"; |
| 1012 } | 649 } |
| 1013 } | 650 } |
| 1014 | 651 |
| 1015 | 652 |
| 1016 void Ia32CodeGenerator::GenericBinaryOperation(Token::Value op, | 653 void CodeGenerator::GenericBinaryOperation(Token::Value op, |
| 1017 OverwriteMode overwrite_mode) { | 654 OverwriteMode overwrite_mode) { |
| 1018 Comment cmnt(masm_, "[ BinaryOperation"); | 655 Comment cmnt(masm_, "[ BinaryOperation"); |
| 1019 Comment cmnt_token(masm_, Token::String(op)); | 656 Comment cmnt_token(masm_, Token::String(op)); |
| 1020 switch (op) { | 657 switch (op) { |
| 1021 case Token::ADD: | 658 case Token::ADD: |
| 1022 case Token::SUB: | 659 case Token::SUB: |
| 1023 case Token::MUL: | 660 case Token::MUL: |
| 1024 case Token::DIV: | 661 case Token::DIV: |
| 1025 case Token::MOD: { | 662 case Token::MOD: { |
| 1026 GenericBinaryOpStub stub(op, overwrite_mode); | 663 GenericBinaryOpStub stub(op, overwrite_mode); |
| (...skipping 236 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1263 GenericBinaryOpStub igostub(Token::SUB, overwrite_mode_); | 900 GenericBinaryOpStub igostub(Token::SUB, overwrite_mode_); |
| 1264 __ CallStub(&igostub); | 901 __ CallStub(&igostub); |
| 1265 } | 902 } |
| 1266 | 903 |
| 1267 private: | 904 private: |
| 1268 Register tos_reg_; | 905 Register tos_reg_; |
| 1269 OverwriteMode overwrite_mode_; | 906 OverwriteMode overwrite_mode_; |
| 1270 }; | 907 }; |
| 1271 | 908 |
| 1272 | 909 |
| 1273 void Ia32CodeGenerator::SmiOperation(Token::Value op, | 910 void CodeGenerator::SmiOperation(Token::Value op, |
| 1274 Handle<Object> value, | 911 Handle<Object> value, |
| 1275 bool reversed, | 912 bool reversed, |
| 1276 OverwriteMode overwrite_mode) { | 913 OverwriteMode overwrite_mode) { |
| 1277 // NOTE: This is an attempt to inline (a bit) more of the code for | 914 // NOTE: This is an attempt to inline (a bit) more of the code for |
| 1278 // some possible smi operations (like + and -) when (at least) one | 915 // some possible smi operations (like + and -) when (at least) one |
| 1279 // of the operands is a literal smi. With this optimization, the | 916 // of the operands is a literal smi. With this optimization, the |
| 1280 // performance of the system is increased by ~15%, and the generated | 917 // performance of the system is increased by ~15%, and the generated |
| 1281 // code size is increased by ~1% (measured on a combination of | 918 // code size is increased by ~1% (measured on a combination of |
| 1282 // different benchmarks). | 919 // different benchmarks). |
| 1283 | 920 |
| (...skipping 185 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1469 #ifdef DEBUG | 1106 #ifdef DEBUG |
| 1470 void Print() { | 1107 void Print() { |
| 1471 PrintF("CompareStub (cc %d), (strict %s)\n", | 1108 PrintF("CompareStub (cc %d), (strict %s)\n", |
| 1472 static_cast<int>(cc_), | 1109 static_cast<int>(cc_), |
| 1473 strict_ ? "true" : "false"); | 1110 strict_ ? "true" : "false"); |
| 1474 } | 1111 } |
| 1475 #endif | 1112 #endif |
| 1476 }; | 1113 }; |
| 1477 | 1114 |
| 1478 | 1115 |
| 1479 void Ia32CodeGenerator::Comparison(Condition cc, bool strict) { | 1116 void CodeGenerator::Comparison(Condition cc, bool strict) { |
| 1480 // Strict only makes sense for equality comparisons. | 1117 // Strict only makes sense for equality comparisons. |
| 1481 ASSERT(!strict || cc == equal); | 1118 ASSERT(!strict || cc == equal); |
| 1482 | 1119 |
| 1483 // Implement '>' and '<=' by reversal to obtain ECMA-262 conversion order. | 1120 // Implement '>' and '<=' by reversal to obtain ECMA-262 conversion order. |
| 1484 if (cc == greater || cc == less_equal) { | 1121 if (cc == greater || cc == less_equal) { |
| 1485 cc = ReverseCondition(cc); | 1122 cc = ReverseCondition(cc); |
| 1486 __ pop(edx); | 1123 __ pop(edx); |
| 1487 __ pop(eax); | 1124 __ pop(eax); |
| 1488 } else { | 1125 } else { |
| 1489 __ pop(eax); | 1126 __ pop(eax); |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1536 CompareStub stub(cc_, strict_); | 1173 CompareStub stub(cc_, strict_); |
| 1537 // Setup parameters and call stub. | 1174 // Setup parameters and call stub. |
| 1538 __ mov(edx, Operand(eax)); | 1175 __ mov(edx, Operand(eax)); |
| 1539 __ mov(Operand(eax), Immediate(Smi::FromInt(value_))); | 1176 __ mov(Operand(eax), Immediate(Smi::FromInt(value_))); |
| 1540 __ CallStub(&stub); | 1177 __ CallStub(&stub); |
| 1541 __ cmp(eax, 0); | 1178 __ cmp(eax, 0); |
| 1542 // "result" is returned in the flags | 1179 // "result" is returned in the flags |
| 1543 } | 1180 } |
| 1544 | 1181 |
| 1545 | 1182 |
| 1546 void Ia32CodeGenerator::SmiComparison(Condition cc, | 1183 void CodeGenerator::SmiComparison(Condition cc, |
| 1547 Handle<Object> value, | 1184 Handle<Object> value, |
| 1548 bool strict) { | 1185 bool strict) { |
| 1549 // Strict only makes sense for equality comparisons. | 1186 // Strict only makes sense for equality comparisons. |
| 1550 ASSERT(!strict || cc == equal); | 1187 ASSERT(!strict || cc == equal); |
| 1551 | 1188 |
| 1552 int int_value = Smi::cast(*value)->value(); | 1189 int int_value = Smi::cast(*value)->value(); |
| 1553 ASSERT(is_intn(int_value, kMaxSmiInlinedBits)); | 1190 ASSERT(is_intn(int_value, kMaxSmiInlinedBits)); |
| 1554 | 1191 |
| 1555 SmiComparisonDeferred* deferred = | 1192 SmiComparisonDeferred* deferred = |
| 1556 new SmiComparisonDeferred(this, cc, strict, int_value); | 1193 new SmiComparisonDeferred(this, cc, strict, int_value); |
| (...skipping 20 matching lines...) Expand all Loading... |
| 1577 void Print() { PrintF("CallFunctionStub (args %d)\n", argc_); } | 1214 void Print() { PrintF("CallFunctionStub (args %d)\n", argc_); } |
| 1578 #endif | 1215 #endif |
| 1579 | 1216 |
| 1580 Major MajorKey() { return CallFunction; } | 1217 Major MajorKey() { return CallFunction; } |
| 1581 int MinorKey() { return argc_; } | 1218 int MinorKey() { return argc_; } |
| 1582 }; | 1219 }; |
| 1583 | 1220 |
| 1584 | 1221 |
| 1585 // Call the function just below TOS on the stack with the given | 1222 // Call the function just below TOS on the stack with the given |
| 1586 // arguments. The receiver is the TOS. | 1223 // arguments. The receiver is the TOS. |
| 1587 void Ia32CodeGenerator::CallWithArguments(ZoneList<Expression*>* args, | 1224 void CodeGenerator::CallWithArguments(ZoneList<Expression*>* args, |
| 1588 int position) { | 1225 int position) { |
| 1589 // Push the arguments ("left-to-right") on the stack. | 1226 // Push the arguments ("left-to-right") on the stack. |
| 1590 for (int i = 0; i < args->length(); i++) { | 1227 for (int i = 0; i < args->length(); i++) { |
| 1591 Load(args->at(i)); | 1228 Load(args->at(i)); |
| 1592 } | 1229 } |
| 1593 | 1230 |
| 1594 // Record the position for debugging purposes. | 1231 // Record the position for debugging purposes. |
| 1595 __ RecordPosition(position); | 1232 __ RecordPosition(position); |
| 1596 | 1233 |
| 1597 // Use the shared code stub to call the function. | 1234 // Use the shared code stub to call the function. |
| 1598 CallFunctionStub call_function(args->length()); | 1235 CallFunctionStub call_function(args->length()); |
| 1599 __ CallStub(&call_function); | 1236 __ CallStub(&call_function); |
| 1600 | 1237 |
| 1601 // Restore context and pop function from the stack. | 1238 // Restore context and pop function from the stack. |
| 1602 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); | 1239 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); |
| 1603 __ mov(TOS, eax); | 1240 __ mov(TOS, eax); |
| 1604 } | 1241 } |
| 1605 | 1242 |
| 1606 | 1243 |
| 1607 void Ia32CodeGenerator::Branch(bool if_true, Label* L) { | 1244 void CodeGenerator::Branch(bool if_true, Label* L) { |
| 1608 ASSERT(has_cc()); | 1245 ASSERT(has_cc()); |
| 1609 Condition cc = if_true ? cc_reg_ : NegateCondition(cc_reg_); | 1246 Condition cc = if_true ? cc_reg_ : NegateCondition(cc_reg_); |
| 1610 __ j(cc, L); | 1247 __ j(cc, L); |
| 1611 cc_reg_ = no_condition; | 1248 cc_reg_ = no_condition; |
| 1612 } | 1249 } |
| 1613 | 1250 |
| 1614 | 1251 |
| 1615 void Ia32CodeGenerator::CheckStack() { | 1252 void CodeGenerator::CheckStack() { |
| 1616 if (FLAG_check_stack) { | 1253 if (FLAG_check_stack) { |
| 1617 Label stack_is_ok; | 1254 Label stack_is_ok; |
| 1618 StackCheckStub stub; | 1255 StackCheckStub stub; |
| 1619 ExternalReference stack_guard_limit = | 1256 ExternalReference stack_guard_limit = |
| 1620 ExternalReference::address_of_stack_guard_limit(); | 1257 ExternalReference::address_of_stack_guard_limit(); |
| 1621 __ cmp(esp, Operand::StaticVariable(stack_guard_limit)); | 1258 __ cmp(esp, Operand::StaticVariable(stack_guard_limit)); |
| 1622 __ j(above_equal, &stack_is_ok, taken); | 1259 __ j(above_equal, &stack_is_ok, taken); |
| 1623 __ CallStub(&stub); | 1260 __ CallStub(&stub); |
| 1624 __ bind(&stack_is_ok); | 1261 __ bind(&stack_is_ok); |
| 1625 } | 1262 } |
| 1626 } | 1263 } |
| 1627 | 1264 |
| 1628 | 1265 |
| 1629 void Ia32CodeGenerator::VisitBlock(Block* node) { | 1266 void CodeGenerator::VisitBlock(Block* node) { |
| 1630 Comment cmnt(masm_, "[ Block"); | 1267 Comment cmnt(masm_, "[ Block"); |
| 1631 RecordStatementPosition(node); | 1268 RecordStatementPosition(node); |
| 1632 node->set_break_stack_height(break_stack_height_); | 1269 node->set_break_stack_height(break_stack_height_); |
| 1633 VisitStatements(node->statements()); | 1270 VisitStatements(node->statements()); |
| 1634 __ bind(node->break_target()); | 1271 __ bind(node->break_target()); |
| 1635 } | 1272 } |
| 1636 | 1273 |
| 1637 | 1274 |
| 1638 void Ia32CodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) { | 1275 void CodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) { |
| 1639 __ push(Immediate(pairs)); | 1276 __ push(Immediate(pairs)); |
| 1640 __ push(Operand(esi)); | 1277 __ push(Operand(esi)); |
| 1641 __ push(Immediate(Smi::FromInt(is_eval() ? 1 : 0))); | 1278 __ push(Immediate(Smi::FromInt(is_eval() ? 1 : 0))); |
| 1642 __ CallRuntime(Runtime::kDeclareGlobals, 3); | 1279 __ CallRuntime(Runtime::kDeclareGlobals, 3); |
| 1643 // Return value is ignored. | 1280 // Return value is ignored. |
| 1644 } | 1281 } |
| 1645 | 1282 |
| 1646 | 1283 |
| 1647 void Ia32CodeGenerator::VisitDeclaration(Declaration* node) { | 1284 void CodeGenerator::VisitDeclaration(Declaration* node) { |
| 1648 Comment cmnt(masm_, "[ Declaration"); | 1285 Comment cmnt(masm_, "[ Declaration"); |
| 1649 Variable* var = node->proxy()->var(); | 1286 Variable* var = node->proxy()->var(); |
| 1650 ASSERT(var != NULL); // must have been resolved | 1287 ASSERT(var != NULL); // must have been resolved |
| 1651 Slot* slot = var->slot(); | 1288 Slot* slot = var->slot(); |
| 1652 | 1289 |
| 1653 // If it was not possible to allocate the variable at compile time, | 1290 // If it was not possible to allocate the variable at compile time, |
| 1654 // we need to "declare" it at runtime to make sure it actually | 1291 // we need to "declare" it at runtime to make sure it actually |
| 1655 // exists in the local context. | 1292 // exists in the local context. |
| 1656 if (slot != NULL && slot->type() == Slot::LOOKUP) { | 1293 if (slot != NULL && slot->type() == Slot::LOOKUP) { |
| 1657 // Variables with a "LOOKUP" slot were introduced as non-locals | 1294 // Variables with a "LOOKUP" slot were introduced as non-locals |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1698 target.SetValue(NOT_CONST_INIT); | 1335 target.SetValue(NOT_CONST_INIT); |
| 1699 // Get rid of the assigned value (declarations are statements). It's | 1336 // Get rid of the assigned value (declarations are statements). It's |
| 1700 // safe to pop the value lying on top of the reference before unloading | 1337 // safe to pop the value lying on top of the reference before unloading |
| 1701 // the reference itself (which preserves the top of stack) because we | 1338 // the reference itself (which preserves the top of stack) because we |
| 1702 // know that it is a zero-sized reference. | 1339 // know that it is a zero-sized reference. |
| 1703 __ pop(eax); // Pop(no_reg); | 1340 __ pop(eax); // Pop(no_reg); |
| 1704 } | 1341 } |
| 1705 } | 1342 } |
| 1706 | 1343 |
| 1707 | 1344 |
| 1708 void Ia32CodeGenerator::VisitExpressionStatement(ExpressionStatement* node) { | 1345 void CodeGenerator::VisitExpressionStatement(ExpressionStatement* node) { |
| 1709 Comment cmnt(masm_, "[ ExpressionStatement"); | 1346 Comment cmnt(masm_, "[ ExpressionStatement"); |
| 1710 RecordStatementPosition(node); | 1347 RecordStatementPosition(node); |
| 1711 Expression* expression = node->expression(); | 1348 Expression* expression = node->expression(); |
| 1712 expression->MarkAsStatement(); | 1349 expression->MarkAsStatement(); |
| 1713 Load(expression); | 1350 Load(expression); |
| 1714 __ pop(eax); // remove the lingering expression result from the top of stack | 1351 __ pop(eax); // remove the lingering expression result from the top of stack |
| 1715 } | 1352 } |
| 1716 | 1353 |
| 1717 | 1354 |
| 1718 void Ia32CodeGenerator::VisitEmptyStatement(EmptyStatement* node) { | 1355 void CodeGenerator::VisitEmptyStatement(EmptyStatement* node) { |
| 1719 Comment cmnt(masm_, "// EmptyStatement"); | 1356 Comment cmnt(masm_, "// EmptyStatement"); |
| 1720 // nothing to do | 1357 // nothing to do |
| 1721 } | 1358 } |
| 1722 | 1359 |
| 1723 | 1360 |
| 1724 void Ia32CodeGenerator::VisitIfStatement(IfStatement* node) { | 1361 void CodeGenerator::VisitIfStatement(IfStatement* node) { |
| 1725 Comment cmnt(masm_, "[ IfStatement"); | 1362 Comment cmnt(masm_, "[ IfStatement"); |
| 1726 // Generate different code depending on which | 1363 // Generate different code depending on which |
| 1727 // parts of the if statement are present or not. | 1364 // parts of the if statement are present or not. |
| 1728 bool has_then_stm = node->HasThenStatement(); | 1365 bool has_then_stm = node->HasThenStatement(); |
| 1729 bool has_else_stm = node->HasElseStatement(); | 1366 bool has_else_stm = node->HasElseStatement(); |
| 1730 | 1367 |
| 1731 RecordStatementPosition(node); | 1368 RecordStatementPosition(node); |
| 1732 Label exit; | 1369 Label exit; |
| 1733 if (has_then_stm && has_else_stm) { | 1370 if (has_then_stm && has_else_stm) { |
| 1734 Label then; | 1371 Label then; |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1775 // Pop it again, since it is not going to be used. | 1412 // Pop it again, since it is not going to be used. |
| 1776 __ pop(eax); | 1413 __ pop(eax); |
| 1777 } | 1414 } |
| 1778 } | 1415 } |
| 1779 | 1416 |
| 1780 // end | 1417 // end |
| 1781 __ bind(&exit); | 1418 __ bind(&exit); |
| 1782 } | 1419 } |
| 1783 | 1420 |
| 1784 | 1421 |
| 1785 void Ia32CodeGenerator::CleanStack(int num_bytes) { | 1422 void CodeGenerator::CleanStack(int num_bytes) { |
| 1786 ASSERT(num_bytes >= 0); | 1423 ASSERT(num_bytes >= 0); |
| 1787 if (num_bytes > 0) { | 1424 if (num_bytes > 0) { |
| 1788 __ add(Operand(esp), Immediate(num_bytes)); | 1425 __ add(Operand(esp), Immediate(num_bytes)); |
| 1789 } | 1426 } |
| 1790 } | 1427 } |
| 1791 | 1428 |
| 1792 | 1429 |
| 1793 void Ia32CodeGenerator::VisitContinueStatement(ContinueStatement* node) { | 1430 void CodeGenerator::VisitContinueStatement(ContinueStatement* node) { |
| 1794 Comment cmnt(masm_, "[ ContinueStatement"); | 1431 Comment cmnt(masm_, "[ ContinueStatement"); |
| 1795 RecordStatementPosition(node); | 1432 RecordStatementPosition(node); |
| 1796 CleanStack(break_stack_height_ - node->target()->break_stack_height()); | 1433 CleanStack(break_stack_height_ - node->target()->break_stack_height()); |
| 1797 __ jmp(node->target()->continue_target()); | 1434 __ jmp(node->target()->continue_target()); |
| 1798 } | 1435 } |
| 1799 | 1436 |
| 1800 | 1437 |
| 1801 void Ia32CodeGenerator::VisitBreakStatement(BreakStatement* node) { | 1438 void CodeGenerator::VisitBreakStatement(BreakStatement* node) { |
| 1802 Comment cmnt(masm_, "[ BreakStatement"); | 1439 Comment cmnt(masm_, "[ BreakStatement"); |
| 1803 RecordStatementPosition(node); | 1440 RecordStatementPosition(node); |
| 1804 CleanStack(break_stack_height_ - node->target()->break_stack_height()); | 1441 CleanStack(break_stack_height_ - node->target()->break_stack_height()); |
| 1805 __ jmp(node->target()->break_target()); | 1442 __ jmp(node->target()->break_target()); |
| 1806 } | 1443 } |
| 1807 | 1444 |
| 1808 | 1445 |
| 1809 void Ia32CodeGenerator::VisitReturnStatement(ReturnStatement* node) { | 1446 void CodeGenerator::VisitReturnStatement(ReturnStatement* node) { |
| 1810 Comment cmnt(masm_, "[ ReturnStatement"); | 1447 Comment cmnt(masm_, "[ ReturnStatement"); |
| 1811 RecordStatementPosition(node); | 1448 RecordStatementPosition(node); |
| 1812 Load(node->expression()); | 1449 Load(node->expression()); |
| 1813 | 1450 |
| 1814 // Move the function result into eax | 1451 // Move the function result into eax |
| 1815 __ pop(eax); | 1452 __ pop(eax); |
| 1816 | 1453 |
| 1817 // If we're inside a try statement or the return instruction | 1454 // If we're inside a try statement or the return instruction |
| 1818 // sequence has been generated, we just jump to that | 1455 // sequence has been generated, we just jump to that |
| 1819 // point. Otherwise, we generate the return instruction sequence and | 1456 // point. Otherwise, we generate the return instruction sequence and |
| (...skipping 17 matching lines...) Expand all Loading... |
| 1837 __ ret((scope_->num_parameters() + 1) * kPointerSize); | 1474 __ ret((scope_->num_parameters() + 1) * kPointerSize); |
| 1838 | 1475 |
| 1839 // Check that the size of the code used for returning matches what is | 1476 // Check that the size of the code used for returning matches what is |
| 1840 // expected by the debugger. | 1477 // expected by the debugger. |
| 1841 ASSERT_EQ(Debug::kIa32JSReturnSequenceLength, | 1478 ASSERT_EQ(Debug::kIa32JSReturnSequenceLength, |
| 1842 __ SizeOfCodeGeneratedSince(&check_exit_codesize)); | 1479 __ SizeOfCodeGeneratedSince(&check_exit_codesize)); |
| 1843 } | 1480 } |
| 1844 } | 1481 } |
| 1845 | 1482 |
| 1846 | 1483 |
| 1847 void Ia32CodeGenerator::VisitWithEnterStatement(WithEnterStatement* node) { | 1484 void CodeGenerator::VisitWithEnterStatement(WithEnterStatement* node) { |
| 1848 Comment cmnt(masm_, "[ WithEnterStatement"); | 1485 Comment cmnt(masm_, "[ WithEnterStatement"); |
| 1849 RecordStatementPosition(node); | 1486 RecordStatementPosition(node); |
| 1850 Load(node->expression()); | 1487 Load(node->expression()); |
| 1851 __ CallRuntime(Runtime::kPushContext, 1); | 1488 __ CallRuntime(Runtime::kPushContext, 1); |
| 1852 | 1489 |
| 1853 if (kDebug) { | 1490 if (kDebug) { |
| 1854 Label verified_true; | 1491 Label verified_true; |
| 1855 // Verify eax and esi are the same in debug mode | 1492 // Verify eax and esi are the same in debug mode |
| 1856 __ cmp(eax, Operand(esi)); | 1493 __ cmp(eax, Operand(esi)); |
| 1857 __ j(equal, &verified_true); | 1494 __ j(equal, &verified_true); |
| 1858 __ int3(); | 1495 __ int3(); |
| 1859 __ bind(&verified_true); | 1496 __ bind(&verified_true); |
| 1860 } | 1497 } |
| 1861 | 1498 |
| 1862 // Update context local. | 1499 // Update context local. |
| 1863 __ mov(Operand(ebp, StandardFrameConstants::kContextOffset), esi); | 1500 __ mov(Operand(ebp, StandardFrameConstants::kContextOffset), esi); |
| 1864 } | 1501 } |
| 1865 | 1502 |
| 1866 | 1503 |
| 1867 void Ia32CodeGenerator::VisitWithExitStatement(WithExitStatement* node) { | 1504 void CodeGenerator::VisitWithExitStatement(WithExitStatement* node) { |
| 1868 Comment cmnt(masm_, "[ WithExitStatement"); | 1505 Comment cmnt(masm_, "[ WithExitStatement"); |
| 1869 // Pop context. | 1506 // Pop context. |
| 1870 __ mov(esi, ContextOperand(esi, Context::PREVIOUS_INDEX)); | 1507 __ mov(esi, ContextOperand(esi, Context::PREVIOUS_INDEX)); |
| 1871 // Update context local. | 1508 // Update context local. |
| 1872 __ mov(Operand(ebp, StandardFrameConstants::kContextOffset), esi); | 1509 __ mov(Operand(ebp, StandardFrameConstants::kContextOffset), esi); |
| 1873 } | 1510 } |
| 1874 | 1511 |
| 1875 int Ia32CodeGenerator::FastCaseSwitchMaxOverheadFactor() { | 1512 int CodeGenerator::FastCaseSwitchMaxOverheadFactor() { |
| 1876 return kFastSwitchMaxOverheadFactor; | 1513 return kFastSwitchMaxOverheadFactor; |
| 1877 } | 1514 } |
| 1878 | 1515 |
| 1879 int Ia32CodeGenerator::FastCaseSwitchMinCaseCount() { | 1516 int CodeGenerator::FastCaseSwitchMinCaseCount() { |
| 1880 return kFastSwitchMinCaseCount; | 1517 return kFastSwitchMinCaseCount; |
| 1881 } | 1518 } |
| 1882 | 1519 |
| 1883 // Generate a computed jump to a switch case. | 1520 // Generate a computed jump to a switch case. |
| 1884 void Ia32CodeGenerator::GenerateFastCaseSwitchJumpTable( | 1521 void CodeGenerator::GenerateFastCaseSwitchJumpTable( |
| 1885 SwitchStatement* node, int min_index, int range, Label *fail_label, | 1522 SwitchStatement* node, int min_index, int range, Label *fail_label, |
| 1886 SmartPointer<Label*> &case_targets, SmartPointer<Label> &case_labels) { | 1523 SmartPointer<Label*> &case_targets, SmartPointer<Label> &case_labels) { |
| 1887 // Notice: Internal references, used by both the jmp instruction and | 1524 // Notice: Internal references, used by both the jmp instruction and |
| 1888 // the table entries, need to be relocated if the buffer grows. This | 1525 // the table entries, need to be relocated if the buffer grows. This |
| 1889 // prevents the forward use of Labels, since a displacement cannot | 1526 // prevents the forward use of Labels, since a displacement cannot |
| 1890 // survive relocation, and it also cannot safely be distinguished | 1527 // survive relocation, and it also cannot safely be distinguished |
| 1891 // from a real address. Instead we put in zero-values as | 1528 // from a real address. Instead we put in zero-values as |
| 1892 // placeholders, and fill in the addresses after the labels have been | 1529 // placeholders, and fill in the addresses after the labels have been |
| 1893 // bound. | 1530 // bound. |
| 1894 | 1531 |
| (...skipping 25 matching lines...) Expand all Loading... |
| 1920 | 1557 |
| 1921 GenerateFastCaseSwitchCases(node, case_labels); | 1558 GenerateFastCaseSwitchCases(node, case_labels); |
| 1922 | 1559 |
| 1923 for (int i = 0, entry_pos = table_start.pos(); | 1560 for (int i = 0, entry_pos = table_start.pos(); |
| 1924 i < range; i++, entry_pos += sizeof(uint32_t)) { | 1561 i < range; i++, entry_pos += sizeof(uint32_t)) { |
| 1925 __ WriteInternalReference(entry_pos, *case_targets[i]); | 1562 __ WriteInternalReference(entry_pos, *case_targets[i]); |
| 1926 } | 1563 } |
| 1927 } | 1564 } |
| 1928 | 1565 |
| 1929 | 1566 |
| 1930 void Ia32CodeGenerator::VisitSwitchStatement(SwitchStatement* node) { | 1567 void CodeGenerator::VisitSwitchStatement(SwitchStatement* node) { |
| 1931 Comment cmnt(masm_, "[ SwitchStatement"); | 1568 Comment cmnt(masm_, "[ SwitchStatement"); |
| 1932 RecordStatementPosition(node); | 1569 RecordStatementPosition(node); |
| 1933 node->set_break_stack_height(break_stack_height_); | 1570 node->set_break_stack_height(break_stack_height_); |
| 1934 | 1571 |
| 1935 Load(node->tag()); | 1572 Load(node->tag()); |
| 1936 | 1573 |
| 1937 if (TryGenerateFastCaseSwitchStatement(node)) { | 1574 if (TryGenerateFastCaseSwitchStatement(node)) { |
| 1938 return; | 1575 return; |
| 1939 } | 1576 } |
| 1940 | 1577 |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1987 } else { | 1624 } else { |
| 1988 // Remove the switch value from the stack. | 1625 // Remove the switch value from the stack. |
| 1989 __ pop(eax); | 1626 __ pop(eax); |
| 1990 } | 1627 } |
| 1991 | 1628 |
| 1992 __ bind(&fall_through); | 1629 __ bind(&fall_through); |
| 1993 __ bind(node->break_target()); | 1630 __ bind(node->break_target()); |
| 1994 } | 1631 } |
| 1995 | 1632 |
| 1996 | 1633 |
| 1997 void Ia32CodeGenerator::VisitLoopStatement(LoopStatement* node) { | 1634 void CodeGenerator::VisitLoopStatement(LoopStatement* node) { |
| 1998 Comment cmnt(masm_, "[ LoopStatement"); | 1635 Comment cmnt(masm_, "[ LoopStatement"); |
| 1999 RecordStatementPosition(node); | 1636 RecordStatementPosition(node); |
| 2000 node->set_break_stack_height(break_stack_height_); | 1637 node->set_break_stack_height(break_stack_height_); |
| 2001 | 1638 |
| 2002 // simple condition analysis | 1639 // simple condition analysis |
| 2003 enum { ALWAYS_TRUE, ALWAYS_FALSE, DONT_KNOW } info = DONT_KNOW; | 1640 enum { ALWAYS_TRUE, ALWAYS_FALSE, DONT_KNOW } info = DONT_KNOW; |
| 2004 if (node->cond() == NULL) { | 1641 if (node->cond() == NULL) { |
| 2005 ASSERT(node->type() == LoopStatement::FOR_LOOP); | 1642 ASSERT(node->type() == LoopStatement::FOR_LOOP); |
| 2006 info = ALWAYS_TRUE; | 1643 info = ALWAYS_TRUE; |
| 2007 } else { | 1644 } else { |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2056 node->break_target(), true); | 1693 node->break_target(), true); |
| 2057 Branch(true, &loop); | 1694 Branch(true, &loop); |
| 2058 break; | 1695 break; |
| 2059 } | 1696 } |
| 2060 | 1697 |
| 2061 // exit | 1698 // exit |
| 2062 __ bind(node->break_target()); | 1699 __ bind(node->break_target()); |
| 2063 } | 1700 } |
| 2064 | 1701 |
| 2065 | 1702 |
| 2066 void Ia32CodeGenerator::VisitForInStatement(ForInStatement* node) { | 1703 void CodeGenerator::VisitForInStatement(ForInStatement* node) { |
| 2067 Comment cmnt(masm_, "[ ForInStatement"); | 1704 Comment cmnt(masm_, "[ ForInStatement"); |
| 2068 RecordStatementPosition(node); | 1705 RecordStatementPosition(node); |
| 2069 | 1706 |
| 2070 // We keep stuff on the stack while the body is executing. | 1707 // We keep stuff on the stack while the body is executing. |
| 2071 // Record it, so that a break/continue crossing this statement | 1708 // Record it, so that a break/continue crossing this statement |
| 2072 // can restore the stack. | 1709 // can restore the stack. |
| 2073 const int kForInStackSize = 5 * kPointerSize; | 1710 const int kForInStackSize = 5 * kPointerSize; |
| 2074 break_stack_height_ += kForInStackSize; | 1711 break_stack_height_ += kForInStackSize; |
| 2075 node->set_break_stack_height(break_stack_height_); | 1712 node->set_break_stack_height(break_stack_height_); |
| 2076 | 1713 |
| (...skipping 167 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2244 __ bind(node->break_target()); | 1881 __ bind(node->break_target()); |
| 2245 __ add(Operand(esp), Immediate(5 * kPointerSize)); | 1882 __ add(Operand(esp), Immediate(5 * kPointerSize)); |
| 2246 | 1883 |
| 2247 // Exit. | 1884 // Exit. |
| 2248 __ bind(&exit); | 1885 __ bind(&exit); |
| 2249 | 1886 |
| 2250 break_stack_height_ -= kForInStackSize; | 1887 break_stack_height_ -= kForInStackSize; |
| 2251 } | 1888 } |
| 2252 | 1889 |
| 2253 | 1890 |
| 2254 void Ia32CodeGenerator::VisitTryCatch(TryCatch* node) { | 1891 void CodeGenerator::VisitTryCatch(TryCatch* node) { |
| 2255 Comment cmnt(masm_, "[ TryCatch"); | 1892 Comment cmnt(masm_, "[ TryCatch"); |
| 2256 | 1893 |
| 2257 Label try_block, exit; | 1894 Label try_block, exit; |
| 2258 | 1895 |
| 2259 __ call(&try_block); | 1896 __ call(&try_block); |
| 2260 // --- Catch block --- | 1897 // --- Catch block --- |
| 2261 __ push(eax); | 1898 __ push(eax); |
| 2262 | 1899 |
| 2263 // Store the caught exception in the catch variable. | 1900 // Store the caught exception in the catch variable. |
| 2264 { Reference ref(this, node->catch_var()); | 1901 { Reference ref(this, node->catch_var()); |
| (...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2343 Immediate(StackHandlerConstants::kSize - kPointerSize)); | 1980 Immediate(StackHandlerConstants::kSize - kPointerSize)); |
| 2344 // next_sp popped. | 1981 // next_sp popped. |
| 2345 __ jmp(shadows[i]->shadowed()); | 1982 __ jmp(shadows[i]->shadowed()); |
| 2346 } | 1983 } |
| 2347 } | 1984 } |
| 2348 | 1985 |
| 2349 __ bind(&exit); | 1986 __ bind(&exit); |
| 2350 } | 1987 } |
| 2351 | 1988 |
| 2352 | 1989 |
| 2353 void Ia32CodeGenerator::VisitTryFinally(TryFinally* node) { | 1990 void CodeGenerator::VisitTryFinally(TryFinally* node) { |
| 2354 Comment cmnt(masm_, "[ TryFinally"); | 1991 Comment cmnt(masm_, "[ TryFinally"); |
| 2355 | 1992 |
| 2356 // State: Used to keep track of reason for entering the finally | 1993 // State: Used to keep track of reason for entering the finally |
| 2357 // block. Should probably be extended to hold information for | 1994 // block. Should probably be extended to hold information for |
| 2358 // break/continue from within the try block. | 1995 // break/continue from within the try block. |
| 2359 enum { FALLING, THROWING, JUMPING }; | 1996 enum { FALLING, THROWING, JUMPING }; |
| 2360 | 1997 |
| 2361 Label exit, unlink, try_block, finally_block; | 1998 Label exit, unlink, try_block, finally_block; |
| 2362 | 1999 |
| 2363 __ call(&try_block); | 2000 __ call(&try_block); |
| (...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2472 | 2109 |
| 2473 // Rethrow exception. | 2110 // Rethrow exception. |
| 2474 __ push(eax); // undo pop from above | 2111 __ push(eax); // undo pop from above |
| 2475 __ CallRuntime(Runtime::kReThrow, 1); | 2112 __ CallRuntime(Runtime::kReThrow, 1); |
| 2476 | 2113 |
| 2477 // Done. | 2114 // Done. |
| 2478 __ bind(&exit); | 2115 __ bind(&exit); |
| 2479 } | 2116 } |
| 2480 | 2117 |
| 2481 | 2118 |
| 2482 void Ia32CodeGenerator::VisitDebuggerStatement(DebuggerStatement* node) { | 2119 void CodeGenerator::VisitDebuggerStatement(DebuggerStatement* node) { |
| 2483 Comment cmnt(masm_, "[ DebuggerStatement"); | 2120 Comment cmnt(masm_, "[ DebuggerStatement"); |
| 2484 RecordStatementPosition(node); | 2121 RecordStatementPosition(node); |
| 2485 __ CallRuntime(Runtime::kDebugBreak, 1); | 2122 __ CallRuntime(Runtime::kDebugBreak, 1); |
| 2486 __ push(eax); | 2123 __ push(eax); |
| 2487 } | 2124 } |
| 2488 | 2125 |
| 2489 | 2126 |
| 2490 void Ia32CodeGenerator::InstantiateBoilerplate(Handle<JSFunction> boilerplate) { | 2127 void CodeGenerator::InstantiateBoilerplate(Handle<JSFunction> boilerplate) { |
| 2491 ASSERT(boilerplate->IsBoilerplate()); | 2128 ASSERT(boilerplate->IsBoilerplate()); |
| 2492 | 2129 |
| 2493 // Push the boilerplate on the stack. | 2130 // Push the boilerplate on the stack. |
| 2494 __ push(Immediate(boilerplate)); | 2131 __ push(Immediate(boilerplate)); |
| 2495 | 2132 |
| 2496 // Create a new closure. | 2133 // Create a new closure. |
| 2497 __ push(esi); | 2134 __ push(esi); |
| 2498 __ CallRuntime(Runtime::kNewClosure, 2); | 2135 __ CallRuntime(Runtime::kNewClosure, 2); |
| 2499 __ push(eax); | 2136 __ push(eax); |
| 2500 } | 2137 } |
| 2501 | 2138 |
| 2502 | 2139 |
| 2503 void Ia32CodeGenerator::VisitFunctionLiteral(FunctionLiteral* node) { | 2140 void CodeGenerator::VisitFunctionLiteral(FunctionLiteral* node) { |
| 2504 Comment cmnt(masm_, "[ FunctionLiteral"); | 2141 Comment cmnt(masm_, "[ FunctionLiteral"); |
| 2505 | 2142 |
| 2506 // Build the function boilerplate and instantiate it. | 2143 // Build the function boilerplate and instantiate it. |
| 2507 Handle<JSFunction> boilerplate = BuildBoilerplate(node); | 2144 Handle<JSFunction> boilerplate = BuildBoilerplate(node); |
| 2508 // Check for stack-overflow exception. | 2145 // Check for stack-overflow exception. |
| 2509 if (HasStackOverflow()) return; | 2146 if (HasStackOverflow()) return; |
| 2510 InstantiateBoilerplate(boilerplate); | 2147 InstantiateBoilerplate(boilerplate); |
| 2511 } | 2148 } |
| 2512 | 2149 |
| 2513 | 2150 |
| 2514 void Ia32CodeGenerator::VisitFunctionBoilerplateLiteral( | 2151 void CodeGenerator::VisitFunctionBoilerplateLiteral( |
| 2515 FunctionBoilerplateLiteral* node) { | 2152 FunctionBoilerplateLiteral* node) { |
| 2516 Comment cmnt(masm_, "[ FunctionBoilerplateLiteral"); | 2153 Comment cmnt(masm_, "[ FunctionBoilerplateLiteral"); |
| 2517 InstantiateBoilerplate(node->boilerplate()); | 2154 InstantiateBoilerplate(node->boilerplate()); |
| 2518 } | 2155 } |
| 2519 | 2156 |
| 2520 | 2157 |
| 2521 void Ia32CodeGenerator::VisitConditional(Conditional* node) { | 2158 void CodeGenerator::VisitConditional(Conditional* node) { |
| 2522 Comment cmnt(masm_, "[ Conditional"); | 2159 Comment cmnt(masm_, "[ Conditional"); |
| 2523 Label then, else_, exit; | 2160 Label then, else_, exit; |
| 2524 LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &then, &else_, true); | 2161 LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &then, &else_, true); |
| 2525 Branch(false, &else_); | 2162 Branch(false, &else_); |
| 2526 __ bind(&then); | 2163 __ bind(&then); |
| 2527 Load(node->then_expression(), typeof_state()); | 2164 Load(node->then_expression(), typeof_state()); |
| 2528 __ jmp(&exit); | 2165 __ jmp(&exit); |
| 2529 __ bind(&else_); | 2166 __ bind(&else_); |
| 2530 Load(node->else_expression(), typeof_state()); | 2167 Load(node->else_expression(), typeof_state()); |
| 2531 __ bind(&exit); | 2168 __ bind(&exit); |
| 2532 } | 2169 } |
| 2533 | 2170 |
| 2534 | 2171 |
| 2535 void Ia32CodeGenerator::LoadFromSlot(Slot* slot, TypeofState typeof_state) { | 2172 void CodeGenerator::LoadFromSlot(Slot* slot, TypeofState typeof_state) { |
| 2536 if (slot->type() == Slot::LOOKUP) { | 2173 if (slot->type() == Slot::LOOKUP) { |
| 2537 ASSERT(slot->var()->mode() == Variable::DYNAMIC); | 2174 ASSERT(slot->var()->mode() == Variable::DYNAMIC); |
| 2538 | 2175 |
| 2539 // For now, just do a runtime call. | 2176 // For now, just do a runtime call. |
| 2540 __ push(esi); | 2177 __ push(esi); |
| 2541 __ push(Immediate(slot->var()->name())); | 2178 __ push(Immediate(slot->var()->name())); |
| 2542 | 2179 |
| 2543 if (typeof_state == INSIDE_TYPEOF) { | 2180 if (typeof_state == INSIDE_TYPEOF) { |
| 2544 __ CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2); | 2181 __ CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2); |
| 2545 } else { | 2182 } else { |
| (...skipping 17 matching lines...) Expand all Loading... |
| 2563 __ mov(eax, Factory::undefined_value()); | 2200 __ mov(eax, Factory::undefined_value()); |
| 2564 __ bind(&exit); | 2201 __ bind(&exit); |
| 2565 __ push(eax); | 2202 __ push(eax); |
| 2566 } else { | 2203 } else { |
| 2567 __ push(SlotOperand(slot, ecx)); | 2204 __ push(SlotOperand(slot, ecx)); |
| 2568 } | 2205 } |
| 2569 } | 2206 } |
| 2570 } | 2207 } |
| 2571 | 2208 |
| 2572 | 2209 |
| 2573 void Ia32CodeGenerator::VisitSlot(Slot* node) { | 2210 void CodeGenerator::VisitSlot(Slot* node) { |
| 2574 Comment cmnt(masm_, "[ Slot"); | 2211 Comment cmnt(masm_, "[ Slot"); |
| 2575 LoadFromSlot(node, typeof_state()); | 2212 LoadFromSlot(node, typeof_state()); |
| 2576 } | 2213 } |
| 2577 | 2214 |
| 2578 | 2215 |
| 2579 void Ia32CodeGenerator::VisitVariableProxy(VariableProxy* node) { | 2216 void CodeGenerator::VisitVariableProxy(VariableProxy* node) { |
| 2580 Comment cmnt(masm_, "[ VariableProxy"); | 2217 Comment cmnt(masm_, "[ VariableProxy"); |
| 2581 Variable* var = node->var(); | 2218 Variable* var = node->var(); |
| 2582 Expression* expr = var->rewrite(); | 2219 Expression* expr = var->rewrite(); |
| 2583 if (expr != NULL) { | 2220 if (expr != NULL) { |
| 2584 Visit(expr); | 2221 Visit(expr); |
| 2585 } else { | 2222 } else { |
| 2586 ASSERT(var->is_global()); | 2223 ASSERT(var->is_global()); |
| 2587 Reference ref(this, node); | 2224 Reference ref(this, node); |
| 2588 ref.GetValue(typeof_state()); | 2225 ref.GetValue(typeof_state()); |
| 2589 } | 2226 } |
| 2590 } | 2227 } |
| 2591 | 2228 |
| 2592 | 2229 |
| 2593 void Ia32CodeGenerator::VisitLiteral(Literal* node) { | 2230 void CodeGenerator::VisitLiteral(Literal* node) { |
| 2594 Comment cmnt(masm_, "[ Literal"); | 2231 Comment cmnt(masm_, "[ Literal"); |
| 2595 if (node->handle()->IsSmi() && !IsInlineSmi(node)) { | 2232 if (node->handle()->IsSmi() && !IsInlineSmi(node)) { |
| 2596 // To prevent long attacker-controlled byte sequences in code, larger | 2233 // To prevent long attacker-controlled byte sequences in code, larger |
| 2597 // Smis are loaded in two steps. | 2234 // Smis are loaded in two steps. |
| 2598 int bits = reinterpret_cast<int>(*node->handle()); | 2235 int bits = reinterpret_cast<int>(*node->handle()); |
| 2599 __ mov(eax, bits & 0x0000FFFF); | 2236 __ mov(eax, bits & 0x0000FFFF); |
| 2600 __ xor_(eax, bits & 0xFFFF0000); | 2237 __ xor_(eax, bits & 0xFFFF0000); |
| 2601 __ push(eax); | 2238 __ push(eax); |
| 2602 } else { | 2239 } else { |
| 2603 __ push(Immediate(node->handle())); | 2240 __ push(Immediate(node->handle())); |
| (...skipping 23 matching lines...) Expand all Loading... |
| 2627 __ push(Immediate(Smi::FromInt(node_->literal_index()))); | 2264 __ push(Immediate(Smi::FromInt(node_->literal_index()))); |
| 2628 // RegExp pattern (2). | 2265 // RegExp pattern (2). |
| 2629 __ push(Immediate(node_->pattern())); | 2266 __ push(Immediate(node_->pattern())); |
| 2630 // RegExp flags (3). | 2267 // RegExp flags (3). |
| 2631 __ push(Immediate(node_->flags())); | 2268 __ push(Immediate(node_->flags())); |
| 2632 __ CallRuntime(Runtime::kMaterializeRegExpLiteral, 4); | 2269 __ CallRuntime(Runtime::kMaterializeRegExpLiteral, 4); |
| 2633 __ mov(ebx, Operand(eax)); // "caller" expects result in ebx | 2270 __ mov(ebx, Operand(eax)); // "caller" expects result in ebx |
| 2634 } | 2271 } |
| 2635 | 2272 |
| 2636 | 2273 |
| 2637 void Ia32CodeGenerator::VisitRegExpLiteral(RegExpLiteral* node) { | 2274 void CodeGenerator::VisitRegExpLiteral(RegExpLiteral* node) { |
| 2638 Comment cmnt(masm_, "[ RegExp Literal"); | 2275 Comment cmnt(masm_, "[ RegExp Literal"); |
| 2639 RegExpDeferred* deferred = new RegExpDeferred(this, node); | 2276 RegExpDeferred* deferred = new RegExpDeferred(this, node); |
| 2640 | 2277 |
| 2641 // Retrieve the literal array and check the allocated entry. | 2278 // Retrieve the literal array and check the allocated entry. |
| 2642 | 2279 |
| 2643 // Load the function of this activation. | 2280 // Load the function of this activation. |
| 2644 __ mov(ecx, FunctionOperand()); | 2281 __ mov(ecx, FunctionOperand()); |
| 2645 | 2282 |
| 2646 // Load the literals array of the function. | 2283 // Load the literals array of the function. |
| 2647 __ mov(ecx, FieldOperand(ecx, JSFunction::kLiteralsOffset)); | 2284 __ mov(ecx, FieldOperand(ecx, JSFunction::kLiteralsOffset)); |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2687 __ push(Operand(ecx)); | 2324 __ push(Operand(ecx)); |
| 2688 // Literal index (1). | 2325 // Literal index (1). |
| 2689 __ push(Immediate(Smi::FromInt(node_->literal_index()))); | 2326 __ push(Immediate(Smi::FromInt(node_->literal_index()))); |
| 2690 // Constant properties (2). | 2327 // Constant properties (2). |
| 2691 __ push(Immediate(node_->constant_properties())); | 2328 __ push(Immediate(node_->constant_properties())); |
| 2692 __ CallRuntime(Runtime::kCreateObjectLiteralBoilerplate, 3); | 2329 __ CallRuntime(Runtime::kCreateObjectLiteralBoilerplate, 3); |
| 2693 __ mov(ebx, Operand(eax)); | 2330 __ mov(ebx, Operand(eax)); |
| 2694 } | 2331 } |
| 2695 | 2332 |
| 2696 | 2333 |
| 2697 void Ia32CodeGenerator::VisitObjectLiteral(ObjectLiteral* node) { | 2334 void CodeGenerator::VisitObjectLiteral(ObjectLiteral* node) { |
| 2698 Comment cmnt(masm_, "[ ObjectLiteral"); | 2335 Comment cmnt(masm_, "[ ObjectLiteral"); |
| 2699 ObjectLiteralDeferred* deferred = new ObjectLiteralDeferred(this, node); | 2336 ObjectLiteralDeferred* deferred = new ObjectLiteralDeferred(this, node); |
| 2700 | 2337 |
| 2701 // Retrieve the literal array and check the allocated entry. | 2338 // Retrieve the literal array and check the allocated entry. |
| 2702 | 2339 |
| 2703 // Load the function of this activation. | 2340 // Load the function of this activation. |
| 2704 __ mov(ecx, FunctionOperand()); | 2341 __ mov(ecx, FunctionOperand()); |
| 2705 | 2342 |
| 2706 // Load the literals array of the function. | 2343 // Load the literals array of the function. |
| 2707 __ mov(ecx, FieldOperand(ecx, JSFunction::kLiteralsOffset)); | 2344 __ mov(ecx, FieldOperand(ecx, JSFunction::kLiteralsOffset)); |
| (...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2777 __ CallRuntime(Runtime::kDefineAccessor, 4); | 2414 __ CallRuntime(Runtime::kDefineAccessor, 4); |
| 2778 // Ignore result. | 2415 // Ignore result. |
| 2779 break; | 2416 break; |
| 2780 } | 2417 } |
| 2781 default: UNREACHABLE(); | 2418 default: UNREACHABLE(); |
| 2782 } | 2419 } |
| 2783 } | 2420 } |
| 2784 } | 2421 } |
| 2785 | 2422 |
| 2786 | 2423 |
| 2787 void Ia32CodeGenerator::VisitArrayLiteral(ArrayLiteral* node) { | 2424 void CodeGenerator::VisitArrayLiteral(ArrayLiteral* node) { |
| 2788 Comment cmnt(masm_, "[ ArrayLiteral"); | 2425 Comment cmnt(masm_, "[ ArrayLiteral"); |
| 2789 | 2426 |
| 2790 // Call runtime to create the array literal. | 2427 // Call runtime to create the array literal. |
| 2791 __ push(Immediate(node->literals())); | 2428 __ push(Immediate(node->literals())); |
| 2792 // Load the function of this frame. | 2429 // Load the function of this frame. |
| 2793 __ mov(ecx, FunctionOperand()); | 2430 __ mov(ecx, FunctionOperand()); |
| 2794 // Load the literals array of the function. | 2431 // Load the literals array of the function. |
| 2795 __ mov(ecx, FieldOperand(ecx, JSFunction::kLiteralsOffset)); | 2432 __ mov(ecx, FieldOperand(ecx, JSFunction::kLiteralsOffset)); |
| 2796 __ push(ecx); | 2433 __ push(ecx); |
| 2797 __ CallRuntime(Runtime::kCreateArrayLiteral, 2); | 2434 __ CallRuntime(Runtime::kCreateArrayLiteral, 2); |
| (...skipping 23 matching lines...) Expand all Loading... |
| 2821 int offset = i * kPointerSize + Array::kHeaderSize; | 2458 int offset = i * kPointerSize + Array::kHeaderSize; |
| 2822 __ mov(FieldOperand(ecx, offset), eax); | 2459 __ mov(FieldOperand(ecx, offset), eax); |
| 2823 | 2460 |
| 2824 // Update the write barrier for the array address. | 2461 // Update the write barrier for the array address. |
| 2825 __ RecordWrite(ecx, offset, eax, ebx); | 2462 __ RecordWrite(ecx, offset, eax, ebx); |
| 2826 } | 2463 } |
| 2827 } | 2464 } |
| 2828 } | 2465 } |
| 2829 | 2466 |
| 2830 | 2467 |
| 2831 bool Ia32CodeGenerator::IsInlineSmi(Literal* literal) { | 2468 bool CodeGenerator::IsInlineSmi(Literal* literal) { |
| 2832 if (literal == NULL || !literal->handle()->IsSmi()) return false; | 2469 if (literal == NULL || !literal->handle()->IsSmi()) return false; |
| 2833 int int_value = Smi::cast(*literal->handle())->value(); | 2470 int int_value = Smi::cast(*literal->handle())->value(); |
| 2834 return is_intn(int_value, kMaxSmiInlinedBits); | 2471 return is_intn(int_value, kMaxSmiInlinedBits); |
| 2835 } | 2472 } |
| 2836 | 2473 |
| 2837 | 2474 |
| 2838 void Ia32CodeGenerator::VisitAssignment(Assignment* node) { | 2475 void CodeGenerator::VisitAssignment(Assignment* node) { |
| 2839 Comment cmnt(masm_, "[ Assignment"); | 2476 Comment cmnt(masm_, "[ Assignment"); |
| 2840 | 2477 |
| 2841 RecordStatementPosition(node); | 2478 RecordStatementPosition(node); |
| 2842 Reference target(this, node->target()); | 2479 Reference target(this, node->target()); |
| 2843 if (target.is_illegal()) return; | 2480 if (target.is_illegal()) return; |
| 2844 | 2481 |
| 2845 if (node->op() == Token::ASSIGN || | 2482 if (node->op() == Token::ASSIGN || |
| 2846 node->op() == Token::INIT_VAR || | 2483 node->op() == Token::INIT_VAR || |
| 2847 node->op() == Token::INIT_CONST) { | 2484 node->op() == Token::INIT_CONST) { |
| 2848 Load(node->value()); | 2485 Load(node->value()); |
| (...skipping 21 matching lines...) Expand all Loading... |
| 2870 // and initialize the actual constant declared. Dynamic variable | 2507 // and initialize the actual constant declared. Dynamic variable |
| 2871 // initializations are simply assignments and use SetValue. | 2508 // initializations are simply assignments and use SetValue. |
| 2872 target.SetValue(CONST_INIT); | 2509 target.SetValue(CONST_INIT); |
| 2873 } else { | 2510 } else { |
| 2874 target.SetValue(NOT_CONST_INIT); | 2511 target.SetValue(NOT_CONST_INIT); |
| 2875 } | 2512 } |
| 2876 } | 2513 } |
| 2877 } | 2514 } |
| 2878 | 2515 |
| 2879 | 2516 |
| 2880 void Ia32CodeGenerator::VisitThrow(Throw* node) { | 2517 void CodeGenerator::VisitThrow(Throw* node) { |
| 2881 Comment cmnt(masm_, "[ Throw"); | 2518 Comment cmnt(masm_, "[ Throw"); |
| 2882 | 2519 |
| 2883 Load(node->exception()); | 2520 Load(node->exception()); |
| 2884 __ RecordPosition(node->position()); | 2521 __ RecordPosition(node->position()); |
| 2885 __ CallRuntime(Runtime::kThrow, 1); | 2522 __ CallRuntime(Runtime::kThrow, 1); |
| 2886 __ push(eax); | 2523 __ push(eax); |
| 2887 } | 2524 } |
| 2888 | 2525 |
| 2889 | 2526 |
| 2890 void Ia32CodeGenerator::VisitProperty(Property* node) { | 2527 void CodeGenerator::VisitProperty(Property* node) { |
| 2891 Comment cmnt(masm_, "[ Property"); | 2528 Comment cmnt(masm_, "[ Property"); |
| 2529 |
| 2892 Reference property(this, node); | 2530 Reference property(this, node); |
| 2893 property.GetValue(typeof_state()); | 2531 property.GetValue(typeof_state()); |
| 2894 } | 2532 } |
| 2895 | 2533 |
| 2896 | 2534 |
| 2897 void Ia32CodeGenerator::VisitCall(Call* node) { | 2535 void CodeGenerator::VisitCall(Call* node) { |
| 2898 Comment cmnt(masm_, "[ Call"); | 2536 Comment cmnt(masm_, "[ Call"); |
| 2899 | 2537 |
| 2900 ZoneList<Expression*>* args = node->arguments(); | 2538 ZoneList<Expression*>* args = node->arguments(); |
| 2901 | 2539 |
| 2902 RecordStatementPosition(node); | 2540 RecordStatementPosition(node); |
| 2903 | 2541 |
| 2904 // Check if the function is a variable or a property. | 2542 // Check if the function is a variable or a property. |
| 2905 Expression* function = node->expression(); | 2543 Expression* function = node->expression(); |
| 2906 Variable* var = function->AsVariableProxy()->AsVariable(); | 2544 Variable* var = function->AsVariableProxy()->AsVariable(); |
| 2907 Property* property = function->AsProperty(); | 2545 Property* property = function->AsProperty(); |
| (...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3009 | 2647 |
| 3010 // Pass the global object as the receiver. | 2648 // Pass the global object as the receiver. |
| 3011 LoadGlobal(); | 2649 LoadGlobal(); |
| 3012 | 2650 |
| 3013 // Call the function. | 2651 // Call the function. |
| 3014 CallWithArguments(args, node->position()); | 2652 CallWithArguments(args, node->position()); |
| 3015 } | 2653 } |
| 3016 } | 2654 } |
| 3017 | 2655 |
| 3018 | 2656 |
| 3019 void Ia32CodeGenerator::VisitCallNew(CallNew* node) { | 2657 void CodeGenerator::VisitCallNew(CallNew* node) { |
| 3020 Comment cmnt(masm_, "[ CallNew"); | 2658 Comment cmnt(masm_, "[ CallNew"); |
| 3021 | 2659 |
| 3022 // According to ECMA-262, section 11.2.2, page 44, the function | 2660 // According to ECMA-262, section 11.2.2, page 44, the function |
| 3023 // expression in new calls must be evaluated before the | 2661 // expression in new calls must be evaluated before the |
| 3024 // arguments. This is different from ordinary calls, where the | 2662 // arguments. This is different from ordinary calls, where the |
| 3025 // actual function to call is resolved after the arguments have been | 2663 // actual function to call is resolved after the arguments have been |
| 3026 // evaluated. | 2664 // evaluated. |
| 3027 | 2665 |
| 3028 // Compute function to call and use the global object as the | 2666 // Compute function to call and use the global object as the |
| 3029 // receiver. | 2667 // receiver. |
| (...skipping 15 matching lines...) Expand all Loading... |
| 3045 | 2683 |
| 3046 // Call the construct call builtin that handles allocation and | 2684 // Call the construct call builtin that handles allocation and |
| 3047 // constructor invocation. | 2685 // constructor invocation. |
| 3048 __ RecordPosition(node->position()); | 2686 __ RecordPosition(node->position()); |
| 3049 __ call(Handle<Code>(Builtins::builtin(Builtins::JSConstructCall)), | 2687 __ call(Handle<Code>(Builtins::builtin(Builtins::JSConstructCall)), |
| 3050 RelocInfo::CONSTRUCT_CALL); | 2688 RelocInfo::CONSTRUCT_CALL); |
| 3051 __ mov(TOS, eax); // discard the function and "push" the newly created object | 2689 __ mov(TOS, eax); // discard the function and "push" the newly created object |
| 3052 } | 2690 } |
| 3053 | 2691 |
| 3054 | 2692 |
| 3055 void Ia32CodeGenerator::GenerateIsSmi(ZoneList<Expression*>* args) { | 2693 void CodeGenerator::GenerateIsSmi(ZoneList<Expression*>* args) { |
| 3056 ASSERT(args->length() == 1); | 2694 ASSERT(args->length() == 1); |
| 3057 Load(args->at(0)); | 2695 Load(args->at(0)); |
| 3058 __ pop(eax); | 2696 __ pop(eax); |
| 3059 __ test(eax, Immediate(kSmiTagMask)); | 2697 __ test(eax, Immediate(kSmiTagMask)); |
| 3060 cc_reg_ = zero; | 2698 cc_reg_ = zero; |
| 3061 } | 2699 } |
| 3062 | 2700 |
| 3063 | 2701 |
| 3064 void Ia32CodeGenerator::GenerateIsNonNegativeSmi(ZoneList<Expression*>* args) { | 2702 void CodeGenerator::GenerateIsNonNegativeSmi(ZoneList<Expression*>* args) { |
| 3065 ASSERT(args->length() == 1); | 2703 ASSERT(args->length() == 1); |
| 3066 Load(args->at(0)); | 2704 Load(args->at(0)); |
| 3067 __ pop(eax); | 2705 __ pop(eax); |
| 3068 __ test(eax, Immediate(kSmiTagMask | 0x80000000)); | 2706 __ test(eax, Immediate(kSmiTagMask | 0x80000000)); |
| 3069 cc_reg_ = zero; | 2707 cc_reg_ = zero; |
| 3070 } | 2708 } |
| 3071 | 2709 |
| 3072 | 2710 |
| 3073 // This generates code that performs a charCodeAt() call or returns | 2711 // This generates code that performs a charCodeAt() call or returns |
| 3074 // undefined in order to trigger the slow case, Runtime_StringCharCodeAt. | 2712 // undefined in order to trigger the slow case, Runtime_StringCharCodeAt. |
| 3075 // It can handle flat and sliced strings, 8 and 16 bit characters and | 2713 // It can handle flat and sliced strings, 8 and 16 bit characters and |
| 3076 // cons strings where the answer is found in the left hand branch of the | 2714 // cons strings where the answer is found in the left hand branch of the |
| 3077 // cons. The slow case will flatten the string, which will ensure that | 2715 // cons. The slow case will flatten the string, which will ensure that |
| 3078 // the answer is in the left hand side the next time around. | 2716 // the answer is in the left hand side the next time around. |
| 3079 void Ia32CodeGenerator::GenerateFastCharCodeAt(ZoneList<Expression*>* args) { | 2717 void CodeGenerator::GenerateFastCharCodeAt(ZoneList<Expression*>* args) { |
| 3080 ASSERT(args->length() == 2); | 2718 ASSERT(args->length() == 2); |
| 3081 | 2719 |
| 3082 Label slow_case; | 2720 Label slow_case; |
| 3083 Label end; | 2721 Label end; |
| 3084 Label not_a_flat_string; | 2722 Label not_a_flat_string; |
| 3085 Label not_a_cons_string_either; | 2723 Label not_a_cons_string_either; |
| 3086 Label try_again_with_new_string; | 2724 Label try_again_with_new_string; |
| 3087 Label ascii_string; | 2725 Label ascii_string; |
| 3088 Label got_char_code; | 2726 Label got_char_code; |
| 3089 | 2727 |
| (...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3195 __ mov(eax, FieldOperand(eax, SlicedString::kBufferOffset)); | 2833 __ mov(eax, FieldOperand(eax, SlicedString::kBufferOffset)); |
| 3196 __ jmp(&try_again_with_new_string); | 2834 __ jmp(&try_again_with_new_string); |
| 3197 | 2835 |
| 3198 __ bind(&slow_case); | 2836 __ bind(&slow_case); |
| 3199 __ push(Immediate(Factory::undefined_value())); | 2837 __ push(Immediate(Factory::undefined_value())); |
| 3200 | 2838 |
| 3201 __ bind(&end); | 2839 __ bind(&end); |
| 3202 } | 2840 } |
| 3203 | 2841 |
| 3204 | 2842 |
| 3205 void Ia32CodeGenerator::GenerateIsArray(ZoneList<Expression*>* args) { | 2843 void CodeGenerator::GenerateIsArray(ZoneList<Expression*>* args) { |
| 3206 ASSERT(args->length() == 1); | 2844 ASSERT(args->length() == 1); |
| 3207 Load(args->at(0)); | 2845 Load(args->at(0)); |
| 3208 Label answer; | 2846 Label answer; |
| 3209 // We need the CC bits to come out as not_equal in the case where the | 2847 // We need the CC bits to come out as not_equal in the case where the |
| 3210 // object is a smi. This can't be done with the usual test opcode so | 2848 // object is a smi. This can't be done with the usual test opcode so |
| 3211 // we copy the object to ecx and do some destructive ops on it that | 2849 // we copy the object to ecx and do some destructive ops on it that |
| 3212 // result in the right CC bits. | 2850 // result in the right CC bits. |
| 3213 __ pop(eax); | 2851 __ pop(eax); |
| 3214 __ mov(ecx, Operand(eax)); | 2852 __ mov(ecx, Operand(eax)); |
| 3215 __ and_(ecx, kSmiTagMask); | 2853 __ and_(ecx, kSmiTagMask); |
| 3216 __ xor_(ecx, kSmiTagMask); | 2854 __ xor_(ecx, kSmiTagMask); |
| 3217 __ j(not_equal, &answer, not_taken); | 2855 __ j(not_equal, &answer, not_taken); |
| 3218 // It is a heap object - get map. | 2856 // It is a heap object - get map. |
| 3219 __ mov(eax, FieldOperand(eax, HeapObject::kMapOffset)); | 2857 __ mov(eax, FieldOperand(eax, HeapObject::kMapOffset)); |
| 3220 __ movzx_b(eax, FieldOperand(eax, Map::kInstanceTypeOffset)); | 2858 __ movzx_b(eax, FieldOperand(eax, Map::kInstanceTypeOffset)); |
| 3221 // Check if the object is a JS array or not. | 2859 // Check if the object is a JS array or not. |
| 3222 __ cmp(eax, JS_ARRAY_TYPE); | 2860 __ cmp(eax, JS_ARRAY_TYPE); |
| 3223 __ bind(&answer); | 2861 __ bind(&answer); |
| 3224 cc_reg_ = equal; | 2862 cc_reg_ = equal; |
| 3225 } | 2863 } |
| 3226 | 2864 |
| 3227 | 2865 |
| 3228 void Ia32CodeGenerator::GenerateArgumentsLength(ZoneList<Expression*>* args) { | 2866 void CodeGenerator::GenerateArgumentsLength(ZoneList<Expression*>* args) { |
| 3229 ASSERT(args->length() == 0); | 2867 ASSERT(args->length() == 0); |
| 3230 | 2868 |
| 3231 // Seed the result with the formal parameters count, which will be | 2869 // Seed the result with the formal parameters count, which will be |
| 3232 // used in case no arguments adaptor frame is found below the | 2870 // used in case no arguments adaptor frame is found below the |
| 3233 // current frame. | 2871 // current frame. |
| 3234 __ Set(eax, Immediate(Smi::FromInt(scope_->num_parameters()))); | 2872 __ Set(eax, Immediate(Smi::FromInt(scope_->num_parameters()))); |
| 3235 | 2873 |
| 3236 // Call the shared stub to get to the arguments.length. | 2874 // Call the shared stub to get to the arguments.length. |
| 3237 ArgumentsAccessStub stub(ArgumentsAccessStub::READ_LENGTH); | 2875 ArgumentsAccessStub stub(ArgumentsAccessStub::READ_LENGTH); |
| 3238 __ CallStub(&stub); | 2876 __ CallStub(&stub); |
| 3239 __ push(eax); | 2877 __ push(eax); |
| 3240 } | 2878 } |
| 3241 | 2879 |
| 3242 | 2880 |
| 3243 void Ia32CodeGenerator::GenerateValueOf(ZoneList<Expression*>* args) { | 2881 void CodeGenerator::GenerateValueOf(ZoneList<Expression*>* args) { |
| 3244 ASSERT(args->length() == 1); | 2882 ASSERT(args->length() == 1); |
| 3245 Label leave; | 2883 Label leave; |
| 3246 Load(args->at(0)); // Load the object. | 2884 Load(args->at(0)); // Load the object. |
| 3247 __ mov(eax, TOS); | 2885 __ mov(eax, TOS); |
| 3248 // if (object->IsSmi()) return object. | 2886 // if (object->IsSmi()) return object. |
| 3249 __ test(eax, Immediate(kSmiTagMask)); | 2887 __ test(eax, Immediate(kSmiTagMask)); |
| 3250 __ j(zero, &leave, taken); | 2888 __ j(zero, &leave, taken); |
| 3251 // It is a heap object - get map. | 2889 // It is a heap object - get map. |
| 3252 __ mov(ecx, FieldOperand(eax, HeapObject::kMapOffset)); | 2890 __ mov(ecx, FieldOperand(eax, HeapObject::kMapOffset)); |
| 3253 __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset)); | 2891 __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset)); |
| 3254 // if (!object->IsJSValue()) return object. | 2892 // if (!object->IsJSValue()) return object. |
| 3255 __ cmp(ecx, JS_VALUE_TYPE); | 2893 __ cmp(ecx, JS_VALUE_TYPE); |
| 3256 __ j(not_equal, &leave, not_taken); | 2894 __ j(not_equal, &leave, not_taken); |
| 3257 __ mov(eax, FieldOperand(eax, JSValue::kValueOffset)); | 2895 __ mov(eax, FieldOperand(eax, JSValue::kValueOffset)); |
| 3258 __ mov(TOS, eax); | 2896 __ mov(TOS, eax); |
| 3259 __ bind(&leave); | 2897 __ bind(&leave); |
| 3260 } | 2898 } |
| 3261 | 2899 |
| 3262 | 2900 |
| 3263 void Ia32CodeGenerator::GenerateSetValueOf(ZoneList<Expression*>* args) { | 2901 void CodeGenerator::GenerateSetValueOf(ZoneList<Expression*>* args) { |
| 3264 ASSERT(args->length() == 2); | 2902 ASSERT(args->length() == 2); |
| 3265 Label leave; | 2903 Label leave; |
| 3266 Load(args->at(0)); // Load the object. | 2904 Load(args->at(0)); // Load the object. |
| 3267 Load(args->at(1)); // Load the value. | 2905 Load(args->at(1)); // Load the value. |
| 3268 __ mov(eax, (Operand(esp, kPointerSize))); | 2906 __ mov(eax, (Operand(esp, kPointerSize))); |
| 3269 __ mov(ecx, TOS); | 2907 __ mov(ecx, TOS); |
| 3270 // if (object->IsSmi()) return object. | 2908 // if (object->IsSmi()) return object. |
| 3271 __ test(eax, Immediate(kSmiTagMask)); | 2909 __ test(eax, Immediate(kSmiTagMask)); |
| 3272 __ j(zero, &leave, taken); | 2910 __ j(zero, &leave, taken); |
| 3273 // It is a heap object - get map. | 2911 // It is a heap object - get map. |
| 3274 __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset)); | 2912 __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset)); |
| 3275 __ movzx_b(ebx, FieldOperand(ebx, Map::kInstanceTypeOffset)); | 2913 __ movzx_b(ebx, FieldOperand(ebx, Map::kInstanceTypeOffset)); |
| 3276 // if (!object->IsJSValue()) return object. | 2914 // if (!object->IsJSValue()) return object. |
| 3277 __ cmp(ebx, JS_VALUE_TYPE); | 2915 __ cmp(ebx, JS_VALUE_TYPE); |
| 3278 __ j(not_equal, &leave, not_taken); | 2916 __ j(not_equal, &leave, not_taken); |
| 3279 // Store the value. | 2917 // Store the value. |
| 3280 __ mov(FieldOperand(eax, JSValue::kValueOffset), ecx); | 2918 __ mov(FieldOperand(eax, JSValue::kValueOffset), ecx); |
| 3281 // Update the write barrier. | 2919 // Update the write barrier. |
| 3282 __ RecordWrite(eax, JSValue::kValueOffset, ecx, ebx); | 2920 __ RecordWrite(eax, JSValue::kValueOffset, ecx, ebx); |
| 3283 // Leave. | 2921 // Leave. |
| 3284 __ bind(&leave); | 2922 __ bind(&leave); |
| 3285 __ mov(ecx, TOS); | 2923 __ mov(ecx, TOS); |
| 3286 __ pop(eax); | 2924 __ pop(eax); |
| 3287 __ mov(TOS, ecx); | 2925 __ mov(TOS, ecx); |
| 3288 } | 2926 } |
| 3289 | 2927 |
| 3290 | 2928 |
| 3291 void Ia32CodeGenerator::GenerateArgumentsAccess(ZoneList<Expression*>* args) { | 2929 void CodeGenerator::GenerateArgumentsAccess(ZoneList<Expression*>* args) { |
| 3292 ASSERT(args->length() == 1); | 2930 ASSERT(args->length() == 1); |
| 3293 | 2931 |
| 3294 // Load the key onto the stack and set register eax to the formal | 2932 // Load the key onto the stack and set register eax to the formal |
| 3295 // parameters count for the currently executing function. | 2933 // parameters count for the currently executing function. |
| 3296 Load(args->at(0)); | 2934 Load(args->at(0)); |
| 3297 __ Set(eax, Immediate(Smi::FromInt(scope_->num_parameters()))); | 2935 __ Set(eax, Immediate(Smi::FromInt(scope_->num_parameters()))); |
| 3298 | 2936 |
| 3299 // Call the shared stub to get to arguments[key]. | 2937 // Call the shared stub to get to arguments[key]. |
| 3300 ArgumentsAccessStub stub(ArgumentsAccessStub::READ_ELEMENT); | 2938 ArgumentsAccessStub stub(ArgumentsAccessStub::READ_ELEMENT); |
| 3301 __ CallStub(&stub); | 2939 __ CallStub(&stub); |
| 3302 __ mov(TOS, eax); | 2940 __ mov(TOS, eax); |
| 3303 } | 2941 } |
| 3304 | 2942 |
| 3305 | 2943 |
| 3306 void Ia32CodeGenerator::GenerateObjectEquals(ZoneList<Expression*>* args) { | 2944 void CodeGenerator::GenerateObjectEquals(ZoneList<Expression*>* args) { |
| 3307 ASSERT(args->length() == 2); | 2945 ASSERT(args->length() == 2); |
| 3308 | 2946 |
| 3309 // Load the two objects into registers and perform the comparison. | 2947 // Load the two objects into registers and perform the comparison. |
| 3310 Load(args->at(0)); | 2948 Load(args->at(0)); |
| 3311 Load(args->at(1)); | 2949 Load(args->at(1)); |
| 3312 __ pop(eax); | 2950 __ pop(eax); |
| 3313 __ pop(ecx); | 2951 __ pop(ecx); |
| 3314 __ cmp(eax, Operand(ecx)); | 2952 __ cmp(eax, Operand(ecx)); |
| 3315 cc_reg_ = equal; | 2953 cc_reg_ = equal; |
| 3316 } | 2954 } |
| 3317 | 2955 |
| 3318 | 2956 |
| 3319 void Ia32CodeGenerator::VisitCallRuntime(CallRuntime* node) { | 2957 void CodeGenerator::VisitCallRuntime(CallRuntime* node) { |
| 3320 if (CheckForInlineRuntimeCall(node)) return; | 2958 if (CheckForInlineRuntimeCall(node)) return; |
| 3321 | 2959 |
| 3322 ZoneList<Expression*>* args = node->arguments(); | 2960 ZoneList<Expression*>* args = node->arguments(); |
| 3323 Comment cmnt(masm_, "[ CallRuntime"); | 2961 Comment cmnt(masm_, "[ CallRuntime"); |
| 3324 Runtime::Function* function = node->function(); | 2962 Runtime::Function* function = node->function(); |
| 3325 | 2963 |
| 3326 if (function == NULL) { | 2964 if (function == NULL) { |
| 3327 // Prepare stack for calling JS runtime function. | 2965 // Prepare stack for calling JS runtime function. |
| 3328 __ push(Immediate(node->name())); | 2966 __ push(Immediate(node->name())); |
| 3329 // Push the builtins object found in the current global object. | 2967 // Push the builtins object found in the current global object. |
| (...skipping 13 matching lines...) Expand all Loading... |
| 3343 // Call the JS runtime function. | 2981 // Call the JS runtime function. |
| 3344 Handle<Code> stub = ComputeCallInitialize(args->length()); | 2982 Handle<Code> stub = ComputeCallInitialize(args->length()); |
| 3345 __ Set(eax, Immediate(args->length())); | 2983 __ Set(eax, Immediate(args->length())); |
| 3346 __ call(stub, RelocInfo::CODE_TARGET); | 2984 __ call(stub, RelocInfo::CODE_TARGET); |
| 3347 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); | 2985 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); |
| 3348 __ mov(TOS, eax); | 2986 __ mov(TOS, eax); |
| 3349 } | 2987 } |
| 3350 } | 2988 } |
| 3351 | 2989 |
| 3352 | 2990 |
| 3353 void Ia32CodeGenerator::VisitUnaryOperation(UnaryOperation* node) { | 2991 void CodeGenerator::VisitUnaryOperation(UnaryOperation* node) { |
| 3354 Comment cmnt(masm_, "[ UnaryOperation"); | 2992 Comment cmnt(masm_, "[ UnaryOperation"); |
| 3355 | 2993 |
| 3356 Token::Value op = node->op(); | 2994 Token::Value op = node->op(); |
| 3357 | 2995 |
| 3358 if (op == Token::NOT) { | 2996 if (op == Token::NOT) { |
| 3359 LoadCondition(node->expression(), NOT_INSIDE_TYPEOF, | 2997 LoadCondition(node->expression(), NOT_INSIDE_TYPEOF, |
| 3360 false_target(), true_target(), true); | 2998 false_target(), true_target(), true); |
| 3361 cc_reg_ = NegateCondition(cc_reg_); | 2999 cc_reg_ = NegateCondition(cc_reg_); |
| 3362 | 3000 |
| 3363 } else if (op == Token::DELETE) { | 3001 } else if (op == Token::DELETE) { |
| (...skipping 188 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3552 void CountOperationDeferred::Generate() { | 3190 void CountOperationDeferred::Generate() { |
| 3553 if (is_postfix_) { | 3191 if (is_postfix_) { |
| 3554 RevertToNumberStub to_number_stub(is_increment_); | 3192 RevertToNumberStub to_number_stub(is_increment_); |
| 3555 __ CallStub(&to_number_stub); | 3193 __ CallStub(&to_number_stub); |
| 3556 } | 3194 } |
| 3557 CounterOpStub stub(result_offset_, is_postfix_, is_increment_); | 3195 CounterOpStub stub(result_offset_, is_postfix_, is_increment_); |
| 3558 __ CallStub(&stub); | 3196 __ CallStub(&stub); |
| 3559 } | 3197 } |
| 3560 | 3198 |
| 3561 | 3199 |
| 3562 void Ia32CodeGenerator::VisitCountOperation(CountOperation* node) { | 3200 void CodeGenerator::VisitCountOperation(CountOperation* node) { |
| 3563 Comment cmnt(masm_, "[ CountOperation"); | 3201 Comment cmnt(masm_, "[ CountOperation"); |
| 3564 | 3202 |
| 3565 bool is_postfix = node->is_postfix(); | 3203 bool is_postfix = node->is_postfix(); |
| 3566 bool is_increment = node->op() == Token::INC; | 3204 bool is_increment = node->op() == Token::INC; |
| 3567 | 3205 |
| 3568 Variable* var = node->expression()->AsVariableProxy()->AsVariable(); | 3206 Variable* var = node->expression()->AsVariableProxy()->AsVariable(); |
| 3569 bool is_const = (var != NULL && var->mode() == Variable::CONST); | 3207 bool is_const = (var != NULL && var->mode() == Variable::CONST); |
| 3570 | 3208 |
| 3571 // Postfix: Make room for the result. | 3209 // Postfix: Make room for the result. |
| 3572 if (is_postfix) __ push(Immediate(0)); | 3210 if (is_postfix) __ push(Immediate(0)); |
| (...skipping 30 matching lines...) Expand all Loading... |
| 3603 __ bind(deferred->exit()); | 3241 __ bind(deferred->exit()); |
| 3604 __ push(eax); // Push the new value to TOS | 3242 __ push(eax); // Push the new value to TOS |
| 3605 if (!is_const) target.SetValue(NOT_CONST_INIT); | 3243 if (!is_const) target.SetValue(NOT_CONST_INIT); |
| 3606 } | 3244 } |
| 3607 | 3245 |
| 3608 // Postfix: Discard the new value and use the old. | 3246 // Postfix: Discard the new value and use the old. |
| 3609 if (is_postfix) __ pop(eax); | 3247 if (is_postfix) __ pop(eax); |
| 3610 } | 3248 } |
| 3611 | 3249 |
| 3612 | 3250 |
| 3613 void Ia32CodeGenerator::VisitBinaryOperation(BinaryOperation* node) { | 3251 void CodeGenerator::VisitBinaryOperation(BinaryOperation* node) { |
| 3614 Comment cmnt(masm_, "[ BinaryOperation"); | 3252 Comment cmnt(masm_, "[ BinaryOperation"); |
| 3615 Token::Value op = node->op(); | 3253 Token::Value op = node->op(); |
| 3616 | 3254 |
| 3617 // According to ECMA-262 section 11.11, page 58, the binary logical | 3255 // According to ECMA-262 section 11.11, page 58, the binary logical |
| 3618 // operators must yield the result of one of the two expressions | 3256 // operators must yield the result of one of the two expressions |
| 3619 // before any ToBoolean() conversions. This means that the value | 3257 // before any ToBoolean() conversions. This means that the value |
| 3620 // produced by a && or || operator is not necessarily a boolean. | 3258 // produced by a && or || operator is not necessarily a boolean. |
| 3621 | 3259 |
| 3622 // NOTE: If the left hand side produces a materialized value (not in | 3260 // NOTE: If the left hand side produces a materialized value (not in |
| 3623 // the CC register), we force the right hand side to do the | 3261 // the CC register), we force the right hand side to do the |
| (...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3725 | 3363 |
| 3726 } else { | 3364 } else { |
| 3727 Load(node->left()); | 3365 Load(node->left()); |
| 3728 Load(node->right()); | 3366 Load(node->right()); |
| 3729 GenericBinaryOperation(node->op(), overwrite_mode); | 3367 GenericBinaryOperation(node->op(), overwrite_mode); |
| 3730 } | 3368 } |
| 3731 } | 3369 } |
| 3732 } | 3370 } |
| 3733 | 3371 |
| 3734 | 3372 |
| 3735 void Ia32CodeGenerator::VisitThisFunction(ThisFunction* node) { | 3373 void CodeGenerator::VisitThisFunction(ThisFunction* node) { |
| 3736 __ push(FunctionOperand()); | 3374 __ push(FunctionOperand()); |
| 3737 } | 3375 } |
| 3738 | 3376 |
| 3739 | 3377 |
| 3740 class InstanceofStub: public CodeStub { | 3378 class InstanceofStub: public CodeStub { |
| 3741 public: | 3379 public: |
| 3742 InstanceofStub() { } | 3380 InstanceofStub() { } |
| 3743 | 3381 |
| 3744 void Generate(MacroAssembler* masm); | 3382 void Generate(MacroAssembler* masm); |
| 3745 | 3383 |
| 3746 private: | 3384 private: |
| 3747 Major MajorKey() { return Instanceof; } | 3385 Major MajorKey() { return Instanceof; } |
| 3748 int MinorKey() { return 0; } | 3386 int MinorKey() { return 0; } |
| 3749 }; | 3387 }; |
| 3750 | 3388 |
| 3751 | 3389 |
| 3752 void Ia32CodeGenerator::VisitCompareOperation(CompareOperation* node) { | 3390 void CodeGenerator::VisitCompareOperation(CompareOperation* node) { |
| 3753 Comment cmnt(masm_, "[ CompareOperation"); | 3391 Comment cmnt(masm_, "[ CompareOperation"); |
| 3754 | 3392 |
| 3755 // Get the expressions from the node. | 3393 // Get the expressions from the node. |
| 3756 Expression* left = node->left(); | 3394 Expression* left = node->left(); |
| 3757 Expression* right = node->right(); | 3395 Expression* right = node->right(); |
| 3758 Token::Value op = node->op(); | 3396 Token::Value op = node->op(); |
| 3759 | 3397 |
| 3760 // NOTE: To make null checks efficient, we check if either left or | 3398 // NOTE: To make null checks efficient, we check if either left or |
| 3761 // right is the literal 'null'. If so, we optimize the code by | 3399 // right is the literal 'null'. If so, we optimize the code by |
| 3762 // inlining a null check instead of calling the (very) general | 3400 // inlining a null check instead of calling the (very) general |
| (...skipping 188 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3951 SmiComparison(cc, right->AsLiteral()->handle(), strict); | 3589 SmiComparison(cc, right->AsLiteral()->handle(), strict); |
| 3952 return; | 3590 return; |
| 3953 } | 3591 } |
| 3954 | 3592 |
| 3955 Load(left); | 3593 Load(left); |
| 3956 Load(right); | 3594 Load(right); |
| 3957 Comparison(cc, strict); | 3595 Comparison(cc, strict); |
| 3958 } | 3596 } |
| 3959 | 3597 |
| 3960 | 3598 |
| 3961 void Ia32CodeGenerator::RecordStatementPosition(Node* node) { | 3599 void CodeGenerator::RecordStatementPosition(Node* node) { |
| 3962 if (FLAG_debug_info) { | 3600 if (FLAG_debug_info) { |
| 3963 int pos = node->statement_pos(); | 3601 int pos = node->statement_pos(); |
| 3964 if (pos != RelocInfo::kNoPosition) { | 3602 if (pos != RelocInfo::kNoPosition) { |
| 3965 __ RecordStatementPosition(pos); | 3603 __ RecordStatementPosition(pos); |
| 3966 } | 3604 } |
| 3967 } | 3605 } |
| 3968 } | 3606 } |
| 3969 | 3607 |
| 3970 | 3608 |
| 3971 void Ia32CodeGenerator::EnterJSFrame() { | 3609 void CodeGenerator::EnterJSFrame() { |
| 3972 __ push(ebp); | 3610 __ push(ebp); |
| 3973 __ mov(ebp, Operand(esp)); | 3611 __ mov(ebp, Operand(esp)); |
| 3974 | 3612 |
| 3975 // Store the context and the function in the frame. | 3613 // Store the context and the function in the frame. |
| 3976 __ push(esi); | 3614 __ push(esi); |
| 3977 __ push(edi); | 3615 __ push(edi); |
| 3978 | 3616 |
| 3979 // Clear the function slot when generating debug code. | 3617 // Clear the function slot when generating debug code. |
| 3980 if (FLAG_debug_code) { | 3618 if (FLAG_debug_code) { |
| 3981 __ Set(edi, Immediate(reinterpret_cast<int>(kZapValue))); | 3619 __ Set(edi, Immediate(reinterpret_cast<int>(kZapValue))); |
| 3982 } | 3620 } |
| 3983 } | 3621 } |
| 3984 | 3622 |
| 3985 | 3623 |
| 3986 void Ia32CodeGenerator::ExitJSFrame() { | 3624 void CodeGenerator::ExitJSFrame() { |
| 3987 // Record the location of the JS exit code for patching when setting | 3625 // Record the location of the JS exit code for patching when setting |
| 3988 // break point. | 3626 // break point. |
| 3989 __ RecordJSReturn(); | 3627 __ RecordJSReturn(); |
| 3990 | 3628 |
| 3991 // Avoid using the leave instruction here, because it is too | 3629 // Avoid using the leave instruction here, because it is too |
| 3992 // short. We need the return sequence to be a least the size of a | 3630 // short. We need the return sequence to be a least the size of a |
| 3993 // call instruction to support patching the exit code in the | 3631 // call instruction to support patching the exit code in the |
| 3994 // debugger. See VisitReturnStatement for the full return sequence. | 3632 // debugger. See VisitReturnStatement for the full return sequence. |
| 3995 __ mov(esp, Operand(ebp)); | 3633 __ mov(esp, Operand(ebp)); |
| 3996 __ pop(ebp); | 3634 __ pop(ebp); |
| (...skipping 1339 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5336 __ ret(2 * kPointerSize); | 4974 __ ret(2 * kPointerSize); |
| 5337 | 4975 |
| 5338 // Slow-case: Go through the JavaScript implementation. | 4976 // Slow-case: Go through the JavaScript implementation. |
| 5339 __ bind(&slow); | 4977 __ bind(&slow); |
| 5340 __ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION); | 4978 __ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION); |
| 5341 } | 4979 } |
| 5342 | 4980 |
| 5343 | 4981 |
| 5344 #undef __ | 4982 #undef __ |
| 5345 | 4983 |
| 5346 // ----------------------------------------------------------------------------- | |
| 5347 // CodeGenerator interfaces | |
| 5348 | |
| 5349 // MakeCode() is just a wrapper for CodeGenerator::MakeCode() | |
| 5350 // so we don't have to expose the entire CodeGenerator class in | |
| 5351 // the .h file. | |
| 5352 Handle<Code> CodeGenerator::MakeCode(FunctionLiteral* fun, | |
| 5353 Handle<Script> script, | |
| 5354 bool is_eval) { | |
| 5355 Handle<Code> code = Ia32CodeGenerator::MakeCode(fun, script, is_eval); | |
| 5356 if (!code.is_null()) { | |
| 5357 Counters::total_compiled_code_size.Increment(code->instruction_size()); | |
| 5358 } | |
| 5359 return code; | |
| 5360 } | |
| 5361 | |
| 5362 | |
| 5363 } } // namespace v8::internal | 4984 } } // namespace v8::internal |
| OLD | NEW |