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