| OLD | NEW |
| 1 // Copyright 2011 the V8 project authors. All rights reserved. | 1 // Copyright 2011 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 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 94 void EmitJumpIfSmi(Register reg, Label* target) { | 94 void EmitJumpIfSmi(Register reg, Label* target) { |
| 95 Assembler::BlockTrampolinePoolScope block_trampoline_pool(masm_); | 95 Assembler::BlockTrampolinePoolScope block_trampoline_pool(masm_); |
| 96 ASSERT(!patch_site_.is_bound() && !info_emitted_); | 96 ASSERT(!patch_site_.is_bound() && !info_emitted_); |
| 97 __ bind(&patch_site_); | 97 __ bind(&patch_site_); |
| 98 __ andi(at, reg, 0); | 98 __ andi(at, reg, 0); |
| 99 // Never taken before patched. | 99 // Never taken before patched. |
| 100 __ Branch(target, ne, at, Operand(zero_reg)); | 100 __ Branch(target, ne, at, Operand(zero_reg)); |
| 101 } | 101 } |
| 102 | 102 |
| 103 void EmitPatchInfo() { | 103 void EmitPatchInfo() { |
| 104 int delta_to_patch_site = masm_->InstructionsGeneratedSince(&patch_site_); | 104 if (patch_site_.is_bound()) { |
| 105 Register reg = Register::from_code(delta_to_patch_site / kImm16Mask); | 105 int delta_to_patch_site = masm_->InstructionsGeneratedSince(&patch_site_); |
| 106 __ andi(at, reg, delta_to_patch_site % kImm16Mask); | 106 Register reg = Register::from_code(delta_to_patch_site / kImm16Mask); |
| 107 __ andi(at, reg, delta_to_patch_site % kImm16Mask); |
| 107 #ifdef DEBUG | 108 #ifdef DEBUG |
| 108 info_emitted_ = true; | 109 info_emitted_ = true; |
| 109 #endif | 110 #endif |
| 111 } else { |
| 112 __ nop(); // Signals no inlined code. |
| 113 } |
| 110 } | 114 } |
| 111 | 115 |
| 112 bool is_bound() const { return patch_site_.is_bound(); } | |
| 113 | |
| 114 private: | 116 private: |
| 115 MacroAssembler* masm_; | 117 MacroAssembler* masm_; |
| 116 Label patch_site_; | 118 Label patch_site_; |
| 117 #ifdef DEBUG | 119 #ifdef DEBUG |
| 118 bool info_emitted_; | 120 bool info_emitted_; |
| 119 #endif | 121 #endif |
| 120 }; | 122 }; |
| 121 | 123 |
| 122 | 124 |
| 123 // Generate code for a JS function. On entry to the function the receiver | 125 // Generate code for a JS function. On entry to the function the receiver |
| 124 // and arguments have been pushed on the stack left to right. The actual | 126 // and arguments have been pushed on the stack left to right. The actual |
| 125 // argument count matches the formal parameter count expected by the | 127 // argument count matches the formal parameter count expected by the |
| 126 // function. | 128 // function. |
| 127 // | 129 // |
| 128 // The live registers are: | 130 // The live registers are: |
| 129 // o a1: the JS function object being called (ie, ourselves) | 131 // o a1: the JS function object being called (ie, ourselves) |
| 130 // o cp: our context | 132 // o cp: our context |
| 131 // o fp: our caller's frame pointer | 133 // o fp: our caller's frame pointer |
| 132 // o sp: stack pointer | 134 // o sp: stack pointer |
| 133 // o ra: return address | 135 // o ra: return address |
| 134 // | 136 // |
| 135 // The function builds a JS frame. Please see JavaScriptFrameConstants in | 137 // The function builds a JS frame. Please see JavaScriptFrameConstants in |
| 136 // frames-mips.h for its layout. | 138 // frames-mips.h for its layout. |
| 137 void FullCodeGenerator::Generate(CompilationInfo* info) { | 139 void FullCodeGenerator::Generate(CompilationInfo* info) { |
| 138 ASSERT(info_ == NULL); | 140 ASSERT(info_ == NULL); |
| 139 info_ = info; | 141 info_ = info; |
| 142 scope_ = info->scope(); |
| 140 SetFunctionPosition(function()); | 143 SetFunctionPosition(function()); |
| 141 Comment cmnt(masm_, "[ function compiled by full code generator"); | 144 Comment cmnt(masm_, "[ function compiled by full code generator"); |
| 142 | 145 |
| 143 #ifdef DEBUG | 146 #ifdef DEBUG |
| 144 if (strlen(FLAG_stop_at) > 0 && | 147 if (strlen(FLAG_stop_at) > 0 && |
| 145 info->function()->name()->IsEqualTo(CStrVector(FLAG_stop_at))) { | 148 info->function()->name()->IsEqualTo(CStrVector(FLAG_stop_at))) { |
| 146 __ stop("stop-at"); | 149 __ stop("stop-at"); |
| 147 } | 150 } |
| 148 #endif | 151 #endif |
| 149 | 152 |
| 150 // Strict mode functions need to replace the receiver with undefined | 153 // Strict mode functions and builtins need to replace the receiver |
| 151 // when called as functions (without an explicit receiver | 154 // with undefined when called as functions (without an explicit |
| 152 // object). t1 is zero for method calls and non-zero for function | 155 // receiver object). t1 is zero for method calls and non-zero for |
| 153 // calls. | 156 // function calls. |
| 154 if (info->is_strict_mode()) { | 157 if (info->is_strict_mode() || info->is_native()) { |
| 155 Label ok; | 158 Label ok; |
| 156 __ Branch(&ok, eq, t1, Operand(zero_reg)); | 159 __ Branch(&ok, eq, t1, Operand(zero_reg)); |
| 157 int receiver_offset = scope()->num_parameters() * kPointerSize; | 160 int receiver_offset = info->scope()->num_parameters() * kPointerSize; |
| 158 __ LoadRoot(a2, Heap::kUndefinedValueRootIndex); | 161 __ LoadRoot(a2, Heap::kUndefinedValueRootIndex); |
| 159 __ sw(a2, MemOperand(sp, receiver_offset)); | 162 __ sw(a2, MemOperand(sp, receiver_offset)); |
| 160 __ bind(&ok); | 163 __ bind(&ok); |
| 161 } | 164 } |
| 162 | 165 |
| 163 int locals_count = scope()->num_stack_slots(); | 166 int locals_count = info->scope()->num_stack_slots(); |
| 164 | 167 |
| 165 __ Push(ra, fp, cp, a1); | 168 __ Push(ra, fp, cp, a1); |
| 166 if (locals_count > 0) { | 169 if (locals_count > 0) { |
| 167 // Load undefined value here, so the value is ready for the loop | 170 // Load undefined value here, so the value is ready for the loop |
| 168 // below. | 171 // below. |
| 169 __ LoadRoot(at, Heap::kUndefinedValueRootIndex); | 172 __ LoadRoot(at, Heap::kUndefinedValueRootIndex); |
| 170 } | 173 } |
| 171 // Adjust fp to point to caller's fp. | 174 // Adjust fp to point to caller's fp. |
| 172 __ Addu(fp, sp, Operand(2 * kPointerSize)); | 175 __ Addu(fp, sp, Operand(2 * kPointerSize)); |
| 173 | 176 |
| 174 { Comment cmnt(masm_, "[ Allocate locals"); | 177 { Comment cmnt(masm_, "[ Allocate locals"); |
| 175 for (int i = 0; i < locals_count; i++) { | 178 for (int i = 0; i < locals_count; i++) { |
| 176 __ push(at); | 179 __ push(at); |
| 177 } | 180 } |
| 178 } | 181 } |
| 179 | 182 |
| 180 bool function_in_register = true; | 183 bool function_in_register = true; |
| 181 | 184 |
| 182 // Possibly allocate a local context. | 185 // Possibly allocate a local context. |
| 183 int heap_slots = scope()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS; | 186 int heap_slots = info->scope()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS; |
| 184 if (heap_slots > 0) { | 187 if (heap_slots > 0) { |
| 185 Comment cmnt(masm_, "[ Allocate local context"); | 188 Comment cmnt(masm_, "[ Allocate local context"); |
| 186 // Argument to NewContext is the function, which is in a1. | 189 // Argument to NewContext is the function, which is in a1. |
| 187 __ push(a1); | 190 __ push(a1); |
| 188 if (heap_slots <= FastNewContextStub::kMaximumSlots) { | 191 if (heap_slots <= FastNewContextStub::kMaximumSlots) { |
| 189 FastNewContextStub stub(heap_slots); | 192 FastNewContextStub stub(heap_slots); |
| 190 __ CallStub(&stub); | 193 __ CallStub(&stub); |
| 191 } else { | 194 } else { |
| 192 __ CallRuntime(Runtime::kNewContext, 1); | 195 __ CallRuntime(Runtime::kNewFunctionContext, 1); |
| 193 } | 196 } |
| 194 function_in_register = false; | 197 function_in_register = false; |
| 195 // Context is returned in both v0 and cp. It replaces the context | 198 // Context is returned in both v0 and cp. It replaces the context |
| 196 // passed to us. It's saved in the stack and kept live in cp. | 199 // passed to us. It's saved in the stack and kept live in cp. |
| 197 __ sw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); | 200 __ sw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); |
| 198 // Copy any necessary parameters into the context. | 201 // Copy any necessary parameters into the context. |
| 199 int num_parameters = scope()->num_parameters(); | 202 int num_parameters = info->scope()->num_parameters(); |
| 200 for (int i = 0; i < num_parameters; i++) { | 203 for (int i = 0; i < num_parameters; i++) { |
| 201 Slot* slot = scope()->parameter(i)->AsSlot(); | 204 Slot* slot = scope()->parameter(i)->AsSlot(); |
| 202 if (slot != NULL && slot->type() == Slot::CONTEXT) { | 205 if (slot != NULL && slot->type() == Slot::CONTEXT) { |
| 203 int parameter_offset = StandardFrameConstants::kCallerSPOffset + | 206 int parameter_offset = StandardFrameConstants::kCallerSPOffset + |
| 204 (num_parameters - 1 - i) * kPointerSize; | 207 (num_parameters - 1 - i) * kPointerSize; |
| 205 // Load parameter from stack. | 208 // Load parameter from stack. |
| 206 __ lw(a0, MemOperand(fp, parameter_offset)); | 209 __ lw(a0, MemOperand(fp, parameter_offset)); |
| 207 // Store it in the context. | 210 // Store it in the context. |
| 208 __ li(a1, Operand(Context::SlotOffset(slot->index()))); | 211 __ li(a1, Operand(Context::SlotOffset(slot->index()))); |
| 209 __ addu(a2, cp, a1); | 212 __ addu(a2, cp, a1); |
| (...skipping 11 matching lines...) Expand all Loading... |
| 221 if (arguments != NULL) { | 224 if (arguments != NULL) { |
| 222 // Function uses arguments object. | 225 // Function uses arguments object. |
| 223 Comment cmnt(masm_, "[ Allocate arguments object"); | 226 Comment cmnt(masm_, "[ Allocate arguments object"); |
| 224 if (!function_in_register) { | 227 if (!function_in_register) { |
| 225 // Load this again, if it's used by the local context below. | 228 // Load this again, if it's used by the local context below. |
| 226 __ lw(a3, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset)); | 229 __ lw(a3, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset)); |
| 227 } else { | 230 } else { |
| 228 __ mov(a3, a1); | 231 __ mov(a3, a1); |
| 229 } | 232 } |
| 230 // Receiver is just before the parameters on the caller's stack. | 233 // Receiver is just before the parameters on the caller's stack. |
| 231 int offset = scope()->num_parameters() * kPointerSize; | 234 int num_parameters = info->scope()->num_parameters(); |
| 235 int offset = num_parameters * kPointerSize; |
| 232 __ Addu(a2, fp, | 236 __ Addu(a2, fp, |
| 233 Operand(StandardFrameConstants::kCallerSPOffset + offset)); | 237 Operand(StandardFrameConstants::kCallerSPOffset + offset)); |
| 234 __ li(a1, Operand(Smi::FromInt(scope()->num_parameters()))); | 238 __ li(a1, Operand(Smi::FromInt(num_parameters))); |
| 235 __ Push(a3, a2, a1); | 239 __ Push(a3, a2, a1); |
| 236 | 240 |
| 237 // Arguments to ArgumentsAccessStub: | 241 // Arguments to ArgumentsAccessStub: |
| 238 // function, receiver address, parameter count. | 242 // function, receiver address, parameter count. |
| 239 // The stub will rewrite receiever and parameter count if the previous | 243 // The stub will rewrite receiever and parameter count if the previous |
| 240 // stack frame was an arguments adapter frame. | 244 // stack frame was an arguments adapter frame. |
| 241 ArgumentsAccessStub stub( | 245 ArgumentsAccessStub::Type type; |
| 242 is_strict_mode() ? ArgumentsAccessStub::NEW_STRICT | 246 if (is_strict_mode()) { |
| 243 : ArgumentsAccessStub::NEW_NON_STRICT); | 247 type = ArgumentsAccessStub::NEW_STRICT; |
| 248 } else if (function()->has_duplicate_parameters()) { |
| 249 type = ArgumentsAccessStub::NEW_NON_STRICT_SLOW; |
| 250 } else { |
| 251 type = ArgumentsAccessStub::NEW_NON_STRICT_FAST; |
| 252 } |
| 253 ArgumentsAccessStub stub(type); |
| 244 __ CallStub(&stub); | 254 __ CallStub(&stub); |
| 245 | 255 |
| 246 Variable* arguments_shadow = scope()->arguments_shadow(); | |
| 247 if (arguments_shadow != NULL) { | |
| 248 // Duplicate the value; move-to-slot operation might clobber registers. | |
| 249 __ mov(a3, v0); | |
| 250 Move(arguments_shadow->AsSlot(), a3, a1, a2); | |
| 251 } | |
| 252 Move(arguments->AsSlot(), v0, a1, a2); | 256 Move(arguments->AsSlot(), v0, a1, a2); |
| 253 } | 257 } |
| 254 | 258 |
| 255 if (FLAG_trace) { | 259 if (FLAG_trace) { |
| 256 __ CallRuntime(Runtime::kTraceEnter, 0); | 260 __ CallRuntime(Runtime::kTraceEnter, 0); |
| 257 } | 261 } |
| 258 | 262 |
| 259 // Visit the declarations and body unless there is an illegal | 263 // Visit the declarations and body unless there is an illegal |
| 260 // redeclaration. | 264 // redeclaration. |
| 261 if (scope()->HasIllegalRedeclaration()) { | 265 if (scope()->HasIllegalRedeclaration()) { |
| (...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 341 #ifdef DEBUG | 345 #ifdef DEBUG |
| 342 // Add a label for checking the size of the code used for returning. | 346 // Add a label for checking the size of the code used for returning. |
| 343 Label check_exit_codesize; | 347 Label check_exit_codesize; |
| 344 masm_->bind(&check_exit_codesize); | 348 masm_->bind(&check_exit_codesize); |
| 345 #endif | 349 #endif |
| 346 // Make sure that the constant pool is not emitted inside of the return | 350 // Make sure that the constant pool is not emitted inside of the return |
| 347 // sequence. | 351 // sequence. |
| 348 { Assembler::BlockTrampolinePoolScope block_trampoline_pool(masm_); | 352 { Assembler::BlockTrampolinePoolScope block_trampoline_pool(masm_); |
| 349 // Here we use masm_-> instead of the __ macro to avoid the code coverage | 353 // Here we use masm_-> instead of the __ macro to avoid the code coverage |
| 350 // tool from instrumenting as we rely on the code size here. | 354 // tool from instrumenting as we rely on the code size here. |
| 351 int32_t sp_delta = (scope()->num_parameters() + 1) * kPointerSize; | 355 int32_t sp_delta = (info_->scope()->num_parameters() + 1) * kPointerSize; |
| 352 CodeGenerator::RecordPositions(masm_, function()->end_position() - 1); | 356 CodeGenerator::RecordPositions(masm_, function()->end_position() - 1); |
| 353 __ RecordJSReturn(); | 357 __ RecordJSReturn(); |
| 354 masm_->mov(sp, fp); | 358 masm_->mov(sp, fp); |
| 355 masm_->MultiPop(static_cast<RegList>(fp.bit() | ra.bit())); | 359 masm_->MultiPop(static_cast<RegList>(fp.bit() | ra.bit())); |
| 356 masm_->Addu(sp, sp, Operand(sp_delta)); | 360 masm_->Addu(sp, sp, Operand(sp_delta)); |
| 357 masm_->Jump(ra); | 361 masm_->Jump(ra); |
| 358 } | 362 } |
| 359 | 363 |
| 360 #ifdef DEBUG | 364 #ifdef DEBUG |
| 361 // Check that the size of the code used for returning is large enough | 365 // Check that the size of the code used for returning is large enough |
| (...skipping 17 matching lines...) Expand all Loading... |
| 379 void FullCodeGenerator::StackValueContext::Plug(Slot* slot) const { | 383 void FullCodeGenerator::StackValueContext::Plug(Slot* slot) const { |
| 380 codegen()->Move(result_register(), slot); | 384 codegen()->Move(result_register(), slot); |
| 381 __ push(result_register()); | 385 __ push(result_register()); |
| 382 } | 386 } |
| 383 | 387 |
| 384 | 388 |
| 385 void FullCodeGenerator::TestContext::Plug(Slot* slot) const { | 389 void FullCodeGenerator::TestContext::Plug(Slot* slot) const { |
| 386 // For simplicity we always test the accumulator register. | 390 // For simplicity we always test the accumulator register. |
| 387 codegen()->Move(result_register(), slot); | 391 codegen()->Move(result_register(), slot); |
| 388 codegen()->PrepareForBailoutBeforeSplit(TOS_REG, false, NULL, NULL); | 392 codegen()->PrepareForBailoutBeforeSplit(TOS_REG, false, NULL, NULL); |
| 389 codegen()->DoTest(true_label_, false_label_, fall_through_); | 393 codegen()->DoTest(this); |
| 390 } | 394 } |
| 391 | 395 |
| 392 | 396 |
| 393 void FullCodeGenerator::EffectContext::Plug(Heap::RootListIndex index) const { | 397 void FullCodeGenerator::EffectContext::Plug(Heap::RootListIndex index) const { |
| 394 } | 398 } |
| 395 | 399 |
| 396 | 400 |
| 397 void FullCodeGenerator::AccumulatorValueContext::Plug( | 401 void FullCodeGenerator::AccumulatorValueContext::Plug( |
| 398 Heap::RootListIndex index) const { | 402 Heap::RootListIndex index) const { |
| 399 __ LoadRoot(result_register(), index); | 403 __ LoadRoot(result_register(), index); |
| (...skipping 13 matching lines...) Expand all Loading... |
| 413 true_label_, | 417 true_label_, |
| 414 false_label_); | 418 false_label_); |
| 415 if (index == Heap::kUndefinedValueRootIndex || | 419 if (index == Heap::kUndefinedValueRootIndex || |
| 416 index == Heap::kNullValueRootIndex || | 420 index == Heap::kNullValueRootIndex || |
| 417 index == Heap::kFalseValueRootIndex) { | 421 index == Heap::kFalseValueRootIndex) { |
| 418 if (false_label_ != fall_through_) __ Branch(false_label_); | 422 if (false_label_ != fall_through_) __ Branch(false_label_); |
| 419 } else if (index == Heap::kTrueValueRootIndex) { | 423 } else if (index == Heap::kTrueValueRootIndex) { |
| 420 if (true_label_ != fall_through_) __ Branch(true_label_); | 424 if (true_label_ != fall_through_) __ Branch(true_label_); |
| 421 } else { | 425 } else { |
| 422 __ LoadRoot(result_register(), index); | 426 __ LoadRoot(result_register(), index); |
| 423 codegen()->DoTest(true_label_, false_label_, fall_through_); | 427 codegen()->DoTest(this); |
| 424 } | 428 } |
| 425 } | 429 } |
| 426 | 430 |
| 427 | 431 |
| 428 void FullCodeGenerator::EffectContext::Plug(Handle<Object> lit) const { | 432 void FullCodeGenerator::EffectContext::Plug(Handle<Object> lit) const { |
| 429 } | 433 } |
| 430 | 434 |
| 431 | 435 |
| 432 void FullCodeGenerator::AccumulatorValueContext::Plug( | 436 void FullCodeGenerator::AccumulatorValueContext::Plug( |
| 433 Handle<Object> lit) const { | 437 Handle<Object> lit) const { |
| (...skipping 26 matching lines...) Expand all Loading... |
| 460 } | 464 } |
| 461 } else if (lit->IsSmi()) { | 465 } else if (lit->IsSmi()) { |
| 462 if (Smi::cast(*lit)->value() == 0) { | 466 if (Smi::cast(*lit)->value() == 0) { |
| 463 if (false_label_ != fall_through_) __ Branch(false_label_); | 467 if (false_label_ != fall_through_) __ Branch(false_label_); |
| 464 } else { | 468 } else { |
| 465 if (true_label_ != fall_through_) __ Branch(true_label_); | 469 if (true_label_ != fall_through_) __ Branch(true_label_); |
| 466 } | 470 } |
| 467 } else { | 471 } else { |
| 468 // For simplicity we always test the accumulator register. | 472 // For simplicity we always test the accumulator register. |
| 469 __ li(result_register(), Operand(lit)); | 473 __ li(result_register(), Operand(lit)); |
| 470 codegen()->DoTest(true_label_, false_label_, fall_through_); | 474 codegen()->DoTest(this); |
| 471 } | 475 } |
| 472 } | 476 } |
| 473 | 477 |
| 474 | 478 |
| 475 void FullCodeGenerator::EffectContext::DropAndPlug(int count, | 479 void FullCodeGenerator::EffectContext::DropAndPlug(int count, |
| 476 Register reg) const { | 480 Register reg) const { |
| 477 ASSERT(count > 0); | 481 ASSERT(count > 0); |
| 478 __ Drop(count); | 482 __ Drop(count); |
| 479 } | 483 } |
| 480 | 484 |
| (...skipping 15 matching lines...) Expand all Loading... |
| 496 } | 500 } |
| 497 | 501 |
| 498 | 502 |
| 499 void FullCodeGenerator::TestContext::DropAndPlug(int count, | 503 void FullCodeGenerator::TestContext::DropAndPlug(int count, |
| 500 Register reg) const { | 504 Register reg) const { |
| 501 ASSERT(count > 0); | 505 ASSERT(count > 0); |
| 502 // For simplicity we always test the accumulator register. | 506 // For simplicity we always test the accumulator register. |
| 503 __ Drop(count); | 507 __ Drop(count); |
| 504 __ Move(result_register(), reg); | 508 __ Move(result_register(), reg); |
| 505 codegen()->PrepareForBailoutBeforeSplit(TOS_REG, false, NULL, NULL); | 509 codegen()->PrepareForBailoutBeforeSplit(TOS_REG, false, NULL, NULL); |
| 506 codegen()->DoTest(true_label_, false_label_, fall_through_); | 510 codegen()->DoTest(this); |
| 507 } | 511 } |
| 508 | 512 |
| 509 | 513 |
| 510 void FullCodeGenerator::EffectContext::Plug(Label* materialize_true, | 514 void FullCodeGenerator::EffectContext::Plug(Label* materialize_true, |
| 511 Label* materialize_false) const { | 515 Label* materialize_false) const { |
| 512 ASSERT(materialize_true == materialize_false); | 516 ASSERT(materialize_true == materialize_false); |
| 513 __ bind(materialize_true); | 517 __ bind(materialize_true); |
| 514 } | 518 } |
| 515 | 519 |
| 516 | 520 |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 574 true_label_, | 578 true_label_, |
| 575 false_label_); | 579 false_label_); |
| 576 if (flag) { | 580 if (flag) { |
| 577 if (true_label_ != fall_through_) __ Branch(true_label_); | 581 if (true_label_ != fall_through_) __ Branch(true_label_); |
| 578 } else { | 582 } else { |
| 579 if (false_label_ != fall_through_) __ Branch(false_label_); | 583 if (false_label_ != fall_through_) __ Branch(false_label_); |
| 580 } | 584 } |
| 581 } | 585 } |
| 582 | 586 |
| 583 | 587 |
| 584 void FullCodeGenerator::DoTest(Label* if_true, | 588 void FullCodeGenerator::DoTest(Expression* condition, |
| 589 Label* if_true, |
| 585 Label* if_false, | 590 Label* if_false, |
| 586 Label* fall_through) { | 591 Label* fall_through) { |
| 587 if (CpuFeatures::IsSupported(FPU)) { | 592 if (CpuFeatures::IsSupported(FPU)) { |
| 588 ToBooleanStub stub(result_register()); | 593 ToBooleanStub stub(result_register()); |
| 589 __ CallStub(&stub); | 594 __ CallStub(&stub); |
| 590 __ mov(at, zero_reg); | 595 __ mov(at, zero_reg); |
| 591 } else { | 596 } else { |
| 592 // Call the runtime to find the boolean value of the source and then | 597 // Call the runtime to find the boolean value of the source and then |
| 593 // translate it into control flow to the pair of labels. | 598 // translate it into control flow to the pair of labels. |
| 594 __ push(result_register()); | 599 __ push(result_register()); |
| (...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 708 break; | 713 break; |
| 709 | 714 |
| 710 case Slot::CONTEXT: | 715 case Slot::CONTEXT: |
| 711 // We bypass the general EmitSlotSearch because we know more about | 716 // We bypass the general EmitSlotSearch because we know more about |
| 712 // this specific context. | 717 // this specific context. |
| 713 | 718 |
| 714 // The variable in the decl always resides in the current function | 719 // The variable in the decl always resides in the current function |
| 715 // context. | 720 // context. |
| 716 ASSERT_EQ(0, scope()->ContextChainLength(variable->scope())); | 721 ASSERT_EQ(0, scope()->ContextChainLength(variable->scope())); |
| 717 if (FLAG_debug_code) { | 722 if (FLAG_debug_code) { |
| 718 // Check that we're not inside a 'with'. | 723 // Check that we're not inside a with or catch context. |
| 719 __ lw(a1, ContextOperand(cp, Context::FCONTEXT_INDEX)); | 724 __ lw(a1, FieldMemOperand(cp, HeapObject::kMapOffset)); |
| 720 __ Check(eq, "Unexpected declaration in current context.", | 725 __ LoadRoot(t0, Heap::kWithContextMapRootIndex); |
| 721 a1, Operand(cp)); | 726 __ Check(ne, "Declaration in with context.", |
| 727 a1, Operand(t0)); |
| 728 __ LoadRoot(t0, Heap::kCatchContextMapRootIndex); |
| 729 __ Check(ne, "Declaration in catch context.", |
| 730 a1, Operand(t0)); |
| 722 } | 731 } |
| 723 if (mode == Variable::CONST) { | 732 if (mode == Variable::CONST) { |
| 724 __ LoadRoot(at, Heap::kTheHoleValueRootIndex); | 733 __ LoadRoot(at, Heap::kTheHoleValueRootIndex); |
| 725 __ sw(at, ContextOperand(cp, slot->index())); | 734 __ sw(at, ContextOperand(cp, slot->index())); |
| 726 // No write barrier since the_hole_value is in old space. | 735 // No write barrier since the_hole_value is in old space. |
| 727 } else if (function != NULL) { | 736 } else if (function != NULL) { |
| 728 VisitForAccumulatorValue(function); | 737 VisitForAccumulatorValue(function); |
| 729 __ sw(result_register(), ContextOperand(cp, slot->index())); | 738 __ sw(result_register(), ContextOperand(cp, slot->index())); |
| 730 int offset = Context::SlotOffset(slot->index()); | 739 int offset = Context::SlotOffset(slot->index()); |
| 731 // We know that we have written a function, which is not a smi. | 740 // We know that we have written a function, which is not a smi. |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 782 __ mov(a0, result_register()); | 791 __ mov(a0, result_register()); |
| 783 __ pop(a2); | 792 __ pop(a2); |
| 784 | 793 |
| 785 ASSERT(prop->key()->AsLiteral() != NULL && | 794 ASSERT(prop->key()->AsLiteral() != NULL && |
| 786 prop->key()->AsLiteral()->handle()->IsSmi()); | 795 prop->key()->AsLiteral()->handle()->IsSmi()); |
| 787 __ li(a1, Operand(prop->key()->AsLiteral()->handle())); | 796 __ li(a1, Operand(prop->key()->AsLiteral()->handle())); |
| 788 | 797 |
| 789 Handle<Code> ic = is_strict_mode() | 798 Handle<Code> ic = is_strict_mode() |
| 790 ? isolate()->builtins()->KeyedStoreIC_Initialize_Strict() | 799 ? isolate()->builtins()->KeyedStoreIC_Initialize_Strict() |
| 791 : isolate()->builtins()->KeyedStoreIC_Initialize(); | 800 : isolate()->builtins()->KeyedStoreIC_Initialize(); |
| 792 EmitCallIC(ic, RelocInfo::CODE_TARGET, AstNode::kNoNumber); | 801 __ Call(ic); |
| 793 // Value in v0 is ignored (declarations are statements). | 802 // Value in v0 is ignored (declarations are statements). |
| 794 } | 803 } |
| 795 } | 804 } |
| 796 } | 805 } |
| 797 | 806 |
| 798 | 807 |
| 799 void FullCodeGenerator::VisitDeclaration(Declaration* decl) { | 808 void FullCodeGenerator::VisitDeclaration(Declaration* decl) { |
| 800 EmitDeclaration(decl->proxy()->var(), decl->mode(), decl->fun()); | 809 EmitDeclaration(decl->proxy()->var(), decl->mode(), decl->fun()); |
| 801 } | 810 } |
| 802 | 811 |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 857 __ Branch(&next_test, ne, a1, Operand(a0)); | 866 __ Branch(&next_test, ne, a1, Operand(a0)); |
| 858 __ Drop(1); // Switch value is no longer needed. | 867 __ Drop(1); // Switch value is no longer needed. |
| 859 __ Branch(clause->body_target()); | 868 __ Branch(clause->body_target()); |
| 860 | 869 |
| 861 __ bind(&slow_case); | 870 __ bind(&slow_case); |
| 862 } | 871 } |
| 863 | 872 |
| 864 // Record position before stub call for type feedback. | 873 // Record position before stub call for type feedback. |
| 865 SetSourcePosition(clause->position()); | 874 SetSourcePosition(clause->position()); |
| 866 Handle<Code> ic = CompareIC::GetUninitialized(Token::EQ_STRICT); | 875 Handle<Code> ic = CompareIC::GetUninitialized(Token::EQ_STRICT); |
| 867 EmitCallIC(ic, &patch_site, clause->CompareId()); | 876 __ Call(ic, RelocInfo::CODE_TARGET, clause->CompareId()); |
| 877 patch_site.EmitPatchInfo(); |
| 868 | 878 |
| 869 __ Branch(&next_test, ne, v0, Operand(zero_reg)); | 879 __ Branch(&next_test, ne, v0, Operand(zero_reg)); |
| 870 __ Drop(1); // Switch value is no longer needed. | 880 __ Drop(1); // Switch value is no longer needed. |
| 871 __ Branch(clause->body_target()); | 881 __ Branch(clause->body_target()); |
| 872 } | 882 } |
| 873 | 883 |
| 874 // Discard the test value and jump to the default if present, otherwise to | 884 // Discard the test value and jump to the default if present, otherwise to |
| 875 // the end of the statement. | 885 // the end of the statement. |
| 876 __ bind(&next_test); | 886 __ bind(&next_test); |
| 877 __ Drop(1); // Switch value is no longer needed. | 887 __ Drop(1); // Switch value is no longer needed. |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 911 __ LoadRoot(at, Heap::kUndefinedValueRootIndex); | 921 __ LoadRoot(at, Heap::kUndefinedValueRootIndex); |
| 912 __ Branch(&exit, eq, a0, Operand(at)); | 922 __ Branch(&exit, eq, a0, Operand(at)); |
| 913 Register null_value = t1; | 923 Register null_value = t1; |
| 914 __ LoadRoot(null_value, Heap::kNullValueRootIndex); | 924 __ LoadRoot(null_value, Heap::kNullValueRootIndex); |
| 915 __ Branch(&exit, eq, a0, Operand(null_value)); | 925 __ Branch(&exit, eq, a0, Operand(null_value)); |
| 916 | 926 |
| 917 // Convert the object to a JS object. | 927 // Convert the object to a JS object. |
| 918 Label convert, done_convert; | 928 Label convert, done_convert; |
| 919 __ JumpIfSmi(a0, &convert); | 929 __ JumpIfSmi(a0, &convert); |
| 920 __ GetObjectType(a0, a1, a1); | 930 __ GetObjectType(a0, a1, a1); |
| 921 __ Branch(&done_convert, hs, a1, Operand(FIRST_JS_OBJECT_TYPE)); | 931 __ Branch(&done_convert, ge, a1, Operand(FIRST_SPEC_OBJECT_TYPE)); |
| 922 __ bind(&convert); | 932 __ bind(&convert); |
| 923 __ push(a0); | 933 __ push(a0); |
| 924 __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION); | 934 __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION); |
| 925 __ mov(a0, v0); | 935 __ mov(a0, v0); |
| 926 __ bind(&done_convert); | 936 __ bind(&done_convert); |
| 927 __ push(a0); | 937 __ push(a0); |
| 928 | 938 |
| 929 // Check cache validity in generated code. This is a fast case for | 939 // Check cache validity in generated code. This is a fast case for |
| 930 // the JSObject::IsSimpleEnum cache validity checks. If we cannot | 940 // the JSObject::IsSimpleEnum cache validity checks. If we cannot |
| 931 // guarantee cache validity, call the runtime system to check cache | 941 // guarantee cache validity, call the runtime system to check cache |
| (...skipping 189 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1121 | 1131 |
| 1122 Scope* s = scope(); | 1132 Scope* s = scope(); |
| 1123 while (s != NULL) { | 1133 while (s != NULL) { |
| 1124 if (s->num_heap_slots() > 0) { | 1134 if (s->num_heap_slots() > 0) { |
| 1125 if (s->calls_eval()) { | 1135 if (s->calls_eval()) { |
| 1126 // Check that extension is NULL. | 1136 // Check that extension is NULL. |
| 1127 __ lw(temp, ContextOperand(current, Context::EXTENSION_INDEX)); | 1137 __ lw(temp, ContextOperand(current, Context::EXTENSION_INDEX)); |
| 1128 __ Branch(slow, ne, temp, Operand(zero_reg)); | 1138 __ Branch(slow, ne, temp, Operand(zero_reg)); |
| 1129 } | 1139 } |
| 1130 // Load next context in chain. | 1140 // Load next context in chain. |
| 1131 __ lw(next, ContextOperand(current, Context::CLOSURE_INDEX)); | 1141 __ lw(next, ContextOperand(current, Context::PREVIOUS_INDEX)); |
| 1132 __ lw(next, FieldMemOperand(next, JSFunction::kContextOffset)); | |
| 1133 // Walk the rest of the chain without clobbering cp. | 1142 // Walk the rest of the chain without clobbering cp. |
| 1134 current = next; | 1143 current = next; |
| 1135 } | 1144 } |
| 1136 // If no outer scope calls eval, we do not need to check more | 1145 // If no outer scope calls eval, we do not need to check more |
| 1137 // context extensions. | 1146 // context extensions. |
| 1138 if (!s->outer_scope_calls_eval() || s->is_eval_scope()) break; | 1147 if (!s->outer_scope_calls_eval() || s->is_eval_scope()) break; |
| 1139 s = s->outer_scope(); | 1148 s = s->outer_scope(); |
| 1140 } | 1149 } |
| 1141 | 1150 |
| 1142 if (s->is_eval_scope()) { | 1151 if (s->is_eval_scope()) { |
| 1143 Label loop, fast; | 1152 Label loop, fast; |
| 1144 if (!current.is(next)) { | 1153 if (!current.is(next)) { |
| 1145 __ Move(next, current); | 1154 __ Move(next, current); |
| 1146 } | 1155 } |
| 1147 __ bind(&loop); | 1156 __ bind(&loop); |
| 1148 // Terminate at global context. | 1157 // Terminate at global context. |
| 1149 __ lw(temp, FieldMemOperand(next, HeapObject::kMapOffset)); | 1158 __ lw(temp, FieldMemOperand(next, HeapObject::kMapOffset)); |
| 1150 __ LoadRoot(t0, Heap::kGlobalContextMapRootIndex); | 1159 __ LoadRoot(t0, Heap::kGlobalContextMapRootIndex); |
| 1151 __ Branch(&fast, eq, temp, Operand(t0)); | 1160 __ Branch(&fast, eq, temp, Operand(t0)); |
| 1152 // Check that extension is NULL. | 1161 // Check that extension is NULL. |
| 1153 __ lw(temp, ContextOperand(next, Context::EXTENSION_INDEX)); | 1162 __ lw(temp, ContextOperand(next, Context::EXTENSION_INDEX)); |
| 1154 __ Branch(slow, ne, temp, Operand(zero_reg)); | 1163 __ Branch(slow, ne, temp, Operand(zero_reg)); |
| 1155 // Load next context in chain. | 1164 // Load next context in chain. |
| 1156 __ lw(next, ContextOperand(next, Context::CLOSURE_INDEX)); | 1165 __ lw(next, ContextOperand(next, Context::PREVIOUS_INDEX)); |
| 1157 __ lw(next, FieldMemOperand(next, JSFunction::kContextOffset)); | |
| 1158 __ Branch(&loop); | 1166 __ Branch(&loop); |
| 1159 __ bind(&fast); | 1167 __ bind(&fast); |
| 1160 } | 1168 } |
| 1161 | 1169 |
| 1162 __ lw(a0, GlobalObjectOperand()); | 1170 __ lw(a0, GlobalObjectOperand()); |
| 1163 __ li(a2, Operand(slot->var()->name())); | 1171 __ li(a2, Operand(slot->var()->name())); |
| 1164 RelocInfo::Mode mode = (typeof_state == INSIDE_TYPEOF) | 1172 RelocInfo::Mode mode = (typeof_state == INSIDE_TYPEOF) |
| 1165 ? RelocInfo::CODE_TARGET | 1173 ? RelocInfo::CODE_TARGET |
| 1166 : RelocInfo::CODE_TARGET_CONTEXT; | 1174 : RelocInfo::CODE_TARGET_CONTEXT; |
| 1167 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize(); | 1175 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize(); |
| 1168 EmitCallIC(ic, mode, AstNode::kNoNumber); | 1176 __ Call(ic, mode); |
| 1169 } | 1177 } |
| 1170 | 1178 |
| 1171 | 1179 |
| 1172 MemOperand FullCodeGenerator::ContextSlotOperandCheckExtensions( | 1180 MemOperand FullCodeGenerator::ContextSlotOperandCheckExtensions( |
| 1173 Slot* slot, | 1181 Slot* slot, |
| 1174 Label* slow) { | 1182 Label* slow) { |
| 1175 ASSERT(slot->type() == Slot::CONTEXT); | 1183 ASSERT(slot->type() == Slot::CONTEXT); |
| 1176 Register context = cp; | 1184 Register context = cp; |
| 1177 Register next = a3; | 1185 Register next = a3; |
| 1178 Register temp = t0; | 1186 Register temp = t0; |
| 1179 | 1187 |
| 1180 for (Scope* s = scope(); s != slot->var()->scope(); s = s->outer_scope()) { | 1188 for (Scope* s = scope(); s != slot->var()->scope(); s = s->outer_scope()) { |
| 1181 if (s->num_heap_slots() > 0) { | 1189 if (s->num_heap_slots() > 0) { |
| 1182 if (s->calls_eval()) { | 1190 if (s->calls_eval()) { |
| 1183 // Check that extension is NULL. | 1191 // Check that extension is NULL. |
| 1184 __ lw(temp, ContextOperand(context, Context::EXTENSION_INDEX)); | 1192 __ lw(temp, ContextOperand(context, Context::EXTENSION_INDEX)); |
| 1185 __ Branch(slow, ne, temp, Operand(zero_reg)); | 1193 __ Branch(slow, ne, temp, Operand(zero_reg)); |
| 1186 } | 1194 } |
| 1187 __ lw(next, ContextOperand(context, Context::CLOSURE_INDEX)); | 1195 __ lw(next, ContextOperand(context, Context::PREVIOUS_INDEX)); |
| 1188 __ lw(next, FieldMemOperand(next, JSFunction::kContextOffset)); | |
| 1189 // Walk the rest of the chain without clobbering cp. | 1196 // Walk the rest of the chain without clobbering cp. |
| 1190 context = next; | 1197 context = next; |
| 1191 } | 1198 } |
| 1192 } | 1199 } |
| 1193 // Check that last extension is NULL. | 1200 // Check that last extension is NULL. |
| 1194 __ lw(temp, ContextOperand(context, Context::EXTENSION_INDEX)); | 1201 __ lw(temp, ContextOperand(context, Context::EXTENSION_INDEX)); |
| 1195 __ Branch(slow, ne, temp, Operand(zero_reg)); | 1202 __ Branch(slow, ne, temp, Operand(zero_reg)); |
| 1196 | 1203 |
| 1197 // This function is used only for loads, not stores, so it's safe to | 1204 // This function is used only for loads, not stores, so it's safe to |
| 1198 // return an cp-based operand (the write barrier cannot be allowed to | 1205 // return an cp-based operand (the write barrier cannot be allowed to |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1239 key_literal->handle()->IsSmi()) { | 1246 key_literal->handle()->IsSmi()) { |
| 1240 // Load arguments object if there are no eval-introduced | 1247 // Load arguments object if there are no eval-introduced |
| 1241 // variables. Then load the argument from the arguments | 1248 // variables. Then load the argument from the arguments |
| 1242 // object using keyed load. | 1249 // object using keyed load. |
| 1243 __ lw(a1, | 1250 __ lw(a1, |
| 1244 ContextSlotOperandCheckExtensions(obj_proxy->var()->AsSlot(), | 1251 ContextSlotOperandCheckExtensions(obj_proxy->var()->AsSlot(), |
| 1245 slow)); | 1252 slow)); |
| 1246 __ li(a0, Operand(key_literal->handle())); | 1253 __ li(a0, Operand(key_literal->handle())); |
| 1247 Handle<Code> ic = | 1254 Handle<Code> ic = |
| 1248 isolate()->builtins()->KeyedLoadIC_Initialize(); | 1255 isolate()->builtins()->KeyedLoadIC_Initialize(); |
| 1249 EmitCallIC(ic, RelocInfo::CODE_TARGET, GetPropertyId(property)); | 1256 __ Call(ic, RelocInfo::CODE_TARGET, GetPropertyId(property)); |
| 1250 __ Branch(done); | 1257 __ Branch(done); |
| 1251 } | 1258 } |
| 1252 } | 1259 } |
| 1253 } | 1260 } |
| 1254 } | 1261 } |
| 1255 } | 1262 } |
| 1256 | 1263 |
| 1257 | 1264 |
| 1258 void FullCodeGenerator::EmitVariableLoad(Variable* var) { | 1265 void FullCodeGenerator::EmitVariableLoad(Variable* var) { |
| 1259 // Four cases: non-this global variables, lookup slots, all other | 1266 // Three cases: non-this global variables, lookup slots, and all other |
| 1260 // types of slots, and parameters that rewrite to explicit property | 1267 // types of slots. |
| 1261 // accesses on the arguments object. | |
| 1262 Slot* slot = var->AsSlot(); | 1268 Slot* slot = var->AsSlot(); |
| 1263 Property* property = var->AsProperty(); | 1269 ASSERT((var->is_global() && !var->is_this()) == (slot == NULL)); |
| 1264 | 1270 |
| 1265 if (var->is_global() && !var->is_this()) { | 1271 if (slot == NULL) { |
| 1266 Comment cmnt(masm_, "Global variable"); | 1272 Comment cmnt(masm_, "Global variable"); |
| 1267 // Use inline caching. Variable name is passed in a2 and the global | 1273 // Use inline caching. Variable name is passed in a2 and the global |
| 1268 // object (receiver) in a0. | 1274 // object (receiver) in a0. |
| 1269 __ lw(a0, GlobalObjectOperand()); | 1275 __ lw(a0, GlobalObjectOperand()); |
| 1270 __ li(a2, Operand(var->name())); | 1276 __ li(a2, Operand(var->name())); |
| 1271 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize(); | 1277 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize(); |
| 1272 EmitCallIC(ic, RelocInfo::CODE_TARGET_CONTEXT, AstNode::kNoNumber); | 1278 __ Call(ic, RelocInfo::CODE_TARGET_CONTEXT); |
| 1273 context()->Plug(v0); | 1279 context()->Plug(v0); |
| 1274 | 1280 |
| 1275 } else if (slot != NULL && slot->type() == Slot::LOOKUP) { | 1281 } else if (slot->type() == Slot::LOOKUP) { |
| 1276 Label done, slow; | 1282 Label done, slow; |
| 1277 | 1283 |
| 1278 // Generate code for loading from variables potentially shadowed | 1284 // Generate code for loading from variables potentially shadowed |
| 1279 // by eval-introduced variables. | 1285 // by eval-introduced variables. |
| 1280 EmitDynamicLoadFromSlotFastCase(slot, NOT_INSIDE_TYPEOF, &slow, &done); | 1286 EmitDynamicLoadFromSlotFastCase(slot, NOT_INSIDE_TYPEOF, &slow, &done); |
| 1281 | 1287 |
| 1282 __ bind(&slow); | 1288 __ bind(&slow); |
| 1283 Comment cmnt(masm_, "Lookup slot"); | 1289 Comment cmnt(masm_, "Lookup slot"); |
| 1284 __ li(a1, Operand(var->name())); | 1290 __ li(a1, Operand(var->name())); |
| 1285 __ Push(cp, a1); // Context and name. | 1291 __ Push(cp, a1); // Context and name. |
| 1286 __ CallRuntime(Runtime::kLoadContextSlot, 2); | 1292 __ CallRuntime(Runtime::kLoadContextSlot, 2); |
| 1287 __ bind(&done); | 1293 __ bind(&done); |
| 1288 | 1294 |
| 1289 context()->Plug(v0); | 1295 context()->Plug(v0); |
| 1290 | 1296 |
| 1291 } else if (slot != NULL) { | 1297 } else { |
| 1292 Comment cmnt(masm_, (slot->type() == Slot::CONTEXT) | 1298 Comment cmnt(masm_, (slot->type() == Slot::CONTEXT) |
| 1293 ? "Context slot" | 1299 ? "Context slot" |
| 1294 : "Stack slot"); | 1300 : "Stack slot"); |
| 1295 if (var->mode() == Variable::CONST) { | 1301 if (var->mode() == Variable::CONST) { |
| 1296 // Constants may be the hole value if they have not been initialized. | 1302 // Constants may be the hole value if they have not been initialized. |
| 1297 // Unhole them. | 1303 // Unhole them. |
| 1298 MemOperand slot_operand = EmitSlotSearch(slot, a0); | 1304 MemOperand slot_operand = EmitSlotSearch(slot, a0); |
| 1299 __ lw(v0, slot_operand); | 1305 __ lw(v0, slot_operand); |
| 1300 __ LoadRoot(at, Heap::kTheHoleValueRootIndex); | 1306 __ LoadRoot(at, Heap::kTheHoleValueRootIndex); |
| 1301 __ subu(at, v0, at); // Sub as compare: at == 0 on eq. | 1307 __ subu(at, v0, at); // Sub as compare: at == 0 on eq. |
| 1302 __ LoadRoot(a0, Heap::kUndefinedValueRootIndex); | 1308 __ LoadRoot(a0, Heap::kUndefinedValueRootIndex); |
| 1303 __ movz(v0, a0, at); // Conditional move. | 1309 __ movz(v0, a0, at); // Conditional move. |
| 1304 context()->Plug(v0); | 1310 context()->Plug(v0); |
| 1305 } else { | 1311 } else { |
| 1306 context()->Plug(slot); | 1312 context()->Plug(slot); |
| 1307 } | 1313 } |
| 1308 } else { | |
| 1309 Comment cmnt(masm_, "Rewritten parameter"); | |
| 1310 ASSERT_NOT_NULL(property); | |
| 1311 // Rewritten parameter accesses are of the form "slot[literal]". | |
| 1312 // Assert that the object is in a slot. | |
| 1313 Variable* object_var = property->obj()->AsVariableProxy()->AsVariable(); | |
| 1314 ASSERT_NOT_NULL(object_var); | |
| 1315 Slot* object_slot = object_var->AsSlot(); | |
| 1316 ASSERT_NOT_NULL(object_slot); | |
| 1317 | |
| 1318 // Load the object. | |
| 1319 Move(a1, object_slot); | |
| 1320 | |
| 1321 // Assert that the key is a smi. | |
| 1322 Literal* key_literal = property->key()->AsLiteral(); | |
| 1323 ASSERT_NOT_NULL(key_literal); | |
| 1324 ASSERT(key_literal->handle()->IsSmi()); | |
| 1325 | |
| 1326 // Load the key. | |
| 1327 __ li(a0, Operand(key_literal->handle())); | |
| 1328 | |
| 1329 // Call keyed load IC. It has arguments key and receiver in a0 and a1. | |
| 1330 Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Initialize(); | |
| 1331 EmitCallIC(ic, RelocInfo::CODE_TARGET, GetPropertyId(property)); | |
| 1332 context()->Plug(v0); | |
| 1333 } | 1314 } |
| 1334 } | 1315 } |
| 1335 | 1316 |
| 1336 | 1317 |
| 1337 void FullCodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) { | 1318 void FullCodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) { |
| 1338 Comment cmnt(masm_, "[ RegExpLiteral"); | 1319 Comment cmnt(masm_, "[ RegExpLiteral"); |
| 1339 Label materialized; | 1320 Label materialized; |
| 1340 // Registers will be used as follows: | 1321 // Registers will be used as follows: |
| 1341 // t1 = materialized value (RegExp literal) | 1322 // t1 = materialized value (RegExp literal) |
| 1342 // t0 = JS function, literals array | 1323 // t0 = JS function, literals array |
| (...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1433 case ObjectLiteral::Property::COMPUTED: | 1414 case ObjectLiteral::Property::COMPUTED: |
| 1434 if (key->handle()->IsSymbol()) { | 1415 if (key->handle()->IsSymbol()) { |
| 1435 if (property->emit_store()) { | 1416 if (property->emit_store()) { |
| 1436 VisitForAccumulatorValue(value); | 1417 VisitForAccumulatorValue(value); |
| 1437 __ mov(a0, result_register()); | 1418 __ mov(a0, result_register()); |
| 1438 __ li(a2, Operand(key->handle())); | 1419 __ li(a2, Operand(key->handle())); |
| 1439 __ lw(a1, MemOperand(sp)); | 1420 __ lw(a1, MemOperand(sp)); |
| 1440 Handle<Code> ic = is_strict_mode() | 1421 Handle<Code> ic = is_strict_mode() |
| 1441 ? isolate()->builtins()->StoreIC_Initialize_Strict() | 1422 ? isolate()->builtins()->StoreIC_Initialize_Strict() |
| 1442 : isolate()->builtins()->StoreIC_Initialize(); | 1423 : isolate()->builtins()->StoreIC_Initialize(); |
| 1443 EmitCallIC(ic, RelocInfo::CODE_TARGET, key->id()); | 1424 __ Call(ic, RelocInfo::CODE_TARGET, key->id()); |
| 1444 PrepareForBailoutForId(key->id(), NO_REGISTERS); | 1425 PrepareForBailoutForId(key->id(), NO_REGISTERS); |
| 1445 } else { | 1426 } else { |
| 1446 VisitForEffect(value); | 1427 VisitForEffect(value); |
| 1447 } | 1428 } |
| 1448 break; | 1429 break; |
| 1449 } | 1430 } |
| 1450 // Fall through. | 1431 // Fall through. |
| 1451 case ObjectLiteral::Property::PROTOTYPE: | 1432 case ObjectLiteral::Property::PROTOTYPE: |
| 1452 // Duplicate receiver on stack. | 1433 // Duplicate receiver on stack. |
| 1453 __ lw(a0, MemOperand(sp)); | 1434 __ lw(a0, MemOperand(sp)); |
| (...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1566 void FullCodeGenerator::VisitAssignment(Assignment* expr) { | 1547 void FullCodeGenerator::VisitAssignment(Assignment* expr) { |
| 1567 Comment cmnt(masm_, "[ Assignment"); | 1548 Comment cmnt(masm_, "[ Assignment"); |
| 1568 // Invalid left-hand sides are rewritten to have a 'throw ReferenceError' | 1549 // Invalid left-hand sides are rewritten to have a 'throw ReferenceError' |
| 1569 // on the left-hand side. | 1550 // on the left-hand side. |
| 1570 if (!expr->target()->IsValidLeftHandSide()) { | 1551 if (!expr->target()->IsValidLeftHandSide()) { |
| 1571 VisitForEffect(expr->target()); | 1552 VisitForEffect(expr->target()); |
| 1572 return; | 1553 return; |
| 1573 } | 1554 } |
| 1574 | 1555 |
| 1575 // Left-hand side can only be a property, a global or a (parameter or local) | 1556 // Left-hand side can only be a property, a global or a (parameter or local) |
| 1576 // slot. Variables with rewrite to .arguments are treated as KEYED_PROPERTY. | 1557 // slot. |
| 1577 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY }; | 1558 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY }; |
| 1578 LhsKind assign_type = VARIABLE; | 1559 LhsKind assign_type = VARIABLE; |
| 1579 Property* property = expr->target()->AsProperty(); | 1560 Property* property = expr->target()->AsProperty(); |
| 1580 if (property != NULL) { | 1561 if (property != NULL) { |
| 1581 assign_type = (property->key()->IsPropertyName()) | 1562 assign_type = (property->key()->IsPropertyName()) |
| 1582 ? NAMED_PROPERTY | 1563 ? NAMED_PROPERTY |
| 1583 : KEYED_PROPERTY; | 1564 : KEYED_PROPERTY; |
| 1584 } | 1565 } |
| 1585 | 1566 |
| 1586 // Evaluate LHS expression. | 1567 // Evaluate LHS expression. |
| 1587 switch (assign_type) { | 1568 switch (assign_type) { |
| 1588 case VARIABLE: | 1569 case VARIABLE: |
| 1589 // Nothing to do here. | 1570 // Nothing to do here. |
| 1590 break; | 1571 break; |
| 1591 case NAMED_PROPERTY: | 1572 case NAMED_PROPERTY: |
| 1592 if (expr->is_compound()) { | 1573 if (expr->is_compound()) { |
| 1593 // We need the receiver both on the stack and in the accumulator. | 1574 // We need the receiver both on the stack and in the accumulator. |
| 1594 VisitForAccumulatorValue(property->obj()); | 1575 VisitForAccumulatorValue(property->obj()); |
| 1595 __ push(result_register()); | 1576 __ push(result_register()); |
| 1596 } else { | 1577 } else { |
| 1597 VisitForStackValue(property->obj()); | 1578 VisitForStackValue(property->obj()); |
| 1598 } | 1579 } |
| 1599 break; | 1580 break; |
| 1600 case KEYED_PROPERTY: | 1581 case KEYED_PROPERTY: |
| 1601 // We need the key and receiver on both the stack and in v0 and a1. | 1582 // We need the key and receiver on both the stack and in v0 and a1. |
| 1602 if (expr->is_compound()) { | 1583 if (expr->is_compound()) { |
| 1603 if (property->is_arguments_access()) { | 1584 VisitForStackValue(property->obj()); |
| 1604 VariableProxy* obj_proxy = property->obj()->AsVariableProxy(); | 1585 VisitForAccumulatorValue(property->key()); |
| 1605 __ lw(v0, EmitSlotSearch(obj_proxy->var()->AsSlot(), v0)); | |
| 1606 __ push(v0); | |
| 1607 __ li(v0, Operand(property->key()->AsLiteral()->handle())); | |
| 1608 } else { | |
| 1609 VisitForStackValue(property->obj()); | |
| 1610 VisitForAccumulatorValue(property->key()); | |
| 1611 } | |
| 1612 __ lw(a1, MemOperand(sp, 0)); | 1586 __ lw(a1, MemOperand(sp, 0)); |
| 1613 __ push(v0); | 1587 __ push(v0); |
| 1614 } else { | 1588 } else { |
| 1615 if (property->is_arguments_access()) { | 1589 VisitForStackValue(property->obj()); |
| 1616 VariableProxy* obj_proxy = property->obj()->AsVariableProxy(); | 1590 VisitForStackValue(property->key()); |
| 1617 __ lw(a1, EmitSlotSearch(obj_proxy->var()->AsSlot(), v0)); | |
| 1618 __ li(v0, Operand(property->key()->AsLiteral()->handle())); | |
| 1619 __ Push(a1, v0); | |
| 1620 } else { | |
| 1621 VisitForStackValue(property->obj()); | |
| 1622 VisitForStackValue(property->key()); | |
| 1623 } | |
| 1624 } | 1591 } |
| 1625 break; | 1592 break; |
| 1626 } | 1593 } |
| 1627 | 1594 |
| 1628 // For compound assignments we need another deoptimization point after the | 1595 // For compound assignments we need another deoptimization point after the |
| 1629 // variable/property load. | 1596 // variable/property load. |
| 1630 if (expr->is_compound()) { | 1597 if (expr->is_compound()) { |
| 1631 { AccumulatorValueContext context(this); | 1598 { AccumulatorValueContext context(this); |
| 1632 switch (assign_type) { | 1599 switch (assign_type) { |
| 1633 case VARIABLE: | 1600 case VARIABLE: |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1691 } | 1658 } |
| 1692 | 1659 |
| 1693 | 1660 |
| 1694 void FullCodeGenerator::EmitNamedPropertyLoad(Property* prop) { | 1661 void FullCodeGenerator::EmitNamedPropertyLoad(Property* prop) { |
| 1695 SetSourcePosition(prop->position()); | 1662 SetSourcePosition(prop->position()); |
| 1696 Literal* key = prop->key()->AsLiteral(); | 1663 Literal* key = prop->key()->AsLiteral(); |
| 1697 __ mov(a0, result_register()); | 1664 __ mov(a0, result_register()); |
| 1698 __ li(a2, Operand(key->handle())); | 1665 __ li(a2, Operand(key->handle())); |
| 1699 // Call load IC. It has arguments receiver and property name a0 and a2. | 1666 // Call load IC. It has arguments receiver and property name a0 and a2. |
| 1700 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize(); | 1667 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize(); |
| 1701 EmitCallIC(ic, RelocInfo::CODE_TARGET, GetPropertyId(prop)); | 1668 __ Call(ic, RelocInfo::CODE_TARGET, GetPropertyId(prop)); |
| 1702 } | 1669 } |
| 1703 | 1670 |
| 1704 | 1671 |
| 1705 void FullCodeGenerator::EmitKeyedPropertyLoad(Property* prop) { | 1672 void FullCodeGenerator::EmitKeyedPropertyLoad(Property* prop) { |
| 1706 SetSourcePosition(prop->position()); | 1673 SetSourcePosition(prop->position()); |
| 1707 __ mov(a0, result_register()); | 1674 __ mov(a0, result_register()); |
| 1708 // Call keyed load IC. It has arguments key and receiver in a0 and a1. | 1675 // Call keyed load IC. It has arguments key and receiver in a0 and a1. |
| 1709 Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Initialize(); | 1676 Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Initialize(); |
| 1710 EmitCallIC(ic, RelocInfo::CODE_TARGET, GetPropertyId(prop)); | 1677 __ Call(ic, RelocInfo::CODE_TARGET, GetPropertyId(prop)); |
| 1711 } | 1678 } |
| 1712 | 1679 |
| 1713 | 1680 |
| 1714 void FullCodeGenerator::EmitInlineSmiBinaryOp(BinaryOperation* expr, | 1681 void FullCodeGenerator::EmitInlineSmiBinaryOp(BinaryOperation* expr, |
| 1715 Token::Value op, | 1682 Token::Value op, |
| 1716 OverwriteMode mode, | 1683 OverwriteMode mode, |
| 1717 Expression* left_expr, | 1684 Expression* left_expr, |
| 1718 Expression* right_expr) { | 1685 Expression* right_expr) { |
| 1719 Label done, smi_case, stub_call; | 1686 Label done, smi_case, stub_call; |
| 1720 | 1687 |
| 1721 Register scratch1 = a2; | 1688 Register scratch1 = a2; |
| 1722 Register scratch2 = a3; | 1689 Register scratch2 = a3; |
| 1723 | 1690 |
| 1724 // Get the arguments. | 1691 // Get the arguments. |
| 1725 Register left = a1; | 1692 Register left = a1; |
| 1726 Register right = a0; | 1693 Register right = a0; |
| 1727 __ pop(left); | 1694 __ pop(left); |
| 1728 __ mov(a0, result_register()); | 1695 __ mov(a0, result_register()); |
| 1729 | 1696 |
| 1730 // Perform combined smi check on both operands. | 1697 // Perform combined smi check on both operands. |
| 1731 __ Or(scratch1, left, Operand(right)); | 1698 __ Or(scratch1, left, Operand(right)); |
| 1732 STATIC_ASSERT(kSmiTag == 0); | 1699 STATIC_ASSERT(kSmiTag == 0); |
| 1733 JumpPatchSite patch_site(masm_); | 1700 JumpPatchSite patch_site(masm_); |
| 1734 patch_site.EmitJumpIfSmi(scratch1, &smi_case); | 1701 patch_site.EmitJumpIfSmi(scratch1, &smi_case); |
| 1735 | 1702 |
| 1736 __ bind(&stub_call); | 1703 __ bind(&stub_call); |
| 1737 BinaryOpStub stub(op, mode); | 1704 BinaryOpStub stub(op, mode); |
| 1738 EmitCallIC(stub.GetCode(), &patch_site, expr->id()); | 1705 __ Call(stub.GetCode(), RelocInfo::CODE_TARGET, expr->id()); |
| 1706 patch_site.EmitPatchInfo(); |
| 1739 __ jmp(&done); | 1707 __ jmp(&done); |
| 1740 | 1708 |
| 1741 __ bind(&smi_case); | 1709 __ bind(&smi_case); |
| 1742 // Smi case. This code works the same way as the smi-smi case in the type | 1710 // Smi case. This code works the same way as the smi-smi case in the type |
| 1743 // recording binary operation stub, see | 1711 // recording binary operation stub, see |
| 1744 // BinaryOpStub::GenerateSmiSmiOperation for comments. | 1712 // BinaryOpStub::GenerateSmiSmiOperation for comments. |
| 1745 switch (op) { | 1713 switch (op) { |
| 1746 case Token::SAR: | 1714 case Token::SAR: |
| 1747 __ Branch(&stub_call); | 1715 __ Branch(&stub_call); |
| 1748 __ GetLeastBitsFromSmi(scratch1, right, 5); | 1716 __ GetLeastBitsFromSmi(scratch1, right, 5); |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1809 context()->Plug(v0); | 1777 context()->Plug(v0); |
| 1810 } | 1778 } |
| 1811 | 1779 |
| 1812 | 1780 |
| 1813 void FullCodeGenerator::EmitBinaryOp(BinaryOperation* expr, | 1781 void FullCodeGenerator::EmitBinaryOp(BinaryOperation* expr, |
| 1814 Token::Value op, | 1782 Token::Value op, |
| 1815 OverwriteMode mode) { | 1783 OverwriteMode mode) { |
| 1816 __ mov(a0, result_register()); | 1784 __ mov(a0, result_register()); |
| 1817 __ pop(a1); | 1785 __ pop(a1); |
| 1818 BinaryOpStub stub(op, mode); | 1786 BinaryOpStub stub(op, mode); |
| 1819 EmitCallIC(stub.GetCode(), NULL, expr->id()); | 1787 JumpPatchSite patch_site(masm_); // unbound, signals no inlined smi code. |
| 1788 __ Call(stub.GetCode(), RelocInfo::CODE_TARGET, expr->id()); |
| 1789 patch_site.EmitPatchInfo(); |
| 1820 context()->Plug(v0); | 1790 context()->Plug(v0); |
| 1821 } | 1791 } |
| 1822 | 1792 |
| 1823 | 1793 |
| 1824 void FullCodeGenerator::EmitAssignment(Expression* expr, int bailout_ast_id) { | 1794 void FullCodeGenerator::EmitAssignment(Expression* expr, int bailout_ast_id) { |
| 1825 // Invalid left-hand sides are rewritten to have a 'throw | 1795 // Invalid left-hand sides are rewritten to have a 'throw |
| 1826 // ReferenceError' on the left-hand side. | 1796 // ReferenceError' on the left-hand side. |
| 1827 if (!expr->IsValidLeftHandSide()) { | 1797 if (!expr->IsValidLeftHandSide()) { |
| 1828 VisitForEffect(expr); | 1798 VisitForEffect(expr); |
| 1829 return; | 1799 return; |
| 1830 } | 1800 } |
| 1831 | 1801 |
| 1832 // Left-hand side can only be a property, a global or a (parameter or local) | 1802 // Left-hand side can only be a property, a global or a (parameter or local) |
| 1833 // slot. Variables with rewrite to .arguments are treated as KEYED_PROPERTY. | 1803 // slot. |
| 1834 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY }; | 1804 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY }; |
| 1835 LhsKind assign_type = VARIABLE; | 1805 LhsKind assign_type = VARIABLE; |
| 1836 Property* prop = expr->AsProperty(); | 1806 Property* prop = expr->AsProperty(); |
| 1837 if (prop != NULL) { | 1807 if (prop != NULL) { |
| 1838 assign_type = (prop->key()->IsPropertyName()) | 1808 assign_type = (prop->key()->IsPropertyName()) |
| 1839 ? NAMED_PROPERTY | 1809 ? NAMED_PROPERTY |
| 1840 : KEYED_PROPERTY; | 1810 : KEYED_PROPERTY; |
| 1841 } | 1811 } |
| 1842 | 1812 |
| 1843 switch (assign_type) { | 1813 switch (assign_type) { |
| 1844 case VARIABLE: { | 1814 case VARIABLE: { |
| 1845 Variable* var = expr->AsVariableProxy()->var(); | 1815 Variable* var = expr->AsVariableProxy()->var(); |
| 1846 EffectContext context(this); | 1816 EffectContext context(this); |
| 1847 EmitVariableAssignment(var, Token::ASSIGN); | 1817 EmitVariableAssignment(var, Token::ASSIGN); |
| 1848 break; | 1818 break; |
| 1849 } | 1819 } |
| 1850 case NAMED_PROPERTY: { | 1820 case NAMED_PROPERTY: { |
| 1851 __ push(result_register()); // Preserve value. | 1821 __ push(result_register()); // Preserve value. |
| 1852 VisitForAccumulatorValue(prop->obj()); | 1822 VisitForAccumulatorValue(prop->obj()); |
| 1853 __ mov(a1, result_register()); | 1823 __ mov(a1, result_register()); |
| 1854 __ pop(a0); // Restore value. | 1824 __ pop(a0); // Restore value. |
| 1855 __ li(a2, Operand(prop->key()->AsLiteral()->handle())); | 1825 __ li(a2, Operand(prop->key()->AsLiteral()->handle())); |
| 1856 Handle<Code> ic = is_strict_mode() | 1826 Handle<Code> ic = is_strict_mode() |
| 1857 ? isolate()->builtins()->StoreIC_Initialize_Strict() | 1827 ? isolate()->builtins()->StoreIC_Initialize_Strict() |
| 1858 : isolate()->builtins()->StoreIC_Initialize(); | 1828 : isolate()->builtins()->StoreIC_Initialize(); |
| 1859 EmitCallIC(ic, RelocInfo::CODE_TARGET, AstNode::kNoNumber); | 1829 __ Call(ic); |
| 1860 break; | 1830 break; |
| 1861 } | 1831 } |
| 1862 case KEYED_PROPERTY: { | 1832 case KEYED_PROPERTY: { |
| 1863 __ push(result_register()); // Preserve value. | 1833 __ push(result_register()); // Preserve value. |
| 1864 if (prop->is_synthetic()) { | 1834 VisitForStackValue(prop->obj()); |
| 1865 ASSERT(prop->obj()->AsVariableProxy() != NULL); | 1835 VisitForAccumulatorValue(prop->key()); |
| 1866 ASSERT(prop->key()->AsLiteral() != NULL); | 1836 __ mov(a1, result_register()); |
| 1867 { AccumulatorValueContext for_object(this); | 1837 __ pop(a2); |
| 1868 EmitVariableLoad(prop->obj()->AsVariableProxy()->var()); | |
| 1869 } | |
| 1870 __ mov(a2, result_register()); | |
| 1871 __ li(a1, Operand(prop->key()->AsLiteral()->handle())); | |
| 1872 } else { | |
| 1873 VisitForStackValue(prop->obj()); | |
| 1874 VisitForAccumulatorValue(prop->key()); | |
| 1875 __ mov(a1, result_register()); | |
| 1876 __ pop(a2); | |
| 1877 } | |
| 1878 __ pop(a0); // Restore value. | 1838 __ pop(a0); // Restore value. |
| 1879 Handle<Code> ic = is_strict_mode() | 1839 Handle<Code> ic = is_strict_mode() |
| 1880 ? isolate()->builtins()->KeyedStoreIC_Initialize_Strict() | 1840 ? isolate()->builtins()->KeyedStoreIC_Initialize_Strict() |
| 1881 : isolate()->builtins()->KeyedStoreIC_Initialize(); | 1841 : isolate()->builtins()->KeyedStoreIC_Initialize(); |
| 1882 EmitCallIC(ic, RelocInfo::CODE_TARGET, AstNode::kNoNumber); | 1842 __ Call(ic); |
| 1883 break; | 1843 break; |
| 1884 } | 1844 } |
| 1885 } | 1845 } |
| 1886 PrepareForBailoutForId(bailout_ast_id, TOS_REG); | 1846 PrepareForBailoutForId(bailout_ast_id, TOS_REG); |
| 1887 context()->Plug(v0); | 1847 context()->Plug(v0); |
| 1888 } | 1848 } |
| 1889 | 1849 |
| 1890 | 1850 |
| 1891 void FullCodeGenerator::EmitVariableAssignment(Variable* var, | 1851 void FullCodeGenerator::EmitVariableAssignment(Variable* var, |
| 1892 Token::Value op) { | 1852 Token::Value op) { |
| 1893 // Left-hand sides that rewrite to explicit property accesses do not reach | |
| 1894 // here. | |
| 1895 ASSERT(var != NULL); | 1853 ASSERT(var != NULL); |
| 1896 ASSERT(var->is_global() || var->AsSlot() != NULL); | 1854 ASSERT(var->is_global() || var->AsSlot() != NULL); |
| 1897 | 1855 |
| 1898 if (var->is_global()) { | 1856 if (var->is_global()) { |
| 1899 ASSERT(!var->is_this()); | 1857 ASSERT(!var->is_this()); |
| 1900 // Assignment to a global variable. Use inline caching for the | 1858 // Assignment to a global variable. Use inline caching for the |
| 1901 // assignment. Right-hand-side value is passed in a0, variable name in | 1859 // assignment. Right-hand-side value is passed in a0, variable name in |
| 1902 // a2, and the global object in a1. | 1860 // a2, and the global object in a1. |
| 1903 __ mov(a0, result_register()); | 1861 __ mov(a0, result_register()); |
| 1904 __ li(a2, Operand(var->name())); | 1862 __ li(a2, Operand(var->name())); |
| 1905 __ lw(a1, GlobalObjectOperand()); | 1863 __ lw(a1, GlobalObjectOperand()); |
| 1906 Handle<Code> ic = is_strict_mode() | 1864 Handle<Code> ic = is_strict_mode() |
| 1907 ? isolate()->builtins()->StoreIC_Initialize_Strict() | 1865 ? isolate()->builtins()->StoreIC_Initialize_Strict() |
| 1908 : isolate()->builtins()->StoreIC_Initialize(); | 1866 : isolate()->builtins()->StoreIC_Initialize(); |
| 1909 EmitCallIC(ic, RelocInfo::CODE_TARGET_CONTEXT, AstNode::kNoNumber); | 1867 __ Call(ic, RelocInfo::CODE_TARGET_CONTEXT); |
| 1910 | 1868 |
| 1911 } else if (op == Token::INIT_CONST) { | 1869 } else if (op == Token::INIT_CONST) { |
| 1912 // Like var declarations, const declarations are hoisted to function | 1870 // Like var declarations, const declarations are hoisted to function |
| 1913 // scope. However, unlike var initializers, const initializers are able | 1871 // scope. However, unlike var initializers, const initializers are able |
| 1914 // to drill a hole to that function context, even from inside a 'with' | 1872 // to drill a hole to that function context, even from inside a 'with' |
| 1915 // context. We thus bypass the normal static scope lookup. | 1873 // context. We thus bypass the normal static scope lookup. |
| 1916 Slot* slot = var->AsSlot(); | 1874 Slot* slot = var->AsSlot(); |
| 1917 Label skip; | 1875 Label skip; |
| 1918 switch (slot->type()) { | 1876 switch (slot->type()) { |
| 1919 case Slot::PARAMETER: | 1877 case Slot::PARAMETER: |
| 1920 // No const parameters. | 1878 // No const parameters. |
| 1921 UNREACHABLE(); | 1879 UNREACHABLE(); |
| 1922 break; | 1880 break; |
| 1923 case Slot::LOCAL: | 1881 case Slot::LOCAL: |
| 1924 // Detect const reinitialization by checking for the hole value. | 1882 // Detect const reinitialization by checking for the hole value. |
| 1925 __ lw(a1, MemOperand(fp, SlotOffset(slot))); | 1883 __ lw(a1, MemOperand(fp, SlotOffset(slot))); |
| 1926 __ LoadRoot(t0, Heap::kTheHoleValueRootIndex); | 1884 __ LoadRoot(t0, Heap::kTheHoleValueRootIndex); |
| 1927 __ Branch(&skip, ne, a1, Operand(t0)); | 1885 __ Branch(&skip, ne, a1, Operand(t0)); |
| 1928 __ sw(result_register(), MemOperand(fp, SlotOffset(slot))); | 1886 __ sw(result_register(), MemOperand(fp, SlotOffset(slot))); |
| 1929 break; | 1887 break; |
| 1930 case Slot::CONTEXT: { | 1888 case Slot::CONTEXT: |
| 1931 __ lw(a1, ContextOperand(cp, Context::FCONTEXT_INDEX)); | |
| 1932 __ lw(a2, ContextOperand(a1, slot->index())); | |
| 1933 __ LoadRoot(t0, Heap::kTheHoleValueRootIndex); | |
| 1934 __ Branch(&skip, ne, a2, Operand(t0)); | |
| 1935 __ sw(result_register(), ContextOperand(a1, slot->index())); | |
| 1936 int offset = Context::SlotOffset(slot->index()); | |
| 1937 __ mov(a3, result_register()); // Preserve the stored value in v0. | |
| 1938 __ RecordWrite(a1, Operand(offset), a3, a2); | |
| 1939 break; | |
| 1940 } | |
| 1941 case Slot::LOOKUP: | 1889 case Slot::LOOKUP: |
| 1942 __ push(result_register()); | 1890 __ push(result_register()); |
| 1943 __ li(a0, Operand(slot->var()->name())); | 1891 __ li(a0, Operand(slot->var()->name())); |
| 1944 __ Push(cp, a0); // Context and name. | 1892 __ Push(cp, a0); // Context and name. |
| 1945 __ CallRuntime(Runtime::kInitializeConstContextSlot, 3); | 1893 __ CallRuntime(Runtime::kInitializeConstContextSlot, 3); |
| 1946 break; | 1894 break; |
| 1947 } | 1895 } |
| 1948 __ bind(&skip); | 1896 __ bind(&skip); |
| 1949 | 1897 |
| 1950 } else if (var->mode() != Variable::CONST) { | 1898 } else if (var->mode() != Variable::CONST) { |
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2007 // receiver into fast case. | 1955 // receiver into fast case. |
| 2008 if (expr->ends_initialization_block()) { | 1956 if (expr->ends_initialization_block()) { |
| 2009 __ lw(a1, MemOperand(sp)); | 1957 __ lw(a1, MemOperand(sp)); |
| 2010 } else { | 1958 } else { |
| 2011 __ pop(a1); | 1959 __ pop(a1); |
| 2012 } | 1960 } |
| 2013 | 1961 |
| 2014 Handle<Code> ic = is_strict_mode() | 1962 Handle<Code> ic = is_strict_mode() |
| 2015 ? isolate()->builtins()->StoreIC_Initialize_Strict() | 1963 ? isolate()->builtins()->StoreIC_Initialize_Strict() |
| 2016 : isolate()->builtins()->StoreIC_Initialize(); | 1964 : isolate()->builtins()->StoreIC_Initialize(); |
| 2017 EmitCallIC(ic, RelocInfo::CODE_TARGET, expr->id()); | 1965 __ Call(ic, RelocInfo::CODE_TARGET, expr->id()); |
| 2018 | 1966 |
| 2019 // If the assignment ends an initialization block, revert to fast case. | 1967 // If the assignment ends an initialization block, revert to fast case. |
| 2020 if (expr->ends_initialization_block()) { | 1968 if (expr->ends_initialization_block()) { |
| 2021 __ push(v0); // Result of assignment, saved even if not needed. | 1969 __ push(v0); // Result of assignment, saved even if not needed. |
| 2022 // Receiver is under the result value. | 1970 // Receiver is under the result value. |
| 2023 __ lw(t0, MemOperand(sp, kPointerSize)); | 1971 __ lw(t0, MemOperand(sp, kPointerSize)); |
| 2024 __ push(t0); | 1972 __ push(t0); |
| 2025 __ CallRuntime(Runtime::kToFastProperties, 1); | 1973 __ CallRuntime(Runtime::kToFastProperties, 1); |
| 2026 __ pop(v0); | 1974 __ pop(v0); |
| 2027 __ Drop(1); | 1975 __ Drop(1); |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2059 // receiver into fast case. | 2007 // receiver into fast case. |
| 2060 if (expr->ends_initialization_block()) { | 2008 if (expr->ends_initialization_block()) { |
| 2061 __ lw(a2, MemOperand(sp)); | 2009 __ lw(a2, MemOperand(sp)); |
| 2062 } else { | 2010 } else { |
| 2063 __ pop(a2); | 2011 __ pop(a2); |
| 2064 } | 2012 } |
| 2065 | 2013 |
| 2066 Handle<Code> ic = is_strict_mode() | 2014 Handle<Code> ic = is_strict_mode() |
| 2067 ? isolate()->builtins()->KeyedStoreIC_Initialize_Strict() | 2015 ? isolate()->builtins()->KeyedStoreIC_Initialize_Strict() |
| 2068 : isolate()->builtins()->KeyedStoreIC_Initialize(); | 2016 : isolate()->builtins()->KeyedStoreIC_Initialize(); |
| 2069 EmitCallIC(ic, RelocInfo::CODE_TARGET, expr->id()); | 2017 __ Call(ic, RelocInfo::CODE_TARGET, expr->id()); |
| 2070 | 2018 |
| 2071 // If the assignment ends an initialization block, revert to fast case. | 2019 // If the assignment ends an initialization block, revert to fast case. |
| 2072 if (expr->ends_initialization_block()) { | 2020 if (expr->ends_initialization_block()) { |
| 2073 __ push(v0); // Result of assignment, saved even if not needed. | 2021 __ push(v0); // Result of assignment, saved even if not needed. |
| 2074 // Receiver is under the result value. | 2022 // Receiver is under the result value. |
| 2075 __ lw(t0, MemOperand(sp, kPointerSize)); | 2023 __ lw(t0, MemOperand(sp, kPointerSize)); |
| 2076 __ push(t0); | 2024 __ push(t0); |
| 2077 __ CallRuntime(Runtime::kToFastProperties, 1); | 2025 __ CallRuntime(Runtime::kToFastProperties, 1); |
| 2078 __ pop(v0); | 2026 __ pop(v0); |
| 2079 __ Drop(1); | 2027 __ Drop(1); |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2112 VisitForStackValue(args->at(i)); | 2060 VisitForStackValue(args->at(i)); |
| 2113 } | 2061 } |
| 2114 __ li(a2, Operand(name)); | 2062 __ li(a2, Operand(name)); |
| 2115 } | 2063 } |
| 2116 // Record source position for debugger. | 2064 // Record source position for debugger. |
| 2117 SetSourcePosition(expr->position()); | 2065 SetSourcePosition(expr->position()); |
| 2118 // Call the IC initialization code. | 2066 // Call the IC initialization code. |
| 2119 InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP; | 2067 InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP; |
| 2120 Handle<Code> ic = | 2068 Handle<Code> ic = |
| 2121 isolate()->stub_cache()->ComputeCallInitialize(arg_count, in_loop, mode); | 2069 isolate()->stub_cache()->ComputeCallInitialize(arg_count, in_loop, mode); |
| 2122 EmitCallIC(ic, mode, expr->id()); | 2070 __ Call(ic, mode, expr->id()); |
| 2123 RecordJSReturnSite(expr); | 2071 RecordJSReturnSite(expr); |
| 2124 // Restore context register. | 2072 // Restore context register. |
| 2125 __ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); | 2073 __ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); |
| 2126 context()->Plug(v0); | 2074 context()->Plug(v0); |
| 2127 } | 2075 } |
| 2128 | 2076 |
| 2129 | 2077 |
| 2130 void FullCodeGenerator::EmitKeyedCallWithIC(Call* expr, | 2078 void FullCodeGenerator::EmitKeyedCallWithIC(Call* expr, |
| 2131 Expression* key) { | 2079 Expression* key) { |
| 2132 // Load the key. | 2080 // Load the key. |
| (...skipping 13 matching lines...) Expand all Loading... |
| 2146 VisitForStackValue(args->at(i)); | 2094 VisitForStackValue(args->at(i)); |
| 2147 } | 2095 } |
| 2148 } | 2096 } |
| 2149 // Record source position for debugger. | 2097 // Record source position for debugger. |
| 2150 SetSourcePosition(expr->position()); | 2098 SetSourcePosition(expr->position()); |
| 2151 // Call the IC initialization code. | 2099 // Call the IC initialization code. |
| 2152 InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP; | 2100 InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP; |
| 2153 Handle<Code> ic = | 2101 Handle<Code> ic = |
| 2154 isolate()->stub_cache()->ComputeKeyedCallInitialize(arg_count, in_loop); | 2102 isolate()->stub_cache()->ComputeKeyedCallInitialize(arg_count, in_loop); |
| 2155 __ lw(a2, MemOperand(sp, (arg_count + 1) * kPointerSize)); // Key. | 2103 __ lw(a2, MemOperand(sp, (arg_count + 1) * kPointerSize)); // Key. |
| 2156 EmitCallIC(ic, RelocInfo::CODE_TARGET, expr->id()); | 2104 __ Call(ic, RelocInfo::CODE_TARGET, expr->id()); |
| 2157 RecordJSReturnSite(expr); | 2105 RecordJSReturnSite(expr); |
| 2158 // Restore context register. | 2106 // Restore context register. |
| 2159 __ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); | 2107 __ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); |
| 2160 context()->DropAndPlug(1, v0); // Drop the key still on the stack. | 2108 context()->DropAndPlug(1, v0); // Drop the key still on the stack. |
| 2161 } | 2109 } |
| 2162 | 2110 |
| 2163 | 2111 |
| 2164 void FullCodeGenerator::EmitCallWithStub(Call* expr, CallFunctionFlags flags) { | 2112 void FullCodeGenerator::EmitCallWithStub(Call* expr, CallFunctionFlags flags) { |
| 2165 // Code common for calls using the call stub. | 2113 // Code common for calls using the call stub. |
| 2166 ZoneList<Expression*>* args = expr->arguments(); | 2114 ZoneList<Expression*>* args = expr->arguments(); |
| (...skipping 19 matching lines...) Expand all Loading... |
| 2186 int arg_count) { | 2134 int arg_count) { |
| 2187 // Push copy of the first argument or undefined if it doesn't exist. | 2135 // Push copy of the first argument or undefined if it doesn't exist. |
| 2188 if (arg_count > 0) { | 2136 if (arg_count > 0) { |
| 2189 __ lw(a1, MemOperand(sp, arg_count * kPointerSize)); | 2137 __ lw(a1, MemOperand(sp, arg_count * kPointerSize)); |
| 2190 } else { | 2138 } else { |
| 2191 __ LoadRoot(a1, Heap::kUndefinedValueRootIndex); | 2139 __ LoadRoot(a1, Heap::kUndefinedValueRootIndex); |
| 2192 } | 2140 } |
| 2193 __ push(a1); | 2141 __ push(a1); |
| 2194 | 2142 |
| 2195 // Push the receiver of the enclosing function and do runtime call. | 2143 // Push the receiver of the enclosing function and do runtime call. |
| 2196 __ lw(a1, MemOperand(fp, (2 + scope()->num_parameters()) * kPointerSize)); | 2144 int receiver_offset = 2 + info_->scope()->num_parameters(); |
| 2145 __ lw(a1, MemOperand(fp, receiver_offset * kPointerSize)); |
| 2197 __ push(a1); | 2146 __ push(a1); |
| 2198 // Push the strict mode flag. | 2147 // Push the strict mode flag. |
| 2199 __ li(a1, Operand(Smi::FromInt(strict_mode_flag()))); | 2148 __ li(a1, Operand(Smi::FromInt(strict_mode_flag()))); |
| 2200 __ push(a1); | 2149 __ push(a1); |
| 2201 | 2150 |
| 2202 __ CallRuntime(flag == SKIP_CONTEXT_LOOKUP | 2151 __ CallRuntime(flag == SKIP_CONTEXT_LOOKUP |
| 2203 ? Runtime::kResolvePossiblyDirectEvalNoLookup | 2152 ? Runtime::kResolvePossiblyDirectEvalNoLookup |
| 2204 : Runtime::kResolvePossiblyDirectEval, 4); | 2153 : Runtime::kResolvePossiblyDirectEval, 4); |
| 2205 } | 2154 } |
| 2206 | 2155 |
| (...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2303 | 2252 |
| 2304 // If fast case code has been generated, emit code to push the | 2253 // If fast case code has been generated, emit code to push the |
| 2305 // function and receiver and have the slow path jump around this | 2254 // function and receiver and have the slow path jump around this |
| 2306 // code. | 2255 // code. |
| 2307 if (done.is_linked()) { | 2256 if (done.is_linked()) { |
| 2308 Label call; | 2257 Label call; |
| 2309 __ Branch(&call); | 2258 __ Branch(&call); |
| 2310 __ bind(&done); | 2259 __ bind(&done); |
| 2311 // Push function. | 2260 // Push function. |
| 2312 __ push(v0); | 2261 __ push(v0); |
| 2313 // Push global receiver. | 2262 // The receiver is implicitly the global receiver. Indicate this |
| 2314 __ lw(a1, GlobalObjectOperand()); | 2263 // by passing the hole to the call function stub. |
| 2315 __ lw(a1, FieldMemOperand(a1, GlobalObject::kGlobalReceiverOffset)); | 2264 __ LoadRoot(a1, Heap::kTheHoleValueRootIndex); |
| 2316 __ push(a1); | 2265 __ push(a1); |
| 2317 __ bind(&call); | 2266 __ bind(&call); |
| 2318 } | 2267 } |
| 2319 | 2268 |
| 2320 // The receiver is either the global receiver or an object found | 2269 // The receiver is either the global receiver or an object found |
| 2321 // by LoadContextSlot. That object could be the hole if the | 2270 // by LoadContextSlot. That object could be the hole if the |
| 2322 // receiver is implicitly the global object. | 2271 // receiver is implicitly the global object. |
| 2323 EmitCallWithStub(expr, RECEIVER_MIGHT_BE_IMPLICIT); | 2272 EmitCallWithStub(expr, RECEIVER_MIGHT_BE_IMPLICIT); |
| 2324 } else if (fun->AsProperty() != NULL) { | 2273 } else if (fun->AsProperty() != NULL) { |
| 2325 // Call to an object property. | 2274 // Call to an object property. |
| 2326 Property* prop = fun->AsProperty(); | 2275 Property* prop = fun->AsProperty(); |
| 2327 Literal* key = prop->key()->AsLiteral(); | 2276 Literal* key = prop->key()->AsLiteral(); |
| 2328 if (key != NULL && key->handle()->IsSymbol()) { | 2277 if (key != NULL && key->handle()->IsSymbol()) { |
| 2329 // Call to a named property, use call IC. | 2278 // Call to a named property, use call IC. |
| 2330 { PreservePositionScope scope(masm()->positions_recorder()); | 2279 { PreservePositionScope scope(masm()->positions_recorder()); |
| 2331 VisitForStackValue(prop->obj()); | 2280 VisitForStackValue(prop->obj()); |
| 2332 } | 2281 } |
| 2333 EmitCallWithIC(expr, key->handle(), RelocInfo::CODE_TARGET); | 2282 EmitCallWithIC(expr, key->handle(), RelocInfo::CODE_TARGET); |
| 2334 } else { | 2283 } else { |
| 2335 // Call to a keyed property. | 2284 // Call to a keyed property. |
| 2336 // For a synthetic property use keyed load IC followed by function call, | 2285 // For a synthetic property use keyed load IC followed by function call, |
| 2337 // for a regular property use keyed EmitCallIC. | 2286 // for a regular property use EmitKeyedCallWithIC. |
| 2338 if (prop->is_synthetic()) { | 2287 if (prop->is_synthetic()) { |
| 2339 // Do not visit the object and key subexpressions (they are shared | 2288 // Do not visit the object and key subexpressions (they are shared |
| 2340 // by all occurrences of the same rewritten parameter). | 2289 // by all occurrences of the same rewritten parameter). |
| 2341 ASSERT(prop->obj()->AsVariableProxy() != NULL); | 2290 ASSERT(prop->obj()->AsVariableProxy() != NULL); |
| 2342 ASSERT(prop->obj()->AsVariableProxy()->var()->AsSlot() != NULL); | 2291 ASSERT(prop->obj()->AsVariableProxy()->var()->AsSlot() != NULL); |
| 2343 Slot* slot = prop->obj()->AsVariableProxy()->var()->AsSlot(); | 2292 Slot* slot = prop->obj()->AsVariableProxy()->var()->AsSlot(); |
| 2344 MemOperand operand = EmitSlotSearch(slot, a1); | 2293 MemOperand operand = EmitSlotSearch(slot, a1); |
| 2345 __ lw(a1, operand); | 2294 __ lw(a1, operand); |
| 2346 | 2295 |
| 2347 ASSERT(prop->key()->AsLiteral() != NULL); | 2296 ASSERT(prop->key()->AsLiteral() != NULL); |
| 2348 ASSERT(prop->key()->AsLiteral()->handle()->IsSmi()); | 2297 ASSERT(prop->key()->AsLiteral()->handle()->IsSmi()); |
| 2349 __ li(a0, Operand(prop->key()->AsLiteral()->handle())); | 2298 __ li(a0, Operand(prop->key()->AsLiteral()->handle())); |
| 2350 | 2299 |
| 2351 // Record source code position for IC call. | 2300 // Record source code position for IC call. |
| 2352 SetSourcePosition(prop->position()); | 2301 SetSourcePosition(prop->position()); |
| 2353 | 2302 |
| 2354 Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Initialize(); | 2303 Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Initialize(); |
| 2355 EmitCallIC(ic, RelocInfo::CODE_TARGET, GetPropertyId(prop)); | 2304 __ Call(ic, RelocInfo::CODE_TARGET, GetPropertyId(prop)); |
| 2356 __ lw(a1, GlobalObjectOperand()); | 2305 __ lw(a1, GlobalObjectOperand()); |
| 2357 __ lw(a1, FieldMemOperand(a1, GlobalObject::kGlobalReceiverOffset)); | 2306 __ lw(a1, FieldMemOperand(a1, GlobalObject::kGlobalReceiverOffset)); |
| 2358 __ Push(v0, a1); // Function, receiver. | 2307 __ Push(v0, a1); // Function, receiver. |
| 2359 EmitCallWithStub(expr, NO_CALL_FUNCTION_FLAGS); | 2308 EmitCallWithStub(expr, NO_CALL_FUNCTION_FLAGS); |
| 2360 } else { | 2309 } else { |
| 2361 { PreservePositionScope scope(masm()->positions_recorder()); | 2310 { PreservePositionScope scope(masm()->positions_recorder()); |
| 2362 VisitForStackValue(prop->obj()); | 2311 VisitForStackValue(prop->obj()); |
| 2363 } | 2312 } |
| 2364 EmitKeyedCallWithIC(expr, prop->key()); | 2313 EmitKeyedCallWithIC(expr, prop->key()); |
| 2365 } | 2314 } |
| (...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2470 | 2419 |
| 2471 __ JumpIfSmi(v0, if_false); | 2420 __ JumpIfSmi(v0, if_false); |
| 2472 __ LoadRoot(at, Heap::kNullValueRootIndex); | 2421 __ LoadRoot(at, Heap::kNullValueRootIndex); |
| 2473 __ Branch(if_true, eq, v0, Operand(at)); | 2422 __ Branch(if_true, eq, v0, Operand(at)); |
| 2474 __ lw(a2, FieldMemOperand(v0, HeapObject::kMapOffset)); | 2423 __ lw(a2, FieldMemOperand(v0, HeapObject::kMapOffset)); |
| 2475 // Undetectable objects behave like undefined when tested with typeof. | 2424 // Undetectable objects behave like undefined when tested with typeof. |
| 2476 __ lbu(a1, FieldMemOperand(a2, Map::kBitFieldOffset)); | 2425 __ lbu(a1, FieldMemOperand(a2, Map::kBitFieldOffset)); |
| 2477 __ And(at, a1, Operand(1 << Map::kIsUndetectable)); | 2426 __ And(at, a1, Operand(1 << Map::kIsUndetectable)); |
| 2478 __ Branch(if_false, ne, at, Operand(zero_reg)); | 2427 __ Branch(if_false, ne, at, Operand(zero_reg)); |
| 2479 __ lbu(a1, FieldMemOperand(a2, Map::kInstanceTypeOffset)); | 2428 __ lbu(a1, FieldMemOperand(a2, Map::kInstanceTypeOffset)); |
| 2480 __ Branch(if_false, lt, a1, Operand(FIRST_JS_OBJECT_TYPE)); | 2429 __ Branch(if_false, lt, a1, Operand(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE)); |
| 2481 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); | 2430 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); |
| 2482 Split(le, a1, Operand(LAST_JS_OBJECT_TYPE), if_true, if_false, fall_through); | 2431 Split(le, a1, Operand(LAST_NONCALLABLE_SPEC_OBJECT_TYPE), |
| 2432 if_true, if_false, fall_through); |
| 2483 | 2433 |
| 2484 context()->Plug(if_true, if_false); | 2434 context()->Plug(if_true, if_false); |
| 2485 } | 2435 } |
| 2486 | 2436 |
| 2487 | 2437 |
| 2488 void FullCodeGenerator::EmitIsSpecObject(ZoneList<Expression*>* args) { | 2438 void FullCodeGenerator::EmitIsSpecObject(ZoneList<Expression*>* args) { |
| 2489 ASSERT(args->length() == 1); | 2439 ASSERT(args->length() == 1); |
| 2490 | 2440 |
| 2491 VisitForAccumulatorValue(args->at(0)); | 2441 VisitForAccumulatorValue(args->at(0)); |
| 2492 | 2442 |
| 2493 Label materialize_true, materialize_false; | 2443 Label materialize_true, materialize_false; |
| 2494 Label* if_true = NULL; | 2444 Label* if_true = NULL; |
| 2495 Label* if_false = NULL; | 2445 Label* if_false = NULL; |
| 2496 Label* fall_through = NULL; | 2446 Label* fall_through = NULL; |
| 2497 context()->PrepareTest(&materialize_true, &materialize_false, | 2447 context()->PrepareTest(&materialize_true, &materialize_false, |
| 2498 &if_true, &if_false, &fall_through); | 2448 &if_true, &if_false, &fall_through); |
| 2499 | 2449 |
| 2500 __ JumpIfSmi(v0, if_false); | 2450 __ JumpIfSmi(v0, if_false); |
| 2501 __ GetObjectType(v0, a1, a1); | 2451 __ GetObjectType(v0, a1, a1); |
| 2502 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); | 2452 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); |
| 2503 Split(ge, a1, Operand(FIRST_JS_OBJECT_TYPE), | 2453 Split(ge, a1, Operand(FIRST_SPEC_OBJECT_TYPE), |
| 2504 if_true, if_false, fall_through); | 2454 if_true, if_false, fall_through); |
| 2505 | 2455 |
| 2506 context()->Plug(if_true, if_false); | 2456 context()->Plug(if_true, if_false); |
| 2507 } | 2457 } |
| 2508 | 2458 |
| 2509 | 2459 |
| 2510 void FullCodeGenerator::EmitIsUndetectableObject(ZoneList<Expression*>* args) { | 2460 void FullCodeGenerator::EmitIsUndetectableObject(ZoneList<Expression*>* args) { |
| 2511 ASSERT(args->length() == 1); | 2461 ASSERT(args->length() == 1); |
| 2512 | 2462 |
| 2513 VisitForAccumulatorValue(args->at(0)); | 2463 VisitForAccumulatorValue(args->at(0)); |
| (...skipping 217 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2731 } | 2681 } |
| 2732 | 2682 |
| 2733 | 2683 |
| 2734 void FullCodeGenerator::EmitArguments(ZoneList<Expression*>* args) { | 2684 void FullCodeGenerator::EmitArguments(ZoneList<Expression*>* args) { |
| 2735 ASSERT(args->length() == 1); | 2685 ASSERT(args->length() == 1); |
| 2736 | 2686 |
| 2737 // ArgumentsAccessStub expects the key in a1 and the formal | 2687 // ArgumentsAccessStub expects the key in a1 and the formal |
| 2738 // parameter count in a0. | 2688 // parameter count in a0. |
| 2739 VisitForAccumulatorValue(args->at(0)); | 2689 VisitForAccumulatorValue(args->at(0)); |
| 2740 __ mov(a1, v0); | 2690 __ mov(a1, v0); |
| 2741 __ li(a0, Operand(Smi::FromInt(scope()->num_parameters()))); | 2691 __ li(a0, Operand(Smi::FromInt(info_->scope()->num_parameters()))); |
| 2742 ArgumentsAccessStub stub(ArgumentsAccessStub::READ_ELEMENT); | 2692 ArgumentsAccessStub stub(ArgumentsAccessStub::READ_ELEMENT); |
| 2743 __ CallStub(&stub); | 2693 __ CallStub(&stub); |
| 2744 context()->Plug(v0); | 2694 context()->Plug(v0); |
| 2745 } | 2695 } |
| 2746 | 2696 |
| 2747 | 2697 |
| 2748 void FullCodeGenerator::EmitArgumentsLength(ZoneList<Expression*>* args) { | 2698 void FullCodeGenerator::EmitArgumentsLength(ZoneList<Expression*>* args) { |
| 2749 ASSERT(args->length() == 0); | 2699 ASSERT(args->length() == 0); |
| 2750 | 2700 |
| 2751 Label exit; | 2701 Label exit; |
| 2752 // Get the number of formal parameters. | 2702 // Get the number of formal parameters. |
| 2753 __ li(v0, Operand(Smi::FromInt(scope()->num_parameters()))); | 2703 __ li(v0, Operand(Smi::FromInt(info_->scope()->num_parameters()))); |
| 2754 | 2704 |
| 2755 // Check if the calling frame is an arguments adaptor frame. | 2705 // Check if the calling frame is an arguments adaptor frame. |
| 2756 __ lw(a2, MemOperand(fp, StandardFrameConstants::kCallerFPOffset)); | 2706 __ lw(a2, MemOperand(fp, StandardFrameConstants::kCallerFPOffset)); |
| 2757 __ lw(a3, MemOperand(a2, StandardFrameConstants::kContextOffset)); | 2707 __ lw(a3, MemOperand(a2, StandardFrameConstants::kContextOffset)); |
| 2758 __ Branch(&exit, ne, a3, | 2708 __ Branch(&exit, ne, a3, |
| 2759 Operand(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR))); | 2709 Operand(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR))); |
| 2760 | 2710 |
| 2761 // Arguments adaptor case: Read the arguments length from the | 2711 // Arguments adaptor case: Read the arguments length from the |
| 2762 // adaptor frame. | 2712 // adaptor frame. |
| 2763 __ lw(v0, MemOperand(a2, ArgumentsAdaptorFrameConstants::kLengthOffset)); | 2713 __ lw(v0, MemOperand(a2, ArgumentsAdaptorFrameConstants::kLengthOffset)); |
| 2764 | 2714 |
| 2765 __ bind(&exit); | 2715 __ bind(&exit); |
| 2766 context()->Plug(v0); | 2716 context()->Plug(v0); |
| 2767 } | 2717 } |
| 2768 | 2718 |
| 2769 | 2719 |
| 2770 void FullCodeGenerator::EmitClassOf(ZoneList<Expression*>* args) { | 2720 void FullCodeGenerator::EmitClassOf(ZoneList<Expression*>* args) { |
| 2771 ASSERT(args->length() == 1); | 2721 ASSERT(args->length() == 1); |
| 2772 Label done, null, function, non_function_constructor; | 2722 Label done, null, function, non_function_constructor; |
| 2773 | 2723 |
| 2774 VisitForAccumulatorValue(args->at(0)); | 2724 VisitForAccumulatorValue(args->at(0)); |
| 2775 | 2725 |
| 2776 // If the object is a smi, we return null. | 2726 // If the object is a smi, we return null. |
| 2777 __ JumpIfSmi(v0, &null); | 2727 __ JumpIfSmi(v0, &null); |
| 2778 | 2728 |
| 2779 // Check that the object is a JS object but take special care of JS | 2729 // Check that the object is a JS object but take special care of JS |
| 2780 // functions to make sure they have 'Function' as their class. | 2730 // functions to make sure they have 'Function' as their class. |
| 2781 __ GetObjectType(v0, v0, a1); // Map is now in v0. | 2731 __ GetObjectType(v0, v0, a1); // Map is now in v0. |
| 2782 __ Branch(&null, lt, a1, Operand(FIRST_JS_OBJECT_TYPE)); | 2732 __ Branch(&null, lt, a1, Operand(FIRST_SPEC_OBJECT_TYPE)); |
| 2783 | 2733 |
| 2784 // As long as JS_FUNCTION_TYPE is the last instance type and it is | 2734 // As long as LAST_CALLABLE_SPEC_OBJECT_TYPE is the last instance type, and |
| 2785 // right after LAST_JS_OBJECT_TYPE, we can avoid checking for | 2735 // FIRST_CALLABLE_SPEC_OBJECT_TYPE comes right after |
| 2786 // LAST_JS_OBJECT_TYPE. | 2736 // LAST_NONCALLABLE_SPEC_OBJECT_TYPE, we can avoid checking for the latter. |
| 2787 ASSERT(LAST_TYPE == JS_FUNCTION_TYPE); | 2737 STATIC_ASSERT(LAST_TYPE == LAST_CALLABLE_SPEC_OBJECT_TYPE); |
| 2788 ASSERT(JS_FUNCTION_TYPE == LAST_JS_OBJECT_TYPE + 1); | 2738 STATIC_ASSERT(FIRST_CALLABLE_SPEC_OBJECT_TYPE == |
| 2789 __ Branch(&function, eq, a1, Operand(JS_FUNCTION_TYPE)); | 2739 LAST_NONCALLABLE_SPEC_OBJECT_TYPE + 1); |
| 2740 __ Branch(&function, ge, a1, Operand(FIRST_CALLABLE_SPEC_OBJECT_TYPE)); |
| 2790 | 2741 |
| 2791 // Check if the constructor in the map is a function. | 2742 // Check if the constructor in the map is a function. |
| 2792 __ lw(v0, FieldMemOperand(v0, Map::kConstructorOffset)); | 2743 __ lw(v0, FieldMemOperand(v0, Map::kConstructorOffset)); |
| 2793 __ GetObjectType(v0, a1, a1); | 2744 __ GetObjectType(v0, a1, a1); |
| 2794 __ Branch(&non_function_constructor, ne, a1, Operand(JS_FUNCTION_TYPE)); | 2745 __ Branch(&non_function_constructor, ne, a1, Operand(JS_FUNCTION_TYPE)); |
| 2795 | 2746 |
| 2796 // v0 now contains the constructor function. Grab the | 2747 // v0 now contains the constructor function. Grab the |
| 2797 // instance class name from there. | 2748 // instance class name from there. |
| 2798 __ lw(v0, FieldMemOperand(v0, JSFunction::kSharedFunctionInfoOffset)); | 2749 __ lw(v0, FieldMemOperand(v0, JSFunction::kSharedFunctionInfoOffset)); |
| 2799 __ lw(v0, FieldMemOperand(v0, SharedFunctionInfo::kInstanceClassNameOffset)); | 2750 __ lw(v0, FieldMemOperand(v0, SharedFunctionInfo::kInstanceClassNameOffset)); |
| (...skipping 377 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3177 | 3128 |
| 3178 int arg_count = args->length() - 2; // 2 ~ receiver and function. | 3129 int arg_count = args->length() - 2; // 2 ~ receiver and function. |
| 3179 for (int i = 0; i < arg_count + 1; i++) { | 3130 for (int i = 0; i < arg_count + 1; i++) { |
| 3180 VisitForStackValue(args->at(i)); | 3131 VisitForStackValue(args->at(i)); |
| 3181 } | 3132 } |
| 3182 VisitForAccumulatorValue(args->last()); // Function. | 3133 VisitForAccumulatorValue(args->last()); // Function. |
| 3183 | 3134 |
| 3184 // InvokeFunction requires the function in a1. Move it in there. | 3135 // InvokeFunction requires the function in a1. Move it in there. |
| 3185 __ mov(a1, result_register()); | 3136 __ mov(a1, result_register()); |
| 3186 ParameterCount count(arg_count); | 3137 ParameterCount count(arg_count); |
| 3187 __ InvokeFunction(a1, count, CALL_FUNCTION); | 3138 __ InvokeFunction(a1, count, CALL_FUNCTION, |
| 3139 NullCallWrapper(), CALL_AS_METHOD); |
| 3188 __ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); | 3140 __ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); |
| 3189 context()->Plug(v0); | 3141 context()->Plug(v0); |
| 3190 } | 3142 } |
| 3191 | 3143 |
| 3192 | 3144 |
| 3193 void FullCodeGenerator::EmitRegExpConstructResult(ZoneList<Expression*>* args) { | 3145 void FullCodeGenerator::EmitRegExpConstructResult(ZoneList<Expression*>* args) { |
| 3194 RegExpConstructResultStub stub; | 3146 RegExpConstructResultStub stub; |
| 3195 ASSERT(args->length() == 3); | 3147 ASSERT(args->length() == 3); |
| 3196 VisitForStackValue(args->at(0)); | 3148 VisitForStackValue(args->at(0)); |
| 3197 VisitForStackValue(args->at(1)); | 3149 VisitForStackValue(args->at(1)); |
| (...skipping 238 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3436 | 3388 |
| 3437 // Separator operand is on the stack. | 3389 // Separator operand is on the stack. |
| 3438 __ pop(separator); | 3390 __ pop(separator); |
| 3439 | 3391 |
| 3440 // Check that the array is a JSArray. | 3392 // Check that the array is a JSArray. |
| 3441 __ JumpIfSmi(array, &bailout); | 3393 __ JumpIfSmi(array, &bailout); |
| 3442 __ GetObjectType(array, scratch1, scratch2); | 3394 __ GetObjectType(array, scratch1, scratch2); |
| 3443 __ Branch(&bailout, ne, scratch2, Operand(JS_ARRAY_TYPE)); | 3395 __ Branch(&bailout, ne, scratch2, Operand(JS_ARRAY_TYPE)); |
| 3444 | 3396 |
| 3445 // Check that the array has fast elements. | 3397 // Check that the array has fast elements. |
| 3446 __ lbu(scratch2, FieldMemOperand(scratch1, Map::kBitField2Offset)); | 3398 __ CheckFastElements(scratch1, scratch2, &bailout); |
| 3447 __ And(scratch3, scratch2, Operand(1 << Map::kHasFastElements)); | |
| 3448 __ Branch(&bailout, eq, scratch3, Operand(zero_reg)); | |
| 3449 | 3399 |
| 3450 // If the array has length zero, return the empty string. | 3400 // If the array has length zero, return the empty string. |
| 3451 __ lw(array_length, FieldMemOperand(array, JSArray::kLengthOffset)); | 3401 __ lw(array_length, FieldMemOperand(array, JSArray::kLengthOffset)); |
| 3452 __ SmiUntag(array_length); | 3402 __ SmiUntag(array_length); |
| 3453 __ Branch(&non_trivial_array, ne, array_length, Operand(zero_reg)); | 3403 __ Branch(&non_trivial_array, ne, array_length, Operand(zero_reg)); |
| 3454 __ LoadRoot(v0, Heap::kEmptyStringRootIndex); | 3404 __ LoadRoot(v0, Heap::kEmptyStringRootIndex); |
| 3455 __ Branch(&done); | 3405 __ Branch(&done); |
| 3456 | 3406 |
| 3457 __ bind(&non_trivial_array); | 3407 __ bind(&non_trivial_array); |
| 3458 | 3408 |
| (...skipping 183 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3642 ASSERT(result.is(v0)); | 3592 ASSERT(result.is(v0)); |
| 3643 __ Branch(&done); | 3593 __ Branch(&done); |
| 3644 | 3594 |
| 3645 __ bind(&bailout); | 3595 __ bind(&bailout); |
| 3646 __ LoadRoot(v0, Heap::kUndefinedValueRootIndex); | 3596 __ LoadRoot(v0, Heap::kUndefinedValueRootIndex); |
| 3647 __ bind(&done); | 3597 __ bind(&done); |
| 3648 context()->Plug(v0); | 3598 context()->Plug(v0); |
| 3649 } | 3599 } |
| 3650 | 3600 |
| 3651 | 3601 |
| 3602 void FullCodeGenerator::EmitIsNativeOrStrictMode(ZoneList<Expression*>* args) { |
| 3603 ASSERT(args->length() == 1); |
| 3604 |
| 3605 // Load the function into v0. |
| 3606 VisitForAccumulatorValue(args->at(0)); |
| 3607 |
| 3608 // Prepare for the test. |
| 3609 Label materialize_true, materialize_false; |
| 3610 Label* if_true = NULL; |
| 3611 Label* if_false = NULL; |
| 3612 Label* fall_through = NULL; |
| 3613 context()->PrepareTest(&materialize_true, &materialize_false, |
| 3614 &if_true, &if_false, &fall_through); |
| 3615 |
| 3616 // Test for strict mode function. |
| 3617 __ lw(a1, FieldMemOperand(v0, JSFunction::kSharedFunctionInfoOffset)); |
| 3618 __ lw(a1, FieldMemOperand(a1, SharedFunctionInfo::kCompilerHintsOffset)); |
| 3619 __ And(at, a1, Operand(1 << (SharedFunctionInfo::kStrictModeFunction + |
| 3620 kSmiTagSize))); |
| 3621 __ Branch(if_true, ne, at, Operand(zero_reg)); |
| 3622 |
| 3623 // Test for native function. |
| 3624 __ And(at, a1, Operand(1 << (SharedFunctionInfo::kNative + kSmiTagSize))); |
| 3625 __ Branch(if_true, ne, at, Operand(zero_reg)); |
| 3626 |
| 3627 // Not native or strict-mode function. |
| 3628 __ Branch(if_false); |
| 3629 |
| 3630 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); |
| 3631 context()->Plug(if_true, if_false); |
| 3632 } |
| 3633 |
| 3634 |
| 3652 void FullCodeGenerator::VisitCallRuntime(CallRuntime* expr) { | 3635 void FullCodeGenerator::VisitCallRuntime(CallRuntime* expr) { |
| 3653 Handle<String> name = expr->name(); | 3636 Handle<String> name = expr->name(); |
| 3654 if (name->length() > 0 && name->Get(0) == '_') { | 3637 if (name->length() > 0 && name->Get(0) == '_') { |
| 3655 Comment cmnt(masm_, "[ InlineRuntimeCall"); | 3638 Comment cmnt(masm_, "[ InlineRuntimeCall"); |
| 3656 EmitInlineRuntimeCall(expr); | 3639 EmitInlineRuntimeCall(expr); |
| 3657 return; | 3640 return; |
| 3658 } | 3641 } |
| 3659 | 3642 |
| 3660 Comment cmnt(masm_, "[ CallRuntime"); | 3643 Comment cmnt(masm_, "[ CallRuntime"); |
| 3661 ZoneList<Expression*>* args = expr->arguments(); | 3644 ZoneList<Expression*>* args = expr->arguments(); |
| (...skipping 12 matching lines...) Expand all Loading... |
| 3674 } | 3657 } |
| 3675 | 3658 |
| 3676 if (expr->is_jsruntime()) { | 3659 if (expr->is_jsruntime()) { |
| 3677 // Call the JS runtime function. | 3660 // Call the JS runtime function. |
| 3678 __ li(a2, Operand(expr->name())); | 3661 __ li(a2, Operand(expr->name())); |
| 3679 RelocInfo::Mode mode = RelocInfo::CODE_TARGET; | 3662 RelocInfo::Mode mode = RelocInfo::CODE_TARGET; |
| 3680 Handle<Code> ic = | 3663 Handle<Code> ic = |
| 3681 isolate()->stub_cache()->ComputeCallInitialize(arg_count, | 3664 isolate()->stub_cache()->ComputeCallInitialize(arg_count, |
| 3682 NOT_IN_LOOP, | 3665 NOT_IN_LOOP, |
| 3683 mode); | 3666 mode); |
| 3684 EmitCallIC(ic, mode, expr->id()); | 3667 __ Call(ic, mode, expr->id()); |
| 3685 // Restore context register. | 3668 // Restore context register. |
| 3686 __ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); | 3669 __ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); |
| 3687 } else { | 3670 } else { |
| 3688 // Call the C runtime function. | 3671 // Call the C runtime function. |
| 3689 __ CallRuntime(expr->function(), arg_count); | 3672 __ CallRuntime(expr->function(), arg_count); |
| 3690 } | 3673 } |
| 3691 context()->Plug(v0); | 3674 context()->Plug(v0); |
| 3692 } | 3675 } |
| 3693 | 3676 |
| 3694 | 3677 |
| (...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3817 // TODO(svenpanne): Allowing format strings in Comment would be nice here... | 3800 // TODO(svenpanne): Allowing format strings in Comment would be nice here... |
| 3818 Comment cmt(masm_, comment); | 3801 Comment cmt(masm_, comment); |
| 3819 bool can_overwrite = expr->expression()->ResultOverwriteAllowed(); | 3802 bool can_overwrite = expr->expression()->ResultOverwriteAllowed(); |
| 3820 UnaryOverwriteMode overwrite = | 3803 UnaryOverwriteMode overwrite = |
| 3821 can_overwrite ? UNARY_OVERWRITE : UNARY_NO_OVERWRITE; | 3804 can_overwrite ? UNARY_OVERWRITE : UNARY_NO_OVERWRITE; |
| 3822 UnaryOpStub stub(expr->op(), overwrite); | 3805 UnaryOpStub stub(expr->op(), overwrite); |
| 3823 // GenericUnaryOpStub expects the argument to be in a0. | 3806 // GenericUnaryOpStub expects the argument to be in a0. |
| 3824 VisitForAccumulatorValue(expr->expression()); | 3807 VisitForAccumulatorValue(expr->expression()); |
| 3825 SetSourcePosition(expr->position()); | 3808 SetSourcePosition(expr->position()); |
| 3826 __ mov(a0, result_register()); | 3809 __ mov(a0, result_register()); |
| 3827 EmitCallIC(stub.GetCode(), NULL, expr->id()); | 3810 __ Call(stub.GetCode(), RelocInfo::CODE_TARGET, expr->id()); |
| 3828 context()->Plug(v0); | 3811 context()->Plug(v0); |
| 3829 } | 3812 } |
| 3830 | 3813 |
| 3831 | 3814 |
| 3832 void FullCodeGenerator::VisitCountOperation(CountOperation* expr) { | 3815 void FullCodeGenerator::VisitCountOperation(CountOperation* expr) { |
| 3833 Comment cmnt(masm_, "[ CountOperation"); | 3816 Comment cmnt(masm_, "[ CountOperation"); |
| 3834 SetSourcePosition(expr->position()); | 3817 SetSourcePosition(expr->position()); |
| 3835 | 3818 |
| 3836 // Invalid left-hand sides are rewritten to have a 'throw ReferenceError' | 3819 // Invalid left-hand sides are rewritten to have a 'throw ReferenceError' |
| 3837 // as the left-hand side. | 3820 // as the left-hand side. |
| 3838 if (!expr->expression()->IsValidLeftHandSide()) { | 3821 if (!expr->expression()->IsValidLeftHandSide()) { |
| 3839 VisitForEffect(expr->expression()); | 3822 VisitForEffect(expr->expression()); |
| 3840 return; | 3823 return; |
| 3841 } | 3824 } |
| 3842 | 3825 |
| 3843 // Expression can only be a property, a global or a (parameter or local) | 3826 // Expression can only be a property, a global or a (parameter or local) |
| 3844 // slot. Variables with rewrite to .arguments are treated as KEYED_PROPERTY. | 3827 // slot. |
| 3845 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY }; | 3828 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY }; |
| 3846 LhsKind assign_type = VARIABLE; | 3829 LhsKind assign_type = VARIABLE; |
| 3847 Property* prop = expr->expression()->AsProperty(); | 3830 Property* prop = expr->expression()->AsProperty(); |
| 3848 // In case of a property we use the uninitialized expression context | 3831 // In case of a property we use the uninitialized expression context |
| 3849 // of the key to detect a named property. | 3832 // of the key to detect a named property. |
| 3850 if (prop != NULL) { | 3833 if (prop != NULL) { |
| 3851 assign_type = | 3834 assign_type = |
| 3852 (prop->key()->IsPropertyName()) ? NAMED_PROPERTY : KEYED_PROPERTY; | 3835 (prop->key()->IsPropertyName()) ? NAMED_PROPERTY : KEYED_PROPERTY; |
| 3853 } | 3836 } |
| 3854 | 3837 |
| 3855 // Evaluate expression and get value. | 3838 // Evaluate expression and get value. |
| 3856 if (assign_type == VARIABLE) { | 3839 if (assign_type == VARIABLE) { |
| 3857 ASSERT(expr->expression()->AsVariableProxy()->var() != NULL); | 3840 ASSERT(expr->expression()->AsVariableProxy()->var() != NULL); |
| 3858 AccumulatorValueContext context(this); | 3841 AccumulatorValueContext context(this); |
| 3859 EmitVariableLoad(expr->expression()->AsVariableProxy()->var()); | 3842 EmitVariableLoad(expr->expression()->AsVariableProxy()->var()); |
| 3860 } else { | 3843 } else { |
| 3861 // Reserve space for result of postfix operation. | 3844 // Reserve space for result of postfix operation. |
| 3862 if (expr->is_postfix() && !context()->IsEffect()) { | 3845 if (expr->is_postfix() && !context()->IsEffect()) { |
| 3863 __ li(at, Operand(Smi::FromInt(0))); | 3846 __ li(at, Operand(Smi::FromInt(0))); |
| 3864 __ push(at); | 3847 __ push(at); |
| 3865 } | 3848 } |
| 3866 if (assign_type == NAMED_PROPERTY) { | 3849 if (assign_type == NAMED_PROPERTY) { |
| 3867 // Put the object both on the stack and in the accumulator. | 3850 // Put the object both on the stack and in the accumulator. |
| 3868 VisitForAccumulatorValue(prop->obj()); | 3851 VisitForAccumulatorValue(prop->obj()); |
| 3869 __ push(v0); | 3852 __ push(v0); |
| 3870 EmitNamedPropertyLoad(prop); | 3853 EmitNamedPropertyLoad(prop); |
| 3871 } else { | 3854 } else { |
| 3872 if (prop->is_arguments_access()) { | 3855 VisitForStackValue(prop->obj()); |
| 3873 VariableProxy* obj_proxy = prop->obj()->AsVariableProxy(); | 3856 VisitForAccumulatorValue(prop->key()); |
| 3874 __ lw(v0, EmitSlotSearch(obj_proxy->var()->AsSlot(), v0)); | |
| 3875 __ push(v0); | |
| 3876 __ li(v0, Operand(prop->key()->AsLiteral()->handle())); | |
| 3877 } else { | |
| 3878 VisitForStackValue(prop->obj()); | |
| 3879 VisitForAccumulatorValue(prop->key()); | |
| 3880 } | |
| 3881 __ lw(a1, MemOperand(sp, 0)); | 3857 __ lw(a1, MemOperand(sp, 0)); |
| 3882 __ push(v0); | 3858 __ push(v0); |
| 3883 EmitKeyedPropertyLoad(prop); | 3859 EmitKeyedPropertyLoad(prop); |
| 3884 } | 3860 } |
| 3885 } | 3861 } |
| 3886 | 3862 |
| 3887 // We need a second deoptimization point after loading the value | 3863 // We need a second deoptimization point after loading the value |
| 3888 // in case evaluating the property load my have a side effect. | 3864 // in case evaluating the property load my have a side effect. |
| 3889 if (assign_type == VARIABLE) { | 3865 if (assign_type == VARIABLE) { |
| 3890 PrepareForBailout(expr->expression(), TOS_REG); | 3866 PrepareForBailout(expr->expression(), TOS_REG); |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3935 // We could eliminate this smi check if we split the code at | 3911 // We could eliminate this smi check if we split the code at |
| 3936 // the first smi check before calling ToNumber. | 3912 // the first smi check before calling ToNumber. |
| 3937 patch_site.EmitJumpIfSmi(v0, &done); | 3913 patch_site.EmitJumpIfSmi(v0, &done); |
| 3938 __ bind(&stub_call); | 3914 __ bind(&stub_call); |
| 3939 } | 3915 } |
| 3940 | 3916 |
| 3941 // Record position before stub call. | 3917 // Record position before stub call. |
| 3942 SetSourcePosition(expr->position()); | 3918 SetSourcePosition(expr->position()); |
| 3943 | 3919 |
| 3944 BinaryOpStub stub(Token::ADD, NO_OVERWRITE); | 3920 BinaryOpStub stub(Token::ADD, NO_OVERWRITE); |
| 3945 EmitCallIC(stub.GetCode(), &patch_site, expr->CountId()); | 3921 __ Call(stub.GetCode(), RelocInfo::CODE_TARGET, expr->CountId()); |
| 3922 patch_site.EmitPatchInfo(); |
| 3946 __ bind(&done); | 3923 __ bind(&done); |
| 3947 | 3924 |
| 3948 // Store the value returned in v0. | 3925 // Store the value returned in v0. |
| 3949 switch (assign_type) { | 3926 switch (assign_type) { |
| 3950 case VARIABLE: | 3927 case VARIABLE: |
| 3951 if (expr->is_postfix()) { | 3928 if (expr->is_postfix()) { |
| 3952 { EffectContext context(this); | 3929 { EffectContext context(this); |
| 3953 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(), | 3930 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(), |
| 3954 Token::ASSIGN); | 3931 Token::ASSIGN); |
| 3955 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); | 3932 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); |
| (...skipping 11 matching lines...) Expand all Loading... |
| 3967 context()->Plug(v0); | 3944 context()->Plug(v0); |
| 3968 } | 3945 } |
| 3969 break; | 3946 break; |
| 3970 case NAMED_PROPERTY: { | 3947 case NAMED_PROPERTY: { |
| 3971 __ mov(a0, result_register()); // Value. | 3948 __ mov(a0, result_register()); // Value. |
| 3972 __ li(a2, Operand(prop->key()->AsLiteral()->handle())); // Name. | 3949 __ li(a2, Operand(prop->key()->AsLiteral()->handle())); // Name. |
| 3973 __ pop(a1); // Receiver. | 3950 __ pop(a1); // Receiver. |
| 3974 Handle<Code> ic = is_strict_mode() | 3951 Handle<Code> ic = is_strict_mode() |
| 3975 ? isolate()->builtins()->StoreIC_Initialize_Strict() | 3952 ? isolate()->builtins()->StoreIC_Initialize_Strict() |
| 3976 : isolate()->builtins()->StoreIC_Initialize(); | 3953 : isolate()->builtins()->StoreIC_Initialize(); |
| 3977 EmitCallIC(ic, RelocInfo::CODE_TARGET, expr->id()); | 3954 __ Call(ic, RelocInfo::CODE_TARGET, expr->id()); |
| 3978 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); | 3955 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); |
| 3979 if (expr->is_postfix()) { | 3956 if (expr->is_postfix()) { |
| 3980 if (!context()->IsEffect()) { | 3957 if (!context()->IsEffect()) { |
| 3981 context()->PlugTOS(); | 3958 context()->PlugTOS(); |
| 3982 } | 3959 } |
| 3983 } else { | 3960 } else { |
| 3984 context()->Plug(v0); | 3961 context()->Plug(v0); |
| 3985 } | 3962 } |
| 3986 break; | 3963 break; |
| 3987 } | 3964 } |
| 3988 case KEYED_PROPERTY: { | 3965 case KEYED_PROPERTY: { |
| 3989 __ mov(a0, result_register()); // Value. | 3966 __ mov(a0, result_register()); // Value. |
| 3990 __ pop(a1); // Key. | 3967 __ pop(a1); // Key. |
| 3991 __ pop(a2); // Receiver. | 3968 __ pop(a2); // Receiver. |
| 3992 Handle<Code> ic = is_strict_mode() | 3969 Handle<Code> ic = is_strict_mode() |
| 3993 ? isolate()->builtins()->KeyedStoreIC_Initialize_Strict() | 3970 ? isolate()->builtins()->KeyedStoreIC_Initialize_Strict() |
| 3994 : isolate()->builtins()->KeyedStoreIC_Initialize(); | 3971 : isolate()->builtins()->KeyedStoreIC_Initialize(); |
| 3995 EmitCallIC(ic, RelocInfo::CODE_TARGET, expr->id()); | 3972 __ Call(ic, RelocInfo::CODE_TARGET, expr->id()); |
| 3996 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); | 3973 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); |
| 3997 if (expr->is_postfix()) { | 3974 if (expr->is_postfix()) { |
| 3998 if (!context()->IsEffect()) { | 3975 if (!context()->IsEffect()) { |
| 3999 context()->PlugTOS(); | 3976 context()->PlugTOS(); |
| 4000 } | 3977 } |
| 4001 } else { | 3978 } else { |
| 4002 context()->Plug(v0); | 3979 context()->Plug(v0); |
| 4003 } | 3980 } |
| 4004 break; | 3981 break; |
| 4005 } | 3982 } |
| 4006 } | 3983 } |
| 4007 } | 3984 } |
| 4008 | 3985 |
| 4009 | 3986 |
| 4010 void FullCodeGenerator::VisitForTypeofValue(Expression* expr) { | 3987 void FullCodeGenerator::VisitForTypeofValue(Expression* expr) { |
| 4011 VariableProxy* proxy = expr->AsVariableProxy(); | 3988 VariableProxy* proxy = expr->AsVariableProxy(); |
| 4012 if (proxy != NULL && !proxy->var()->is_this() && proxy->var()->is_global()) { | 3989 if (proxy != NULL && !proxy->var()->is_this() && proxy->var()->is_global()) { |
| 4013 Comment cmnt(masm_, "Global variable"); | 3990 Comment cmnt(masm_, "Global variable"); |
| 4014 __ lw(a0, GlobalObjectOperand()); | 3991 __ lw(a0, GlobalObjectOperand()); |
| 4015 __ li(a2, Operand(proxy->name())); | 3992 __ li(a2, Operand(proxy->name())); |
| 4016 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize(); | 3993 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize(); |
| 4017 // Use a regular load, not a contextual load, to avoid a reference | 3994 // Use a regular load, not a contextual load, to avoid a reference |
| 4018 // error. | 3995 // error. |
| 4019 EmitCallIC(ic, RelocInfo::CODE_TARGET, AstNode::kNoNumber); | 3996 __ Call(ic); |
| 4020 PrepareForBailout(expr, TOS_REG); | 3997 PrepareForBailout(expr, TOS_REG); |
| 4021 context()->Plug(v0); | 3998 context()->Plug(v0); |
| 4022 } else if (proxy != NULL && | 3999 } else if (proxy != NULL && |
| 4023 proxy->var()->AsSlot() != NULL && | 4000 proxy->var()->AsSlot() != NULL && |
| 4024 proxy->var()->AsSlot()->type() == Slot::LOOKUP) { | 4001 proxy->var()->AsSlot()->type() == Slot::LOOKUP) { |
| 4025 Label done, slow; | 4002 Label done, slow; |
| 4026 | 4003 |
| 4027 // Generate code for loading from variables potentially shadowed | 4004 // Generate code for loading from variables potentially shadowed |
| 4028 // by eval-introduced variables. | 4005 // by eval-introduced variables. |
| 4029 Slot* slot = proxy->var()->AsSlot(); | 4006 Slot* slot = proxy->var()->AsSlot(); |
| 4030 EmitDynamicLoadFromSlotFastCase(slot, INSIDE_TYPEOF, &slow, &done); | 4007 EmitDynamicLoadFromSlotFastCase(slot, INSIDE_TYPEOF, &slow, &done); |
| 4031 | 4008 |
| 4032 __ bind(&slow); | 4009 __ bind(&slow); |
| 4033 __ li(a0, Operand(proxy->name())); | 4010 __ li(a0, Operand(proxy->name())); |
| 4034 __ Push(cp, a0); | 4011 __ Push(cp, a0); |
| 4035 __ CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2); | 4012 __ CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2); |
| 4036 PrepareForBailout(expr, TOS_REG); | 4013 PrepareForBailout(expr, TOS_REG); |
| 4037 __ bind(&done); | 4014 __ bind(&done); |
| 4038 | 4015 |
| 4039 context()->Plug(v0); | 4016 context()->Plug(v0); |
| 4040 } else { | 4017 } else { |
| 4041 // This expression cannot throw a reference error at the top level. | 4018 // This expression cannot throw a reference error at the top level. |
| 4042 context()->HandleExpression(expr); | 4019 VisitInCurrentContext(expr); |
| 4043 } | 4020 } |
| 4044 } | 4021 } |
| 4045 | 4022 |
| 4046 | 4023 void FullCodeGenerator::EmitLiteralCompareTypeof(Expression* expr, |
| 4047 bool FullCodeGenerator::TryLiteralCompare(Token::Value op, | 4024 Handle<String> check, |
| 4048 Expression* left, | 4025 Label* if_true, |
| 4049 Expression* right, | 4026 Label* if_false, |
| 4050 Label* if_true, | 4027 Label* fall_through) { |
| 4051 Label* if_false, | |
| 4052 Label* fall_through) { | |
| 4053 if (op != Token::EQ && op != Token::EQ_STRICT) return false; | |
| 4054 | |
| 4055 // Check for the pattern: typeof <expression> == <string literal>. | |
| 4056 Literal* right_literal = right->AsLiteral(); | |
| 4057 if (right_literal == NULL) return false; | |
| 4058 Handle<Object> right_literal_value = right_literal->handle(); | |
| 4059 if (!right_literal_value->IsString()) return false; | |
| 4060 UnaryOperation* left_unary = left->AsUnaryOperation(); | |
| 4061 if (left_unary == NULL || left_unary->op() != Token::TYPEOF) return false; | |
| 4062 Handle<String> check = Handle<String>::cast(right_literal_value); | |
| 4063 | |
| 4064 { AccumulatorValueContext context(this); | 4028 { AccumulatorValueContext context(this); |
| 4065 VisitForTypeofValue(left_unary->expression()); | 4029 VisitForTypeofValue(expr); |
| 4066 } | 4030 } |
| 4067 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); | 4031 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); |
| 4068 | 4032 |
| 4069 if (check->Equals(isolate()->heap()->number_symbol())) { | 4033 if (check->Equals(isolate()->heap()->number_symbol())) { |
| 4070 __ JumpIfSmi(v0, if_true); | 4034 __ JumpIfSmi(v0, if_true); |
| 4071 __ lw(v0, FieldMemOperand(v0, HeapObject::kMapOffset)); | 4035 __ lw(v0, FieldMemOperand(v0, HeapObject::kMapOffset)); |
| 4072 __ LoadRoot(at, Heap::kHeapNumberMapRootIndex); | 4036 __ LoadRoot(at, Heap::kHeapNumberMapRootIndex); |
| 4073 Split(eq, v0, Operand(at), if_true, if_false, fall_through); | 4037 Split(eq, v0, Operand(at), if_true, if_false, fall_through); |
| 4074 } else if (check->Equals(isolate()->heap()->string_symbol())) { | 4038 } else if (check->Equals(isolate()->heap()->string_symbol())) { |
| 4075 __ JumpIfSmi(v0, if_false); | 4039 __ JumpIfSmi(v0, if_false); |
| (...skipping 14 matching lines...) Expand all Loading... |
| 4090 __ Branch(if_true, eq, v0, Operand(at)); | 4054 __ Branch(if_true, eq, v0, Operand(at)); |
| 4091 __ JumpIfSmi(v0, if_false); | 4055 __ JumpIfSmi(v0, if_false); |
| 4092 // Check for undetectable objects => true. | 4056 // Check for undetectable objects => true. |
| 4093 __ lw(v0, FieldMemOperand(v0, HeapObject::kMapOffset)); | 4057 __ lw(v0, FieldMemOperand(v0, HeapObject::kMapOffset)); |
| 4094 __ lbu(a1, FieldMemOperand(v0, Map::kBitFieldOffset)); | 4058 __ lbu(a1, FieldMemOperand(v0, Map::kBitFieldOffset)); |
| 4095 __ And(a1, a1, Operand(1 << Map::kIsUndetectable)); | 4059 __ And(a1, a1, Operand(1 << Map::kIsUndetectable)); |
| 4096 Split(ne, a1, Operand(zero_reg), if_true, if_false, fall_through); | 4060 Split(ne, a1, Operand(zero_reg), if_true, if_false, fall_through); |
| 4097 } else if (check->Equals(isolate()->heap()->function_symbol())) { | 4061 } else if (check->Equals(isolate()->heap()->function_symbol())) { |
| 4098 __ JumpIfSmi(v0, if_false); | 4062 __ JumpIfSmi(v0, if_false); |
| 4099 __ GetObjectType(v0, a1, v0); // Leave map in a1. | 4063 __ GetObjectType(v0, a1, v0); // Leave map in a1. |
| 4100 Split(ge, v0, Operand(FIRST_FUNCTION_CLASS_TYPE), | 4064 Split(ge, v0, Operand(FIRST_CALLABLE_SPEC_OBJECT_TYPE), |
| 4101 if_true, if_false, fall_through); | 4065 if_true, if_false, fall_through); |
| 4102 | 4066 |
| 4103 } else if (check->Equals(isolate()->heap()->object_symbol())) { | 4067 } else if (check->Equals(isolate()->heap()->object_symbol())) { |
| 4104 __ JumpIfSmi(v0, if_false); | 4068 __ JumpIfSmi(v0, if_false); |
| 4105 __ LoadRoot(at, Heap::kNullValueRootIndex); | 4069 __ LoadRoot(at, Heap::kNullValueRootIndex); |
| 4106 __ Branch(if_true, eq, v0, Operand(at)); | 4070 __ Branch(if_true, eq, v0, Operand(at)); |
| 4107 // Check for JS objects => true. | 4071 // Check for JS objects => true. |
| 4108 __ GetObjectType(v0, v0, a1); | 4072 __ GetObjectType(v0, v0, a1); |
| 4109 __ Branch(if_false, lo, a1, Operand(FIRST_JS_OBJECT_TYPE)); | 4073 __ Branch(if_false, lt, a1, Operand(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE)); |
| 4110 __ lbu(a1, FieldMemOperand(v0, Map::kInstanceTypeOffset)); | 4074 __ lbu(a1, FieldMemOperand(v0, Map::kInstanceTypeOffset)); |
| 4111 __ Branch(if_false, hs, a1, Operand(FIRST_FUNCTION_CLASS_TYPE)); | 4075 __ Branch(if_false, gt, a1, Operand(LAST_NONCALLABLE_SPEC_OBJECT_TYPE)); |
| 4112 // Check for undetectable objects => false. | 4076 // Check for undetectable objects => false. |
| 4113 __ lbu(a1, FieldMemOperand(v0, Map::kBitFieldOffset)); | 4077 __ lbu(a1, FieldMemOperand(v0, Map::kBitFieldOffset)); |
| 4114 __ And(a1, a1, Operand(1 << Map::kIsUndetectable)); | 4078 __ And(a1, a1, Operand(1 << Map::kIsUndetectable)); |
| 4115 Split(eq, a1, Operand(zero_reg), if_true, if_false, fall_through); | 4079 Split(eq, a1, Operand(zero_reg), if_true, if_false, fall_through); |
| 4116 } else { | 4080 } else { |
| 4117 if (if_false != fall_through) __ jmp(if_false); | 4081 if (if_false != fall_through) __ jmp(if_false); |
| 4118 } | 4082 } |
| 4119 | |
| 4120 return true; | |
| 4121 } | 4083 } |
| 4122 | 4084 |
| 4123 | 4085 |
| 4086 void FullCodeGenerator::EmitLiteralCompareUndefined(Expression* expr, |
| 4087 Label* if_true, |
| 4088 Label* if_false, |
| 4089 Label* fall_through) { |
| 4090 VisitForAccumulatorValue(expr); |
| 4091 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); |
| 4092 |
| 4093 __ LoadRoot(at, Heap::kUndefinedValueRootIndex); |
| 4094 Split(eq, v0, Operand(at), if_true, if_false, fall_through); |
| 4095 } |
| 4096 |
| 4097 |
| 4124 void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) { | 4098 void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) { |
| 4125 Comment cmnt(masm_, "[ CompareOperation"); | 4099 Comment cmnt(masm_, "[ CompareOperation"); |
| 4126 SetSourcePosition(expr->position()); | 4100 SetSourcePosition(expr->position()); |
| 4127 | 4101 |
| 4128 // Always perform the comparison for its control flow. Pack the result | 4102 // Always perform the comparison for its control flow. Pack the result |
| 4129 // into the expression's context after the comparison is performed. | 4103 // into the expression's context after the comparison is performed. |
| 4130 | 4104 |
| 4131 Label materialize_true, materialize_false; | 4105 Label materialize_true, materialize_false; |
| 4132 Label* if_true = NULL; | 4106 Label* if_true = NULL; |
| 4133 Label* if_false = NULL; | 4107 Label* if_false = NULL; |
| 4134 Label* fall_through = NULL; | 4108 Label* fall_through = NULL; |
| 4135 context()->PrepareTest(&materialize_true, &materialize_false, | 4109 context()->PrepareTest(&materialize_true, &materialize_false, |
| 4136 &if_true, &if_false, &fall_through); | 4110 &if_true, &if_false, &fall_through); |
| 4137 | 4111 |
| 4138 // First we try a fast inlined version of the compare when one of | 4112 // First we try a fast inlined version of the compare when one of |
| 4139 // the operands is a literal. | 4113 // the operands is a literal. |
| 4140 Token::Value op = expr->op(); | 4114 if (TryLiteralCompare(expr, if_true, if_false, fall_through)) { |
| 4141 Expression* left = expr->left(); | |
| 4142 Expression* right = expr->right(); | |
| 4143 if (TryLiteralCompare(op, left, right, if_true, if_false, fall_through)) { | |
| 4144 context()->Plug(if_true, if_false); | 4115 context()->Plug(if_true, if_false); |
| 4145 return; | 4116 return; |
| 4146 } | 4117 } |
| 4147 | 4118 |
| 4119 Token::Value op = expr->op(); |
| 4148 VisitForStackValue(expr->left()); | 4120 VisitForStackValue(expr->left()); |
| 4149 switch (op) { | 4121 switch (op) { |
| 4150 case Token::IN: | 4122 case Token::IN: |
| 4151 VisitForStackValue(expr->right()); | 4123 VisitForStackValue(expr->right()); |
| 4152 __ InvokeBuiltin(Builtins::IN, CALL_FUNCTION); | 4124 __ InvokeBuiltin(Builtins::IN, CALL_FUNCTION); |
| 4153 PrepareForBailoutBeforeSplit(TOS_REG, false, NULL, NULL); | 4125 PrepareForBailoutBeforeSplit(TOS_REG, false, NULL, NULL); |
| 4154 __ LoadRoot(t0, Heap::kTrueValueRootIndex); | 4126 __ LoadRoot(t0, Heap::kTrueValueRootIndex); |
| 4155 Split(eq, v0, Operand(t0), if_true, if_false, fall_through); | 4127 Split(eq, v0, Operand(t0), if_true, if_false, fall_through); |
| 4156 break; | 4128 break; |
| 4157 | 4129 |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4211 if (inline_smi_code) { | 4183 if (inline_smi_code) { |
| 4212 Label slow_case; | 4184 Label slow_case; |
| 4213 __ Or(a2, a0, Operand(a1)); | 4185 __ Or(a2, a0, Operand(a1)); |
| 4214 patch_site.EmitJumpIfNotSmi(a2, &slow_case); | 4186 patch_site.EmitJumpIfNotSmi(a2, &slow_case); |
| 4215 Split(cc, a1, Operand(a0), if_true, if_false, NULL); | 4187 Split(cc, a1, Operand(a0), if_true, if_false, NULL); |
| 4216 __ bind(&slow_case); | 4188 __ bind(&slow_case); |
| 4217 } | 4189 } |
| 4218 // Record position and call the compare IC. | 4190 // Record position and call the compare IC. |
| 4219 SetSourcePosition(expr->position()); | 4191 SetSourcePosition(expr->position()); |
| 4220 Handle<Code> ic = CompareIC::GetUninitialized(op); | 4192 Handle<Code> ic = CompareIC::GetUninitialized(op); |
| 4221 EmitCallIC(ic, &patch_site, expr->id()); | 4193 __ Call(ic, RelocInfo::CODE_TARGET, expr->id()); |
| 4194 patch_site.EmitPatchInfo(); |
| 4222 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); | 4195 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); |
| 4223 Split(cc, v0, Operand(zero_reg), if_true, if_false, fall_through); | 4196 Split(cc, v0, Operand(zero_reg), if_true, if_false, fall_through); |
| 4224 } | 4197 } |
| 4225 } | 4198 } |
| 4226 | 4199 |
| 4227 // Convert the result of the comparison into one expected for this | 4200 // Convert the result of the comparison into one expected for this |
| 4228 // expression's context. | 4201 // expression's context. |
| 4229 context()->Plug(if_true, if_false); | 4202 context()->Plug(if_true, if_false); |
| 4230 } | 4203 } |
| 4231 | 4204 |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4270 Register FullCodeGenerator::result_register() { | 4243 Register FullCodeGenerator::result_register() { |
| 4271 return v0; | 4244 return v0; |
| 4272 } | 4245 } |
| 4273 | 4246 |
| 4274 | 4247 |
| 4275 Register FullCodeGenerator::context_register() { | 4248 Register FullCodeGenerator::context_register() { |
| 4276 return cp; | 4249 return cp; |
| 4277 } | 4250 } |
| 4278 | 4251 |
| 4279 | 4252 |
| 4280 void FullCodeGenerator::EmitCallIC(Handle<Code> ic, | |
| 4281 RelocInfo::Mode mode, | |
| 4282 unsigned ast_id) { | |
| 4283 ASSERT(mode == RelocInfo::CODE_TARGET || | |
| 4284 mode == RelocInfo::CODE_TARGET_CONTEXT); | |
| 4285 Counters* counters = isolate()->counters(); | |
| 4286 switch (ic->kind()) { | |
| 4287 case Code::LOAD_IC: | |
| 4288 __ IncrementCounter(counters->named_load_full(), 1, a1, a2); | |
| 4289 break; | |
| 4290 case Code::KEYED_LOAD_IC: | |
| 4291 __ IncrementCounter(counters->keyed_load_full(), 1, a1, a2); | |
| 4292 break; | |
| 4293 case Code::STORE_IC: | |
| 4294 __ IncrementCounter(counters->named_store_full(), 1, a1, a2); | |
| 4295 break; | |
| 4296 case Code::KEYED_STORE_IC: | |
| 4297 __ IncrementCounter(counters->keyed_store_full(), 1, a1, a2); | |
| 4298 default: | |
| 4299 break; | |
| 4300 } | |
| 4301 if (ast_id == kNoASTId || mode == RelocInfo::CODE_TARGET_CONTEXT) { | |
| 4302 __ Call(ic, mode); | |
| 4303 } else { | |
| 4304 ASSERT(mode == RelocInfo::CODE_TARGET); | |
| 4305 mode = RelocInfo::CODE_TARGET_WITH_ID; | |
| 4306 __ CallWithAstId(ic, mode, ast_id); | |
| 4307 } | |
| 4308 } | |
| 4309 | |
| 4310 | |
| 4311 void FullCodeGenerator::EmitCallIC(Handle<Code> ic, | |
| 4312 JumpPatchSite* patch_site, | |
| 4313 unsigned ast_id) { | |
| 4314 Counters* counters = isolate()->counters(); | |
| 4315 switch (ic->kind()) { | |
| 4316 case Code::LOAD_IC: | |
| 4317 __ IncrementCounter(counters->named_load_full(), 1, a1, a2); | |
| 4318 break; | |
| 4319 case Code::KEYED_LOAD_IC: | |
| 4320 __ IncrementCounter(counters->keyed_load_full(), 1, a1, a2); | |
| 4321 break; | |
| 4322 case Code::STORE_IC: | |
| 4323 __ IncrementCounter(counters->named_store_full(), 1, a1, a2); | |
| 4324 break; | |
| 4325 case Code::KEYED_STORE_IC: | |
| 4326 __ IncrementCounter(counters->keyed_store_full(), 1, a1, a2); | |
| 4327 default: | |
| 4328 break; | |
| 4329 } | |
| 4330 | |
| 4331 if (ast_id == kNoASTId) { | |
| 4332 __ Call(ic, RelocInfo::CODE_TARGET); | |
| 4333 } else { | |
| 4334 __ CallWithAstId(ic, RelocInfo::CODE_TARGET_WITH_ID, ast_id); | |
| 4335 } | |
| 4336 if (patch_site != NULL && patch_site->is_bound()) { | |
| 4337 patch_site->EmitPatchInfo(); | |
| 4338 } else { | |
| 4339 __ nop(); // Signals no inlined code. | |
| 4340 } | |
| 4341 } | |
| 4342 | |
| 4343 | |
| 4344 void FullCodeGenerator::StoreToFrameField(int frame_offset, Register value) { | 4253 void FullCodeGenerator::StoreToFrameField(int frame_offset, Register value) { |
| 4345 ASSERT_EQ(POINTER_SIZE_ALIGN(frame_offset), frame_offset); | 4254 ASSERT_EQ(POINTER_SIZE_ALIGN(frame_offset), frame_offset); |
| 4346 __ sw(value, MemOperand(fp, frame_offset)); | 4255 __ sw(value, MemOperand(fp, frame_offset)); |
| 4347 } | 4256 } |
| 4348 | 4257 |
| 4349 | 4258 |
| 4350 void FullCodeGenerator::LoadContextField(Register dst, int context_index) { | 4259 void FullCodeGenerator::LoadContextField(Register dst, int context_index) { |
| 4351 __ lw(dst, ContextOperand(cp, context_index)); | 4260 __ lw(dst, ContextOperand(cp, context_index)); |
| 4352 } | 4261 } |
| 4353 | 4262 |
| 4354 | 4263 |
| 4264 void FullCodeGenerator::PushFunctionArgumentForContextAllocation() { |
| 4265 Scope* declaration_scope = scope()->DeclarationScope(); |
| 4266 if (declaration_scope->is_global_scope()) { |
| 4267 // Contexts nested in the global context have a canonical empty function |
| 4268 // as their closure, not the anonymous closure containing the global |
| 4269 // code. Pass a smi sentinel and let the runtime look up the empty |
| 4270 // function. |
| 4271 __ li(at, Operand(Smi::FromInt(0))); |
| 4272 } else if (declaration_scope->is_eval_scope()) { |
| 4273 // Contexts created by a call to eval have the same closure as the |
| 4274 // context calling eval, not the anonymous closure containing the eval |
| 4275 // code. Fetch it from the context. |
| 4276 __ lw(at, ContextOperand(cp, Context::CLOSURE_INDEX)); |
| 4277 } else { |
| 4278 ASSERT(declaration_scope->is_function_scope()); |
| 4279 __ lw(at, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset)); |
| 4280 } |
| 4281 __ push(at); |
| 4282 } |
| 4283 |
| 4284 |
| 4355 // ---------------------------------------------------------------------------- | 4285 // ---------------------------------------------------------------------------- |
| 4356 // Non-local control flow support. | 4286 // Non-local control flow support. |
| 4357 | 4287 |
| 4358 void FullCodeGenerator::EnterFinallyBlock() { | 4288 void FullCodeGenerator::EnterFinallyBlock() { |
| 4359 ASSERT(!result_register().is(a1)); | 4289 ASSERT(!result_register().is(a1)); |
| 4360 // Store result register while executing finally block. | 4290 // Store result register while executing finally block. |
| 4361 __ push(result_register()); | 4291 __ push(result_register()); |
| 4362 // Cook return address in link register to stack (smi encoded Code* delta). | 4292 // Cook return address in link register to stack (smi encoded Code* delta). |
| 4363 __ Subu(a1, ra, Operand(masm_->CodeObject())); | 4293 __ Subu(a1, ra, Operand(masm_->CodeObject())); |
| 4364 ASSERT_EQ(1, kSmiTagSize + kSmiShiftSize); | 4294 ASSERT_EQ(1, kSmiTagSize + kSmiShiftSize); |
| (...skipping 14 matching lines...) Expand all Loading... |
| 4379 __ Addu(at, a1, Operand(masm_->CodeObject())); | 4309 __ Addu(at, a1, Operand(masm_->CodeObject())); |
| 4380 __ Jump(at); | 4310 __ Jump(at); |
| 4381 } | 4311 } |
| 4382 | 4312 |
| 4383 | 4313 |
| 4384 #undef __ | 4314 #undef __ |
| 4385 | 4315 |
| 4386 } } // namespace v8::internal | 4316 } } // namespace v8::internal |
| 4387 | 4317 |
| 4388 #endif // V8_TARGET_ARCH_MIPS | 4318 #endif // V8_TARGET_ARCH_MIPS |
| OLD | NEW |