OLD | NEW |
1 // Copyright 2014 the V8 project authors. All rights reserved. | 1 // Copyright 2015 the V8 project authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #if V8_TARGET_ARCH_PPC | 5 #if V8_TARGET_ARCH_S390 |
6 | 6 |
7 #include "src/ast/scopes.h" | 7 #include "src/ast/scopes.h" |
8 #include "src/code-factory.h" | 8 #include "src/code-factory.h" |
9 #include "src/code-stubs.h" | 9 #include "src/code-stubs.h" |
10 #include "src/codegen.h" | 10 #include "src/codegen.h" |
11 #include "src/debug/debug.h" | 11 #include "src/debug/debug.h" |
12 #include "src/full-codegen/full-codegen.h" | 12 #include "src/full-codegen/full-codegen.h" |
13 #include "src/ic/ic.h" | 13 #include "src/ic/ic.h" |
14 #include "src/parsing/parser.h" | 14 #include "src/parsing/parser.h" |
15 | 15 |
16 #include "src/ppc/code-stubs-ppc.h" | 16 #include "src/s390/code-stubs-s390.h" |
17 #include "src/ppc/macro-assembler-ppc.h" | 17 #include "src/s390/macro-assembler-s390.h" |
18 | 18 |
19 namespace v8 { | 19 namespace v8 { |
20 namespace internal { | 20 namespace internal { |
21 | 21 |
22 #define __ ACCESS_MASM(masm()) | 22 #define __ ACCESS_MASM(masm()) |
23 | 23 |
24 // A patch site is a location in the code which it is possible to patch. This | 24 // A patch site is a location in the code which it is possible to patch. This |
25 // class has a number of methods to emit the code which is patchable and the | 25 // class has a number of methods to emit the code which is patchable and the |
26 // method EmitPatchInfo to record a marker back to the patchable code. This | 26 // method EmitPatchInfo to record a marker back to the patchable code. This |
27 // marker is a cmpi rx, #yyy instruction, and x * 0x0000ffff + yyy (raw 16 bit | 27 // marker is a cmpi rx, #yyy instruction, and x * 0x0000ffff + yyy (raw 16 bit |
28 // immediate value is used) is the delta from the pc to the first instruction of | 28 // immediate value is used) is the delta from the pc to the first instruction of |
29 // the patchable code. | 29 // the patchable code. |
30 // See PatchInlinedSmiCode in ic-ppc.cc for the code that patches it | 30 // See PatchInlinedSmiCode in ic-s390.cc for the code that patches it |
31 class JumpPatchSite BASE_EMBEDDED { | 31 class JumpPatchSite BASE_EMBEDDED { |
32 public: | 32 public: |
33 explicit JumpPatchSite(MacroAssembler* masm) : masm_(masm) { | 33 explicit JumpPatchSite(MacroAssembler* masm) : masm_(masm) { |
34 #ifdef DEBUG | 34 #ifdef DEBUG |
35 info_emitted_ = false; | 35 info_emitted_ = false; |
36 #endif | 36 #endif |
37 } | 37 } |
38 | 38 |
39 ~JumpPatchSite() { DCHECK(patch_site_.is_bound() == info_emitted_); } | 39 ~JumpPatchSite() { DCHECK(patch_site_.is_bound() == info_emitted_); } |
40 | 40 |
41 // When initially emitting this ensure that a jump is always generated to skip | 41 // When initially emitting this ensure that a jump is always generated to skip |
42 // the inlined smi code. | 42 // the inlined smi code. |
43 void EmitJumpIfNotSmi(Register reg, Label* target) { | 43 void EmitJumpIfNotSmi(Register reg, Label* target) { |
44 DCHECK(!patch_site_.is_bound() && !info_emitted_); | 44 DCHECK(!patch_site_.is_bound() && !info_emitted_); |
45 Assembler::BlockTrampolinePoolScope block_trampoline_pool(masm_); | |
46 __ bind(&patch_site_); | 45 __ bind(&patch_site_); |
47 __ cmp(reg, reg, cr0); | 46 __ CmpP(reg, reg); |
48 __ beq(target, cr0); // Always taken before patched. | 47 // Emit the Nop to make bigger place for patching on 31-bit |
| 48 // as the TestIfSmi sequence uses 4-byte TMLL |
| 49 #ifndef V8_TARGET_ARCH_S390X |
| 50 __ nop(); |
| 51 #endif |
| 52 __ beq(target); // Always taken before patched. |
49 } | 53 } |
50 | 54 |
51 // When initially emitting this ensure that a jump is never generated to skip | 55 // When initially emitting this ensure that a jump is never generated to skip |
52 // the inlined smi code. | 56 // the inlined smi code. |
53 void EmitJumpIfSmi(Register reg, Label* target) { | 57 void EmitJumpIfSmi(Register reg, Label* target) { |
54 Assembler::BlockTrampolinePoolScope block_trampoline_pool(masm_); | |
55 DCHECK(!patch_site_.is_bound() && !info_emitted_); | 58 DCHECK(!patch_site_.is_bound() && !info_emitted_); |
56 __ bind(&patch_site_); | 59 __ bind(&patch_site_); |
57 __ cmp(reg, reg, cr0); | 60 __ CmpP(reg, reg); |
58 __ bne(target, cr0); // Never taken before patched. | 61 // Emit the Nop to make bigger place for patching on 31-bit |
| 62 // as the TestIfSmi sequence uses 4-byte TMLL |
| 63 #ifndef V8_TARGET_ARCH_S390X |
| 64 __ nop(); |
| 65 #endif |
| 66 __ bne(target); // Never taken before patched. |
59 } | 67 } |
60 | 68 |
61 void EmitPatchInfo() { | 69 void EmitPatchInfo() { |
62 if (patch_site_.is_bound()) { | 70 if (patch_site_.is_bound()) { |
63 int delta_to_patch_site = masm_->InstructionsGeneratedSince(&patch_site_); | 71 int delta_to_patch_site = masm_->SizeOfCodeGeneratedSince(&patch_site_); |
64 Register reg; | 72 DCHECK(is_int16(delta_to_patch_site)); |
65 // I believe this is using reg as the high bits of of the offset | 73 __ chi(r0, Operand(delta_to_patch_site)); |
66 reg.set_code(delta_to_patch_site / kOff16Mask); | |
67 __ cmpi(reg, Operand(delta_to_patch_site % kOff16Mask)); | |
68 #ifdef DEBUG | 74 #ifdef DEBUG |
69 info_emitted_ = true; | 75 info_emitted_ = true; |
70 #endif | 76 #endif |
71 } else { | 77 } else { |
72 __ nop(); // Signals no inlined code. | 78 __ nop(); |
| 79 __ nop(); |
73 } | 80 } |
74 } | 81 } |
75 | 82 |
76 private: | 83 private: |
77 MacroAssembler* masm() { return masm_; } | 84 MacroAssembler* masm() { return masm_; } |
78 MacroAssembler* masm_; | 85 MacroAssembler* masm_; |
79 Label patch_site_; | 86 Label patch_site_; |
80 #ifdef DEBUG | 87 #ifdef DEBUG |
81 bool info_emitted_; | 88 bool info_emitted_; |
82 #endif | 89 #endif |
83 }; | 90 }; |
84 | 91 |
85 | |
86 // Generate code for a JS function. On entry to the function the receiver | 92 // Generate code for a JS function. On entry to the function the receiver |
87 // and arguments have been pushed on the stack left to right. The actual | 93 // and arguments have been pushed on the stack left to right. The actual |
88 // argument count matches the formal parameter count expected by the | 94 // argument count matches the formal parameter count expected by the |
89 // function. | 95 // function. |
90 // | 96 // |
91 // The live registers are: | 97 // The live registers are: |
92 // o r4: the JS function object being called (i.e., ourselves) | 98 // o r3: the JS function object being called (i.e., ourselves) |
93 // o r6: the new target value | 99 // o r5: the new target value |
94 // o cp: our context | 100 // o cp: our context |
95 // o fp: our caller's frame pointer (aka r31) | 101 // o fp: our caller's frame pointer |
96 // o sp: stack pointer | 102 // o sp: stack pointer |
97 // o lr: return address | 103 // o lr: return address |
98 // o ip: our own function entry (required by the prologue) | 104 // o ip: our own function entry (required by the prologue) |
99 // | 105 // |
100 // The function builds a JS frame. Please see JavaScriptFrameConstants in | 106 // The function builds a JS frame. Please see JavaScriptFrameConstants in |
101 // frames-ppc.h for its layout. | 107 // frames-s390.h for its layout. |
102 void FullCodeGenerator::Generate() { | 108 void FullCodeGenerator::Generate() { |
103 CompilationInfo* info = info_; | 109 CompilationInfo* info = info_; |
104 profiling_counter_ = isolate()->factory()->NewCell( | 110 profiling_counter_ = isolate()->factory()->NewCell( |
105 Handle<Smi>(Smi::FromInt(FLAG_interrupt_budget), isolate())); | 111 Handle<Smi>(Smi::FromInt(FLAG_interrupt_budget), isolate())); |
106 SetFunctionPosition(literal()); | 112 SetFunctionPosition(literal()); |
107 Comment cmnt(masm_, "[ function compiled by full code generator"); | 113 Comment cmnt(masm_, "[ function compiled by full code generator"); |
108 | 114 |
109 ProfileEntryHookStub::MaybeCallEntryHook(masm_); | 115 ProfileEntryHookStub::MaybeCallEntryHook(masm_); |
110 | 116 |
111 if (FLAG_debug_code && info->ExpectsJSReceiverAsReceiver()) { | 117 if (FLAG_debug_code && info->ExpectsJSReceiverAsReceiver()) { |
112 int receiver_offset = info->scope()->num_parameters() * kPointerSize; | 118 int receiver_offset = info->scope()->num_parameters() * kPointerSize; |
113 __ LoadP(r5, MemOperand(sp, receiver_offset), r0); | 119 __ LoadP(r4, MemOperand(sp, receiver_offset), r0); |
114 __ AssertNotSmi(r5); | 120 __ AssertNotSmi(r4); |
115 __ CompareObjectType(r5, r5, no_reg, FIRST_JS_RECEIVER_TYPE); | 121 __ CompareObjectType(r4, r4, no_reg, FIRST_JS_RECEIVER_TYPE); |
116 __ Assert(ge, kSloppyFunctionExpectsJSReceiverReceiver); | 122 __ Assert(ge, kSloppyFunctionExpectsJSReceiverReceiver); |
117 } | 123 } |
118 | 124 |
119 // Open a frame scope to indicate that there is a frame on the stack. The | 125 // Open a frame scope to indicate that there is a frame on the stack. The |
120 // MANUAL indicates that the scope shouldn't actually generate code to set up | 126 // MANUAL indicates that the scope shouldn't actually generate code to set up |
121 // the frame (that is done below). | 127 // the frame (that is done below). |
122 FrameScope frame_scope(masm_, StackFrame::MANUAL); | 128 FrameScope frame_scope(masm_, StackFrame::MANUAL); |
123 int prologue_offset = masm_->pc_offset(); | 129 int prologue_offset = masm_->pc_offset(); |
124 | 130 |
125 if (prologue_offset) { | |
126 // Prologue logic requires it's starting address in ip and the | |
127 // corresponding offset from the function entry. | |
128 prologue_offset += Instruction::kInstrSize; | |
129 __ addi(ip, ip, Operand(prologue_offset)); | |
130 } | |
131 info->set_prologue_offset(prologue_offset); | 131 info->set_prologue_offset(prologue_offset); |
132 __ Prologue(info->GeneratePreagedPrologue(), ip, prologue_offset); | 132 __ Prologue(info->GeneratePreagedPrologue(), ip, prologue_offset); |
133 | 133 |
134 { | 134 { |
135 Comment cmnt(masm_, "[ Allocate locals"); | 135 Comment cmnt(masm_, "[ Allocate locals"); |
136 int locals_count = info->scope()->num_stack_slots(); | 136 int locals_count = info->scope()->num_stack_slots(); |
137 // Generators allocate locals, if any, in context slots. | 137 // Generators allocate locals, if any, in context slots. |
138 DCHECK(!IsGeneratorFunction(info->literal()->kind()) || locals_count == 0); | 138 DCHECK(!IsGeneratorFunction(info->literal()->kind()) || locals_count == 0); |
139 OperandStackDepthIncrement(locals_count); | 139 OperandStackDepthIncrement(locals_count); |
140 if (locals_count > 0) { | 140 if (locals_count > 0) { |
141 if (locals_count >= 128) { | 141 if (locals_count >= 128) { |
142 Label ok; | 142 Label ok; |
143 __ Add(ip, sp, -(locals_count * kPointerSize), r0); | 143 __ AddP(ip, sp, Operand(-(locals_count * kPointerSize))); |
144 __ LoadRoot(r5, Heap::kRealStackLimitRootIndex); | 144 __ LoadRoot(r5, Heap::kRealStackLimitRootIndex); |
145 __ cmpl(ip, r5); | 145 __ CmpLogicalP(ip, r5); |
146 __ bc_short(ge, &ok); | 146 __ bge(&ok, Label::kNear); |
147 __ CallRuntime(Runtime::kThrowStackOverflow); | 147 __ CallRuntime(Runtime::kThrowStackOverflow); |
148 __ bind(&ok); | 148 __ bind(&ok); |
149 } | 149 } |
150 __ LoadRoot(ip, Heap::kUndefinedValueRootIndex); | 150 __ LoadRoot(ip, Heap::kUndefinedValueRootIndex); |
151 int kMaxPushes = FLAG_optimize_for_size ? 4 : 32; | 151 int kMaxPushes = FLAG_optimize_for_size ? 4 : 32; |
152 if (locals_count >= kMaxPushes) { | 152 if (locals_count >= kMaxPushes) { |
153 int loop_iterations = locals_count / kMaxPushes; | 153 int loop_iterations = locals_count / kMaxPushes; |
154 __ mov(r5, Operand(loop_iterations)); | 154 __ mov(r4, Operand(loop_iterations)); |
155 __ mtctr(r5); | |
156 Label loop_header; | 155 Label loop_header; |
157 __ bind(&loop_header); | 156 __ bind(&loop_header); |
158 // Do pushes. | 157 // Do pushes. |
| 158 // TODO(joransiu): Use MVC for better performance |
| 159 __ lay(sp, MemOperand(sp, -kMaxPushes * kPointerSize)); |
159 for (int i = 0; i < kMaxPushes; i++) { | 160 for (int i = 0; i < kMaxPushes; i++) { |
160 __ push(ip); | 161 __ StoreP(ip, MemOperand(sp, i * kPointerSize)); |
161 } | 162 } |
162 // Continue loop if not done. | 163 // Continue loop if not done. |
163 __ bdnz(&loop_header); | 164 __ BranchOnCount(r4, &loop_header); |
164 } | 165 } |
165 int remaining = locals_count % kMaxPushes; | 166 int remaining = locals_count % kMaxPushes; |
166 // Emit the remaining pushes. | 167 // Emit the remaining pushes. |
167 for (int i = 0; i < remaining; i++) { | 168 // TODO(joransiu): Use MVC for better performance |
168 __ push(ip); | 169 if (remaining > 0) { |
| 170 __ lay(sp, MemOperand(sp, -remaining * kPointerSize)); |
| 171 for (int i = 0; i < remaining; i++) { |
| 172 __ StoreP(ip, MemOperand(sp, i * kPointerSize)); |
| 173 } |
169 } | 174 } |
170 } | 175 } |
171 } | 176 } |
172 | 177 |
173 bool function_in_register_r4 = true; | 178 bool function_in_register_r3 = true; |
174 | 179 |
175 // Possibly allocate a local context. | 180 // Possibly allocate a local context. |
176 if (info->scope()->num_heap_slots() > 0) { | 181 if (info->scope()->num_heap_slots() > 0) { |
177 // Argument to NewContext is the function, which is still in r4. | 182 // Argument to NewContext is the function, which is still in r3. |
178 Comment cmnt(masm_, "[ Allocate context"); | 183 Comment cmnt(masm_, "[ Allocate context"); |
179 bool need_write_barrier = true; | 184 bool need_write_barrier = true; |
180 int slots = info->scope()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS; | 185 int slots = info->scope()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS; |
181 if (info->scope()->is_script_scope()) { | 186 if (info->scope()->is_script_scope()) { |
182 __ push(r4); | 187 __ push(r3); |
183 __ Push(info->scope()->GetScopeInfo(info->isolate())); | 188 __ Push(info->scope()->GetScopeInfo(info->isolate())); |
184 __ CallRuntime(Runtime::kNewScriptContext); | 189 __ CallRuntime(Runtime::kNewScriptContext); |
185 PrepareForBailoutForId(BailoutId::ScriptContext(), TOS_REG); | 190 PrepareForBailoutForId(BailoutId::ScriptContext(), TOS_REG); |
186 // The new target value is not used, clobbering is safe. | 191 // The new target value is not used, clobbering is safe. |
187 DCHECK_NULL(info->scope()->new_target_var()); | 192 DCHECK_NULL(info->scope()->new_target_var()); |
188 } else { | 193 } else { |
189 if (info->scope()->new_target_var() != nullptr) { | 194 if (info->scope()->new_target_var() != nullptr) { |
190 __ push(r6); // Preserve new target. | 195 __ push(r5); // Preserve new target. |
191 } | 196 } |
192 if (slots <= FastNewContextStub::kMaximumSlots) { | 197 if (slots <= FastNewContextStub::kMaximumSlots) { |
193 FastNewContextStub stub(isolate(), slots); | 198 FastNewContextStub stub(isolate(), slots); |
194 __ CallStub(&stub); | 199 __ CallStub(&stub); |
195 // Result of FastNewContextStub is always in new space. | 200 // Result of FastNewContextStub is always in new space. |
196 need_write_barrier = false; | 201 need_write_barrier = false; |
197 } else { | 202 } else { |
198 __ push(r4); | 203 __ push(r3); |
199 __ CallRuntime(Runtime::kNewFunctionContext); | 204 __ CallRuntime(Runtime::kNewFunctionContext); |
200 } | 205 } |
201 if (info->scope()->new_target_var() != nullptr) { | 206 if (info->scope()->new_target_var() != nullptr) { |
202 __ pop(r6); // Preserve new target. | 207 __ pop(r5); // Preserve new target. |
203 } | 208 } |
204 } | 209 } |
205 function_in_register_r4 = false; | 210 function_in_register_r3 = false; |
206 // Context is returned in r3. It replaces the context passed to us. | 211 // Context is returned in r2. It replaces the context passed to us. |
207 // It's saved in the stack and kept live in cp. | 212 // It's saved in the stack and kept live in cp. |
208 __ mr(cp, r3); | 213 __ LoadRR(cp, r2); |
209 __ StoreP(r3, MemOperand(fp, StandardFrameConstants::kContextOffset)); | 214 __ StoreP(r2, MemOperand(fp, StandardFrameConstants::kContextOffset)); |
210 // Copy any necessary parameters into the context. | 215 // Copy any necessary parameters into the context. |
211 int num_parameters = info->scope()->num_parameters(); | 216 int num_parameters = info->scope()->num_parameters(); |
212 int first_parameter = info->scope()->has_this_declaration() ? -1 : 0; | 217 int first_parameter = info->scope()->has_this_declaration() ? -1 : 0; |
213 for (int i = first_parameter; i < num_parameters; i++) { | 218 for (int i = first_parameter; i < num_parameters; i++) { |
214 Variable* var = (i == -1) ? scope()->receiver() : scope()->parameter(i); | 219 Variable* var = (i == -1) ? scope()->receiver() : scope()->parameter(i); |
215 if (var->IsContextSlot()) { | 220 if (var->IsContextSlot()) { |
216 int parameter_offset = StandardFrameConstants::kCallerSPOffset + | 221 int parameter_offset = StandardFrameConstants::kCallerSPOffset + |
217 (num_parameters - 1 - i) * kPointerSize; | 222 (num_parameters - 1 - i) * kPointerSize; |
218 // Load parameter from stack. | 223 // Load parameter from stack. |
219 __ LoadP(r3, MemOperand(fp, parameter_offset), r0); | 224 __ LoadP(r2, MemOperand(fp, parameter_offset), r0); |
220 // Store it in the context. | 225 // Store it in the context. |
221 MemOperand target = ContextMemOperand(cp, var->index()); | 226 MemOperand target = ContextMemOperand(cp, var->index()); |
222 __ StoreP(r3, target, r0); | 227 __ StoreP(r2, target); |
223 | 228 |
224 // Update the write barrier. | 229 // Update the write barrier. |
225 if (need_write_barrier) { | 230 if (need_write_barrier) { |
226 __ RecordWriteContextSlot(cp, target.offset(), r3, r5, | 231 __ RecordWriteContextSlot(cp, target.offset(), r2, r4, |
227 kLRHasBeenSaved, kDontSaveFPRegs); | 232 kLRHasBeenSaved, kDontSaveFPRegs); |
228 } else if (FLAG_debug_code) { | 233 } else if (FLAG_debug_code) { |
229 Label done; | 234 Label done; |
230 __ JumpIfInNewSpace(cp, r3, &done); | 235 __ JumpIfInNewSpace(cp, r2, &done); |
231 __ Abort(kExpectedNewSpaceObject); | 236 __ Abort(kExpectedNewSpaceObject); |
232 __ bind(&done); | 237 __ bind(&done); |
233 } | 238 } |
234 } | 239 } |
235 } | 240 } |
236 } | 241 } |
237 | 242 |
238 // Register holding this function and new target are both trashed in case we | 243 // Register holding this function and new target are both trashed in case we |
239 // bailout here. But since that can happen only when new target is not used | 244 // bailout here. But since that can happen only when new target is not used |
240 // and we allocate a context, the value of |function_in_register| is correct. | 245 // and we allocate a context, the value of |function_in_register| is correct. |
241 PrepareForBailoutForId(BailoutId::FunctionContext(), NO_REGISTERS); | 246 PrepareForBailoutForId(BailoutId::FunctionContext(), NO_REGISTERS); |
242 | 247 |
243 // Possibly set up a local binding to the this function which is used in | 248 // Possibly set up a local binding to the this function which is used in |
244 // derived constructors with super calls. | 249 // derived constructors with super calls. |
245 Variable* this_function_var = scope()->this_function_var(); | 250 Variable* this_function_var = scope()->this_function_var(); |
246 if (this_function_var != nullptr) { | 251 if (this_function_var != nullptr) { |
247 Comment cmnt(masm_, "[ This function"); | 252 Comment cmnt(masm_, "[ This function"); |
248 if (!function_in_register_r4) { | 253 if (!function_in_register_r3) { |
249 __ LoadP(r4, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset)); | 254 __ LoadP(r3, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset)); |
250 // The write barrier clobbers register again, keep it marked as such. | 255 // The write barrier clobbers register again, keep it marked as such. |
251 } | 256 } |
252 SetVar(this_function_var, r4, r3, r5); | 257 SetVar(this_function_var, r3, r2, r4); |
253 } | 258 } |
254 | 259 |
255 // Possibly set up a local binding to the new target value. | 260 // Possibly set up a local binding to the new target value. |
256 Variable* new_target_var = scope()->new_target_var(); | 261 Variable* new_target_var = scope()->new_target_var(); |
257 if (new_target_var != nullptr) { | 262 if (new_target_var != nullptr) { |
258 Comment cmnt(masm_, "[ new.target"); | 263 Comment cmnt(masm_, "[ new.target"); |
259 SetVar(new_target_var, r6, r3, r5); | 264 SetVar(new_target_var, r5, r2, r4); |
260 } | 265 } |
261 | 266 |
262 // Possibly allocate RestParameters | 267 // Possibly allocate RestParameters |
263 int rest_index; | 268 int rest_index; |
264 Variable* rest_param = scope()->rest_parameter(&rest_index); | 269 Variable* rest_param = scope()->rest_parameter(&rest_index); |
265 if (rest_param) { | 270 if (rest_param) { |
266 Comment cmnt(masm_, "[ Allocate rest parameter array"); | 271 Comment cmnt(masm_, "[ Allocate rest parameter array"); |
267 if (!function_in_register_r4) { | 272 |
268 __ LoadP(r4, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset)); | 273 if (!function_in_register_r3) { |
| 274 __ LoadP(r3, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset)); |
269 } | 275 } |
270 FastNewRestParameterStub stub(isolate()); | 276 FastNewRestParameterStub stub(isolate()); |
271 __ CallStub(&stub); | 277 __ CallStub(&stub); |
272 function_in_register_r4 = false; | 278 |
273 SetVar(rest_param, r3, r4, r5); | 279 function_in_register_r3 = false; |
| 280 SetVar(rest_param, r2, r3, r4); |
274 } | 281 } |
275 | 282 |
276 Variable* arguments = scope()->arguments(); | 283 Variable* arguments = scope()->arguments(); |
277 if (arguments != NULL) { | 284 if (arguments != NULL) { |
278 // Function uses arguments object. | 285 // Function uses arguments object. |
279 Comment cmnt(masm_, "[ Allocate arguments object"); | 286 Comment cmnt(masm_, "[ Allocate arguments object"); |
280 if (!function_in_register_r4) { | 287 if (!function_in_register_r3) { |
281 // Load this again, if it's used by the local context below. | 288 // Load this again, if it's used by the local context below. |
282 __ LoadP(r4, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset)); | 289 __ LoadP(r3, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset)); |
283 } | 290 } |
284 if (is_strict(language_mode()) || !has_simple_parameters()) { | 291 if (is_strict(language_mode()) || !has_simple_parameters()) { |
285 FastNewStrictArgumentsStub stub(isolate()); | 292 FastNewStrictArgumentsStub stub(isolate()); |
286 __ CallStub(&stub); | 293 __ CallStub(&stub); |
287 } else if (literal()->has_duplicate_parameters()) { | 294 } else if (literal()->has_duplicate_parameters()) { |
288 __ Push(r4); | 295 __ Push(r3); |
289 __ CallRuntime(Runtime::kNewSloppyArguments_Generic); | 296 __ CallRuntime(Runtime::kNewSloppyArguments_Generic); |
290 } else { | 297 } else { |
291 FastNewSloppyArgumentsStub stub(isolate()); | 298 FastNewSloppyArgumentsStub stub(isolate()); |
292 __ CallStub(&stub); | 299 __ CallStub(&stub); |
293 } | 300 } |
294 | 301 |
295 SetVar(arguments, r3, r4, r5); | 302 SetVar(arguments, r2, r3, r4); |
296 } | 303 } |
297 | 304 |
298 if (FLAG_trace) { | 305 if (FLAG_trace) { |
299 __ CallRuntime(Runtime::kTraceEnter); | 306 __ CallRuntime(Runtime::kTraceEnter); |
300 } | 307 } |
301 | 308 |
302 // Visit the declarations and body unless there is an illegal | 309 // Visit the declarations and body unless there is an illegal |
303 // redeclaration. | 310 // redeclaration. |
304 if (scope()->HasIllegalRedeclaration()) { | 311 if (scope()->HasIllegalRedeclaration()) { |
305 EmitIllegalRedeclaration(); | 312 Comment cmnt(masm_, "[ Declarations"); |
| 313 VisitForEffect(scope()->GetIllegalRedeclaration()); |
| 314 |
306 } else { | 315 } else { |
307 PrepareForBailoutForId(BailoutId::FunctionEntry(), NO_REGISTERS); | 316 PrepareForBailoutForId(BailoutId::FunctionEntry(), NO_REGISTERS); |
308 { | 317 { |
309 Comment cmnt(masm_, "[ Declarations"); | 318 Comment cmnt(masm_, "[ Declarations"); |
310 VisitDeclarations(scope()->declarations()); | 319 VisitDeclarations(scope()->declarations()); |
311 } | 320 } |
312 | 321 |
313 // Assert that the declarations do not use ICs. Otherwise the debugger | 322 // Assert that the declarations do not use ICs. Otherwise the debugger |
314 // won't be able to redirect a PC at an IC to the correct IC in newly | 323 // won't be able to redirect a PC at an IC to the correct IC in newly |
315 // recompiled code. | 324 // recompiled code. |
316 DCHECK_EQ(0, ic_total_count_); | 325 DCHECK_EQ(0, ic_total_count_); |
317 | 326 |
318 { | 327 { |
319 Comment cmnt(masm_, "[ Stack check"); | 328 Comment cmnt(masm_, "[ Stack check"); |
320 PrepareForBailoutForId(BailoutId::Declarations(), NO_REGISTERS); | 329 PrepareForBailoutForId(BailoutId::Declarations(), NO_REGISTERS); |
321 Label ok; | 330 Label ok; |
322 __ LoadRoot(ip, Heap::kStackLimitRootIndex); | 331 __ LoadRoot(ip, Heap::kStackLimitRootIndex); |
323 __ cmpl(sp, ip); | 332 __ CmpLogicalP(sp, ip); |
324 __ bc_short(ge, &ok); | 333 __ bge(&ok, Label::kNear); |
325 __ Call(isolate()->builtins()->StackCheck(), RelocInfo::CODE_TARGET); | 334 __ Call(isolate()->builtins()->StackCheck(), RelocInfo::CODE_TARGET); |
326 __ bind(&ok); | 335 __ bind(&ok); |
327 } | 336 } |
328 | 337 |
329 { | 338 { |
330 Comment cmnt(masm_, "[ Body"); | 339 Comment cmnt(masm_, "[ Body"); |
331 DCHECK(loop_depth() == 0); | 340 DCHECK(loop_depth() == 0); |
332 VisitStatements(literal()->body()); | 341 VisitStatements(literal()->body()); |
333 DCHECK(loop_depth() == 0); | 342 DCHECK(loop_depth() == 0); |
334 } | 343 } |
335 } | 344 } |
336 | 345 |
337 // Always emit a 'return undefined' in case control fell off the end of | 346 // Always emit a 'return undefined' in case control fell off the end of |
338 // the body. | 347 // the body. |
339 { | 348 { |
340 Comment cmnt(masm_, "[ return <undefined>;"); | 349 Comment cmnt(masm_, "[ return <undefined>;"); |
341 __ LoadRoot(r3, Heap::kUndefinedValueRootIndex); | 350 __ LoadRoot(r2, Heap::kUndefinedValueRootIndex); |
342 } | 351 } |
343 EmitReturnSequence(); | 352 EmitReturnSequence(); |
| 353 } |
344 | 354 |
345 if (HasStackOverflow()) { | 355 void FullCodeGenerator::ClearAccumulator() { |
346 masm_->AbortConstantPoolBuilding(); | 356 __ LoadSmiLiteral(r2, Smi::FromInt(0)); |
| 357 } |
| 358 |
| 359 void FullCodeGenerator::EmitProfilingCounterDecrement(int delta) { |
| 360 __ mov(r4, Operand(profiling_counter_)); |
| 361 intptr_t smi_delta = reinterpret_cast<intptr_t>(Smi::FromInt(delta)); |
| 362 if (CpuFeatures::IsSupported(GENERAL_INSTR_EXT) && is_int8(-smi_delta)) { |
| 363 __ AddP(FieldMemOperand(r4, Cell::kValueOffset), Operand(-smi_delta)); |
| 364 __ LoadP(r5, FieldMemOperand(r4, Cell::kValueOffset)); |
| 365 } else { |
| 366 __ LoadP(r5, FieldMemOperand(r4, Cell::kValueOffset)); |
| 367 __ SubSmiLiteral(r5, r5, Smi::FromInt(delta), r0); |
| 368 __ StoreP(r5, FieldMemOperand(r4, Cell::kValueOffset)); |
347 } | 369 } |
348 } | 370 } |
349 | 371 |
350 | |
351 void FullCodeGenerator::ClearAccumulator() { | |
352 __ LoadSmiLiteral(r3, Smi::FromInt(0)); | |
353 } | |
354 | |
355 | |
356 void FullCodeGenerator::EmitProfilingCounterDecrement(int delta) { | |
357 __ mov(r5, Operand(profiling_counter_)); | |
358 __ LoadP(r6, FieldMemOperand(r5, Cell::kValueOffset)); | |
359 __ SubSmiLiteral(r6, r6, Smi::FromInt(delta), r0); | |
360 __ StoreP(r6, FieldMemOperand(r5, Cell::kValueOffset), r0); | |
361 } | |
362 | |
363 | |
364 void FullCodeGenerator::EmitProfilingCounterReset() { | 372 void FullCodeGenerator::EmitProfilingCounterReset() { |
365 int reset_value = FLAG_interrupt_budget; | 373 int reset_value = FLAG_interrupt_budget; |
366 __ mov(r5, Operand(profiling_counter_)); | 374 __ mov(r4, Operand(profiling_counter_)); |
367 __ LoadSmiLiteral(r6, Smi::FromInt(reset_value)); | 375 __ LoadSmiLiteral(r5, Smi::FromInt(reset_value)); |
368 __ StoreP(r6, FieldMemOperand(r5, Cell::kValueOffset), r0); | 376 __ StoreP(r5, FieldMemOperand(r4, Cell::kValueOffset)); |
369 } | 377 } |
370 | 378 |
371 | |
372 void FullCodeGenerator::EmitBackEdgeBookkeeping(IterationStatement* stmt, | 379 void FullCodeGenerator::EmitBackEdgeBookkeeping(IterationStatement* stmt, |
373 Label* back_edge_target) { | 380 Label* back_edge_target) { |
374 Comment cmnt(masm_, "[ Back edge bookkeeping"); | 381 Comment cmnt(masm_, "[ Back edge bookkeeping"); |
375 Label ok; | 382 Label ok; |
376 | 383 |
377 DCHECK(back_edge_target->is_bound()); | 384 DCHECK(back_edge_target->is_bound()); |
378 int distance = masm_->SizeOfCodeGeneratedSince(back_edge_target) + | 385 int distance = masm_->SizeOfCodeGeneratedSince(back_edge_target) + |
379 kCodeSizeMultiplier / 2; | 386 kCodeSizeMultiplier / 2; |
380 int weight = Min(kMaxBackEdgeWeight, Max(1, distance / kCodeSizeMultiplier)); | 387 int weight = Min(kMaxBackEdgeWeight, Max(1, distance / kCodeSizeMultiplier)); |
381 EmitProfilingCounterDecrement(weight); | 388 EmitProfilingCounterDecrement(weight); |
382 { | 389 { |
383 Assembler::BlockTrampolinePoolScope block_trampoline_pool(masm_); | |
384 Assembler::BlockConstantPoolEntrySharingScope prevent_entry_sharing(masm_); | |
385 // BackEdgeTable::PatchAt manipulates this sequence. | 390 // BackEdgeTable::PatchAt manipulates this sequence. |
386 __ cmpi(r6, Operand::Zero()); | 391 __ bge(&ok, Label::kNear); |
387 __ bc_short(ge, &ok); | |
388 __ Call(isolate()->builtins()->InterruptCheck(), RelocInfo::CODE_TARGET); | 392 __ Call(isolate()->builtins()->InterruptCheck(), RelocInfo::CODE_TARGET); |
389 | 393 |
390 // Record a mapping of this PC offset to the OSR id. This is used to find | 394 // Record a mapping of this PC offset to the OSR id. This is used to find |
391 // the AST id from the unoptimized code in order to use it as a key into | 395 // the AST id from the unoptimized code in order to use it as a key into |
392 // the deoptimization input data found in the optimized code. | 396 // the deoptimization input data found in the optimized code. |
393 RecordBackEdge(stmt->OsrEntryId()); | 397 RecordBackEdge(stmt->OsrEntryId()); |
394 } | 398 } |
395 EmitProfilingCounterReset(); | 399 EmitProfilingCounterReset(); |
396 | 400 |
397 __ bind(&ok); | 401 __ bind(&ok); |
398 PrepareForBailoutForId(stmt->EntryId(), NO_REGISTERS); | 402 PrepareForBailoutForId(stmt->EntryId(), NO_REGISTERS); |
399 // Record a mapping of the OSR id to this PC. This is used if the OSR | 403 // Record a mapping of the OSR id to this PC. This is used if the OSR |
400 // entry becomes the target of a bailout. We don't expect it to be, but | 404 // entry becomes the target of a bailout. We don't expect it to be, but |
401 // we want it to work if it is. | 405 // we want it to work if it is. |
402 PrepareForBailoutForId(stmt->OsrEntryId(), NO_REGISTERS); | 406 PrepareForBailoutForId(stmt->OsrEntryId(), NO_REGISTERS); |
403 } | 407 } |
404 | 408 |
405 void FullCodeGenerator::EmitProfilingCounterHandlingForReturnSequence( | 409 void FullCodeGenerator::EmitProfilingCounterHandlingForReturnSequence( |
406 bool is_tail_call) { | 410 bool is_tail_call) { |
407 // Pretend that the exit is a backwards jump to the entry. | 411 // Pretend that the exit is a backwards jump to the entry. |
408 int weight = 1; | 412 int weight = 1; |
409 if (info_->ShouldSelfOptimize()) { | 413 if (info_->ShouldSelfOptimize()) { |
410 weight = FLAG_interrupt_budget / FLAG_self_opt_count; | 414 weight = FLAG_interrupt_budget / FLAG_self_opt_count; |
411 } else { | 415 } else { |
412 int distance = masm_->pc_offset() + kCodeSizeMultiplier / 2; | 416 int distance = masm_->pc_offset() + kCodeSizeMultiplier / 2; |
413 weight = Min(kMaxBackEdgeWeight, Max(1, distance / kCodeSizeMultiplier)); | 417 weight = Min(kMaxBackEdgeWeight, Max(1, distance / kCodeSizeMultiplier)); |
414 } | 418 } |
415 EmitProfilingCounterDecrement(weight); | 419 EmitProfilingCounterDecrement(weight); |
416 Label ok; | 420 Label ok; |
417 __ cmpi(r6, Operand::Zero()); | 421 __ CmpP(r5, Operand::Zero()); |
418 __ bge(&ok); | 422 __ bge(&ok); |
419 // Don't need to save result register if we are going to do a tail call. | 423 // Don't need to save result register if we are going to do a tail call. |
420 if (!is_tail_call) { | 424 if (!is_tail_call) { |
421 __ push(r3); | 425 __ push(r2); |
422 } | 426 } |
423 __ Call(isolate()->builtins()->InterruptCheck(), RelocInfo::CODE_TARGET); | 427 __ Call(isolate()->builtins()->InterruptCheck(), RelocInfo::CODE_TARGET); |
424 if (!is_tail_call) { | 428 if (!is_tail_call) { |
425 __ pop(r3); | 429 __ pop(r2); |
426 } | 430 } |
427 EmitProfilingCounterReset(); | 431 EmitProfilingCounterReset(); |
428 __ bind(&ok); | 432 __ bind(&ok); |
429 } | 433 } |
430 | 434 |
431 void FullCodeGenerator::EmitReturnSequence() { | 435 void FullCodeGenerator::EmitReturnSequence() { |
432 Comment cmnt(masm_, "[ Return sequence"); | 436 Comment cmnt(masm_, "[ Return sequence"); |
433 if (return_label_.is_bound()) { | 437 if (return_label_.is_bound()) { |
434 __ b(&return_label_); | 438 __ b(&return_label_); |
435 } else { | 439 } else { |
436 __ bind(&return_label_); | 440 __ bind(&return_label_); |
437 if (FLAG_trace) { | 441 if (FLAG_trace) { |
438 // Push the return value on the stack as the parameter. | 442 // Push the return value on the stack as the parameter. |
439 // Runtime::TraceExit returns its parameter in r3 | 443 // Runtime::TraceExit returns its parameter in r2 |
440 __ push(r3); | 444 __ push(r2); |
441 __ CallRuntime(Runtime::kTraceExit); | 445 __ CallRuntime(Runtime::kTraceExit); |
442 } | 446 } |
443 EmitProfilingCounterHandlingForReturnSequence(false); | 447 EmitProfilingCounterHandlingForReturnSequence(false); |
444 | 448 |
445 // Make sure that the constant pool is not emitted inside of the return | 449 // Make sure that the constant pool is not emitted inside of the return |
446 // sequence. | 450 // sequence. |
447 { | 451 { |
448 Assembler::BlockTrampolinePoolScope block_trampoline_pool(masm_); | 452 // Here we use masm_-> instead of the __ macro to avoid the code coverage |
| 453 // tool from instrumenting as we rely on the code size here. |
449 int32_t arg_count = info_->scope()->num_parameters() + 1; | 454 int32_t arg_count = info_->scope()->num_parameters() + 1; |
450 int32_t sp_delta = arg_count * kPointerSize; | 455 int32_t sp_delta = arg_count * kPointerSize; |
451 SetReturnPosition(literal()); | 456 SetReturnPosition(literal()); |
452 __ LeaveFrame(StackFrame::JAVA_SCRIPT, sp_delta); | 457 __ LeaveFrame(StackFrame::JAVA_SCRIPT, sp_delta); |
453 __ blr(); | 458 |
| 459 __ Ret(); |
454 } | 460 } |
455 } | 461 } |
456 } | 462 } |
457 | 463 |
458 | |
459 void FullCodeGenerator::StackValueContext::Plug(Variable* var) const { | 464 void FullCodeGenerator::StackValueContext::Plug(Variable* var) const { |
460 DCHECK(var->IsStackAllocated() || var->IsContextSlot()); | 465 DCHECK(var->IsStackAllocated() || var->IsContextSlot()); |
461 codegen()->GetVar(result_register(), var); | 466 codegen()->GetVar(result_register(), var); |
462 codegen()->PushOperand(result_register()); | 467 codegen()->PushOperand(result_register()); |
463 } | 468 } |
464 | 469 |
465 | |
466 void FullCodeGenerator::EffectContext::Plug(Heap::RootListIndex index) const {} | 470 void FullCodeGenerator::EffectContext::Plug(Heap::RootListIndex index) const {} |
467 | 471 |
468 | |
469 void FullCodeGenerator::AccumulatorValueContext::Plug( | 472 void FullCodeGenerator::AccumulatorValueContext::Plug( |
470 Heap::RootListIndex index) const { | 473 Heap::RootListIndex index) const { |
471 __ LoadRoot(result_register(), index); | 474 __ LoadRoot(result_register(), index); |
472 } | 475 } |
473 | 476 |
474 | |
475 void FullCodeGenerator::StackValueContext::Plug( | 477 void FullCodeGenerator::StackValueContext::Plug( |
476 Heap::RootListIndex index) const { | 478 Heap::RootListIndex index) const { |
477 __ LoadRoot(result_register(), index); | 479 __ LoadRoot(result_register(), index); |
478 codegen()->PushOperand(result_register()); | 480 codegen()->PushOperand(result_register()); |
479 } | 481 } |
480 | 482 |
481 | |
482 void FullCodeGenerator::TestContext::Plug(Heap::RootListIndex index) const { | 483 void FullCodeGenerator::TestContext::Plug(Heap::RootListIndex index) const { |
483 codegen()->PrepareForBailoutBeforeSplit(condition(), true, true_label_, | 484 codegen()->PrepareForBailoutBeforeSplit(condition(), true, true_label_, |
484 false_label_); | 485 false_label_); |
485 if (index == Heap::kUndefinedValueRootIndex || | 486 if (index == Heap::kUndefinedValueRootIndex || |
486 index == Heap::kNullValueRootIndex || | 487 index == Heap::kNullValueRootIndex || |
487 index == Heap::kFalseValueRootIndex) { | 488 index == Heap::kFalseValueRootIndex) { |
488 if (false_label_ != fall_through_) __ b(false_label_); | 489 if (false_label_ != fall_through_) __ b(false_label_); |
489 } else if (index == Heap::kTrueValueRootIndex) { | 490 } else if (index == Heap::kTrueValueRootIndex) { |
490 if (true_label_ != fall_through_) __ b(true_label_); | 491 if (true_label_ != fall_through_) __ b(true_label_); |
491 } else { | 492 } else { |
492 __ LoadRoot(result_register(), index); | 493 __ LoadRoot(result_register(), index); |
493 codegen()->DoTest(this); | 494 codegen()->DoTest(this); |
494 } | 495 } |
495 } | 496 } |
496 | 497 |
497 | |
498 void FullCodeGenerator::EffectContext::Plug(Handle<Object> lit) const {} | 498 void FullCodeGenerator::EffectContext::Plug(Handle<Object> lit) const {} |
499 | 499 |
500 | |
501 void FullCodeGenerator::AccumulatorValueContext::Plug( | 500 void FullCodeGenerator::AccumulatorValueContext::Plug( |
502 Handle<Object> lit) const { | 501 Handle<Object> lit) const { |
503 __ mov(result_register(), Operand(lit)); | 502 __ mov(result_register(), Operand(lit)); |
504 } | 503 } |
505 | 504 |
506 | |
507 void FullCodeGenerator::StackValueContext::Plug(Handle<Object> lit) const { | 505 void FullCodeGenerator::StackValueContext::Plug(Handle<Object> lit) const { |
508 // Immediates cannot be pushed directly. | 506 // Immediates cannot be pushed directly. |
509 __ mov(result_register(), Operand(lit)); | 507 __ mov(result_register(), Operand(lit)); |
510 codegen()->PushOperand(result_register()); | 508 codegen()->PushOperand(result_register()); |
511 } | 509 } |
512 | 510 |
513 | |
514 void FullCodeGenerator::TestContext::Plug(Handle<Object> lit) const { | 511 void FullCodeGenerator::TestContext::Plug(Handle<Object> lit) const { |
515 codegen()->PrepareForBailoutBeforeSplit(condition(), true, true_label_, | 512 codegen()->PrepareForBailoutBeforeSplit(condition(), true, true_label_, |
516 false_label_); | 513 false_label_); |
517 DCHECK(lit->IsNull() || lit->IsUndefined() || !lit->IsUndetectable()); | 514 DCHECK(lit->IsNull() || lit->IsUndefined() || !lit->IsUndetectableObject()); |
518 if (lit->IsUndefined() || lit->IsNull() || lit->IsFalse()) { | 515 if (lit->IsUndefined() || lit->IsNull() || lit->IsFalse()) { |
519 if (false_label_ != fall_through_) __ b(false_label_); | 516 if (false_label_ != fall_through_) __ b(false_label_); |
520 } else if (lit->IsTrue() || lit->IsJSObject()) { | 517 } else if (lit->IsTrue() || lit->IsJSObject()) { |
521 if (true_label_ != fall_through_) __ b(true_label_); | 518 if (true_label_ != fall_through_) __ b(true_label_); |
522 } else if (lit->IsString()) { | 519 } else if (lit->IsString()) { |
523 if (String::cast(*lit)->length() == 0) { | 520 if (String::cast(*lit)->length() == 0) { |
524 if (false_label_ != fall_through_) __ b(false_label_); | 521 if (false_label_ != fall_through_) __ b(false_label_); |
525 } else { | 522 } else { |
526 if (true_label_ != fall_through_) __ b(true_label_); | 523 if (true_label_ != fall_through_) __ b(true_label_); |
527 } | 524 } |
528 } else if (lit->IsSmi()) { | 525 } else if (lit->IsSmi()) { |
529 if (Smi::cast(*lit)->value() == 0) { | 526 if (Smi::cast(*lit)->value() == 0) { |
530 if (false_label_ != fall_through_) __ b(false_label_); | 527 if (false_label_ != fall_through_) __ b(false_label_); |
531 } else { | 528 } else { |
532 if (true_label_ != fall_through_) __ b(true_label_); | 529 if (true_label_ != fall_through_) __ b(true_label_); |
533 } | 530 } |
534 } else { | 531 } else { |
535 // For simplicity we always test the accumulator register. | 532 // For simplicity we always test the accumulator register. |
536 __ mov(result_register(), Operand(lit)); | 533 __ mov(result_register(), Operand(lit)); |
537 codegen()->DoTest(this); | 534 codegen()->DoTest(this); |
538 } | 535 } |
539 } | 536 } |
540 | 537 |
541 | |
542 void FullCodeGenerator::StackValueContext::DropAndPlug(int count, | 538 void FullCodeGenerator::StackValueContext::DropAndPlug(int count, |
543 Register reg) const { | 539 Register reg) const { |
544 DCHECK(count > 0); | 540 DCHECK(count > 0); |
545 if (count > 1) codegen()->DropOperands(count - 1); | 541 if (count > 1) codegen()->DropOperands(count - 1); |
546 __ StoreP(reg, MemOperand(sp, 0)); | 542 __ StoreP(reg, MemOperand(sp, 0)); |
547 } | 543 } |
548 | 544 |
549 | |
550 void FullCodeGenerator::EffectContext::Plug(Label* materialize_true, | 545 void FullCodeGenerator::EffectContext::Plug(Label* materialize_true, |
551 Label* materialize_false) const { | 546 Label* materialize_false) const { |
552 DCHECK(materialize_true == materialize_false); | 547 DCHECK(materialize_true == materialize_false); |
553 __ bind(materialize_true); | 548 __ bind(materialize_true); |
554 } | 549 } |
555 | 550 |
556 | |
557 void FullCodeGenerator::AccumulatorValueContext::Plug( | 551 void FullCodeGenerator::AccumulatorValueContext::Plug( |
558 Label* materialize_true, Label* materialize_false) const { | 552 Label* materialize_true, Label* materialize_false) const { |
559 Label done; | 553 Label done; |
560 __ bind(materialize_true); | 554 __ bind(materialize_true); |
561 __ LoadRoot(result_register(), Heap::kTrueValueRootIndex); | 555 __ LoadRoot(result_register(), Heap::kTrueValueRootIndex); |
562 __ b(&done); | 556 __ b(&done, Label::kNear); |
563 __ bind(materialize_false); | 557 __ bind(materialize_false); |
564 __ LoadRoot(result_register(), Heap::kFalseValueRootIndex); | 558 __ LoadRoot(result_register(), Heap::kFalseValueRootIndex); |
565 __ bind(&done); | 559 __ bind(&done); |
566 } | 560 } |
567 | 561 |
568 | |
569 void FullCodeGenerator::StackValueContext::Plug( | 562 void FullCodeGenerator::StackValueContext::Plug( |
570 Label* materialize_true, Label* materialize_false) const { | 563 Label* materialize_true, Label* materialize_false) const { |
571 Label done; | 564 Label done; |
572 __ bind(materialize_true); | 565 __ bind(materialize_true); |
573 __ LoadRoot(ip, Heap::kTrueValueRootIndex); | 566 __ LoadRoot(ip, Heap::kTrueValueRootIndex); |
574 __ b(&done); | 567 __ b(&done, Label::kNear); |
575 __ bind(materialize_false); | 568 __ bind(materialize_false); |
576 __ LoadRoot(ip, Heap::kFalseValueRootIndex); | 569 __ LoadRoot(ip, Heap::kFalseValueRootIndex); |
577 __ bind(&done); | 570 __ bind(&done); |
578 codegen()->PushOperand(ip); | 571 codegen()->PushOperand(ip); |
579 } | 572 } |
580 | 573 |
581 | |
582 void FullCodeGenerator::TestContext::Plug(Label* materialize_true, | 574 void FullCodeGenerator::TestContext::Plug(Label* materialize_true, |
583 Label* materialize_false) const { | 575 Label* materialize_false) const { |
584 DCHECK(materialize_true == true_label_); | 576 DCHECK(materialize_true == true_label_); |
585 DCHECK(materialize_false == false_label_); | 577 DCHECK(materialize_false == false_label_); |
586 } | 578 } |
587 | 579 |
588 | |
589 void FullCodeGenerator::AccumulatorValueContext::Plug(bool flag) const { | 580 void FullCodeGenerator::AccumulatorValueContext::Plug(bool flag) const { |
590 Heap::RootListIndex value_root_index = | 581 Heap::RootListIndex value_root_index = |
591 flag ? Heap::kTrueValueRootIndex : Heap::kFalseValueRootIndex; | 582 flag ? Heap::kTrueValueRootIndex : Heap::kFalseValueRootIndex; |
592 __ LoadRoot(result_register(), value_root_index); | 583 __ LoadRoot(result_register(), value_root_index); |
593 } | 584 } |
594 | 585 |
595 | |
596 void FullCodeGenerator::StackValueContext::Plug(bool flag) const { | 586 void FullCodeGenerator::StackValueContext::Plug(bool flag) const { |
597 Heap::RootListIndex value_root_index = | 587 Heap::RootListIndex value_root_index = |
598 flag ? Heap::kTrueValueRootIndex : Heap::kFalseValueRootIndex; | 588 flag ? Heap::kTrueValueRootIndex : Heap::kFalseValueRootIndex; |
599 __ LoadRoot(ip, value_root_index); | 589 __ LoadRoot(ip, value_root_index); |
600 codegen()->PushOperand(ip); | 590 codegen()->PushOperand(ip); |
601 } | 591 } |
602 | 592 |
603 | |
604 void FullCodeGenerator::TestContext::Plug(bool flag) const { | 593 void FullCodeGenerator::TestContext::Plug(bool flag) const { |
605 codegen()->PrepareForBailoutBeforeSplit(condition(), true, true_label_, | 594 codegen()->PrepareForBailoutBeforeSplit(condition(), true, true_label_, |
606 false_label_); | 595 false_label_); |
607 if (flag) { | 596 if (flag) { |
608 if (true_label_ != fall_through_) __ b(true_label_); | 597 if (true_label_ != fall_through_) __ b(true_label_); |
609 } else { | 598 } else { |
610 if (false_label_ != fall_through_) __ b(false_label_); | 599 if (false_label_ != fall_through_) __ b(false_label_); |
611 } | 600 } |
612 } | 601 } |
613 | 602 |
614 | |
615 void FullCodeGenerator::DoTest(Expression* condition, Label* if_true, | 603 void FullCodeGenerator::DoTest(Expression* condition, Label* if_true, |
616 Label* if_false, Label* fall_through) { | 604 Label* if_false, Label* fall_through) { |
617 Handle<Code> ic = ToBooleanICStub::GetUninitialized(isolate()); | 605 Handle<Code> ic = ToBooleanStub::GetUninitialized(isolate()); |
618 CallIC(ic, condition->test_id()); | 606 CallIC(ic, condition->test_id()); |
619 __ CompareRoot(result_register(), Heap::kTrueValueRootIndex); | 607 __ CompareRoot(result_register(), Heap::kTrueValueRootIndex); |
620 Split(eq, if_true, if_false, fall_through); | 608 Split(eq, if_true, if_false, fall_through); |
621 } | 609 } |
622 | 610 |
623 | |
624 void FullCodeGenerator::Split(Condition cond, Label* if_true, Label* if_false, | 611 void FullCodeGenerator::Split(Condition cond, Label* if_true, Label* if_false, |
625 Label* fall_through, CRegister cr) { | 612 Label* fall_through) { |
626 if (if_false == fall_through) { | 613 if (if_false == fall_through) { |
627 __ b(cond, if_true, cr); | 614 __ b(cond, if_true); |
628 } else if (if_true == fall_through) { | 615 } else if (if_true == fall_through) { |
629 __ b(NegateCondition(cond), if_false, cr); | 616 __ b(NegateCondition(cond), if_false); |
630 } else { | 617 } else { |
631 __ b(cond, if_true, cr); | 618 __ b(cond, if_true); |
632 __ b(if_false); | 619 __ b(if_false); |
633 } | 620 } |
634 } | 621 } |
635 | 622 |
636 | |
637 MemOperand FullCodeGenerator::StackOperand(Variable* var) { | 623 MemOperand FullCodeGenerator::StackOperand(Variable* var) { |
638 DCHECK(var->IsStackAllocated()); | 624 DCHECK(var->IsStackAllocated()); |
639 // Offset is negative because higher indexes are at lower addresses. | 625 // Offset is negative because higher indexes are at lower addresses. |
640 int offset = -var->index() * kPointerSize; | 626 int offset = -var->index() * kPointerSize; |
641 // Adjust by a (parameter or local) base offset. | 627 // Adjust by a (parameter or local) base offset. |
642 if (var->IsParameter()) { | 628 if (var->IsParameter()) { |
643 offset += (info_->scope()->num_parameters() + 1) * kPointerSize; | 629 offset += (info_->scope()->num_parameters() + 1) * kPointerSize; |
644 } else { | 630 } else { |
645 offset += JavaScriptFrameConstants::kLocal0Offset; | 631 offset += JavaScriptFrameConstants::kLocal0Offset; |
646 } | 632 } |
647 return MemOperand(fp, offset); | 633 return MemOperand(fp, offset); |
648 } | 634 } |
649 | 635 |
650 | |
651 MemOperand FullCodeGenerator::VarOperand(Variable* var, Register scratch) { | 636 MemOperand FullCodeGenerator::VarOperand(Variable* var, Register scratch) { |
652 DCHECK(var->IsContextSlot() || var->IsStackAllocated()); | 637 DCHECK(var->IsContextSlot() || var->IsStackAllocated()); |
653 if (var->IsContextSlot()) { | 638 if (var->IsContextSlot()) { |
654 int context_chain_length = scope()->ContextChainLength(var->scope()); | 639 int context_chain_length = scope()->ContextChainLength(var->scope()); |
655 __ LoadContext(scratch, context_chain_length); | 640 __ LoadContext(scratch, context_chain_length); |
656 return ContextMemOperand(scratch, var->index()); | 641 return ContextMemOperand(scratch, var->index()); |
657 } else { | 642 } else { |
658 return StackOperand(var); | 643 return StackOperand(var); |
659 } | 644 } |
660 } | 645 } |
661 | 646 |
662 | |
663 void FullCodeGenerator::GetVar(Register dest, Variable* var) { | 647 void FullCodeGenerator::GetVar(Register dest, Variable* var) { |
664 // Use destination as scratch. | 648 // Use destination as scratch. |
665 MemOperand location = VarOperand(var, dest); | 649 MemOperand location = VarOperand(var, dest); |
666 __ LoadP(dest, location, r0); | 650 __ LoadP(dest, location, r0); |
667 } | 651 } |
668 | 652 |
669 | |
670 void FullCodeGenerator::SetVar(Variable* var, Register src, Register scratch0, | 653 void FullCodeGenerator::SetVar(Variable* var, Register src, Register scratch0, |
671 Register scratch1) { | 654 Register scratch1) { |
672 DCHECK(var->IsContextSlot() || var->IsStackAllocated()); | 655 DCHECK(var->IsContextSlot() || var->IsStackAllocated()); |
673 DCHECK(!scratch0.is(src)); | 656 DCHECK(!scratch0.is(src)); |
674 DCHECK(!scratch0.is(scratch1)); | 657 DCHECK(!scratch0.is(scratch1)); |
675 DCHECK(!scratch1.is(src)); | 658 DCHECK(!scratch1.is(src)); |
676 MemOperand location = VarOperand(var, scratch0); | 659 MemOperand location = VarOperand(var, scratch0); |
677 __ StoreP(src, location, r0); | 660 __ StoreP(src, location); |
678 | 661 |
679 // Emit the write barrier code if the location is in the heap. | 662 // Emit the write barrier code if the location is in the heap. |
680 if (var->IsContextSlot()) { | 663 if (var->IsContextSlot()) { |
681 __ RecordWriteContextSlot(scratch0, location.offset(), src, scratch1, | 664 __ RecordWriteContextSlot(scratch0, location.offset(), src, scratch1, |
682 kLRHasBeenSaved, kDontSaveFPRegs); | 665 kLRHasBeenSaved, kDontSaveFPRegs); |
683 } | 666 } |
684 } | 667 } |
685 | 668 |
686 | |
687 void FullCodeGenerator::PrepareForBailoutBeforeSplit(Expression* expr, | 669 void FullCodeGenerator::PrepareForBailoutBeforeSplit(Expression* expr, |
688 bool should_normalize, | 670 bool should_normalize, |
689 Label* if_true, | 671 Label* if_true, |
690 Label* if_false) { | 672 Label* if_false) { |
691 // Only prepare for bailouts before splits if we're in a test | 673 // Only prepare for bailouts before splits if we're in a test |
692 // context. Otherwise, we let the Visit function deal with the | 674 // context. Otherwise, we let the Visit function deal with the |
693 // preparation to avoid preparing with the same AST id twice. | 675 // preparation to avoid preparing with the same AST id twice. |
694 if (!context()->IsTest()) return; | 676 if (!context()->IsTest()) return; |
695 | 677 |
696 Label skip; | 678 Label skip; |
697 if (should_normalize) __ b(&skip); | 679 if (should_normalize) __ b(&skip); |
698 PrepareForBailout(expr, TOS_REG); | 680 PrepareForBailout(expr, TOS_REG); |
699 if (should_normalize) { | 681 if (should_normalize) { |
700 __ LoadRoot(ip, Heap::kTrueValueRootIndex); | 682 __ CompareRoot(r2, Heap::kTrueValueRootIndex); |
701 __ cmp(r3, ip); | |
702 Split(eq, if_true, if_false, NULL); | 683 Split(eq, if_true, if_false, NULL); |
703 __ bind(&skip); | 684 __ bind(&skip); |
704 } | 685 } |
705 } | 686 } |
706 | 687 |
707 | |
708 void FullCodeGenerator::EmitDebugCheckDeclarationContext(Variable* variable) { | 688 void FullCodeGenerator::EmitDebugCheckDeclarationContext(Variable* variable) { |
709 // The variable in the declaration always resides in the current function | 689 // The variable in the declaration always resides in the current function |
710 // context. | 690 // context. |
711 DCHECK_EQ(0, scope()->ContextChainLength(variable->scope())); | 691 DCHECK_EQ(0, scope()->ContextChainLength(variable->scope())); |
712 if (FLAG_debug_code) { | 692 if (FLAG_debug_code) { |
713 // Check that we're not inside a with or catch context. | 693 // Check that we're not inside a with or catch context. |
714 __ LoadP(r4, FieldMemOperand(cp, HeapObject::kMapOffset)); | 694 __ LoadP(r3, FieldMemOperand(cp, HeapObject::kMapOffset)); |
715 __ CompareRoot(r4, Heap::kWithContextMapRootIndex); | 695 __ CompareRoot(r3, Heap::kWithContextMapRootIndex); |
716 __ Check(ne, kDeclarationInWithContext); | 696 __ Check(ne, kDeclarationInWithContext); |
717 __ CompareRoot(r4, Heap::kCatchContextMapRootIndex); | 697 __ CompareRoot(r3, Heap::kCatchContextMapRootIndex); |
718 __ Check(ne, kDeclarationInCatchContext); | 698 __ Check(ne, kDeclarationInCatchContext); |
719 } | 699 } |
720 } | 700 } |
721 | 701 |
722 | |
723 void FullCodeGenerator::VisitVariableDeclaration( | 702 void FullCodeGenerator::VisitVariableDeclaration( |
724 VariableDeclaration* declaration) { | 703 VariableDeclaration* declaration) { |
725 // If it was not possible to allocate the variable at compile time, we | 704 // If it was not possible to allocate the variable at compile time, we |
726 // need to "declare" it at runtime to make sure it actually exists in the | 705 // need to "declare" it at runtime to make sure it actually exists in the |
727 // local context. | 706 // local context. |
728 VariableProxy* proxy = declaration->proxy(); | 707 VariableProxy* proxy = declaration->proxy(); |
729 VariableMode mode = declaration->mode(); | 708 VariableMode mode = declaration->mode(); |
730 Variable* variable = proxy->var(); | 709 Variable* variable = proxy->var(); |
731 bool hole_init = mode == LET || mode == CONST || mode == CONST_LEGACY; | 710 bool hole_init = mode == LET || mode == CONST || mode == CONST_LEGACY; |
732 switch (variable->location()) { | 711 switch (variable->location()) { |
(...skipping 13 matching lines...) Expand all Loading... |
746 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex); | 725 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex); |
747 __ StoreP(ip, StackOperand(variable)); | 726 __ StoreP(ip, StackOperand(variable)); |
748 } | 727 } |
749 break; | 728 break; |
750 | 729 |
751 case VariableLocation::CONTEXT: | 730 case VariableLocation::CONTEXT: |
752 if (hole_init) { | 731 if (hole_init) { |
753 Comment cmnt(masm_, "[ VariableDeclaration"); | 732 Comment cmnt(masm_, "[ VariableDeclaration"); |
754 EmitDebugCheckDeclarationContext(variable); | 733 EmitDebugCheckDeclarationContext(variable); |
755 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex); | 734 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex); |
756 __ StoreP(ip, ContextMemOperand(cp, variable->index()), r0); | 735 __ StoreP(ip, ContextMemOperand(cp, variable->index())); |
757 // No write barrier since the_hole_value is in old space. | 736 // No write barrier since the_hole_value is in old space. |
758 PrepareForBailoutForId(proxy->id(), NO_REGISTERS); | 737 PrepareForBailoutForId(proxy->id(), NO_REGISTERS); |
759 } | 738 } |
760 break; | 739 break; |
761 | 740 |
762 case VariableLocation::LOOKUP: { | 741 case VariableLocation::LOOKUP: { |
763 Comment cmnt(masm_, "[ VariableDeclaration"); | 742 Comment cmnt(masm_, "[ VariableDeclaration"); |
764 __ mov(r5, Operand(variable->name())); | 743 __ mov(r4, Operand(variable->name())); |
765 // Declaration nodes are always introduced in one of four modes. | 744 // Declaration nodes are always introduced in one of four modes. |
766 DCHECK(IsDeclaredVariableMode(mode)); | 745 DCHECK(IsDeclaredVariableMode(mode)); |
767 // Push initial value, if any. | 746 // Push initial value, if any. |
768 // Note: For variables we must not push an initial value (such as | 747 // Note: For variables we must not push an initial value (such as |
769 // 'undefined') because we may have a (legal) redeclaration and we | 748 // 'undefined') because we may have a (legal) redeclaration and we |
770 // must not destroy the current value. | 749 // must not destroy the current value. |
771 if (hole_init) { | 750 if (hole_init) { |
772 __ LoadRoot(r3, Heap::kTheHoleValueRootIndex); | 751 __ LoadRoot(r2, Heap::kTheHoleValueRootIndex); |
773 } else { | 752 } else { |
774 __ LoadSmiLiteral(r3, Smi::FromInt(0)); // Indicates no initial value. | 753 __ LoadSmiLiteral(r2, Smi::FromInt(0)); // Indicates no initial value. |
775 } | 754 } |
776 __ Push(r5, r3); | 755 __ Push(r4, r2); |
777 __ Push(Smi::FromInt(variable->DeclarationPropertyAttributes())); | 756 __ Push(Smi::FromInt(variable->DeclarationPropertyAttributes())); |
778 __ CallRuntime(Runtime::kDeclareLookupSlot); | 757 __ CallRuntime(Runtime::kDeclareLookupSlot); |
779 break; | 758 break; |
780 } | 759 } |
781 } | 760 } |
782 } | 761 } |
783 | 762 |
784 | |
785 void FullCodeGenerator::VisitFunctionDeclaration( | 763 void FullCodeGenerator::VisitFunctionDeclaration( |
786 FunctionDeclaration* declaration) { | 764 FunctionDeclaration* declaration) { |
787 VariableProxy* proxy = declaration->proxy(); | 765 VariableProxy* proxy = declaration->proxy(); |
788 Variable* variable = proxy->var(); | 766 Variable* variable = proxy->var(); |
789 switch (variable->location()) { | 767 switch (variable->location()) { |
790 case VariableLocation::GLOBAL: | 768 case VariableLocation::GLOBAL: |
791 case VariableLocation::UNALLOCATED: { | 769 case VariableLocation::UNALLOCATED: { |
792 globals_->Add(variable->name(), zone()); | 770 globals_->Add(variable->name(), zone()); |
793 Handle<SharedFunctionInfo> function = | 771 Handle<SharedFunctionInfo> function = |
794 Compiler::GetSharedFunctionInfo(declaration->fun(), script(), info_); | 772 Compiler::GetSharedFunctionInfo(declaration->fun(), script(), info_); |
795 // Check for stack-overflow exception. | 773 // Check for stack-overflow exception. |
796 if (function.is_null()) return SetStackOverflow(); | 774 if (function.is_null()) return SetStackOverflow(); |
797 globals_->Add(function, zone()); | 775 globals_->Add(function, zone()); |
798 break; | 776 break; |
799 } | 777 } |
800 | 778 |
801 case VariableLocation::PARAMETER: | 779 case VariableLocation::PARAMETER: |
802 case VariableLocation::LOCAL: { | 780 case VariableLocation::LOCAL: { |
803 Comment cmnt(masm_, "[ FunctionDeclaration"); | 781 Comment cmnt(masm_, "[ FunctionDeclaration"); |
804 VisitForAccumulatorValue(declaration->fun()); | 782 VisitForAccumulatorValue(declaration->fun()); |
805 __ StoreP(result_register(), StackOperand(variable)); | 783 __ StoreP(result_register(), StackOperand(variable)); |
806 break; | 784 break; |
807 } | 785 } |
808 | 786 |
809 case VariableLocation::CONTEXT: { | 787 case VariableLocation::CONTEXT: { |
810 Comment cmnt(masm_, "[ FunctionDeclaration"); | 788 Comment cmnt(masm_, "[ FunctionDeclaration"); |
811 EmitDebugCheckDeclarationContext(variable); | 789 EmitDebugCheckDeclarationContext(variable); |
812 VisitForAccumulatorValue(declaration->fun()); | 790 VisitForAccumulatorValue(declaration->fun()); |
813 __ StoreP(result_register(), ContextMemOperand(cp, variable->index()), | 791 __ StoreP(result_register(), ContextMemOperand(cp, variable->index())); |
814 r0); | |
815 int offset = Context::SlotOffset(variable->index()); | 792 int offset = Context::SlotOffset(variable->index()); |
816 // We know that we have written a function, which is not a smi. | 793 // We know that we have written a function, which is not a smi. |
817 __ RecordWriteContextSlot(cp, offset, result_register(), r5, | 794 __ RecordWriteContextSlot(cp, offset, result_register(), r4, |
818 kLRHasBeenSaved, kDontSaveFPRegs, | 795 kLRHasBeenSaved, kDontSaveFPRegs, |
819 EMIT_REMEMBERED_SET, OMIT_SMI_CHECK); | 796 EMIT_REMEMBERED_SET, OMIT_SMI_CHECK); |
820 PrepareForBailoutForId(proxy->id(), NO_REGISTERS); | 797 PrepareForBailoutForId(proxy->id(), NO_REGISTERS); |
821 break; | 798 break; |
822 } | 799 } |
823 | 800 |
824 case VariableLocation::LOOKUP: { | 801 case VariableLocation::LOOKUP: { |
825 Comment cmnt(masm_, "[ FunctionDeclaration"); | 802 Comment cmnt(masm_, "[ FunctionDeclaration"); |
826 __ mov(r5, Operand(variable->name())); | 803 __ mov(r4, Operand(variable->name())); |
827 PushOperand(r5); | 804 PushOperand(r4); |
828 // Push initial value for function declaration. | 805 // Push initial value for function declaration. |
829 VisitForStackValue(declaration->fun()); | 806 VisitForStackValue(declaration->fun()); |
830 PushOperand(Smi::FromInt(variable->DeclarationPropertyAttributes())); | 807 PushOperand(Smi::FromInt(variable->DeclarationPropertyAttributes())); |
831 CallRuntimeWithOperands(Runtime::kDeclareLookupSlot); | 808 CallRuntimeWithOperands(Runtime::kDeclareLookupSlot); |
832 break; | 809 break; |
833 } | 810 } |
834 } | 811 } |
835 } | 812 } |
836 | 813 |
837 | |
838 void FullCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) { | 814 void FullCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) { |
839 // Call the runtime to declare the globals. | 815 // Call the runtime to declare the globals. |
840 __ mov(r4, Operand(pairs)); | 816 __ mov(r3, Operand(pairs)); |
841 __ LoadSmiLiteral(r3, Smi::FromInt(DeclareGlobalsFlags())); | 817 __ LoadSmiLiteral(r2, Smi::FromInt(DeclareGlobalsFlags())); |
842 __ Push(r4, r3); | 818 __ Push(r3, r2); |
843 __ CallRuntime(Runtime::kDeclareGlobals); | 819 __ CallRuntime(Runtime::kDeclareGlobals); |
844 // Return value is ignored. | 820 // Return value is ignored. |
845 } | 821 } |
846 | 822 |
847 | |
848 void FullCodeGenerator::DeclareModules(Handle<FixedArray> descriptions) { | 823 void FullCodeGenerator::DeclareModules(Handle<FixedArray> descriptions) { |
849 // Call the runtime to declare the modules. | 824 // Call the runtime to declare the modules. |
850 __ Push(descriptions); | 825 __ Push(descriptions); |
851 __ CallRuntime(Runtime::kDeclareModules); | 826 __ CallRuntime(Runtime::kDeclareModules); |
852 // Return value is ignored. | 827 // Return value is ignored. |
853 } | 828 } |
854 | 829 |
855 | |
856 void FullCodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) { | 830 void FullCodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) { |
857 Comment cmnt(masm_, "[ SwitchStatement"); | 831 Comment cmnt(masm_, "[ SwitchStatement"); |
858 Breakable nested_statement(this, stmt); | 832 Breakable nested_statement(this, stmt); |
859 SetStatementPosition(stmt); | 833 SetStatementPosition(stmt); |
860 | 834 |
861 // Keep the switch value on the stack until a case matches. | 835 // Keep the switch value on the stack until a case matches. |
862 VisitForStackValue(stmt->tag()); | 836 VisitForStackValue(stmt->tag()); |
863 PrepareForBailoutForId(stmt->EntryId(), NO_REGISTERS); | 837 PrepareForBailoutForId(stmt->EntryId(), NO_REGISTERS); |
864 | 838 |
865 ZoneList<CaseClause*>* clauses = stmt->cases(); | 839 ZoneList<CaseClause*>* clauses = stmt->cases(); |
(...skipping 12 matching lines...) Expand all Loading... |
878 } | 852 } |
879 | 853 |
880 Comment cmnt(masm_, "[ Case comparison"); | 854 Comment cmnt(masm_, "[ Case comparison"); |
881 __ bind(&next_test); | 855 __ bind(&next_test); |
882 next_test.Unuse(); | 856 next_test.Unuse(); |
883 | 857 |
884 // Compile the label expression. | 858 // Compile the label expression. |
885 VisitForAccumulatorValue(clause->label()); | 859 VisitForAccumulatorValue(clause->label()); |
886 | 860 |
887 // Perform the comparison as if via '==='. | 861 // Perform the comparison as if via '==='. |
888 __ LoadP(r4, MemOperand(sp, 0)); // Switch value. | 862 __ LoadP(r3, MemOperand(sp, 0)); // Switch value. |
889 bool inline_smi_code = ShouldInlineSmiCase(Token::EQ_STRICT); | 863 bool inline_smi_code = ShouldInlineSmiCase(Token::EQ_STRICT); |
890 JumpPatchSite patch_site(masm_); | 864 JumpPatchSite patch_site(masm_); |
891 if (inline_smi_code) { | 865 if (inline_smi_code) { |
892 Label slow_case; | 866 Label slow_case; |
893 __ orx(r5, r4, r3); | 867 __ LoadRR(r4, r2); |
894 patch_site.EmitJumpIfNotSmi(r5, &slow_case); | 868 __ OrP(r4, r3); |
| 869 patch_site.EmitJumpIfNotSmi(r4, &slow_case); |
895 | 870 |
896 __ cmp(r4, r3); | 871 __ CmpP(r3, r2); |
897 __ bne(&next_test); | 872 __ bne(&next_test); |
898 __ Drop(1); // Switch value is no longer needed. | 873 __ Drop(1); // Switch value is no longer needed. |
899 __ b(clause->body_target()); | 874 __ b(clause->body_target()); |
900 __ bind(&slow_case); | 875 __ bind(&slow_case); |
901 } | 876 } |
902 | 877 |
903 // Record position before stub call for type feedback. | 878 // Record position before stub call for type feedback. |
904 SetExpressionPosition(clause); | 879 SetExpressionPosition(clause); |
905 Handle<Code> ic = | 880 Handle<Code> ic = |
906 CodeFactory::CompareIC(isolate(), Token::EQ_STRICT).code(); | 881 CodeFactory::CompareIC(isolate(), Token::EQ_STRICT).code(); |
907 CallIC(ic, clause->CompareId()); | 882 CallIC(ic, clause->CompareId()); |
908 patch_site.EmitPatchInfo(); | 883 patch_site.EmitPatchInfo(); |
909 | 884 |
910 Label skip; | 885 Label skip; |
911 __ b(&skip); | 886 __ b(&skip); |
912 PrepareForBailout(clause, TOS_REG); | 887 PrepareForBailout(clause, TOS_REG); |
913 __ LoadRoot(ip, Heap::kTrueValueRootIndex); | 888 __ CompareRoot(r2, Heap::kTrueValueRootIndex); |
914 __ cmp(r3, ip); | |
915 __ bne(&next_test); | 889 __ bne(&next_test); |
916 __ Drop(1); | 890 __ Drop(1); |
917 __ b(clause->body_target()); | 891 __ b(clause->body_target()); |
918 __ bind(&skip); | 892 __ bind(&skip); |
919 | 893 |
920 __ cmpi(r3, Operand::Zero()); | 894 __ CmpP(r2, Operand::Zero()); |
921 __ bne(&next_test); | 895 __ bne(&next_test); |
922 __ Drop(1); // Switch value is no longer needed. | 896 __ Drop(1); // Switch value is no longer needed. |
923 __ b(clause->body_target()); | 897 __ b(clause->body_target()); |
924 } | 898 } |
925 | 899 |
926 // Discard the test value and jump to the default if present, otherwise to | 900 // Discard the test value and jump to the default if present, otherwise to |
927 // the end of the statement. | 901 // the end of the statement. |
928 __ bind(&next_test); | 902 __ bind(&next_test); |
929 DropOperands(1); // Switch value is no longer needed. | 903 DropOperands(1); // Switch value is no longer needed. |
930 if (default_clause == NULL) { | 904 if (default_clause == NULL) { |
931 __ b(nested_statement.break_label()); | 905 __ b(nested_statement.break_label()); |
932 } else { | 906 } else { |
933 __ b(default_clause->body_target()); | 907 __ b(default_clause->body_target()); |
934 } | 908 } |
935 | 909 |
936 // Compile all the case bodies. | 910 // Compile all the case bodies. |
937 for (int i = 0; i < clauses->length(); i++) { | 911 for (int i = 0; i < clauses->length(); i++) { |
938 Comment cmnt(masm_, "[ Case body"); | 912 Comment cmnt(masm_, "[ Case body"); |
939 CaseClause* clause = clauses->at(i); | 913 CaseClause* clause = clauses->at(i); |
940 __ bind(clause->body_target()); | 914 __ bind(clause->body_target()); |
941 PrepareForBailoutForId(clause->EntryId(), NO_REGISTERS); | 915 PrepareForBailoutForId(clause->EntryId(), NO_REGISTERS); |
942 VisitStatements(clause->statements()); | 916 VisitStatements(clause->statements()); |
943 } | 917 } |
944 | 918 |
945 __ bind(nested_statement.break_label()); | 919 __ bind(nested_statement.break_label()); |
946 PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS); | 920 PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS); |
947 } | 921 } |
948 | 922 |
949 | |
950 void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) { | 923 void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) { |
951 Comment cmnt(masm_, "[ ForInStatement"); | 924 Comment cmnt(masm_, "[ ForInStatement"); |
952 SetStatementPosition(stmt, SKIP_BREAK); | 925 SetStatementPosition(stmt, SKIP_BREAK); |
953 | 926 |
954 FeedbackVectorSlot slot = stmt->ForInFeedbackSlot(); | 927 FeedbackVectorSlot slot = stmt->ForInFeedbackSlot(); |
955 | 928 |
956 // Get the object to enumerate over. | 929 // Get the object to enumerate over. |
957 SetExpressionAsStatementPosition(stmt->enumerable()); | 930 SetExpressionAsStatementPosition(stmt->enumerable()); |
958 VisitForAccumulatorValue(stmt->enumerable()); | 931 VisitForAccumulatorValue(stmt->enumerable()); |
959 OperandStackDepthIncrement(5); | 932 OperandStackDepthIncrement(5); |
960 | 933 |
961 Label loop, exit; | 934 Label loop, exit; |
962 Iteration loop_statement(this, stmt); | 935 Iteration loop_statement(this, stmt); |
963 increment_loop_depth(); | 936 increment_loop_depth(); |
964 | 937 |
965 // If the object is null or undefined, skip over the loop, otherwise convert | 938 // If the object is null or undefined, skip over the loop, otherwise convert |
966 // it to a JS receiver. See ECMA-262 version 5, section 12.6.4. | 939 // it to a JS receiver. See ECMA-262 version 5, section 12.6.4. |
967 Label convert, done_convert; | 940 Label convert, done_convert; |
968 __ JumpIfSmi(r3, &convert); | 941 __ JumpIfSmi(r2, &convert); |
969 __ CompareObjectType(r3, r4, r4, FIRST_JS_RECEIVER_TYPE); | 942 __ CompareObjectType(r2, r3, r3, FIRST_JS_RECEIVER_TYPE); |
970 __ bge(&done_convert); | 943 __ bge(&done_convert); |
971 __ CompareRoot(r3, Heap::kNullValueRootIndex); | 944 __ CompareRoot(r2, Heap::kNullValueRootIndex); |
972 __ beq(&exit); | 945 __ beq(&exit); |
973 __ CompareRoot(r3, Heap::kUndefinedValueRootIndex); | 946 __ CompareRoot(r2, Heap::kUndefinedValueRootIndex); |
974 __ beq(&exit); | 947 __ beq(&exit); |
975 __ bind(&convert); | 948 __ bind(&convert); |
976 ToObjectStub stub(isolate()); | 949 ToObjectStub stub(isolate()); |
977 __ CallStub(&stub); | 950 __ CallStub(&stub); |
978 __ bind(&done_convert); | 951 __ bind(&done_convert); |
979 PrepareForBailoutForId(stmt->ToObjectId(), TOS_REG); | 952 PrepareForBailoutForId(stmt->ToObjectId(), TOS_REG); |
980 __ push(r3); | 953 __ push(r2); |
981 | 954 |
982 // Check cache validity in generated code. This is a fast case for | 955 // Check cache validity in generated code. This is a fast case for |
983 // the JSObject::IsSimpleEnum cache validity checks. If we cannot | 956 // the JSObject::IsSimpleEnum cache validity checks. If we cannot |
984 // guarantee cache validity, call the runtime system to check cache | 957 // guarantee cache validity, call the runtime system to check cache |
985 // validity or get the property names in a fixed array. | 958 // validity or get the property names in a fixed array. |
986 // Note: Proxies never have an enum cache, so will always take the | 959 // Note: Proxies never have an enum cache, so will always take the |
987 // slow path. | 960 // slow path. |
988 Label call_runtime; | 961 Label call_runtime; |
989 __ CheckEnumCache(&call_runtime); | 962 __ CheckEnumCache(&call_runtime); |
990 | 963 |
991 // The enum cache is valid. Load the map of the object being | 964 // The enum cache is valid. Load the map of the object being |
992 // iterated over and use the cache for the iteration. | 965 // iterated over and use the cache for the iteration. |
993 Label use_cache; | 966 Label use_cache; |
994 __ LoadP(r3, FieldMemOperand(r3, HeapObject::kMapOffset)); | 967 __ LoadP(r2, FieldMemOperand(r2, HeapObject::kMapOffset)); |
995 __ b(&use_cache); | 968 __ b(&use_cache); |
996 | 969 |
997 // Get the set of properties to enumerate. | 970 // Get the set of properties to enumerate. |
998 __ bind(&call_runtime); | 971 __ bind(&call_runtime); |
999 __ push(r3); // Duplicate the enumerable object on the stack. | 972 __ push(r2); // Duplicate the enumerable object on the stack. |
1000 __ CallRuntime(Runtime::kForInEnumerate); | 973 __ CallRuntime(Runtime::kForInEnumerate); |
1001 PrepareForBailoutForId(stmt->EnumId(), TOS_REG); | 974 PrepareForBailoutForId(stmt->EnumId(), TOS_REG); |
1002 | 975 |
1003 // If we got a map from the runtime call, we can do a fast | 976 // If we got a map from the runtime call, we can do a fast |
1004 // modification check. Otherwise, we got a fixed array, and we have | 977 // modification check. Otherwise, we got a fixed array, and we have |
1005 // to do a slow check. | 978 // to do a slow check. |
1006 Label fixed_array; | 979 Label fixed_array; |
1007 __ LoadP(r5, FieldMemOperand(r3, HeapObject::kMapOffset)); | 980 __ LoadP(r4, FieldMemOperand(r2, HeapObject::kMapOffset)); |
1008 __ LoadRoot(ip, Heap::kMetaMapRootIndex); | 981 __ CompareRoot(r4, Heap::kMetaMapRootIndex); |
1009 __ cmp(r5, ip); | |
1010 __ bne(&fixed_array); | 982 __ bne(&fixed_array); |
1011 | 983 |
1012 // We got a map in register r3. Get the enumeration cache from it. | 984 // We got a map in register r2. Get the enumeration cache from it. |
1013 Label no_descriptors; | 985 Label no_descriptors; |
1014 __ bind(&use_cache); | 986 __ bind(&use_cache); |
1015 | 987 |
1016 __ EnumLength(r4, r3); | 988 __ EnumLength(r3, r2); |
1017 __ CmpSmiLiteral(r4, Smi::FromInt(0), r0); | 989 __ CmpSmiLiteral(r3, Smi::FromInt(0), r0); |
1018 __ beq(&no_descriptors); | 990 __ beq(&no_descriptors, Label::kNear); |
1019 | 991 |
1020 __ LoadInstanceDescriptors(r3, r5); | 992 __ LoadInstanceDescriptors(r2, r4); |
1021 __ LoadP(r5, FieldMemOperand(r5, DescriptorArray::kEnumCacheOffset)); | 993 __ LoadP(r4, FieldMemOperand(r4, DescriptorArray::kEnumCacheOffset)); |
1022 __ LoadP(r5, | 994 __ LoadP(r4, |
1023 FieldMemOperand(r5, DescriptorArray::kEnumCacheBridgeCacheOffset)); | 995 FieldMemOperand(r4, DescriptorArray::kEnumCacheBridgeCacheOffset)); |
1024 | 996 |
1025 // Set up the four remaining stack slots. | 997 // Set up the four remaining stack slots. |
1026 __ push(r3); // Map. | 998 __ push(r2); // Map. |
1027 __ LoadSmiLiteral(r3, Smi::FromInt(0)); | 999 __ LoadSmiLiteral(r2, Smi::FromInt(0)); |
1028 // Push enumeration cache, enumeration cache length (as smi) and zero. | 1000 // Push enumeration cache, enumeration cache length (as smi) and zero. |
1029 __ Push(r5, r4, r3); | 1001 __ Push(r4, r3, r2); |
1030 __ b(&loop); | 1002 __ b(&loop); |
1031 | 1003 |
1032 __ bind(&no_descriptors); | 1004 __ bind(&no_descriptors); |
1033 __ Drop(1); | 1005 __ Drop(1); |
1034 __ b(&exit); | 1006 __ b(&exit); |
1035 | 1007 |
1036 // We got a fixed array in register r3. Iterate through that. | 1008 // We got a fixed array in register r2. Iterate through that. |
1037 __ bind(&fixed_array); | 1009 __ bind(&fixed_array); |
1038 | 1010 |
1039 __ LoadSmiLiteral(r4, Smi::FromInt(1)); // Smi(1) indicates slow check | 1011 int const vector_index = SmiFromSlot(slot)->value(); |
1040 __ Push(r4, r3); // Smi and array | 1012 __ EmitLoadTypeFeedbackVector(r3); |
1041 __ LoadP(r4, FieldMemOperand(r3, FixedArray::kLengthOffset)); | 1013 __ mov(r4, Operand(TypeFeedbackVector::MegamorphicSentinel(isolate()))); |
1042 __ Push(r4); // Fixed array length (as smi). | 1014 __ StoreP( |
| 1015 r4, FieldMemOperand(r3, FixedArray::OffsetOfElementAt(vector_index)), r0); |
| 1016 __ LoadSmiLiteral(r3, Smi::FromInt(1)); // Smi(1) indicates slow check |
| 1017 __ Push(r3, r2); // Smi and array |
| 1018 __ LoadP(r3, FieldMemOperand(r2, FixedArray::kLengthOffset)); |
| 1019 __ Push(r3); // Fixed array length (as smi). |
1043 PrepareForBailoutForId(stmt->PrepareId(), NO_REGISTERS); | 1020 PrepareForBailoutForId(stmt->PrepareId(), NO_REGISTERS); |
1044 __ LoadSmiLiteral(r3, Smi::FromInt(0)); | 1021 __ LoadSmiLiteral(r2, Smi::FromInt(0)); |
1045 __ Push(r3); // Initial index. | 1022 __ Push(r2); // Initial index. |
1046 | 1023 |
1047 // Generate code for doing the condition check. | 1024 // Generate code for doing the condition check. |
1048 __ bind(&loop); | 1025 __ bind(&loop); |
1049 SetExpressionAsStatementPosition(stmt->each()); | 1026 SetExpressionAsStatementPosition(stmt->each()); |
1050 | 1027 |
1051 // Load the current count to r3, load the length to r4. | 1028 // Load the current count to r2, load the length to r3. |
1052 __ LoadP(r3, MemOperand(sp, 0 * kPointerSize)); | 1029 __ LoadP(r2, MemOperand(sp, 0 * kPointerSize)); |
1053 __ LoadP(r4, MemOperand(sp, 1 * kPointerSize)); | 1030 __ LoadP(r3, MemOperand(sp, 1 * kPointerSize)); |
1054 __ cmpl(r3, r4); // Compare to the array length. | 1031 __ CmpLogicalP(r2, r3); // Compare to the array length. |
1055 __ bge(loop_statement.break_label()); | 1032 __ bge(loop_statement.break_label()); |
1056 | 1033 |
1057 // Get the current entry of the array into register r6. | 1034 // Get the current entry of the array into register r5. |
1058 __ LoadP(r5, MemOperand(sp, 2 * kPointerSize)); | 1035 __ LoadP(r4, MemOperand(sp, 2 * kPointerSize)); |
1059 __ addi(r5, r5, Operand(FixedArray::kHeaderSize - kHeapObjectTag)); | 1036 __ AddP(r4, Operand(FixedArray::kHeaderSize - kHeapObjectTag)); |
1060 __ SmiToPtrArrayOffset(r6, r3); | 1037 __ SmiToPtrArrayOffset(r5, r2); |
1061 __ LoadPX(r6, MemOperand(r6, r5)); | 1038 __ LoadP(r5, MemOperand(r5, r4)); |
1062 | 1039 |
1063 // Get the expected map from the stack or a smi in the | 1040 // Get the expected map from the stack or a smi in the |
1064 // permanent slow case into register r5. | 1041 // permanent slow case into register r4. |
1065 __ LoadP(r5, MemOperand(sp, 3 * kPointerSize)); | 1042 __ LoadP(r4, MemOperand(sp, 3 * kPointerSize)); |
1066 | 1043 |
1067 // Check if the expected map still matches that of the enumerable. | 1044 // Check if the expected map still matches that of the enumerable. |
1068 // If not, we may have to filter the key. | 1045 // If not, we may have to filter the key. |
1069 Label update_each; | 1046 Label update_each; |
1070 __ LoadP(r4, MemOperand(sp, 4 * kPointerSize)); | 1047 __ LoadP(r3, MemOperand(sp, 4 * kPointerSize)); |
1071 __ LoadP(r7, FieldMemOperand(r4, HeapObject::kMapOffset)); | 1048 __ LoadP(r6, FieldMemOperand(r3, HeapObject::kMapOffset)); |
1072 __ cmp(r7, r5); | 1049 __ CmpP(r6, r4); |
1073 __ beq(&update_each); | 1050 __ beq(&update_each); |
1074 | 1051 |
1075 // We need to filter the key, record slow-path here. | 1052 // We might get here from TurboFan or Crankshaft when something in the |
1076 int const vector_index = SmiFromSlot(slot)->value(); | 1053 // for-in loop body deopts and only now notice in fullcodegen, that we |
1077 __ EmitLoadTypeFeedbackVector(r3); | 1054 // can now longer use the enum cache, i.e. left fast mode. So better record |
1078 __ mov(r5, Operand(TypeFeedbackVector::MegamorphicSentinel(isolate()))); | 1055 // this information here, in case we later OSR back into this loop or |
| 1056 // reoptimize the whole function w/o rerunning the loop with the slow |
| 1057 // mode object in fullcodegen (which would result in a deopt loop). |
| 1058 __ EmitLoadTypeFeedbackVector(r2); |
| 1059 __ mov(r4, Operand(TypeFeedbackVector::MegamorphicSentinel(isolate()))); |
1079 __ StoreP( | 1060 __ StoreP( |
1080 r5, FieldMemOperand(r3, FixedArray::OffsetOfElementAt(vector_index)), r0); | 1061 r4, FieldMemOperand(r2, FixedArray::OffsetOfElementAt(vector_index)), r0); |
1081 | 1062 |
1082 // Convert the entry to a string or (smi) 0 if it isn't a property | 1063 // Convert the entry to a string or (smi) 0 if it isn't a property |
1083 // any more. If the property has been removed while iterating, we | 1064 // any more. If the property has been removed while iterating, we |
1084 // just skip it. | 1065 // just skip it. |
1085 __ Push(r4, r6); // Enumerable and current entry. | 1066 __ Push(r3, r5); // Enumerable and current entry. |
1086 __ CallRuntime(Runtime::kForInFilter); | 1067 __ CallRuntime(Runtime::kForInFilter); |
1087 PrepareForBailoutForId(stmt->FilterId(), TOS_REG); | 1068 PrepareForBailoutForId(stmt->FilterId(), TOS_REG); |
1088 __ mr(r6, r3); | 1069 __ LoadRR(r5, r2); |
1089 __ LoadRoot(r0, Heap::kUndefinedValueRootIndex); | 1070 __ LoadRoot(r0, Heap::kUndefinedValueRootIndex); |
1090 __ cmp(r3, r0); | 1071 __ CmpP(r2, r0); |
1091 __ beq(loop_statement.continue_label()); | 1072 __ beq(loop_statement.continue_label()); |
1092 | 1073 |
1093 // Update the 'each' property or variable from the possibly filtered | 1074 // Update the 'each' property or variable from the possibly filtered |
1094 // entry in register r6. | 1075 // entry in register r5. |
1095 __ bind(&update_each); | 1076 __ bind(&update_each); |
1096 __ mr(result_register(), r6); | 1077 __ LoadRR(result_register(), r5); |
1097 // Perform the assignment as if via '='. | 1078 // Perform the assignment as if via '='. |
1098 { | 1079 { |
1099 EffectContext context(this); | 1080 EffectContext context(this); |
1100 EmitAssignment(stmt->each(), stmt->EachFeedbackSlot()); | 1081 EmitAssignment(stmt->each(), stmt->EachFeedbackSlot()); |
1101 PrepareForBailoutForId(stmt->AssignmentId(), NO_REGISTERS); | 1082 PrepareForBailoutForId(stmt->AssignmentId(), NO_REGISTERS); |
1102 } | 1083 } |
1103 | 1084 |
1104 // Both Crankshaft and Turbofan expect BodyId to be right before stmt->body(). | 1085 // Both Crankshaft and Turbofan expect BodyId to be right before stmt->body(). |
1105 PrepareForBailoutForId(stmt->BodyId(), NO_REGISTERS); | 1086 PrepareForBailoutForId(stmt->BodyId(), NO_REGISTERS); |
1106 // Generate code for the body of the loop. | 1087 // Generate code for the body of the loop. |
1107 Visit(stmt->body()); | 1088 Visit(stmt->body()); |
1108 | 1089 |
1109 // Generate code for the going to the next element by incrementing | 1090 // Generate code for the going to the next element by incrementing |
1110 // the index (smi) stored on top of the stack. | 1091 // the index (smi) stored on top of the stack. |
1111 __ bind(loop_statement.continue_label()); | 1092 __ bind(loop_statement.continue_label()); |
1112 __ pop(r3); | 1093 __ pop(r2); |
1113 __ AddSmiLiteral(r3, r3, Smi::FromInt(1), r0); | 1094 __ AddSmiLiteral(r2, r2, Smi::FromInt(1), r0); |
1114 __ push(r3); | 1095 __ push(r2); |
1115 | 1096 |
1116 EmitBackEdgeBookkeeping(stmt, &loop); | 1097 EmitBackEdgeBookkeeping(stmt, &loop); |
1117 __ b(&loop); | 1098 __ b(&loop); |
1118 | 1099 |
1119 // Remove the pointers stored on the stack. | 1100 // Remove the pointers stored on the stack. |
1120 __ bind(loop_statement.break_label()); | 1101 __ bind(loop_statement.break_label()); |
1121 DropOperands(5); | 1102 DropOperands(5); |
1122 | 1103 |
1123 // Exit and decrement the loop depth. | 1104 // Exit and decrement the loop depth. |
1124 PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS); | 1105 PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS); |
1125 __ bind(&exit); | 1106 __ bind(&exit); |
1126 decrement_loop_depth(); | 1107 decrement_loop_depth(); |
1127 } | 1108 } |
1128 | 1109 |
1129 | |
1130 void FullCodeGenerator::EmitSetHomeObject(Expression* initializer, int offset, | 1110 void FullCodeGenerator::EmitSetHomeObject(Expression* initializer, int offset, |
1131 FeedbackVectorSlot slot) { | 1111 FeedbackVectorSlot slot) { |
1132 DCHECK(NeedsHomeObject(initializer)); | 1112 DCHECK(NeedsHomeObject(initializer)); |
1133 __ LoadP(StoreDescriptor::ReceiverRegister(), MemOperand(sp)); | 1113 __ LoadP(StoreDescriptor::ReceiverRegister(), MemOperand(sp)); |
1134 __ mov(StoreDescriptor::NameRegister(), | 1114 __ mov(StoreDescriptor::NameRegister(), |
1135 Operand(isolate()->factory()->home_object_symbol())); | 1115 Operand(isolate()->factory()->home_object_symbol())); |
1136 __ LoadP(StoreDescriptor::ValueRegister(), | 1116 __ LoadP(StoreDescriptor::ValueRegister(), |
1137 MemOperand(sp, offset * kPointerSize)); | 1117 MemOperand(sp, offset * kPointerSize)); |
1138 EmitLoadStoreICSlot(slot); | 1118 EmitLoadStoreICSlot(slot); |
1139 CallStoreIC(); | 1119 CallStoreIC(); |
1140 } | 1120 } |
1141 | 1121 |
1142 | |
1143 void FullCodeGenerator::EmitSetHomeObjectAccumulator(Expression* initializer, | 1122 void FullCodeGenerator::EmitSetHomeObjectAccumulator(Expression* initializer, |
1144 int offset, | 1123 int offset, |
1145 FeedbackVectorSlot slot) { | 1124 FeedbackVectorSlot slot) { |
1146 DCHECK(NeedsHomeObject(initializer)); | 1125 DCHECK(NeedsHomeObject(initializer)); |
1147 __ Move(StoreDescriptor::ReceiverRegister(), r3); | 1126 __ Move(StoreDescriptor::ReceiverRegister(), r2); |
1148 __ mov(StoreDescriptor::NameRegister(), | 1127 __ mov(StoreDescriptor::NameRegister(), |
1149 Operand(isolate()->factory()->home_object_symbol())); | 1128 Operand(isolate()->factory()->home_object_symbol())); |
1150 __ LoadP(StoreDescriptor::ValueRegister(), | 1129 __ LoadP(StoreDescriptor::ValueRegister(), |
1151 MemOperand(sp, offset * kPointerSize)); | 1130 MemOperand(sp, offset * kPointerSize)); |
1152 EmitLoadStoreICSlot(slot); | 1131 EmitLoadStoreICSlot(slot); |
1153 CallStoreIC(); | 1132 CallStoreIC(); |
1154 } | 1133 } |
1155 | 1134 |
1156 | |
1157 void FullCodeGenerator::EmitLoadGlobalCheckExtensions(VariableProxy* proxy, | 1135 void FullCodeGenerator::EmitLoadGlobalCheckExtensions(VariableProxy* proxy, |
1158 TypeofMode typeof_mode, | 1136 TypeofMode typeof_mode, |
1159 Label* slow) { | 1137 Label* slow) { |
1160 Register current = cp; | 1138 Register current = cp; |
1161 Register next = r4; | 1139 Register next = r3; |
1162 Register temp = r5; | 1140 Register temp = r4; |
1163 | 1141 |
1164 Scope* s = scope(); | 1142 Scope* s = scope(); |
1165 while (s != NULL) { | 1143 while (s != NULL) { |
1166 if (s->num_heap_slots() > 0) { | 1144 if (s->num_heap_slots() > 0) { |
1167 if (s->calls_sloppy_eval()) { | 1145 if (s->calls_sloppy_eval()) { |
1168 // Check that extension is "the hole". | 1146 // Check that extension is "the hole". |
1169 __ LoadP(temp, ContextMemOperand(current, Context::EXTENSION_INDEX)); | 1147 __ LoadP(temp, ContextMemOperand(current, Context::EXTENSION_INDEX)); |
1170 __ JumpIfNotRoot(temp, Heap::kTheHoleValueRootIndex, slow); | 1148 __ JumpIfNotRoot(temp, Heap::kTheHoleValueRootIndex, slow); |
1171 } | 1149 } |
1172 // Load next context in chain. | 1150 // Load next context in chain. |
1173 __ LoadP(next, ContextMemOperand(current, Context::PREVIOUS_INDEX)); | 1151 __ LoadP(next, ContextMemOperand(current, Context::PREVIOUS_INDEX)); |
1174 // Walk the rest of the chain without clobbering cp. | 1152 // Walk the rest of the chain without clobbering cp. |
1175 current = next; | 1153 current = next; |
1176 } | 1154 } |
1177 // If no outer scope calls eval, we do not need to check more | 1155 // If no outer scope calls eval, we do not need to check more |
1178 // context extensions. | 1156 // context extensions. |
1179 if (!s->outer_scope_calls_sloppy_eval() || s->is_eval_scope()) break; | 1157 if (!s->outer_scope_calls_sloppy_eval() || s->is_eval_scope()) break; |
1180 s = s->outer_scope(); | 1158 s = s->outer_scope(); |
1181 } | 1159 } |
1182 | 1160 |
1183 if (s->is_eval_scope()) { | 1161 if (s->is_eval_scope()) { |
1184 Label loop, fast; | 1162 Label loop, fast; |
1185 if (!current.is(next)) { | 1163 if (!current.is(next)) { |
1186 __ Move(next, current); | 1164 __ Move(next, current); |
1187 } | 1165 } |
1188 __ bind(&loop); | 1166 __ bind(&loop); |
1189 // Terminate at native context. | 1167 // Terminate at native context. |
1190 __ LoadP(temp, FieldMemOperand(next, HeapObject::kMapOffset)); | 1168 __ LoadP(temp, FieldMemOperand(next, HeapObject::kMapOffset)); |
1191 __ LoadRoot(ip, Heap::kNativeContextMapRootIndex); | 1169 __ CompareRoot(temp, Heap::kNativeContextMapRootIndex); |
1192 __ cmp(temp, ip); | 1170 __ beq(&fast, Label::kNear); |
1193 __ beq(&fast); | |
1194 // Check that extension is "the hole". | 1171 // Check that extension is "the hole". |
1195 __ LoadP(temp, ContextMemOperand(next, Context::EXTENSION_INDEX)); | 1172 __ LoadP(temp, ContextMemOperand(next, Context::EXTENSION_INDEX)); |
1196 __ JumpIfNotRoot(temp, Heap::kTheHoleValueRootIndex, slow); | 1173 __ JumpIfNotRoot(temp, Heap::kTheHoleValueRootIndex, slow); |
1197 // Load next context in chain. | 1174 // Load next context in chain. |
1198 __ LoadP(next, ContextMemOperand(next, Context::PREVIOUS_INDEX)); | 1175 __ LoadP(next, ContextMemOperand(next, Context::PREVIOUS_INDEX)); |
1199 __ b(&loop); | 1176 __ b(&loop); |
1200 __ bind(&fast); | 1177 __ bind(&fast); |
1201 } | 1178 } |
1202 | 1179 |
1203 // All extension objects were empty and it is safe to use a normal global | 1180 // All extension objects were empty and it is safe to use a normal global |
1204 // load machinery. | 1181 // load machinery. |
1205 EmitGlobalVariableLoad(proxy, typeof_mode); | 1182 EmitGlobalVariableLoad(proxy, typeof_mode); |
1206 } | 1183 } |
1207 | 1184 |
1208 | |
1209 MemOperand FullCodeGenerator::ContextSlotOperandCheckExtensions(Variable* var, | 1185 MemOperand FullCodeGenerator::ContextSlotOperandCheckExtensions(Variable* var, |
1210 Label* slow) { | 1186 Label* slow) { |
1211 DCHECK(var->IsContextSlot()); | 1187 DCHECK(var->IsContextSlot()); |
1212 Register context = cp; | 1188 Register context = cp; |
1213 Register next = r6; | 1189 Register next = r5; |
1214 Register temp = r7; | 1190 Register temp = r6; |
1215 | 1191 |
1216 for (Scope* s = scope(); s != var->scope(); s = s->outer_scope()) { | 1192 for (Scope* s = scope(); s != var->scope(); s = s->outer_scope()) { |
1217 if (s->num_heap_slots() > 0) { | 1193 if (s->num_heap_slots() > 0) { |
1218 if (s->calls_sloppy_eval()) { | 1194 if (s->calls_sloppy_eval()) { |
1219 // Check that extension is "the hole". | 1195 // Check that extension is "the hole". |
1220 __ LoadP(temp, ContextMemOperand(context, Context::EXTENSION_INDEX)); | 1196 __ LoadP(temp, ContextMemOperand(context, Context::EXTENSION_INDEX)); |
1221 __ JumpIfNotRoot(temp, Heap::kTheHoleValueRootIndex, slow); | 1197 __ JumpIfNotRoot(temp, Heap::kTheHoleValueRootIndex, slow); |
1222 } | 1198 } |
1223 __ LoadP(next, ContextMemOperand(context, Context::PREVIOUS_INDEX)); | 1199 __ LoadP(next, ContextMemOperand(context, Context::PREVIOUS_INDEX)); |
1224 // Walk the rest of the chain without clobbering cp. | 1200 // Walk the rest of the chain without clobbering cp. |
1225 context = next; | 1201 context = next; |
1226 } | 1202 } |
1227 } | 1203 } |
1228 // Check that last extension is "the hole". | 1204 // Check that last extension is "the hole". |
1229 __ LoadP(temp, ContextMemOperand(context, Context::EXTENSION_INDEX)); | 1205 __ LoadP(temp, ContextMemOperand(context, Context::EXTENSION_INDEX)); |
1230 __ JumpIfNotRoot(temp, Heap::kTheHoleValueRootIndex, slow); | 1206 __ JumpIfNotRoot(temp, Heap::kTheHoleValueRootIndex, slow); |
1231 | 1207 |
1232 // This function is used only for loads, not stores, so it's safe to | 1208 // This function is used only for loads, not stores, so it's safe to |
1233 // return an cp-based operand (the write barrier cannot be allowed to | 1209 // return an cp-based operand (the write barrier cannot be allowed to |
1234 // destroy the cp register). | 1210 // destroy the cp register). |
1235 return ContextMemOperand(context, var->index()); | 1211 return ContextMemOperand(context, var->index()); |
1236 } | 1212 } |
1237 | 1213 |
1238 | |
1239 void FullCodeGenerator::EmitDynamicLookupFastCase(VariableProxy* proxy, | 1214 void FullCodeGenerator::EmitDynamicLookupFastCase(VariableProxy* proxy, |
1240 TypeofMode typeof_mode, | 1215 TypeofMode typeof_mode, |
1241 Label* slow, Label* done) { | 1216 Label* slow, Label* done) { |
1242 // Generate fast-case code for variables that might be shadowed by | 1217 // Generate fast-case code for variables that might be shadowed by |
1243 // eval-introduced variables. Eval is used a lot without | 1218 // eval-introduced variables. Eval is used a lot without |
1244 // introducing variables. In those cases, we do not want to | 1219 // introducing variables. In those cases, we do not want to |
1245 // perform a runtime call for all variables in the scope | 1220 // perform a runtime call for all variables in the scope |
1246 // containing the eval. | 1221 // containing the eval. |
1247 Variable* var = proxy->var(); | 1222 Variable* var = proxy->var(); |
1248 if (var->mode() == DYNAMIC_GLOBAL) { | 1223 if (var->mode() == DYNAMIC_GLOBAL) { |
1249 EmitLoadGlobalCheckExtensions(proxy, typeof_mode, slow); | 1224 EmitLoadGlobalCheckExtensions(proxy, typeof_mode, slow); |
1250 __ b(done); | 1225 __ b(done); |
1251 } else if (var->mode() == DYNAMIC_LOCAL) { | 1226 } else if (var->mode() == DYNAMIC_LOCAL) { |
1252 Variable* local = var->local_if_not_shadowed(); | 1227 Variable* local = var->local_if_not_shadowed(); |
1253 __ LoadP(r3, ContextSlotOperandCheckExtensions(local, slow)); | 1228 __ LoadP(r2, ContextSlotOperandCheckExtensions(local, slow)); |
1254 if (local->mode() == LET || local->mode() == CONST || | 1229 if (local->mode() == LET || local->mode() == CONST || |
1255 local->mode() == CONST_LEGACY) { | 1230 local->mode() == CONST_LEGACY) { |
1256 __ CompareRoot(r3, Heap::kTheHoleValueRootIndex); | 1231 __ CompareRoot(r2, Heap::kTheHoleValueRootIndex); |
1257 __ bne(done); | 1232 __ bne(done); |
1258 if (local->mode() == CONST_LEGACY) { | 1233 if (local->mode() == CONST_LEGACY) { |
1259 __ LoadRoot(r3, Heap::kUndefinedValueRootIndex); | 1234 __ LoadRoot(r2, Heap::kUndefinedValueRootIndex); |
1260 } else { // LET || CONST | 1235 } else { // LET || CONST |
1261 __ mov(r3, Operand(var->name())); | 1236 __ mov(r2, Operand(var->name())); |
1262 __ push(r3); | 1237 __ push(r2); |
1263 __ CallRuntime(Runtime::kThrowReferenceError); | 1238 __ CallRuntime(Runtime::kThrowReferenceError); |
1264 } | 1239 } |
1265 } | 1240 } |
1266 __ b(done); | 1241 __ b(done); |
1267 } | 1242 } |
1268 } | 1243 } |
1269 | 1244 |
1270 | |
1271 void FullCodeGenerator::EmitGlobalVariableLoad(VariableProxy* proxy, | 1245 void FullCodeGenerator::EmitGlobalVariableLoad(VariableProxy* proxy, |
1272 TypeofMode typeof_mode) { | 1246 TypeofMode typeof_mode) { |
1273 Variable* var = proxy->var(); | 1247 Variable* var = proxy->var(); |
1274 DCHECK(var->IsUnallocatedOrGlobalSlot() || | 1248 DCHECK(var->IsUnallocatedOrGlobalSlot() || |
1275 (var->IsLookupSlot() && var->mode() == DYNAMIC_GLOBAL)); | 1249 (var->IsLookupSlot() && var->mode() == DYNAMIC_GLOBAL)); |
1276 __ LoadGlobalObject(LoadDescriptor::ReceiverRegister()); | 1250 __ LoadGlobalObject(LoadDescriptor::ReceiverRegister()); |
1277 __ mov(LoadDescriptor::NameRegister(), Operand(var->name())); | 1251 __ mov(LoadDescriptor::NameRegister(), Operand(var->name())); |
1278 __ mov(LoadDescriptor::SlotRegister(), | 1252 __ mov(LoadDescriptor::SlotRegister(), |
1279 Operand(SmiFromSlot(proxy->VariableFeedbackSlot()))); | 1253 Operand(SmiFromSlot(proxy->VariableFeedbackSlot()))); |
1280 CallLoadIC(typeof_mode); | 1254 CallLoadIC(typeof_mode); |
1281 } | 1255 } |
1282 | 1256 |
1283 | |
1284 void FullCodeGenerator::EmitVariableLoad(VariableProxy* proxy, | 1257 void FullCodeGenerator::EmitVariableLoad(VariableProxy* proxy, |
1285 TypeofMode typeof_mode) { | 1258 TypeofMode typeof_mode) { |
1286 // Record position before possible IC call. | 1259 // Record position before possible IC call. |
1287 SetExpressionPosition(proxy); | 1260 SetExpressionPosition(proxy); |
1288 PrepareForBailoutForId(proxy->BeforeId(), NO_REGISTERS); | 1261 PrepareForBailoutForId(proxy->BeforeId(), NO_REGISTERS); |
1289 Variable* var = proxy->var(); | 1262 Variable* var = proxy->var(); |
1290 | 1263 |
1291 // Three cases: global variables, lookup variables, and all other types of | 1264 // Three cases: global variables, lookup variables, and all other types of |
1292 // variables. | 1265 // variables. |
1293 switch (var->location()) { | 1266 switch (var->location()) { |
1294 case VariableLocation::GLOBAL: | 1267 case VariableLocation::GLOBAL: |
1295 case VariableLocation::UNALLOCATED: { | 1268 case VariableLocation::UNALLOCATED: { |
1296 Comment cmnt(masm_, "[ Global variable"); | 1269 Comment cmnt(masm_, "[ Global variable"); |
1297 EmitGlobalVariableLoad(proxy, typeof_mode); | 1270 EmitGlobalVariableLoad(proxy, typeof_mode); |
1298 context()->Plug(r3); | 1271 context()->Plug(r2); |
1299 break; | 1272 break; |
1300 } | 1273 } |
1301 | 1274 |
1302 case VariableLocation::PARAMETER: | 1275 case VariableLocation::PARAMETER: |
1303 case VariableLocation::LOCAL: | 1276 case VariableLocation::LOCAL: |
1304 case VariableLocation::CONTEXT: { | 1277 case VariableLocation::CONTEXT: { |
1305 DCHECK_EQ(NOT_INSIDE_TYPEOF, typeof_mode); | 1278 DCHECK_EQ(NOT_INSIDE_TYPEOF, typeof_mode); |
1306 Comment cmnt(masm_, var->IsContextSlot() ? "[ Context variable" | 1279 Comment cmnt(masm_, var->IsContextSlot() ? "[ Context variable" |
1307 : "[ Stack variable"); | 1280 : "[ Stack variable"); |
1308 if (NeedsHoleCheckForLoad(proxy)) { | 1281 if (NeedsHoleCheckForLoad(proxy)) { |
1309 Label done; | 1282 Label done; |
1310 // Let and const need a read barrier. | 1283 // Let and const need a read barrier. |
1311 GetVar(r3, var); | 1284 GetVar(r2, var); |
1312 __ CompareRoot(r3, Heap::kTheHoleValueRootIndex); | 1285 __ CompareRoot(r2, Heap::kTheHoleValueRootIndex); |
1313 __ bne(&done); | 1286 __ bne(&done); |
1314 if (var->mode() == LET || var->mode() == CONST) { | 1287 if (var->mode() == LET || var->mode() == CONST) { |
1315 // Throw a reference error when using an uninitialized let/const | 1288 // Throw a reference error when using an uninitialized let/const |
1316 // binding in harmony mode. | 1289 // binding in harmony mode. |
1317 __ mov(r3, Operand(var->name())); | 1290 __ mov(r2, Operand(var->name())); |
1318 __ push(r3); | 1291 __ push(r2); |
1319 __ CallRuntime(Runtime::kThrowReferenceError); | 1292 __ CallRuntime(Runtime::kThrowReferenceError); |
1320 } else { | 1293 } else { |
1321 // Uninitialized legacy const bindings are unholed. | 1294 // Uninitialized legacy const bindings are unholed. |
1322 DCHECK(var->mode() == CONST_LEGACY); | 1295 DCHECK(var->mode() == CONST_LEGACY); |
1323 __ LoadRoot(r3, Heap::kUndefinedValueRootIndex); | 1296 __ LoadRoot(r2, Heap::kUndefinedValueRootIndex); |
1324 } | 1297 } |
1325 __ bind(&done); | 1298 __ bind(&done); |
1326 context()->Plug(r3); | 1299 context()->Plug(r2); |
1327 break; | 1300 break; |
1328 } | 1301 } |
1329 context()->Plug(var); | 1302 context()->Plug(var); |
1330 break; | 1303 break; |
1331 } | 1304 } |
1332 | 1305 |
1333 case VariableLocation::LOOKUP: { | 1306 case VariableLocation::LOOKUP: { |
1334 Comment cmnt(masm_, "[ Lookup variable"); | 1307 Comment cmnt(masm_, "[ Lookup variable"); |
1335 Label done, slow; | 1308 Label done, slow; |
1336 // Generate code for loading from variables potentially shadowed | 1309 // Generate code for loading from variables potentially shadowed |
1337 // by eval-introduced variables. | 1310 // by eval-introduced variables. |
1338 EmitDynamicLookupFastCase(proxy, typeof_mode, &slow, &done); | 1311 EmitDynamicLookupFastCase(proxy, typeof_mode, &slow, &done); |
1339 __ bind(&slow); | 1312 __ bind(&slow); |
1340 __ Push(var->name()); | 1313 __ Push(var->name()); |
1341 Runtime::FunctionId function_id = | 1314 Runtime::FunctionId function_id = |
1342 typeof_mode == NOT_INSIDE_TYPEOF | 1315 typeof_mode == NOT_INSIDE_TYPEOF |
1343 ? Runtime::kLoadLookupSlot | 1316 ? Runtime::kLoadLookupSlot |
1344 : Runtime::kLoadLookupSlotInsideTypeof; | 1317 : Runtime::kLoadLookupSlotInsideTypeof; |
1345 __ CallRuntime(function_id); | 1318 __ CallRuntime(function_id); |
1346 __ bind(&done); | 1319 __ bind(&done); |
1347 context()->Plug(r3); | 1320 context()->Plug(r2); |
1348 } | 1321 } |
1349 } | 1322 } |
1350 } | 1323 } |
1351 | 1324 |
1352 | |
1353 void FullCodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) { | 1325 void FullCodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) { |
1354 Comment cmnt(masm_, "[ RegExpLiteral"); | 1326 Comment cmnt(masm_, "[ RegExpLiteral"); |
1355 __ LoadP(r6, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset)); | 1327 __ LoadP(r5, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset)); |
1356 __ LoadSmiLiteral(r5, Smi::FromInt(expr->literal_index())); | 1328 __ LoadSmiLiteral(r4, Smi::FromInt(expr->literal_index())); |
1357 __ mov(r4, Operand(expr->pattern())); | 1329 __ mov(r3, Operand(expr->pattern())); |
1358 __ LoadSmiLiteral(r3, Smi::FromInt(expr->flags())); | 1330 __ LoadSmiLiteral(r2, Smi::FromInt(expr->flags())); |
1359 FastCloneRegExpStub stub(isolate()); | 1331 FastCloneRegExpStub stub(isolate()); |
1360 __ CallStub(&stub); | 1332 __ CallStub(&stub); |
1361 context()->Plug(r3); | 1333 context()->Plug(r2); |
1362 } | 1334 } |
1363 | 1335 |
1364 | |
1365 void FullCodeGenerator::EmitAccessor(ObjectLiteralProperty* property) { | 1336 void FullCodeGenerator::EmitAccessor(ObjectLiteralProperty* property) { |
1366 Expression* expression = (property == NULL) ? NULL : property->value(); | 1337 Expression* expression = (property == NULL) ? NULL : property->value(); |
1367 if (expression == NULL) { | 1338 if (expression == NULL) { |
1368 __ LoadRoot(r4, Heap::kNullValueRootIndex); | 1339 __ LoadRoot(r3, Heap::kNullValueRootIndex); |
1369 PushOperand(r4); | 1340 PushOperand(r3); |
1370 } else { | 1341 } else { |
1371 VisitForStackValue(expression); | 1342 VisitForStackValue(expression); |
1372 if (NeedsHomeObject(expression)) { | 1343 if (NeedsHomeObject(expression)) { |
1373 DCHECK(property->kind() == ObjectLiteral::Property::GETTER || | 1344 DCHECK(property->kind() == ObjectLiteral::Property::GETTER || |
1374 property->kind() == ObjectLiteral::Property::SETTER); | 1345 property->kind() == ObjectLiteral::Property::SETTER); |
1375 int offset = property->kind() == ObjectLiteral::Property::GETTER ? 2 : 3; | 1346 int offset = property->kind() == ObjectLiteral::Property::GETTER ? 2 : 3; |
1376 EmitSetHomeObject(expression, offset, property->GetSlot()); | 1347 EmitSetHomeObject(expression, offset, property->GetSlot()); |
1377 } | 1348 } |
1378 } | 1349 } |
1379 } | 1350 } |
1380 | 1351 |
1381 | |
1382 void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { | 1352 void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { |
1383 Comment cmnt(masm_, "[ ObjectLiteral"); | 1353 Comment cmnt(masm_, "[ ObjectLiteral"); |
1384 | 1354 |
1385 Handle<FixedArray> constant_properties = expr->constant_properties(); | 1355 Handle<FixedArray> constant_properties = expr->constant_properties(); |
1386 __ LoadP(r6, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset)); | 1356 __ LoadP(r5, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset)); |
1387 __ LoadSmiLiteral(r5, Smi::FromInt(expr->literal_index())); | 1357 __ LoadSmiLiteral(r4, Smi::FromInt(expr->literal_index())); |
1388 __ mov(r4, Operand(constant_properties)); | 1358 __ mov(r3, Operand(constant_properties)); |
1389 int flags = expr->ComputeFlags(); | 1359 int flags = expr->ComputeFlags(); |
1390 __ LoadSmiLiteral(r3, Smi::FromInt(flags)); | 1360 __ LoadSmiLiteral(r2, Smi::FromInt(flags)); |
1391 if (MustCreateObjectLiteralWithRuntime(expr)) { | 1361 if (MustCreateObjectLiteralWithRuntime(expr)) { |
1392 __ Push(r6, r5, r4, r3); | 1362 __ Push(r5, r4, r3, r2); |
1393 __ CallRuntime(Runtime::kCreateObjectLiteral); | 1363 __ CallRuntime(Runtime::kCreateObjectLiteral); |
1394 } else { | 1364 } else { |
1395 FastCloneShallowObjectStub stub(isolate(), expr->properties_count()); | 1365 FastCloneShallowObjectStub stub(isolate(), expr->properties_count()); |
1396 __ CallStub(&stub); | 1366 __ CallStub(&stub); |
1397 } | 1367 } |
1398 PrepareForBailoutForId(expr->CreateLiteralId(), TOS_REG); | 1368 PrepareForBailoutForId(expr->CreateLiteralId(), TOS_REG); |
1399 | 1369 |
1400 // If result_saved is true the result is on top of the stack. If | 1370 // If result_saved is true the result is on top of the stack. If |
1401 // result_saved is false the result is in r3. | 1371 // result_saved is false the result is in r2. |
1402 bool result_saved = false; | 1372 bool result_saved = false; |
1403 | 1373 |
1404 AccessorTable accessor_table(zone()); | 1374 AccessorTable accessor_table(zone()); |
1405 int property_index = 0; | 1375 int property_index = 0; |
1406 for (; property_index < expr->properties()->length(); property_index++) { | 1376 for (; property_index < expr->properties()->length(); property_index++) { |
1407 ObjectLiteral::Property* property = expr->properties()->at(property_index); | 1377 ObjectLiteral::Property* property = expr->properties()->at(property_index); |
1408 if (property->is_computed_name()) break; | 1378 if (property->is_computed_name()) break; |
1409 if (property->IsCompileTimeValue()) continue; | 1379 if (property->IsCompileTimeValue()) continue; |
1410 | 1380 |
1411 Literal* key = property->key()->AsLiteral(); | 1381 Literal* key = property->key()->AsLiteral(); |
1412 Expression* value = property->value(); | 1382 Expression* value = property->value(); |
1413 if (!result_saved) { | 1383 if (!result_saved) { |
1414 PushOperand(r3); // Save result on stack | 1384 PushOperand(r2); // Save result on stack |
1415 result_saved = true; | 1385 result_saved = true; |
1416 } | 1386 } |
1417 switch (property->kind()) { | 1387 switch (property->kind()) { |
1418 case ObjectLiteral::Property::CONSTANT: | 1388 case ObjectLiteral::Property::CONSTANT: |
1419 UNREACHABLE(); | 1389 UNREACHABLE(); |
1420 case ObjectLiteral::Property::MATERIALIZED_LITERAL: | 1390 case ObjectLiteral::Property::MATERIALIZED_LITERAL: |
1421 DCHECK(!CompileTimeValue::IsCompileTimeValue(property->value())); | 1391 DCHECK(!CompileTimeValue::IsCompileTimeValue(property->value())); |
1422 // Fall through. | 1392 // Fall through. |
1423 case ObjectLiteral::Property::COMPUTED: | 1393 case ObjectLiteral::Property::COMPUTED: |
1424 // It is safe to use [[Put]] here because the boilerplate already | 1394 // It is safe to use [[Put]] here because the boilerplate already |
1425 // contains computed properties with an uninitialized value. | 1395 // contains computed properties with an uninitialized value. |
1426 if (key->value()->IsInternalizedString()) { | 1396 if (key->value()->IsInternalizedString()) { |
1427 if (property->emit_store()) { | 1397 if (property->emit_store()) { |
1428 VisitForAccumulatorValue(value); | 1398 VisitForAccumulatorValue(value); |
1429 DCHECK(StoreDescriptor::ValueRegister().is(r3)); | 1399 DCHECK(StoreDescriptor::ValueRegister().is(r2)); |
1430 __ mov(StoreDescriptor::NameRegister(), Operand(key->value())); | 1400 __ mov(StoreDescriptor::NameRegister(), Operand(key->value())); |
1431 __ LoadP(StoreDescriptor::ReceiverRegister(), MemOperand(sp)); | 1401 __ LoadP(StoreDescriptor::ReceiverRegister(), MemOperand(sp)); |
1432 EmitLoadStoreICSlot(property->GetSlot(0)); | 1402 EmitLoadStoreICSlot(property->GetSlot(0)); |
1433 CallStoreIC(); | 1403 CallStoreIC(); |
1434 PrepareForBailoutForId(key->id(), NO_REGISTERS); | 1404 PrepareForBailoutForId(key->id(), NO_REGISTERS); |
1435 | 1405 |
1436 if (NeedsHomeObject(value)) { | 1406 if (NeedsHomeObject(value)) { |
1437 EmitSetHomeObjectAccumulator(value, 0, property->GetSlot(1)); | 1407 EmitSetHomeObjectAccumulator(value, 0, property->GetSlot(1)); |
1438 } | 1408 } |
1439 } else { | 1409 } else { |
1440 VisitForEffect(value); | 1410 VisitForEffect(value); |
1441 } | 1411 } |
1442 break; | 1412 break; |
1443 } | 1413 } |
1444 // Duplicate receiver on stack. | 1414 // Duplicate receiver on stack. |
1445 __ LoadP(r3, MemOperand(sp)); | 1415 __ LoadP(r2, MemOperand(sp)); |
1446 PushOperand(r3); | 1416 PushOperand(r2); |
1447 VisitForStackValue(key); | 1417 VisitForStackValue(key); |
1448 VisitForStackValue(value); | 1418 VisitForStackValue(value); |
1449 if (property->emit_store()) { | 1419 if (property->emit_store()) { |
1450 if (NeedsHomeObject(value)) { | 1420 if (NeedsHomeObject(value)) { |
1451 EmitSetHomeObject(value, 2, property->GetSlot()); | 1421 EmitSetHomeObject(value, 2, property->GetSlot()); |
1452 } | 1422 } |
1453 __ LoadSmiLiteral(r3, Smi::FromInt(SLOPPY)); // PropertyAttributes | 1423 __ LoadSmiLiteral(r2, Smi::FromInt(SLOPPY)); // PropertyAttributes |
1454 PushOperand(r3); | 1424 PushOperand(r2); |
1455 CallRuntimeWithOperands(Runtime::kSetProperty); | 1425 CallRuntimeWithOperands(Runtime::kSetProperty); |
1456 } else { | 1426 } else { |
1457 DropOperands(3); | 1427 DropOperands(3); |
1458 } | 1428 } |
1459 break; | 1429 break; |
1460 case ObjectLiteral::Property::PROTOTYPE: | 1430 case ObjectLiteral::Property::PROTOTYPE: |
1461 // Duplicate receiver on stack. | 1431 // Duplicate receiver on stack. |
1462 __ LoadP(r3, MemOperand(sp)); | 1432 __ LoadP(r2, MemOperand(sp)); |
1463 PushOperand(r3); | 1433 PushOperand(r2); |
1464 VisitForStackValue(value); | 1434 VisitForStackValue(value); |
1465 DCHECK(property->emit_store()); | 1435 DCHECK(property->emit_store()); |
1466 CallRuntimeWithOperands(Runtime::kInternalSetPrototype); | 1436 CallRuntimeWithOperands(Runtime::kInternalSetPrototype); |
1467 PrepareForBailoutForId(expr->GetIdForPropertySet(property_index), | 1437 PrepareForBailoutForId(expr->GetIdForPropertySet(property_index), |
1468 NO_REGISTERS); | 1438 NO_REGISTERS); |
1469 break; | 1439 break; |
1470 case ObjectLiteral::Property::GETTER: | 1440 case ObjectLiteral::Property::GETTER: |
1471 if (property->emit_store()) { | 1441 if (property->emit_store()) { |
1472 accessor_table.lookup(key)->second->getter = property; | 1442 accessor_table.lookup(key)->second->getter = property; |
1473 } | 1443 } |
1474 break; | 1444 break; |
1475 case ObjectLiteral::Property::SETTER: | 1445 case ObjectLiteral::Property::SETTER: |
1476 if (property->emit_store()) { | 1446 if (property->emit_store()) { |
1477 accessor_table.lookup(key)->second->setter = property; | 1447 accessor_table.lookup(key)->second->setter = property; |
1478 } | 1448 } |
1479 break; | 1449 break; |
1480 } | 1450 } |
1481 } | 1451 } |
1482 | 1452 |
1483 // Emit code to define accessors, using only a single call to the runtime for | 1453 // Emit code to define accessors, using only a single call to the runtime for |
1484 // each pair of corresponding getters and setters. | 1454 // each pair of corresponding getters and setters. |
1485 for (AccessorTable::Iterator it = accessor_table.begin(); | 1455 for (AccessorTable::Iterator it = accessor_table.begin(); |
1486 it != accessor_table.end(); ++it) { | 1456 it != accessor_table.end(); ++it) { |
1487 __ LoadP(r3, MemOperand(sp)); // Duplicate receiver. | 1457 __ LoadP(r2, MemOperand(sp)); // Duplicate receiver. |
1488 PushOperand(r3); | 1458 PushOperand(r2); |
1489 VisitForStackValue(it->first); | 1459 VisitForStackValue(it->first); |
1490 EmitAccessor(it->second->getter); | 1460 EmitAccessor(it->second->getter); |
1491 EmitAccessor(it->second->setter); | 1461 EmitAccessor(it->second->setter); |
1492 __ LoadSmiLiteral(r3, Smi::FromInt(NONE)); | 1462 __ LoadSmiLiteral(r2, Smi::FromInt(NONE)); |
1493 PushOperand(r3); | 1463 PushOperand(r2); |
1494 CallRuntimeWithOperands(Runtime::kDefineAccessorPropertyUnchecked); | 1464 CallRuntimeWithOperands(Runtime::kDefineAccessorPropertyUnchecked); |
1495 } | 1465 } |
1496 | 1466 |
1497 // Object literals have two parts. The "static" part on the left contains no | 1467 // Object literals have two parts. The "static" part on the left contains no |
1498 // computed property names, and so we can compute its map ahead of time; see | 1468 // computed property names, and so we can compute its map ahead of time; see |
1499 // runtime.cc::CreateObjectLiteralBoilerplate. The second "dynamic" part | 1469 // runtime.cc::CreateObjectLiteralBoilerplate. The second "dynamic" part |
1500 // starts with the first computed property name, and continues with all | 1470 // starts with the first computed property name, and continues with all |
1501 // properties to its right. All the code from above initializes the static | 1471 // properties to its right. All the code from above initializes the static |
1502 // component of the object literal, and arranges for the map of the result to | 1472 // component of the object literal, and arranges for the map of the result to |
1503 // reflect the static order in which the keys appear. For the dynamic | 1473 // reflect the static order in which the keys appear. For the dynamic |
1504 // properties, we compile them into a series of "SetOwnProperty" runtime | 1474 // properties, we compile them into a series of "SetOwnProperty" runtime |
1505 // calls. This will preserve insertion order. | 1475 // calls. This will preserve insertion order. |
1506 for (; property_index < expr->properties()->length(); property_index++) { | 1476 for (; property_index < expr->properties()->length(); property_index++) { |
1507 ObjectLiteral::Property* property = expr->properties()->at(property_index); | 1477 ObjectLiteral::Property* property = expr->properties()->at(property_index); |
1508 | 1478 |
1509 Expression* value = property->value(); | 1479 Expression* value = property->value(); |
1510 if (!result_saved) { | 1480 if (!result_saved) { |
1511 PushOperand(r3); // Save result on the stack | 1481 PushOperand(r2); // Save result on the stack |
1512 result_saved = true; | 1482 result_saved = true; |
1513 } | 1483 } |
1514 | 1484 |
1515 __ LoadP(r3, MemOperand(sp)); // Duplicate receiver. | 1485 __ LoadP(r2, MemOperand(sp)); // Duplicate receiver. |
1516 PushOperand(r3); | 1486 PushOperand(r2); |
1517 | 1487 |
1518 if (property->kind() == ObjectLiteral::Property::PROTOTYPE) { | 1488 if (property->kind() == ObjectLiteral::Property::PROTOTYPE) { |
1519 DCHECK(!property->is_computed_name()); | 1489 DCHECK(!property->is_computed_name()); |
1520 VisitForStackValue(value); | 1490 VisitForStackValue(value); |
1521 DCHECK(property->emit_store()); | 1491 DCHECK(property->emit_store()); |
1522 CallRuntimeWithOperands(Runtime::kInternalSetPrototype); | 1492 CallRuntimeWithOperands(Runtime::kInternalSetPrototype); |
1523 PrepareForBailoutForId(expr->GetIdForPropertySet(property_index), | 1493 PrepareForBailoutForId(expr->GetIdForPropertySet(property_index), |
1524 NO_REGISTERS); | 1494 NO_REGISTERS); |
1525 } else { | 1495 } else { |
1526 EmitPropertyKey(property, expr->GetIdForPropertyName(property_index)); | 1496 EmitPropertyKey(property, expr->GetIdForPropertyName(property_index)); |
(...skipping 27 matching lines...) Expand all Loading... |
1554 case ObjectLiteral::Property::SETTER: | 1524 case ObjectLiteral::Property::SETTER: |
1555 PushOperand(Smi::FromInt(NONE)); | 1525 PushOperand(Smi::FromInt(NONE)); |
1556 CallRuntimeWithOperands(Runtime::kDefineSetterPropertyUnchecked); | 1526 CallRuntimeWithOperands(Runtime::kDefineSetterPropertyUnchecked); |
1557 break; | 1527 break; |
1558 } | 1528 } |
1559 } | 1529 } |
1560 } | 1530 } |
1561 | 1531 |
1562 if (expr->has_function()) { | 1532 if (expr->has_function()) { |
1563 DCHECK(result_saved); | 1533 DCHECK(result_saved); |
1564 __ LoadP(r3, MemOperand(sp)); | 1534 __ LoadP(r2, MemOperand(sp)); |
1565 __ push(r3); | 1535 __ push(r2); |
1566 __ CallRuntime(Runtime::kToFastProperties); | 1536 __ CallRuntime(Runtime::kToFastProperties); |
1567 } | 1537 } |
1568 | 1538 |
1569 if (result_saved) { | 1539 if (result_saved) { |
1570 context()->PlugTOS(); | 1540 context()->PlugTOS(); |
1571 } else { | 1541 } else { |
1572 context()->Plug(r3); | 1542 context()->Plug(r2); |
1573 } | 1543 } |
1574 } | 1544 } |
1575 | 1545 |
1576 | |
1577 void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { | 1546 void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { |
1578 Comment cmnt(masm_, "[ ArrayLiteral"); | 1547 Comment cmnt(masm_, "[ ArrayLiteral"); |
1579 | 1548 |
1580 Handle<FixedArray> constant_elements = expr->constant_elements(); | 1549 Handle<FixedArray> constant_elements = expr->constant_elements(); |
1581 bool has_fast_elements = | 1550 bool has_fast_elements = |
1582 IsFastObjectElementsKind(expr->constant_elements_kind()); | 1551 IsFastObjectElementsKind(expr->constant_elements_kind()); |
1583 Handle<FixedArrayBase> constant_elements_values( | 1552 Handle<FixedArrayBase> constant_elements_values( |
1584 FixedArrayBase::cast(constant_elements->get(1))); | 1553 FixedArrayBase::cast(constant_elements->get(1))); |
1585 | 1554 |
1586 AllocationSiteMode allocation_site_mode = TRACK_ALLOCATION_SITE; | 1555 AllocationSiteMode allocation_site_mode = TRACK_ALLOCATION_SITE; |
1587 if (has_fast_elements && !FLAG_allocation_site_pretenuring) { | 1556 if (has_fast_elements && !FLAG_allocation_site_pretenuring) { |
1588 // If the only customer of allocation sites is transitioning, then | 1557 // If the only customer of allocation sites is transitioning, then |
1589 // we can turn it off if we don't have anywhere else to transition to. | 1558 // we can turn it off if we don't have anywhere else to transition to. |
1590 allocation_site_mode = DONT_TRACK_ALLOCATION_SITE; | 1559 allocation_site_mode = DONT_TRACK_ALLOCATION_SITE; |
1591 } | 1560 } |
1592 | 1561 |
1593 __ LoadP(r6, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset)); | 1562 __ LoadP(r5, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset)); |
1594 __ LoadSmiLiteral(r5, Smi::FromInt(expr->literal_index())); | 1563 __ LoadSmiLiteral(r4, Smi::FromInt(expr->literal_index())); |
1595 __ mov(r4, Operand(constant_elements)); | 1564 __ mov(r3, Operand(constant_elements)); |
1596 if (MustCreateArrayLiteralWithRuntime(expr)) { | 1565 if (MustCreateArrayLiteralWithRuntime(expr)) { |
1597 __ LoadSmiLiteral(r3, Smi::FromInt(expr->ComputeFlags())); | 1566 __ LoadSmiLiteral(r2, Smi::FromInt(expr->ComputeFlags())); |
1598 __ Push(r6, r5, r4, r3); | 1567 __ Push(r5, r4, r3, r2); |
1599 __ CallRuntime(Runtime::kCreateArrayLiteral); | 1568 __ CallRuntime(Runtime::kCreateArrayLiteral); |
1600 } else { | 1569 } else { |
1601 FastCloneShallowArrayStub stub(isolate(), allocation_site_mode); | 1570 FastCloneShallowArrayStub stub(isolate(), allocation_site_mode); |
1602 __ CallStub(&stub); | 1571 __ CallStub(&stub); |
1603 } | 1572 } |
1604 PrepareForBailoutForId(expr->CreateLiteralId(), TOS_REG); | 1573 PrepareForBailoutForId(expr->CreateLiteralId(), TOS_REG); |
1605 | 1574 |
1606 bool result_saved = false; // Is the result saved to the stack? | 1575 bool result_saved = false; // Is the result saved to the stack? |
1607 ZoneList<Expression*>* subexprs = expr->values(); | 1576 ZoneList<Expression*>* subexprs = expr->values(); |
1608 int length = subexprs->length(); | 1577 int length = subexprs->length(); |
1609 | 1578 |
1610 // Emit code to evaluate all the non-constant subexpressions and to store | 1579 // Emit code to evaluate all the non-constant subexpressions and to store |
1611 // them into the newly cloned array. | 1580 // them into the newly cloned array. |
1612 int array_index = 0; | 1581 int array_index = 0; |
1613 for (; array_index < length; array_index++) { | 1582 for (; array_index < length; array_index++) { |
1614 Expression* subexpr = subexprs->at(array_index); | 1583 Expression* subexpr = subexprs->at(array_index); |
1615 DCHECK(!subexpr->IsSpread()); | 1584 DCHECK(!subexpr->IsSpread()); |
1616 // If the subexpression is a literal or a simple materialized literal it | 1585 // If the subexpression is a literal or a simple materialized literal it |
1617 // is already set in the cloned array. | 1586 // is already set in the cloned array. |
1618 if (CompileTimeValue::IsCompileTimeValue(subexpr)) continue; | 1587 if (CompileTimeValue::IsCompileTimeValue(subexpr)) continue; |
1619 | 1588 |
1620 if (!result_saved) { | 1589 if (!result_saved) { |
1621 PushOperand(r3); | 1590 PushOperand(r2); |
1622 result_saved = true; | 1591 result_saved = true; |
1623 } | 1592 } |
1624 VisitForAccumulatorValue(subexpr); | 1593 VisitForAccumulatorValue(subexpr); |
1625 | 1594 |
1626 __ LoadSmiLiteral(StoreDescriptor::NameRegister(), | 1595 __ LoadSmiLiteral(StoreDescriptor::NameRegister(), |
1627 Smi::FromInt(array_index)); | 1596 Smi::FromInt(array_index)); |
1628 __ LoadP(StoreDescriptor::ReceiverRegister(), MemOperand(sp, 0)); | 1597 __ LoadP(StoreDescriptor::ReceiverRegister(), MemOperand(sp, 0)); |
1629 EmitLoadStoreICSlot(expr->LiteralFeedbackSlot()); | 1598 EmitLoadStoreICSlot(expr->LiteralFeedbackSlot()); |
1630 Handle<Code> ic = | 1599 Handle<Code> ic = |
1631 CodeFactory::KeyedStoreIC(isolate(), language_mode()).code(); | 1600 CodeFactory::KeyedStoreIC(isolate(), language_mode()).code(); |
1632 CallIC(ic); | 1601 CallIC(ic); |
1633 | 1602 |
1634 PrepareForBailoutForId(expr->GetIdForElement(array_index), NO_REGISTERS); | 1603 PrepareForBailoutForId(expr->GetIdForElement(array_index), NO_REGISTERS); |
1635 } | 1604 } |
1636 | 1605 |
1637 // In case the array literal contains spread expressions it has two parts. The | 1606 // In case the array literal contains spread expressions it has two parts. The |
1638 // first part is the "static" array which has a literal index is handled | 1607 // first part is the "static" array which has a literal index is handled |
1639 // above. The second part is the part after the first spread expression | 1608 // above. The second part is the part after the first spread expression |
1640 // (inclusive) and these elements gets appended to the array. Note that the | 1609 // (inclusive) and these elements gets appended to the array. Note that the |
1641 // number elements an iterable produces is unknown ahead of time. | 1610 // number elements an iterable produces is unknown ahead of time. |
1642 if (array_index < length && result_saved) { | 1611 if (array_index < length && result_saved) { |
1643 PopOperand(r3); | 1612 PopOperand(r2); |
1644 result_saved = false; | 1613 result_saved = false; |
1645 } | 1614 } |
1646 for (; array_index < length; array_index++) { | 1615 for (; array_index < length; array_index++) { |
1647 Expression* subexpr = subexprs->at(array_index); | 1616 Expression* subexpr = subexprs->at(array_index); |
1648 | 1617 |
1649 PushOperand(r3); | 1618 PushOperand(r2); |
1650 DCHECK(!subexpr->IsSpread()); | 1619 DCHECK(!subexpr->IsSpread()); |
1651 VisitForStackValue(subexpr); | 1620 VisitForStackValue(subexpr); |
1652 CallRuntimeWithOperands(Runtime::kAppendElement); | 1621 CallRuntimeWithOperands(Runtime::kAppendElement); |
1653 | 1622 |
1654 PrepareForBailoutForId(expr->GetIdForElement(array_index), NO_REGISTERS); | 1623 PrepareForBailoutForId(expr->GetIdForElement(array_index), NO_REGISTERS); |
1655 } | 1624 } |
1656 | 1625 |
1657 if (result_saved) { | 1626 if (result_saved) { |
1658 context()->PlugTOS(); | 1627 context()->PlugTOS(); |
1659 } else { | 1628 } else { |
1660 context()->Plug(r3); | 1629 context()->Plug(r2); |
1661 } | 1630 } |
1662 } | 1631 } |
1663 | 1632 |
1664 | |
1665 void FullCodeGenerator::VisitAssignment(Assignment* expr) { | 1633 void FullCodeGenerator::VisitAssignment(Assignment* expr) { |
1666 DCHECK(expr->target()->IsValidReferenceExpressionOrThis()); | 1634 DCHECK(expr->target()->IsValidReferenceExpressionOrThis()); |
1667 | 1635 |
1668 Comment cmnt(masm_, "[ Assignment"); | 1636 Comment cmnt(masm_, "[ Assignment"); |
1669 SetExpressionPosition(expr, INSERT_BREAK); | 1637 SetExpressionPosition(expr, INSERT_BREAK); |
1670 | 1638 |
1671 Property* property = expr->target()->AsProperty(); | 1639 Property* property = expr->target()->AsProperty(); |
1672 LhsKind assign_type = Property::GetAssignType(property); | 1640 LhsKind assign_type = Property::GetAssignType(property); |
1673 | 1641 |
1674 // Evaluate LHS expression. | 1642 // Evaluate LHS expression. |
(...skipping 10 matching lines...) Expand all Loading... |
1685 VisitForStackValue(property->obj()); | 1653 VisitForStackValue(property->obj()); |
1686 } | 1654 } |
1687 break; | 1655 break; |
1688 case NAMED_SUPER_PROPERTY: | 1656 case NAMED_SUPER_PROPERTY: |
1689 VisitForStackValue( | 1657 VisitForStackValue( |
1690 property->obj()->AsSuperPropertyReference()->this_var()); | 1658 property->obj()->AsSuperPropertyReference()->this_var()); |
1691 VisitForAccumulatorValue( | 1659 VisitForAccumulatorValue( |
1692 property->obj()->AsSuperPropertyReference()->home_object()); | 1660 property->obj()->AsSuperPropertyReference()->home_object()); |
1693 PushOperand(result_register()); | 1661 PushOperand(result_register()); |
1694 if (expr->is_compound()) { | 1662 if (expr->is_compound()) { |
1695 const Register scratch = r4; | 1663 const Register scratch = r3; |
1696 __ LoadP(scratch, MemOperand(sp, kPointerSize)); | 1664 __ LoadP(scratch, MemOperand(sp, kPointerSize)); |
1697 PushOperands(scratch, result_register()); | 1665 PushOperands(scratch, result_register()); |
1698 } | 1666 } |
1699 break; | 1667 break; |
1700 case KEYED_SUPER_PROPERTY: { | 1668 case KEYED_SUPER_PROPERTY: { |
1701 const Register scratch = r4; | 1669 const Register scratch = r3; |
1702 VisitForStackValue( | 1670 VisitForStackValue( |
1703 property->obj()->AsSuperPropertyReference()->this_var()); | 1671 property->obj()->AsSuperPropertyReference()->this_var()); |
1704 VisitForAccumulatorValue( | 1672 VisitForAccumulatorValue( |
1705 property->obj()->AsSuperPropertyReference()->home_object()); | 1673 property->obj()->AsSuperPropertyReference()->home_object()); |
1706 __ mr(scratch, result_register()); | 1674 __ LoadRR(scratch, result_register()); |
1707 VisitForAccumulatorValue(property->key()); | 1675 VisitForAccumulatorValue(property->key()); |
1708 PushOperands(scratch, result_register()); | 1676 PushOperands(scratch, result_register()); |
1709 if (expr->is_compound()) { | 1677 if (expr->is_compound()) { |
1710 const Register scratch1 = r5; | 1678 const Register scratch1 = r4; |
1711 __ LoadP(scratch1, MemOperand(sp, 2 * kPointerSize)); | 1679 __ LoadP(scratch1, MemOperand(sp, 2 * kPointerSize)); |
1712 PushOperands(scratch1, scratch, result_register()); | 1680 PushOperands(scratch1, scratch, result_register()); |
1713 } | 1681 } |
1714 break; | 1682 break; |
1715 } | 1683 } |
1716 case KEYED_PROPERTY: | 1684 case KEYED_PROPERTY: |
1717 if (expr->is_compound()) { | 1685 if (expr->is_compound()) { |
1718 VisitForStackValue(property->obj()); | 1686 VisitForStackValue(property->obj()); |
1719 VisitForStackValue(property->key()); | 1687 VisitForStackValue(property->key()); |
1720 __ LoadP(LoadDescriptor::ReceiverRegister(), | 1688 __ LoadP(LoadDescriptor::ReceiverRegister(), |
(...skipping 29 matching lines...) Expand all Loading... |
1750 PrepareForBailoutForId(property->LoadId(), TOS_REG); | 1718 PrepareForBailoutForId(property->LoadId(), TOS_REG); |
1751 break; | 1719 break; |
1752 case KEYED_PROPERTY: | 1720 case KEYED_PROPERTY: |
1753 EmitKeyedPropertyLoad(property); | 1721 EmitKeyedPropertyLoad(property); |
1754 PrepareForBailoutForId(property->LoadId(), TOS_REG); | 1722 PrepareForBailoutForId(property->LoadId(), TOS_REG); |
1755 break; | 1723 break; |
1756 } | 1724 } |
1757 } | 1725 } |
1758 | 1726 |
1759 Token::Value op = expr->binary_op(); | 1727 Token::Value op = expr->binary_op(); |
1760 PushOperand(r3); // Left operand goes on the stack. | 1728 PushOperand(r2); // Left operand goes on the stack. |
1761 VisitForAccumulatorValue(expr->value()); | 1729 VisitForAccumulatorValue(expr->value()); |
1762 | 1730 |
1763 AccumulatorValueContext context(this); | 1731 AccumulatorValueContext context(this); |
1764 if (ShouldInlineSmiCase(op)) { | 1732 if (ShouldInlineSmiCase(op)) { |
1765 EmitInlineSmiBinaryOp(expr->binary_operation(), op, expr->target(), | 1733 EmitInlineSmiBinaryOp(expr->binary_operation(), op, expr->target(), |
1766 expr->value()); | 1734 expr->value()); |
1767 } else { | 1735 } else { |
1768 EmitBinaryOp(expr->binary_operation(), op); | 1736 EmitBinaryOp(expr->binary_operation(), op); |
1769 } | 1737 } |
1770 | 1738 |
1771 // Deoptimization point in case the binary operation may have side effects. | 1739 // Deoptimization point in case the binary operation may have side effects. |
1772 PrepareForBailout(expr->binary_operation(), TOS_REG); | 1740 PrepareForBailout(expr->binary_operation(), TOS_REG); |
1773 } else { | 1741 } else { |
1774 VisitForAccumulatorValue(expr->value()); | 1742 VisitForAccumulatorValue(expr->value()); |
1775 } | 1743 } |
1776 | 1744 |
1777 SetExpressionPosition(expr); | 1745 SetExpressionPosition(expr); |
1778 | 1746 |
1779 // Store the value. | 1747 // Store the value. |
1780 switch (assign_type) { | 1748 switch (assign_type) { |
1781 case VARIABLE: | 1749 case VARIABLE: |
1782 EmitVariableAssignment(expr->target()->AsVariableProxy()->var(), | 1750 EmitVariableAssignment(expr->target()->AsVariableProxy()->var(), |
1783 expr->op(), expr->AssignmentSlot()); | 1751 expr->op(), expr->AssignmentSlot()); |
1784 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); | 1752 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); |
1785 context()->Plug(r3); | 1753 context()->Plug(r2); |
1786 break; | 1754 break; |
1787 case NAMED_PROPERTY: | 1755 case NAMED_PROPERTY: |
1788 EmitNamedPropertyAssignment(expr); | 1756 EmitNamedPropertyAssignment(expr); |
1789 break; | 1757 break; |
1790 case NAMED_SUPER_PROPERTY: | 1758 case NAMED_SUPER_PROPERTY: |
1791 EmitNamedSuperPropertyStore(property); | 1759 EmitNamedSuperPropertyStore(property); |
1792 context()->Plug(r3); | 1760 context()->Plug(r2); |
1793 break; | 1761 break; |
1794 case KEYED_SUPER_PROPERTY: | 1762 case KEYED_SUPER_PROPERTY: |
1795 EmitKeyedSuperPropertyStore(property); | 1763 EmitKeyedSuperPropertyStore(property); |
1796 context()->Plug(r3); | 1764 context()->Plug(r2); |
1797 break; | 1765 break; |
1798 case KEYED_PROPERTY: | 1766 case KEYED_PROPERTY: |
1799 EmitKeyedPropertyAssignment(expr); | 1767 EmitKeyedPropertyAssignment(expr); |
1800 break; | 1768 break; |
1801 } | 1769 } |
1802 } | 1770 } |
1803 | 1771 |
1804 | |
1805 void FullCodeGenerator::VisitYield(Yield* expr) { | 1772 void FullCodeGenerator::VisitYield(Yield* expr) { |
1806 Comment cmnt(masm_, "[ Yield"); | 1773 Comment cmnt(masm_, "[ Yield"); |
1807 SetExpressionPosition(expr); | 1774 SetExpressionPosition(expr); |
1808 | 1775 |
1809 // Evaluate yielded value first; the initial iterator definition depends on | 1776 // Evaluate yielded value first; the initial iterator definition depends on |
1810 // this. It stays on the stack while we update the iterator. | 1777 // this. It stays on the stack while we update the iterator. |
1811 VisitForStackValue(expr->expression()); | 1778 VisitForStackValue(expr->expression()); |
1812 | 1779 |
1813 Label suspend, continuation, post_runtime, resume; | 1780 switch (expr->yield_kind()) { |
| 1781 case Yield::kSuspend: |
| 1782 // Pop value from top-of-stack slot; box result into result register. |
| 1783 EmitCreateIteratorResult(false); |
| 1784 PushOperand(result_register()); |
| 1785 // Fall through. |
| 1786 case Yield::kInitial: { |
| 1787 Label suspend, continuation, post_runtime, resume; |
1814 | 1788 |
1815 __ b(&suspend); | 1789 __ b(&suspend, Label::kNear); |
1816 __ bind(&continuation); | 1790 __ bind(&continuation); |
1817 // When we arrive here, the stack top is the resume mode and | 1791 // When we arrive here, the stack top is the resume mode and |
1818 // result_register() holds the input value (the argument given to the | 1792 // result_register() holds the input value (the argument given to the |
1819 // respective resume operation). | 1793 // respective resume operation). |
1820 __ RecordGeneratorContinuation(); | 1794 __ RecordGeneratorContinuation(); |
1821 __ pop(r4); | 1795 __ pop(r3); |
1822 __ CmpSmiLiteral(r4, Smi::FromInt(JSGeneratorObject::RETURN), r0); | 1796 __ CmpSmiLiteral(r3, Smi::FromInt(JSGeneratorObject::RETURN), r0); |
1823 __ bne(&resume); | 1797 __ bne(&resume); |
1824 __ push(result_register()); | 1798 __ push(result_register()); |
1825 EmitCreateIteratorResult(true); | 1799 EmitCreateIteratorResult(true); |
1826 EmitUnwindAndReturn(); | 1800 EmitUnwindAndReturn(); |
1827 | 1801 |
1828 __ bind(&suspend); | 1802 __ bind(&suspend); |
1829 OperandStackDepthIncrement(1); // Not popped on this path. | 1803 OperandStackDepthIncrement(1); // Not popped on this path. |
1830 VisitForAccumulatorValue(expr->generator_object()); | 1804 VisitForAccumulatorValue(expr->generator_object()); |
1831 DCHECK(continuation.pos() > 0 && Smi::IsValid(continuation.pos())); | 1805 DCHECK(continuation.pos() > 0 && Smi::IsValid(continuation.pos())); |
1832 __ LoadSmiLiteral(r4, Smi::FromInt(continuation.pos())); | 1806 __ LoadSmiLiteral(r3, Smi::FromInt(continuation.pos())); |
1833 __ StoreP(r4, FieldMemOperand(r3, JSGeneratorObject::kContinuationOffset), | 1807 __ StoreP(r3, |
1834 r0); | 1808 FieldMemOperand(r2, JSGeneratorObject::kContinuationOffset)); |
1835 __ StoreP(cp, FieldMemOperand(r3, JSGeneratorObject::kContextOffset), r0); | 1809 __ StoreP(cp, FieldMemOperand(r2, JSGeneratorObject::kContextOffset)); |
1836 __ mr(r4, cp); | 1810 __ LoadRR(r3, cp); |
1837 __ RecordWriteField(r3, JSGeneratorObject::kContextOffset, r4, r5, | 1811 __ RecordWriteField(r2, JSGeneratorObject::kContextOffset, r3, r4, |
1838 kLRHasBeenSaved, kDontSaveFPRegs); | 1812 kLRHasBeenSaved, kDontSaveFPRegs); |
1839 __ addi(r4, fp, Operand(StandardFrameConstants::kExpressionsOffset)); | 1813 __ AddP(r3, fp, Operand(StandardFrameConstants::kExpressionsOffset)); |
1840 __ cmp(sp, r4); | 1814 __ CmpP(sp, r3); |
1841 __ beq(&post_runtime); | 1815 __ beq(&post_runtime); |
1842 __ push(r3); // generator object | 1816 __ push(r2); // generator object |
1843 __ CallRuntime(Runtime::kSuspendJSGeneratorObject, 1); | 1817 __ CallRuntime(Runtime::kSuspendJSGeneratorObject, 1); |
1844 __ LoadP(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); | 1818 __ LoadP(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); |
1845 __ bind(&post_runtime); | 1819 __ bind(&post_runtime); |
1846 PopOperand(result_register()); | 1820 PopOperand(result_register()); |
1847 EmitReturnSequence(); | 1821 EmitReturnSequence(); |
1848 | 1822 |
1849 __ bind(&resume); | 1823 __ bind(&resume); |
1850 context()->Plug(result_register()); | 1824 context()->Plug(result_register()); |
| 1825 break; |
| 1826 } |
| 1827 |
| 1828 case Yield::kFinal: { |
| 1829 // Pop value from top-of-stack slot, box result into result register. |
| 1830 EmitCreateIteratorResult(true); |
| 1831 EmitUnwindAndReturn(); |
| 1832 break; |
| 1833 } |
| 1834 |
| 1835 case Yield::kDelegating: |
| 1836 UNREACHABLE(); |
| 1837 } |
1851 } | 1838 } |
1852 | 1839 |
1853 | |
1854 void FullCodeGenerator::EmitGeneratorResume( | 1840 void FullCodeGenerator::EmitGeneratorResume( |
1855 Expression* generator, Expression* value, | 1841 Expression* generator, Expression* value, |
1856 JSGeneratorObject::ResumeMode resume_mode) { | 1842 JSGeneratorObject::ResumeMode resume_mode) { |
1857 // The value stays in r3, and is ultimately read by the resumed generator, as | 1843 // The value stays in r2, and is ultimately read by the resumed generator, as |
1858 // if CallRuntime(Runtime::kSuspendJSGeneratorObject) returned it. Or it | 1844 // if CallRuntime(Runtime::kSuspendJSGeneratorObject) returned it. Or it |
1859 // is read to throw the value when the resumed generator is already closed. | 1845 // is read to throw the value when the resumed generator is already closed. |
1860 // r4 will hold the generator object until the activation has been resumed. | 1846 // r3 will hold the generator object until the activation has been resumed. |
1861 VisitForStackValue(generator); | 1847 VisitForStackValue(generator); |
1862 VisitForAccumulatorValue(value); | 1848 VisitForAccumulatorValue(value); |
1863 PopOperand(r4); | 1849 PopOperand(r3); |
1864 | 1850 |
1865 // Store input value into generator object. | 1851 // Store input value into generator object. |
1866 __ StoreP(result_register(), | 1852 __ StoreP(result_register(), |
1867 FieldMemOperand(r4, JSGeneratorObject::kInputOffset), r0); | 1853 FieldMemOperand(r3, JSGeneratorObject::kInputOffset), r0); |
1868 __ mr(r5, result_register()); | 1854 __ LoadRR(r4, result_register()); |
1869 __ RecordWriteField(r4, JSGeneratorObject::kInputOffset, r5, r6, | 1855 __ RecordWriteField(r3, JSGeneratorObject::kInputOffset, r4, r5, |
1870 kLRHasBeenSaved, kDontSaveFPRegs); | 1856 kLRHasBeenSaved, kDontSaveFPRegs); |
1871 | 1857 |
1872 // Load suspended function and context. | 1858 // Load suspended function and context. |
1873 __ LoadP(cp, FieldMemOperand(r4, JSGeneratorObject::kContextOffset)); | 1859 __ LoadP(cp, FieldMemOperand(r3, JSGeneratorObject::kContextOffset)); |
1874 __ LoadP(r7, FieldMemOperand(r4, JSGeneratorObject::kFunctionOffset)); | 1860 __ LoadP(r6, FieldMemOperand(r3, JSGeneratorObject::kFunctionOffset)); |
1875 | 1861 |
1876 // Load receiver and store as the first argument. | 1862 // Load receiver and store as the first argument. |
1877 __ LoadP(r5, FieldMemOperand(r4, JSGeneratorObject::kReceiverOffset)); | 1863 __ LoadP(r4, FieldMemOperand(r3, JSGeneratorObject::kReceiverOffset)); |
1878 __ push(r5); | 1864 __ push(r4); |
1879 | 1865 |
1880 // Push holes for the rest of the arguments to the generator function. | 1866 // Push holes for the rest of the arguments to the generator function. |
1881 __ LoadP(r6, FieldMemOperand(r7, JSFunction::kSharedFunctionInfoOffset)); | 1867 __ LoadP(r5, FieldMemOperand(r6, JSFunction::kSharedFunctionInfoOffset)); |
1882 __ LoadWordArith( | 1868 __ LoadW( |
1883 r6, FieldMemOperand(r6, SharedFunctionInfo::kFormalParameterCountOffset)); | 1869 r5, FieldMemOperand(r5, SharedFunctionInfo::kFormalParameterCountOffset)); |
1884 __ LoadRoot(r5, Heap::kTheHoleValueRootIndex); | 1870 __ LoadRoot(r4, Heap::kTheHoleValueRootIndex); |
1885 Label argument_loop, push_frame; | 1871 Label argument_loop, push_frame; |
1886 #if V8_TARGET_ARCH_PPC64 | 1872 #if V8_TARGET_ARCH_S390X |
1887 __ cmpi(r6, Operand::Zero()); | 1873 __ CmpP(r5, Operand::Zero()); |
1888 __ beq(&push_frame); | 1874 __ beq(&push_frame, Label::kNear); |
1889 #else | 1875 #else |
1890 __ SmiUntag(r6, SetRC); | 1876 __ SmiUntag(r5); |
1891 __ beq(&push_frame, cr0); | 1877 __ beq(&push_frame, Label::kNear); |
1892 #endif | 1878 #endif |
1893 __ mtctr(r6); | 1879 __ LoadRR(r0, r5); |
1894 __ bind(&argument_loop); | 1880 __ bind(&argument_loop); |
1895 __ push(r5); | 1881 __ push(r4); |
1896 __ bdnz(&argument_loop); | 1882 __ SubP(r0, Operand(1)); |
| 1883 __ bne(&argument_loop); |
1897 | 1884 |
1898 // Enter a new JavaScript frame, and initialize its slots as they were when | 1885 // Enter a new JavaScript frame, and initialize its slots as they were when |
1899 // the generator was suspended. | 1886 // the generator was suspended. |
1900 Label resume_frame, done; | 1887 Label resume_frame, done; |
1901 __ bind(&push_frame); | 1888 __ bind(&push_frame); |
1902 __ b(&resume_frame, SetLK); | 1889 __ b(r14, &resume_frame); // brasl |
1903 __ b(&done); | 1890 __ b(&done); |
1904 __ bind(&resume_frame); | 1891 __ bind(&resume_frame); |
1905 // lr = return address. | 1892 // lr = return address. |
1906 // fp = caller's frame pointer. | 1893 // fp = caller's frame pointer. |
1907 // cp = callee's context, | 1894 // cp = callee's context, |
1908 // r7 = callee's JS function. | 1895 // r6 = callee's JS function. |
1909 __ PushFixedFrame(r7); | 1896 __ PushFixedFrame(r6); |
1910 // Adjust FP to point to saved FP. | 1897 // Adjust FP to point to saved FP. |
1911 __ addi(fp, sp, Operand(StandardFrameConstants::kFixedFrameSizeFromFp)); | 1898 __ lay(fp, MemOperand(sp, StandardFrameConstants::kFixedFrameSizeFromFp)); |
1912 | 1899 |
1913 // Load the operand stack size. | 1900 // Load the operand stack size. |
1914 __ LoadP(r6, FieldMemOperand(r4, JSGeneratorObject::kOperandStackOffset)); | 1901 __ LoadP(r5, FieldMemOperand(r3, JSGeneratorObject::kOperandStackOffset)); |
1915 __ LoadP(r6, FieldMemOperand(r6, FixedArray::kLengthOffset)); | 1902 __ LoadP(r5, FieldMemOperand(r5, FixedArray::kLengthOffset)); |
1916 __ SmiUntag(r6, SetRC); | 1903 __ SmiUntag(r5); |
1917 | 1904 |
1918 // If we are sending a value and there is no operand stack, we can jump back | 1905 // If we are sending a value and there is no operand stack, we can jump back |
1919 // in directly. | 1906 // in directly. |
1920 Label call_resume; | 1907 Label call_resume; |
1921 if (resume_mode == JSGeneratorObject::NEXT) { | 1908 if (resume_mode == JSGeneratorObject::NEXT) { |
1922 Label slow_resume; | 1909 Label slow_resume; |
1923 __ bne(&slow_resume, cr0); | 1910 __ bne(&slow_resume, Label::kNear); |
1924 __ LoadP(ip, FieldMemOperand(r7, JSFunction::kCodeEntryOffset)); | 1911 __ LoadP(ip, FieldMemOperand(r6, JSFunction::kCodeEntryOffset)); |
1925 { | 1912 __ LoadP(r4, FieldMemOperand(r3, JSGeneratorObject::kContinuationOffset)); |
1926 ConstantPoolUnavailableScope constant_pool_unavailable(masm_); | 1913 __ SmiUntag(r4); |
1927 if (FLAG_enable_embedded_constant_pool) { | 1914 __ AddP(ip, ip, r4); |
1928 __ LoadConstantPoolPointerRegisterFromCodeTargetAddress(ip); | 1915 __ LoadSmiLiteral(r4, Smi::FromInt(JSGeneratorObject::kGeneratorExecuting)); |
1929 } | 1916 __ StoreP(r4, FieldMemOperand(r3, JSGeneratorObject::kContinuationOffset)); |
1930 __ LoadP(r5, FieldMemOperand(r4, JSGeneratorObject::kContinuationOffset)); | 1917 __ Push(Smi::FromInt(resume_mode)); // Consumed in continuation. |
1931 __ SmiUntag(r5); | 1918 __ Jump(ip); |
1932 __ add(ip, ip, r5); | 1919 __ bind(&slow_resume); |
1933 __ LoadSmiLiteral(r5, | |
1934 Smi::FromInt(JSGeneratorObject::kGeneratorExecuting)); | |
1935 __ StoreP(r5, FieldMemOperand(r4, JSGeneratorObject::kContinuationOffset), | |
1936 r0); | |
1937 __ Push(Smi::FromInt(resume_mode)); // Consumed in continuation. | |
1938 __ Jump(ip); | |
1939 __ bind(&slow_resume); | |
1940 } | |
1941 } else { | 1920 } else { |
1942 __ beq(&call_resume, cr0); | 1921 __ beq(&call_resume); |
1943 } | 1922 } |
1944 | 1923 |
1945 // Otherwise, we push holes for the operand stack and call the runtime to fix | 1924 // Otherwise, we push holes for the operand stack and call the runtime to fix |
1946 // up the stack and the handlers. | 1925 // up the stack and the handlers. |
1947 Label operand_loop; | 1926 Label operand_loop; |
1948 __ mtctr(r6); | 1927 __ LoadRR(r0, r5); |
1949 __ bind(&operand_loop); | 1928 __ bind(&operand_loop); |
1950 __ push(r5); | 1929 __ push(r4); |
1951 __ bdnz(&operand_loop); | 1930 __ SubP(r0, Operand(1)); |
| 1931 __ bne(&operand_loop); |
1952 | 1932 |
1953 __ bind(&call_resume); | 1933 __ bind(&call_resume); |
1954 __ Push(Smi::FromInt(resume_mode)); // Consumed in continuation. | 1934 __ Push(Smi::FromInt(resume_mode)); // Consumed in continuation. |
1955 DCHECK(!result_register().is(r4)); | 1935 DCHECK(!result_register().is(r3)); |
1956 __ Push(r4, result_register()); | 1936 __ Push(r3, result_register()); |
1957 __ Push(Smi::FromInt(resume_mode)); | 1937 __ Push(Smi::FromInt(resume_mode)); |
1958 __ CallRuntime(Runtime::kResumeJSGeneratorObject); | 1938 __ CallRuntime(Runtime::kResumeJSGeneratorObject); |
1959 // Not reached: the runtime call returns elsewhere. | 1939 // Not reached: the runtime call returns elsewhere. |
1960 __ stop("not-reached"); | 1940 __ stop("not-reached"); |
1961 | 1941 |
1962 __ bind(&done); | 1942 __ bind(&done); |
1963 context()->Plug(result_register()); | 1943 context()->Plug(result_register()); |
1964 } | 1944 } |
1965 | 1945 |
1966 void FullCodeGenerator::PushOperands(Register reg1, Register reg2) { | 1946 void FullCodeGenerator::PushOperands(Register reg1, Register reg2) { |
(...skipping 15 matching lines...) Expand all Loading... |
1982 | 1962 |
1983 void FullCodeGenerator::PopOperands(Register reg1, Register reg2) { | 1963 void FullCodeGenerator::PopOperands(Register reg1, Register reg2) { |
1984 OperandStackDepthDecrement(2); | 1964 OperandStackDepthDecrement(2); |
1985 __ Pop(reg1, reg2); | 1965 __ Pop(reg1, reg2); |
1986 } | 1966 } |
1987 | 1967 |
1988 void FullCodeGenerator::EmitOperandStackDepthCheck() { | 1968 void FullCodeGenerator::EmitOperandStackDepthCheck() { |
1989 if (FLAG_debug_code) { | 1969 if (FLAG_debug_code) { |
1990 int expected_diff = StandardFrameConstants::kFixedFrameSizeFromFp + | 1970 int expected_diff = StandardFrameConstants::kFixedFrameSizeFromFp + |
1991 operand_stack_depth_ * kPointerSize; | 1971 operand_stack_depth_ * kPointerSize; |
1992 __ sub(r3, fp, sp); | 1972 __ SubP(r2, fp, sp); |
1993 __ cmpi(r3, Operand(expected_diff)); | 1973 __ CmpP(r2, Operand(expected_diff)); |
1994 __ Assert(eq, kUnexpectedStackDepth); | 1974 __ Assert(eq, kUnexpectedStackDepth); |
1995 } | 1975 } |
1996 } | 1976 } |
1997 | 1977 |
1998 void FullCodeGenerator::EmitCreateIteratorResult(bool done) { | 1978 void FullCodeGenerator::EmitCreateIteratorResult(bool done) { |
1999 Label allocate, done_allocate; | 1979 Label allocate, done_allocate; |
2000 | 1980 |
2001 __ Allocate(JSIteratorResult::kSize, r3, r5, r6, &allocate, TAG_OBJECT); | 1981 __ Allocate(JSIteratorResult::kSize, r2, r4, r5, &allocate, TAG_OBJECT); |
2002 __ b(&done_allocate); | 1982 __ b(&done_allocate); |
2003 | 1983 |
2004 __ bind(&allocate); | 1984 __ bind(&allocate); |
2005 __ Push(Smi::FromInt(JSIteratorResult::kSize)); | 1985 __ Push(Smi::FromInt(JSIteratorResult::kSize)); |
2006 __ CallRuntime(Runtime::kAllocateInNewSpace); | 1986 __ CallRuntime(Runtime::kAllocateInNewSpace); |
2007 | 1987 |
2008 __ bind(&done_allocate); | 1988 __ bind(&done_allocate); |
2009 __ LoadNativeContextSlot(Context::ITERATOR_RESULT_MAP_INDEX, r4); | 1989 __ LoadNativeContextSlot(Context::ITERATOR_RESULT_MAP_INDEX, r3); |
2010 PopOperand(r5); | 1990 PopOperand(r4); |
2011 __ LoadRoot(r6, | 1991 __ LoadRoot(r5, |
2012 done ? Heap::kTrueValueRootIndex : Heap::kFalseValueRootIndex); | 1992 done ? Heap::kTrueValueRootIndex : Heap::kFalseValueRootIndex); |
2013 __ LoadRoot(r7, Heap::kEmptyFixedArrayRootIndex); | 1993 __ LoadRoot(r6, Heap::kEmptyFixedArrayRootIndex); |
2014 __ StoreP(r4, FieldMemOperand(r3, HeapObject::kMapOffset), r0); | 1994 __ StoreP(r3, FieldMemOperand(r2, HeapObject::kMapOffset), r0); |
2015 __ StoreP(r7, FieldMemOperand(r3, JSObject::kPropertiesOffset), r0); | 1995 __ StoreP(r6, FieldMemOperand(r2, JSObject::kPropertiesOffset), r0); |
2016 __ StoreP(r7, FieldMemOperand(r3, JSObject::kElementsOffset), r0); | 1996 __ StoreP(r6, FieldMemOperand(r2, JSObject::kElementsOffset), r0); |
2017 __ StoreP(r5, FieldMemOperand(r3, JSIteratorResult::kValueOffset), r0); | 1997 __ StoreP(r4, FieldMemOperand(r2, JSIteratorResult::kValueOffset), r0); |
2018 __ StoreP(r6, FieldMemOperand(r3, JSIteratorResult::kDoneOffset), r0); | 1998 __ StoreP(r5, FieldMemOperand(r2, JSIteratorResult::kDoneOffset), r0); |
2019 } | 1999 } |
2020 | 2000 |
2021 | |
2022 void FullCodeGenerator::EmitInlineSmiBinaryOp(BinaryOperation* expr, | 2001 void FullCodeGenerator::EmitInlineSmiBinaryOp(BinaryOperation* expr, |
2023 Token::Value op, | 2002 Token::Value op, |
2024 Expression* left_expr, | 2003 Expression* left_expr, |
2025 Expression* right_expr) { | 2004 Expression* right_expr) { |
2026 Label done, smi_case, stub_call; | 2005 Label done, smi_case, stub_call; |
2027 | 2006 |
2028 Register scratch1 = r5; | 2007 Register scratch1 = r4; |
2029 Register scratch2 = r6; | 2008 Register scratch2 = r5; |
2030 | 2009 |
2031 // Get the arguments. | 2010 // Get the arguments. |
2032 Register left = r4; | 2011 Register left = r3; |
2033 Register right = r3; | 2012 Register right = r2; |
2034 PopOperand(left); | 2013 PopOperand(left); |
2035 | 2014 |
2036 // Perform combined smi check on both operands. | 2015 // Perform combined smi check on both operands. |
2037 __ orx(scratch1, left, right); | 2016 __ LoadRR(scratch1, right); |
| 2017 __ OrP(scratch1, left); |
2038 STATIC_ASSERT(kSmiTag == 0); | 2018 STATIC_ASSERT(kSmiTag == 0); |
2039 JumpPatchSite patch_site(masm_); | 2019 JumpPatchSite patch_site(masm_); |
2040 patch_site.EmitJumpIfSmi(scratch1, &smi_case); | 2020 patch_site.EmitJumpIfSmi(scratch1, &smi_case); |
2041 | 2021 |
2042 __ bind(&stub_call); | 2022 __ bind(&stub_call); |
2043 Handle<Code> code = CodeFactory::BinaryOpIC(isolate(), op).code(); | 2023 Handle<Code> code = CodeFactory::BinaryOpIC(isolate(), op).code(); |
2044 CallIC(code, expr->BinaryOperationFeedbackId()); | 2024 CallIC(code, expr->BinaryOperationFeedbackId()); |
2045 patch_site.EmitPatchInfo(); | 2025 patch_site.EmitPatchInfo(); |
2046 __ b(&done); | 2026 __ b(&done); |
2047 | 2027 |
2048 __ bind(&smi_case); | 2028 __ bind(&smi_case); |
2049 // Smi case. This code works the same way as the smi-smi case in the type | 2029 // Smi case. This code works the same way as the smi-smi case in the type |
2050 // recording binary operation stub. | 2030 // recording binary operation stub. |
2051 switch (op) { | 2031 switch (op) { |
2052 case Token::SAR: | 2032 case Token::SAR: |
2053 __ GetLeastBitsFromSmi(scratch1, right, 5); | 2033 __ GetLeastBitsFromSmi(scratch1, right, 5); |
2054 __ ShiftRightArith(right, left, scratch1); | 2034 __ ShiftRightArithP(right, left, scratch1); |
2055 __ ClearRightImm(right, right, Operand(kSmiTagSize + kSmiShiftSize)); | 2035 __ ClearRightImm(right, right, Operand(kSmiTagSize + kSmiShiftSize)); |
2056 break; | 2036 break; |
2057 case Token::SHL: { | 2037 case Token::SHL: { |
2058 __ GetLeastBitsFromSmi(scratch2, right, 5); | 2038 __ GetLeastBitsFromSmi(scratch2, right, 5); |
2059 #if V8_TARGET_ARCH_PPC64 | 2039 #if V8_TARGET_ARCH_S390X |
2060 __ ShiftLeft_(right, left, scratch2); | 2040 __ ShiftLeftP(right, left, scratch2); |
2061 #else | 2041 #else |
2062 __ SmiUntag(scratch1, left); | 2042 __ SmiUntag(scratch1, left); |
2063 __ ShiftLeft_(scratch1, scratch1, scratch2); | 2043 __ ShiftLeftP(scratch1, scratch1, scratch2); |
2064 // Check that the *signed* result fits in a smi | 2044 // Check that the *signed* result fits in a smi |
2065 __ JumpIfNotSmiCandidate(scratch1, scratch2, &stub_call); | 2045 __ JumpIfNotSmiCandidate(scratch1, scratch2, &stub_call); |
2066 __ SmiTag(right, scratch1); | 2046 __ SmiTag(right, scratch1); |
2067 #endif | 2047 #endif |
2068 break; | 2048 break; |
2069 } | 2049 } |
2070 case Token::SHR: { | 2050 case Token::SHR: { |
2071 __ SmiUntag(scratch1, left); | 2051 __ SmiUntag(scratch1, left); |
2072 __ GetLeastBitsFromSmi(scratch2, right, 5); | 2052 __ GetLeastBitsFromSmi(scratch2, right, 5); |
2073 __ srw(scratch1, scratch1, scratch2); | 2053 __ srl(scratch1, scratch2); |
2074 // Unsigned shift is not allowed to produce a negative number. | 2054 // Unsigned shift is not allowed to produce a negative number. |
2075 __ JumpIfNotUnsignedSmiCandidate(scratch1, r0, &stub_call); | 2055 __ JumpIfNotUnsignedSmiCandidate(scratch1, r0, &stub_call); |
2076 __ SmiTag(right, scratch1); | 2056 __ SmiTag(right, scratch1); |
2077 break; | 2057 break; |
2078 } | 2058 } |
2079 case Token::ADD: { | 2059 case Token::ADD: { |
2080 __ AddAndCheckForOverflow(scratch1, left, right, scratch2, r0); | 2060 __ AddAndCheckForOverflow(scratch1, left, right, scratch2, r0); |
2081 __ BranchOnOverflow(&stub_call); | 2061 __ BranchOnOverflow(&stub_call); |
2082 __ mr(right, scratch1); | 2062 __ LoadRR(right, scratch1); |
2083 break; | 2063 break; |
2084 } | 2064 } |
2085 case Token::SUB: { | 2065 case Token::SUB: { |
2086 __ SubAndCheckForOverflow(scratch1, left, right, scratch2, r0); | 2066 __ SubAndCheckForOverflow(scratch1, left, right, scratch2, r0); |
2087 __ BranchOnOverflow(&stub_call); | 2067 __ BranchOnOverflow(&stub_call); |
2088 __ mr(right, scratch1); | 2068 __ LoadRR(right, scratch1); |
2089 break; | 2069 break; |
2090 } | 2070 } |
2091 case Token::MUL: { | 2071 case Token::MUL: { |
2092 Label mul_zero; | 2072 Label mul_zero; |
2093 #if V8_TARGET_ARCH_PPC64 | 2073 #if V8_TARGET_ARCH_S390X |
2094 // Remove tag from both operands. | 2074 // Remove tag from both operands. |
2095 __ SmiUntag(ip, right); | 2075 __ SmiUntag(ip, right); |
2096 __ SmiUntag(r0, left); | 2076 __ SmiUntag(scratch2, left); |
2097 __ Mul(scratch1, r0, ip); | 2077 __ mr_z(scratch1, ip); |
2098 // Check for overflowing the smi range - no overflow if higher 33 bits of | 2078 // Check for overflowing the smi range - no overflow if higher 33 bits of |
2099 // the result are identical. | 2079 // the result are identical. |
2100 __ TestIfInt32(scratch1, r0); | 2080 __ lr(ip, scratch2); // 32 bit load |
| 2081 __ sra(ip, Operand(31)); |
| 2082 __ cr_z(ip, scratch1); // 32 bit compare |
2101 __ bne(&stub_call); | 2083 __ bne(&stub_call); |
2102 #else | 2084 #else |
2103 __ SmiUntag(ip, right); | 2085 __ SmiUntag(ip, right); |
2104 __ mullw(scratch1, left, ip); | 2086 __ LoadRR(scratch2, left); // load into low order of reg pair |
2105 __ mulhw(scratch2, left, ip); | 2087 __ mr_z(scratch1, ip); // R4:R5 = R5 * ip |
2106 // Check for overflowing the smi range - no overflow if higher 33 bits of | 2088 // Check for overflowing the smi range - no overflow if higher 33 bits of |
2107 // the result are identical. | 2089 // the result are identical. |
2108 __ TestIfInt32(scratch2, scratch1, ip); | 2090 __ TestIfInt32(scratch1, scratch2, ip); |
2109 __ bne(&stub_call); | 2091 __ bne(&stub_call); |
2110 #endif | 2092 #endif |
2111 // Go slow on zero result to handle -0. | 2093 // Go slow on zero result to handle -0. |
2112 __ cmpi(scratch1, Operand::Zero()); | 2094 __ chi(scratch2, Operand::Zero()); |
2113 __ beq(&mul_zero); | 2095 __ beq(&mul_zero, Label::kNear); |
2114 #if V8_TARGET_ARCH_PPC64 | 2096 #if V8_TARGET_ARCH_S390X |
2115 __ SmiTag(right, scratch1); | 2097 __ SmiTag(right, scratch2); |
2116 #else | 2098 #else |
2117 __ mr(right, scratch1); | 2099 __ LoadRR(right, scratch2); |
2118 #endif | 2100 #endif |
2119 __ b(&done); | 2101 __ b(&done); |
2120 // We need -0 if we were multiplying a negative number with 0 to get 0. | 2102 // We need -0 if we were multiplying a negative number with 0 to get 0. |
2121 // We know one of them was zero. | 2103 // We know one of them was zero. |
2122 __ bind(&mul_zero); | 2104 __ bind(&mul_zero); |
2123 __ add(scratch2, right, left); | 2105 __ AddP(scratch2, right, left); |
2124 __ cmpi(scratch2, Operand::Zero()); | 2106 __ CmpP(scratch2, Operand::Zero()); |
2125 __ blt(&stub_call); | 2107 __ blt(&stub_call); |
2126 __ LoadSmiLiteral(right, Smi::FromInt(0)); | 2108 __ LoadSmiLiteral(right, Smi::FromInt(0)); |
2127 break; | 2109 break; |
2128 } | 2110 } |
2129 case Token::BIT_OR: | 2111 case Token::BIT_OR: |
2130 __ orx(right, left, right); | 2112 __ OrP(right, left); |
2131 break; | 2113 break; |
2132 case Token::BIT_AND: | 2114 case Token::BIT_AND: |
2133 __ and_(right, left, right); | 2115 __ AndP(right, left); |
2134 break; | 2116 break; |
2135 case Token::BIT_XOR: | 2117 case Token::BIT_XOR: |
2136 __ xor_(right, left, right); | 2118 __ XorP(right, left); |
2137 break; | 2119 break; |
2138 default: | 2120 default: |
2139 UNREACHABLE(); | 2121 UNREACHABLE(); |
2140 } | 2122 } |
2141 | 2123 |
2142 __ bind(&done); | 2124 __ bind(&done); |
2143 context()->Plug(r3); | 2125 context()->Plug(r2); |
2144 } | 2126 } |
2145 | 2127 |
2146 | |
2147 void FullCodeGenerator::EmitClassDefineProperties(ClassLiteral* lit) { | 2128 void FullCodeGenerator::EmitClassDefineProperties(ClassLiteral* lit) { |
2148 for (int i = 0; i < lit->properties()->length(); i++) { | 2129 for (int i = 0; i < lit->properties()->length(); i++) { |
2149 ObjectLiteral::Property* property = lit->properties()->at(i); | 2130 ObjectLiteral::Property* property = lit->properties()->at(i); |
2150 Expression* value = property->value(); | 2131 Expression* value = property->value(); |
2151 | 2132 |
2152 Register scratch = r4; | 2133 Register scratch = r3; |
2153 if (property->is_static()) { | 2134 if (property->is_static()) { |
2154 __ LoadP(scratch, MemOperand(sp, kPointerSize)); // constructor | 2135 __ LoadP(scratch, MemOperand(sp, kPointerSize)); // constructor |
2155 } else { | 2136 } else { |
2156 __ LoadP(scratch, MemOperand(sp, 0)); // prototype | 2137 __ LoadP(scratch, MemOperand(sp, 0)); // prototype |
2157 } | 2138 } |
2158 PushOperand(scratch); | 2139 PushOperand(scratch); |
2159 EmitPropertyKey(property, lit->GetIdForProperty(i)); | 2140 EmitPropertyKey(property, lit->GetIdForProperty(i)); |
2160 | 2141 |
2161 // The static prototype property is read only. We handle the non computed | 2142 // The static prototype property is read only. We handle the non computed |
2162 // property name case in the parser. Since this is the only case where we | 2143 // property name case in the parser. Since this is the only case where we |
2163 // need to check for an own read only property we special case this so we do | 2144 // need to check for an own read only property we special case this so we do |
2164 // not need to do this for every property. | 2145 // not need to do this for every property. |
2165 if (property->is_static() && property->is_computed_name()) { | 2146 if (property->is_static() && property->is_computed_name()) { |
2166 __ CallRuntime(Runtime::kThrowIfStaticPrototype); | 2147 __ CallRuntime(Runtime::kThrowIfStaticPrototype); |
2167 __ push(r3); | 2148 __ push(r2); |
2168 } | 2149 } |
2169 | 2150 |
2170 VisitForStackValue(value); | 2151 VisitForStackValue(value); |
2171 if (NeedsHomeObject(value)) { | 2152 if (NeedsHomeObject(value)) { |
2172 EmitSetHomeObject(value, 2, property->GetSlot()); | 2153 EmitSetHomeObject(value, 2, property->GetSlot()); |
2173 } | 2154 } |
2174 | 2155 |
2175 switch (property->kind()) { | 2156 switch (property->kind()) { |
2176 case ObjectLiteral::Property::CONSTANT: | 2157 case ObjectLiteral::Property::CONSTANT: |
2177 case ObjectLiteral::Property::MATERIALIZED_LITERAL: | 2158 case ObjectLiteral::Property::MATERIALIZED_LITERAL: |
(...skipping 14 matching lines...) Expand all Loading... |
2192 PushOperand(Smi::FromInt(DONT_ENUM)); | 2173 PushOperand(Smi::FromInt(DONT_ENUM)); |
2193 CallRuntimeWithOperands(Runtime::kDefineSetterPropertyUnchecked); | 2174 CallRuntimeWithOperands(Runtime::kDefineSetterPropertyUnchecked); |
2194 break; | 2175 break; |
2195 | 2176 |
2196 default: | 2177 default: |
2197 UNREACHABLE(); | 2178 UNREACHABLE(); |
2198 } | 2179 } |
2199 } | 2180 } |
2200 } | 2181 } |
2201 | 2182 |
2202 | |
2203 void FullCodeGenerator::EmitBinaryOp(BinaryOperation* expr, Token::Value op) { | 2183 void FullCodeGenerator::EmitBinaryOp(BinaryOperation* expr, Token::Value op) { |
2204 PopOperand(r4); | 2184 PopOperand(r3); |
2205 Handle<Code> code = CodeFactory::BinaryOpIC(isolate(), op).code(); | 2185 Handle<Code> code = CodeFactory::BinaryOpIC(isolate(), op).code(); |
2206 JumpPatchSite patch_site(masm_); // unbound, signals no inlined smi code. | 2186 JumpPatchSite patch_site(masm_); // unbound, signals no inlined smi code. |
2207 CallIC(code, expr->BinaryOperationFeedbackId()); | 2187 CallIC(code, expr->BinaryOperationFeedbackId()); |
2208 patch_site.EmitPatchInfo(); | 2188 patch_site.EmitPatchInfo(); |
2209 context()->Plug(r3); | 2189 context()->Plug(r2); |
2210 } | 2190 } |
2211 | 2191 |
2212 | |
2213 void FullCodeGenerator::EmitAssignment(Expression* expr, | 2192 void FullCodeGenerator::EmitAssignment(Expression* expr, |
2214 FeedbackVectorSlot slot) { | 2193 FeedbackVectorSlot slot) { |
2215 DCHECK(expr->IsValidReferenceExpressionOrThis()); | 2194 DCHECK(expr->IsValidReferenceExpressionOrThis()); |
2216 | 2195 |
2217 Property* prop = expr->AsProperty(); | 2196 Property* prop = expr->AsProperty(); |
2218 LhsKind assign_type = Property::GetAssignType(prop); | 2197 LhsKind assign_type = Property::GetAssignType(prop); |
2219 | 2198 |
2220 switch (assign_type) { | 2199 switch (assign_type) { |
2221 case VARIABLE: { | 2200 case VARIABLE: { |
2222 Variable* var = expr->AsVariableProxy()->var(); | 2201 Variable* var = expr->AsVariableProxy()->var(); |
2223 EffectContext context(this); | 2202 EffectContext context(this); |
2224 EmitVariableAssignment(var, Token::ASSIGN, slot); | 2203 EmitVariableAssignment(var, Token::ASSIGN, slot); |
2225 break; | 2204 break; |
2226 } | 2205 } |
2227 case NAMED_PROPERTY: { | 2206 case NAMED_PROPERTY: { |
2228 PushOperand(r3); // Preserve value. | 2207 PushOperand(r2); // Preserve value. |
2229 VisitForAccumulatorValue(prop->obj()); | 2208 VisitForAccumulatorValue(prop->obj()); |
2230 __ Move(StoreDescriptor::ReceiverRegister(), r3); | 2209 __ Move(StoreDescriptor::ReceiverRegister(), r2); |
2231 PopOperand(StoreDescriptor::ValueRegister()); // Restore value. | 2210 PopOperand(StoreDescriptor::ValueRegister()); // Restore value. |
2232 __ mov(StoreDescriptor::NameRegister(), | 2211 __ mov(StoreDescriptor::NameRegister(), |
2233 Operand(prop->key()->AsLiteral()->value())); | 2212 Operand(prop->key()->AsLiteral()->value())); |
2234 EmitLoadStoreICSlot(slot); | 2213 EmitLoadStoreICSlot(slot); |
2235 CallStoreIC(); | 2214 CallStoreIC(); |
2236 break; | 2215 break; |
2237 } | 2216 } |
2238 case NAMED_SUPER_PROPERTY: { | 2217 case NAMED_SUPER_PROPERTY: { |
2239 PushOperand(r3); | 2218 PushOperand(r2); |
2240 VisitForStackValue(prop->obj()->AsSuperPropertyReference()->this_var()); | 2219 VisitForStackValue(prop->obj()->AsSuperPropertyReference()->this_var()); |
2241 VisitForAccumulatorValue( | 2220 VisitForAccumulatorValue( |
2242 prop->obj()->AsSuperPropertyReference()->home_object()); | 2221 prop->obj()->AsSuperPropertyReference()->home_object()); |
2243 // stack: value, this; r3: home_object | 2222 // stack: value, this; r2: home_object |
2244 Register scratch = r5; | 2223 Register scratch = r4; |
2245 Register scratch2 = r6; | 2224 Register scratch2 = r5; |
2246 __ mr(scratch, result_register()); // home_object | 2225 __ LoadRR(scratch, result_register()); // home_object |
2247 __ LoadP(r3, MemOperand(sp, kPointerSize)); // value | 2226 __ LoadP(r2, MemOperand(sp, kPointerSize)); // value |
2248 __ LoadP(scratch2, MemOperand(sp, 0)); // this | 2227 __ LoadP(scratch2, MemOperand(sp, 0)); // this |
2249 __ StoreP(scratch2, MemOperand(sp, kPointerSize)); // this | 2228 __ StoreP(scratch2, MemOperand(sp, kPointerSize)); // this |
2250 __ StoreP(scratch, MemOperand(sp, 0)); // home_object | 2229 __ StoreP(scratch, MemOperand(sp, 0)); // home_object |
2251 // stack: this, home_object; r3: value | 2230 // stack: this, home_object; r2: value |
2252 EmitNamedSuperPropertyStore(prop); | 2231 EmitNamedSuperPropertyStore(prop); |
2253 break; | 2232 break; |
2254 } | 2233 } |
2255 case KEYED_SUPER_PROPERTY: { | 2234 case KEYED_SUPER_PROPERTY: { |
2256 PushOperand(r3); | 2235 PushOperand(r2); |
2257 VisitForStackValue(prop->obj()->AsSuperPropertyReference()->this_var()); | 2236 VisitForStackValue(prop->obj()->AsSuperPropertyReference()->this_var()); |
2258 VisitForStackValue( | 2237 VisitForStackValue( |
2259 prop->obj()->AsSuperPropertyReference()->home_object()); | 2238 prop->obj()->AsSuperPropertyReference()->home_object()); |
2260 VisitForAccumulatorValue(prop->key()); | 2239 VisitForAccumulatorValue(prop->key()); |
2261 Register scratch = r5; | 2240 Register scratch = r4; |
2262 Register scratch2 = r6; | 2241 Register scratch2 = r5; |
2263 __ LoadP(scratch2, MemOperand(sp, 2 * kPointerSize)); // value | 2242 __ LoadP(scratch2, MemOperand(sp, 2 * kPointerSize)); // value |
2264 // stack: value, this, home_object; r3: key, r6: value | 2243 // stack: value, this, home_object; r3: key, r6: value |
2265 __ LoadP(scratch, MemOperand(sp, kPointerSize)); // this | 2244 __ LoadP(scratch, MemOperand(sp, kPointerSize)); // this |
2266 __ StoreP(scratch, MemOperand(sp, 2 * kPointerSize)); | 2245 __ StoreP(scratch, MemOperand(sp, 2 * kPointerSize)); |
2267 __ LoadP(scratch, MemOperand(sp, 0)); // home_object | 2246 __ LoadP(scratch, MemOperand(sp, 0)); // home_object |
2268 __ StoreP(scratch, MemOperand(sp, kPointerSize)); | 2247 __ StoreP(scratch, MemOperand(sp, kPointerSize)); |
2269 __ StoreP(r3, MemOperand(sp, 0)); | 2248 __ StoreP(r2, MemOperand(sp, 0)); |
2270 __ Move(r3, scratch2); | 2249 __ Move(r2, scratch2); |
2271 // stack: this, home_object, key; r3: value. | 2250 // stack: this, home_object, key; r2: value. |
2272 EmitKeyedSuperPropertyStore(prop); | 2251 EmitKeyedSuperPropertyStore(prop); |
2273 break; | 2252 break; |
2274 } | 2253 } |
2275 case KEYED_PROPERTY: { | 2254 case KEYED_PROPERTY: { |
2276 PushOperand(r3); // Preserve value. | 2255 PushOperand(r2); // Preserve value. |
2277 VisitForStackValue(prop->obj()); | 2256 VisitForStackValue(prop->obj()); |
2278 VisitForAccumulatorValue(prop->key()); | 2257 VisitForAccumulatorValue(prop->key()); |
2279 __ Move(StoreDescriptor::NameRegister(), r3); | 2258 __ Move(StoreDescriptor::NameRegister(), r2); |
2280 PopOperands(StoreDescriptor::ValueRegister(), | 2259 PopOperands(StoreDescriptor::ValueRegister(), |
2281 StoreDescriptor::ReceiverRegister()); | 2260 StoreDescriptor::ReceiverRegister()); |
2282 EmitLoadStoreICSlot(slot); | 2261 EmitLoadStoreICSlot(slot); |
2283 Handle<Code> ic = | 2262 Handle<Code> ic = |
2284 CodeFactory::KeyedStoreIC(isolate(), language_mode()).code(); | 2263 CodeFactory::KeyedStoreIC(isolate(), language_mode()).code(); |
2285 CallIC(ic); | 2264 CallIC(ic); |
2286 break; | 2265 break; |
2287 } | 2266 } |
2288 } | 2267 } |
2289 context()->Plug(r3); | 2268 context()->Plug(r2); |
2290 } | 2269 } |
2291 | 2270 |
2292 | |
2293 void FullCodeGenerator::EmitStoreToStackLocalOrContextSlot( | 2271 void FullCodeGenerator::EmitStoreToStackLocalOrContextSlot( |
2294 Variable* var, MemOperand location) { | 2272 Variable* var, MemOperand location) { |
2295 __ StoreP(result_register(), location, r0); | 2273 __ StoreP(result_register(), location); |
2296 if (var->IsContextSlot()) { | 2274 if (var->IsContextSlot()) { |
2297 // RecordWrite may destroy all its register arguments. | 2275 // RecordWrite may destroy all its register arguments. |
2298 __ mr(r6, result_register()); | 2276 __ LoadRR(r5, result_register()); |
2299 int offset = Context::SlotOffset(var->index()); | 2277 int offset = Context::SlotOffset(var->index()); |
2300 __ RecordWriteContextSlot(r4, offset, r6, r5, kLRHasBeenSaved, | 2278 __ RecordWriteContextSlot(r3, offset, r5, r4, kLRHasBeenSaved, |
2301 kDontSaveFPRegs); | 2279 kDontSaveFPRegs); |
2302 } | 2280 } |
2303 } | 2281 } |
2304 | 2282 |
2305 | |
2306 void FullCodeGenerator::EmitVariableAssignment(Variable* var, Token::Value op, | 2283 void FullCodeGenerator::EmitVariableAssignment(Variable* var, Token::Value op, |
2307 FeedbackVectorSlot slot) { | 2284 FeedbackVectorSlot slot) { |
2308 if (var->IsUnallocated()) { | 2285 if (var->IsUnallocated()) { |
2309 // Global var, const, or let. | 2286 // Global var, const, or let. |
2310 __ mov(StoreDescriptor::NameRegister(), Operand(var->name())); | 2287 __ mov(StoreDescriptor::NameRegister(), Operand(var->name())); |
2311 __ LoadGlobalObject(StoreDescriptor::ReceiverRegister()); | 2288 __ LoadGlobalObject(StoreDescriptor::ReceiverRegister()); |
2312 EmitLoadStoreICSlot(slot); | 2289 EmitLoadStoreICSlot(slot); |
2313 CallStoreIC(); | 2290 CallStoreIC(); |
2314 | 2291 |
2315 } else if (var->mode() == LET && op != Token::INIT) { | 2292 } else if (var->mode() == LET && op != Token::INIT) { |
2316 // Non-initializing assignment to let variable needs a write barrier. | 2293 // Non-initializing assignment to let variable needs a write barrier. |
2317 DCHECK(!var->IsLookupSlot()); | 2294 DCHECK(!var->IsLookupSlot()); |
2318 DCHECK(var->IsStackAllocated() || var->IsContextSlot()); | 2295 DCHECK(var->IsStackAllocated() || var->IsContextSlot()); |
2319 Label assign; | 2296 Label assign; |
2320 MemOperand location = VarOperand(var, r4); | 2297 MemOperand location = VarOperand(var, r3); |
2321 __ LoadP(r6, location); | 2298 __ LoadP(r5, location); |
2322 __ CompareRoot(r6, Heap::kTheHoleValueRootIndex); | 2299 __ CompareRoot(r5, Heap::kTheHoleValueRootIndex); |
2323 __ bne(&assign); | 2300 __ bne(&assign); |
2324 __ mov(r6, Operand(var->name())); | 2301 __ mov(r5, Operand(var->name())); |
2325 __ push(r6); | 2302 __ push(r5); |
2326 __ CallRuntime(Runtime::kThrowReferenceError); | 2303 __ CallRuntime(Runtime::kThrowReferenceError); |
2327 // Perform the assignment. | 2304 // Perform the assignment. |
2328 __ bind(&assign); | 2305 __ bind(&assign); |
2329 EmitStoreToStackLocalOrContextSlot(var, location); | 2306 EmitStoreToStackLocalOrContextSlot(var, location); |
2330 | 2307 |
2331 } else if (var->mode() == CONST && op != Token::INIT) { | 2308 } else if (var->mode() == CONST && op != Token::INIT) { |
2332 // Assignment to const variable needs a write barrier. | 2309 // Assignment to const variable needs a write barrier. |
2333 DCHECK(!var->IsLookupSlot()); | 2310 DCHECK(!var->IsLookupSlot()); |
2334 DCHECK(var->IsStackAllocated() || var->IsContextSlot()); | 2311 DCHECK(var->IsStackAllocated() || var->IsContextSlot()); |
2335 Label const_error; | 2312 Label const_error; |
2336 MemOperand location = VarOperand(var, r4); | 2313 MemOperand location = VarOperand(var, r3); |
2337 __ LoadP(r6, location); | 2314 __ LoadP(r5, location); |
2338 __ CompareRoot(r6, Heap::kTheHoleValueRootIndex); | 2315 __ CompareRoot(r5, Heap::kTheHoleValueRootIndex); |
2339 __ bne(&const_error); | 2316 __ bne(&const_error, Label::kNear); |
2340 __ mov(r6, Operand(var->name())); | 2317 __ mov(r5, Operand(var->name())); |
2341 __ push(r6); | 2318 __ push(r5); |
2342 __ CallRuntime(Runtime::kThrowReferenceError); | 2319 __ CallRuntime(Runtime::kThrowReferenceError); |
2343 __ bind(&const_error); | 2320 __ bind(&const_error); |
2344 __ CallRuntime(Runtime::kThrowConstAssignError); | 2321 __ CallRuntime(Runtime::kThrowConstAssignError); |
2345 | 2322 |
2346 } else if (var->is_this() && var->mode() == CONST && op == Token::INIT) { | 2323 } else if (var->is_this() && var->mode() == CONST && op == Token::INIT) { |
2347 // Initializing assignment to const {this} needs a write barrier. | 2324 // Initializing assignment to const {this} needs a write barrier. |
2348 DCHECK(var->IsStackAllocated() || var->IsContextSlot()); | 2325 DCHECK(var->IsStackAllocated() || var->IsContextSlot()); |
2349 Label uninitialized_this; | 2326 Label uninitialized_this; |
2350 MemOperand location = VarOperand(var, r4); | 2327 MemOperand location = VarOperand(var, r3); |
2351 __ LoadP(r6, location); | 2328 __ LoadP(r5, location); |
2352 __ CompareRoot(r6, Heap::kTheHoleValueRootIndex); | 2329 __ CompareRoot(r5, Heap::kTheHoleValueRootIndex); |
2353 __ beq(&uninitialized_this); | 2330 __ beq(&uninitialized_this); |
2354 __ mov(r4, Operand(var->name())); | 2331 __ mov(r3, Operand(var->name())); |
2355 __ push(r4); | 2332 __ push(r3); |
2356 __ CallRuntime(Runtime::kThrowReferenceError); | 2333 __ CallRuntime(Runtime::kThrowReferenceError); |
2357 __ bind(&uninitialized_this); | 2334 __ bind(&uninitialized_this); |
2358 EmitStoreToStackLocalOrContextSlot(var, location); | 2335 EmitStoreToStackLocalOrContextSlot(var, location); |
2359 | 2336 |
2360 } else if (!var->is_const_mode() || | 2337 } else if (!var->is_const_mode() || |
2361 (var->mode() == CONST && op == Token::INIT)) { | 2338 (var->mode() == CONST && op == Token::INIT)) { |
2362 if (var->IsLookupSlot()) { | 2339 if (var->IsLookupSlot()) { |
2363 // Assignment to var. | 2340 // Assignment to var. |
2364 __ Push(var->name()); | 2341 __ Push(var->name()); |
2365 __ Push(r3); | 2342 __ Push(r2); |
2366 __ CallRuntime(is_strict(language_mode()) | 2343 __ CallRuntime(is_strict(language_mode()) |
2367 ? Runtime::kStoreLookupSlot_Strict | 2344 ? Runtime::kStoreLookupSlot_Strict |
2368 : Runtime::kStoreLookupSlot_Sloppy); | 2345 : Runtime::kStoreLookupSlot_Sloppy); |
2369 } else { | 2346 } else { |
2370 // Assignment to var or initializing assignment to let/const in harmony | 2347 // Assignment to var or initializing assignment to let/const in harmony |
2371 // mode. | 2348 // mode. |
2372 DCHECK((var->IsStackAllocated() || var->IsContextSlot())); | 2349 DCHECK((var->IsStackAllocated() || var->IsContextSlot())); |
2373 MemOperand location = VarOperand(var, r4); | 2350 MemOperand location = VarOperand(var, r3); |
2374 if (FLAG_debug_code && var->mode() == LET && op == Token::INIT) { | 2351 if (FLAG_debug_code && var->mode() == LET && op == Token::INIT) { |
2375 // Check for an uninitialized let binding. | 2352 // Check for an uninitialized let binding. |
2376 __ LoadP(r5, location); | 2353 __ LoadP(r4, location); |
2377 __ CompareRoot(r5, Heap::kTheHoleValueRootIndex); | 2354 __ CompareRoot(r4, Heap::kTheHoleValueRootIndex); |
2378 __ Check(eq, kLetBindingReInitialization); | 2355 __ Check(eq, kLetBindingReInitialization); |
2379 } | 2356 } |
2380 EmitStoreToStackLocalOrContextSlot(var, location); | 2357 EmitStoreToStackLocalOrContextSlot(var, location); |
2381 } | 2358 } |
2382 } else if (var->mode() == CONST_LEGACY && op == Token::INIT) { | 2359 } else if (var->mode() == CONST_LEGACY && op == Token::INIT) { |
2383 // Const initializers need a write barrier. | 2360 // Const initializers need a write barrier. |
2384 DCHECK(!var->IsParameter()); // No const parameters. | 2361 DCHECK(!var->IsParameter()); // No const parameters. |
2385 if (var->IsLookupSlot()) { | 2362 if (var->IsLookupSlot()) { |
2386 __ push(r3); | 2363 __ push(r2); |
2387 __ mov(r3, Operand(var->name())); | 2364 __ mov(r2, Operand(var->name())); |
2388 __ Push(cp, r3); // Context and name. | 2365 __ Push(cp, r2); // Context and name. |
2389 __ CallRuntime(Runtime::kInitializeLegacyConstLookupSlot); | 2366 __ CallRuntime(Runtime::kInitializeLegacyConstLookupSlot); |
2390 } else { | 2367 } else { |
2391 DCHECK(var->IsStackAllocated() || var->IsContextSlot()); | 2368 DCHECK(var->IsStackAllocated() || var->IsContextSlot()); |
2392 Label skip; | 2369 Label skip; |
2393 MemOperand location = VarOperand(var, r4); | 2370 MemOperand location = VarOperand(var, r3); |
2394 __ LoadP(r5, location); | 2371 __ LoadP(r4, location); |
2395 __ CompareRoot(r5, Heap::kTheHoleValueRootIndex); | 2372 __ CompareRoot(r4, Heap::kTheHoleValueRootIndex); |
2396 __ bne(&skip); | 2373 __ bne(&skip); |
2397 EmitStoreToStackLocalOrContextSlot(var, location); | 2374 EmitStoreToStackLocalOrContextSlot(var, location); |
2398 __ bind(&skip); | 2375 __ bind(&skip); |
2399 } | 2376 } |
2400 | 2377 |
2401 } else { | 2378 } else { |
2402 DCHECK(var->mode() == CONST_LEGACY && op != Token::INIT); | 2379 DCHECK(var->mode() == CONST_LEGACY && op != Token::INIT); |
2403 if (is_strict(language_mode())) { | 2380 if (is_strict(language_mode())) { |
2404 __ CallRuntime(Runtime::kThrowConstAssignError); | 2381 __ CallRuntime(Runtime::kThrowConstAssignError); |
2405 } | 2382 } |
2406 // Silently ignore store in sloppy mode. | 2383 // Silently ignore store in sloppy mode. |
2407 } | 2384 } |
2408 } | 2385 } |
2409 | 2386 |
2410 | |
2411 void FullCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) { | 2387 void FullCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) { |
2412 // Assignment to a property, using a named store IC. | 2388 // Assignment to a property, using a named store IC. |
2413 Property* prop = expr->target()->AsProperty(); | 2389 Property* prop = expr->target()->AsProperty(); |
2414 DCHECK(prop != NULL); | 2390 DCHECK(prop != NULL); |
2415 DCHECK(prop->key()->IsLiteral()); | 2391 DCHECK(prop->key()->IsLiteral()); |
2416 | 2392 |
2417 __ mov(StoreDescriptor::NameRegister(), | 2393 __ mov(StoreDescriptor::NameRegister(), |
2418 Operand(prop->key()->AsLiteral()->value())); | 2394 Operand(prop->key()->AsLiteral()->value())); |
2419 PopOperand(StoreDescriptor::ReceiverRegister()); | 2395 PopOperand(StoreDescriptor::ReceiverRegister()); |
2420 EmitLoadStoreICSlot(expr->AssignmentSlot()); | 2396 EmitLoadStoreICSlot(expr->AssignmentSlot()); |
2421 CallStoreIC(); | 2397 CallStoreIC(); |
2422 | 2398 |
2423 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); | 2399 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); |
2424 context()->Plug(r3); | 2400 context()->Plug(r2); |
2425 } | 2401 } |
2426 | 2402 |
2427 | |
2428 void FullCodeGenerator::EmitNamedSuperPropertyStore(Property* prop) { | 2403 void FullCodeGenerator::EmitNamedSuperPropertyStore(Property* prop) { |
2429 // Assignment to named property of super. | 2404 // Assignment to named property of super. |
2430 // r3 : value | 2405 // r2 : value |
2431 // stack : receiver ('this'), home_object | 2406 // stack : receiver ('this'), home_object |
2432 DCHECK(prop != NULL); | 2407 DCHECK(prop != NULL); |
2433 Literal* key = prop->key()->AsLiteral(); | 2408 Literal* key = prop->key()->AsLiteral(); |
2434 DCHECK(key != NULL); | 2409 DCHECK(key != NULL); |
2435 | 2410 |
2436 PushOperand(key->value()); | 2411 PushOperand(key->value()); |
2437 PushOperand(r3); | 2412 PushOperand(r2); |
2438 CallRuntimeWithOperands((is_strict(language_mode()) | 2413 CallRuntimeWithOperands((is_strict(language_mode()) |
2439 ? Runtime::kStoreToSuper_Strict | 2414 ? Runtime::kStoreToSuper_Strict |
2440 : Runtime::kStoreToSuper_Sloppy)); | 2415 : Runtime::kStoreToSuper_Sloppy)); |
2441 } | 2416 } |
2442 | 2417 |
2443 | |
2444 void FullCodeGenerator::EmitKeyedSuperPropertyStore(Property* prop) { | 2418 void FullCodeGenerator::EmitKeyedSuperPropertyStore(Property* prop) { |
2445 // Assignment to named property of super. | 2419 // Assignment to named property of super. |
2446 // r3 : value | 2420 // r2 : value |
2447 // stack : receiver ('this'), home_object, key | 2421 // stack : receiver ('this'), home_object, key |
2448 DCHECK(prop != NULL); | 2422 DCHECK(prop != NULL); |
2449 | 2423 |
2450 PushOperand(r3); | 2424 PushOperand(r2); |
2451 CallRuntimeWithOperands((is_strict(language_mode()) | 2425 CallRuntimeWithOperands((is_strict(language_mode()) |
2452 ? Runtime::kStoreKeyedToSuper_Strict | 2426 ? Runtime::kStoreKeyedToSuper_Strict |
2453 : Runtime::kStoreKeyedToSuper_Sloppy)); | 2427 : Runtime::kStoreKeyedToSuper_Sloppy)); |
2454 } | 2428 } |
2455 | 2429 |
2456 | |
2457 void FullCodeGenerator::EmitKeyedPropertyAssignment(Assignment* expr) { | 2430 void FullCodeGenerator::EmitKeyedPropertyAssignment(Assignment* expr) { |
2458 // Assignment to a property, using a keyed store IC. | 2431 // Assignment to a property, using a keyed store IC. |
2459 PopOperands(StoreDescriptor::ReceiverRegister(), | 2432 PopOperands(StoreDescriptor::ReceiverRegister(), |
2460 StoreDescriptor::NameRegister()); | 2433 StoreDescriptor::NameRegister()); |
2461 DCHECK(StoreDescriptor::ValueRegister().is(r3)); | 2434 DCHECK(StoreDescriptor::ValueRegister().is(r2)); |
2462 | 2435 |
2463 Handle<Code> ic = | 2436 Handle<Code> ic = |
2464 CodeFactory::KeyedStoreIC(isolate(), language_mode()).code(); | 2437 CodeFactory::KeyedStoreIC(isolate(), language_mode()).code(); |
2465 EmitLoadStoreICSlot(expr->AssignmentSlot()); | 2438 EmitLoadStoreICSlot(expr->AssignmentSlot()); |
2466 CallIC(ic); | 2439 CallIC(ic); |
2467 | 2440 |
2468 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); | 2441 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); |
2469 context()->Plug(r3); | 2442 context()->Plug(r2); |
2470 } | 2443 } |
2471 | 2444 |
2472 | |
2473 void FullCodeGenerator::VisitProperty(Property* expr) { | 2445 void FullCodeGenerator::VisitProperty(Property* expr) { |
2474 Comment cmnt(masm_, "[ Property"); | 2446 Comment cmnt(masm_, "[ Property"); |
2475 SetExpressionPosition(expr); | 2447 SetExpressionPosition(expr); |
2476 | 2448 |
2477 Expression* key = expr->key(); | 2449 Expression* key = expr->key(); |
2478 | 2450 |
2479 if (key->IsPropertyName()) { | 2451 if (key->IsPropertyName()) { |
2480 if (!expr->IsSuperAccess()) { | 2452 if (!expr->IsSuperAccess()) { |
2481 VisitForAccumulatorValue(expr->obj()); | 2453 VisitForAccumulatorValue(expr->obj()); |
2482 __ Move(LoadDescriptor::ReceiverRegister(), r3); | 2454 __ Move(LoadDescriptor::ReceiverRegister(), r2); |
2483 EmitNamedPropertyLoad(expr); | 2455 EmitNamedPropertyLoad(expr); |
2484 } else { | 2456 } else { |
2485 VisitForStackValue(expr->obj()->AsSuperPropertyReference()->this_var()); | 2457 VisitForStackValue(expr->obj()->AsSuperPropertyReference()->this_var()); |
2486 VisitForStackValue( | 2458 VisitForStackValue( |
2487 expr->obj()->AsSuperPropertyReference()->home_object()); | 2459 expr->obj()->AsSuperPropertyReference()->home_object()); |
2488 EmitNamedSuperPropertyLoad(expr); | 2460 EmitNamedSuperPropertyLoad(expr); |
2489 } | 2461 } |
2490 } else { | 2462 } else { |
2491 if (!expr->IsSuperAccess()) { | 2463 if (!expr->IsSuperAccess()) { |
2492 VisitForStackValue(expr->obj()); | 2464 VisitForStackValue(expr->obj()); |
2493 VisitForAccumulatorValue(expr->key()); | 2465 VisitForAccumulatorValue(expr->key()); |
2494 __ Move(LoadDescriptor::NameRegister(), r3); | 2466 __ Move(LoadDescriptor::NameRegister(), r2); |
2495 PopOperand(LoadDescriptor::ReceiverRegister()); | 2467 PopOperand(LoadDescriptor::ReceiverRegister()); |
2496 EmitKeyedPropertyLoad(expr); | 2468 EmitKeyedPropertyLoad(expr); |
2497 } else { | 2469 } else { |
2498 VisitForStackValue(expr->obj()->AsSuperPropertyReference()->this_var()); | 2470 VisitForStackValue(expr->obj()->AsSuperPropertyReference()->this_var()); |
2499 VisitForStackValue( | 2471 VisitForStackValue( |
2500 expr->obj()->AsSuperPropertyReference()->home_object()); | 2472 expr->obj()->AsSuperPropertyReference()->home_object()); |
2501 VisitForStackValue(expr->key()); | 2473 VisitForStackValue(expr->key()); |
2502 EmitKeyedSuperPropertyLoad(expr); | 2474 EmitKeyedSuperPropertyLoad(expr); |
2503 } | 2475 } |
2504 } | 2476 } |
2505 PrepareForBailoutForId(expr->LoadId(), TOS_REG); | 2477 PrepareForBailoutForId(expr->LoadId(), TOS_REG); |
2506 context()->Plug(r3); | 2478 context()->Plug(r2); |
2507 } | 2479 } |
2508 | 2480 |
2509 | |
2510 void FullCodeGenerator::CallIC(Handle<Code> code, TypeFeedbackId ast_id) { | 2481 void FullCodeGenerator::CallIC(Handle<Code> code, TypeFeedbackId ast_id) { |
2511 ic_total_count_++; | 2482 ic_total_count_++; |
2512 __ Call(code, RelocInfo::CODE_TARGET, ast_id); | 2483 __ Call(code, RelocInfo::CODE_TARGET, ast_id); |
2513 } | 2484 } |
2514 | 2485 |
2515 | |
2516 // Code common for calls using the IC. | 2486 // Code common for calls using the IC. |
2517 void FullCodeGenerator::EmitCallWithLoadIC(Call* expr) { | 2487 void FullCodeGenerator::EmitCallWithLoadIC(Call* expr) { |
2518 Expression* callee = expr->expression(); | 2488 Expression* callee = expr->expression(); |
2519 | 2489 |
2520 // Get the target function. | 2490 // Get the target function. |
2521 ConvertReceiverMode convert_mode; | 2491 ConvertReceiverMode convert_mode; |
2522 if (callee->IsVariableProxy()) { | 2492 if (callee->IsVariableProxy()) { |
2523 { | 2493 { |
2524 StackValueContext context(this); | 2494 StackValueContext context(this); |
2525 EmitVariableLoad(callee->AsVariableProxy()); | 2495 EmitVariableLoad(callee->AsVariableProxy()); |
2526 PrepareForBailout(callee, NO_REGISTERS); | 2496 PrepareForBailout(callee, NO_REGISTERS); |
2527 } | 2497 } |
2528 // Push undefined as receiver. This is patched in the method prologue if it | 2498 // Push undefined as receiver. This is patched in the method prologue if it |
2529 // is a sloppy mode method. | 2499 // is a sloppy mode method. |
2530 __ LoadRoot(r0, Heap::kUndefinedValueRootIndex); | 2500 __ LoadRoot(r1, Heap::kUndefinedValueRootIndex); |
2531 PushOperand(r0); | 2501 PushOperand(r1); |
2532 convert_mode = ConvertReceiverMode::kNullOrUndefined; | 2502 convert_mode = ConvertReceiverMode::kNullOrUndefined; |
2533 } else { | 2503 } else { |
2534 // Load the function from the receiver. | 2504 // Load the function from the receiver. |
2535 DCHECK(callee->IsProperty()); | 2505 DCHECK(callee->IsProperty()); |
2536 DCHECK(!callee->AsProperty()->IsSuperAccess()); | 2506 DCHECK(!callee->AsProperty()->IsSuperAccess()); |
2537 __ LoadP(LoadDescriptor::ReceiverRegister(), MemOperand(sp, 0)); | 2507 __ LoadP(LoadDescriptor::ReceiverRegister(), MemOperand(sp, 0)); |
2538 EmitNamedPropertyLoad(callee->AsProperty()); | 2508 EmitNamedPropertyLoad(callee->AsProperty()); |
2539 PrepareForBailoutForId(callee->AsProperty()->LoadId(), TOS_REG); | 2509 PrepareForBailoutForId(callee->AsProperty()->LoadId(), TOS_REG); |
2540 // Push the target function under the receiver. | 2510 // Push the target function under the receiver. |
2541 __ LoadP(r0, MemOperand(sp, 0)); | 2511 __ LoadP(r1, MemOperand(sp, 0)); |
2542 PushOperand(r0); | 2512 PushOperand(r1); |
2543 __ StoreP(r3, MemOperand(sp, kPointerSize)); | 2513 __ StoreP(r2, MemOperand(sp, kPointerSize)); |
2544 convert_mode = ConvertReceiverMode::kNotNullOrUndefined; | 2514 convert_mode = ConvertReceiverMode::kNotNullOrUndefined; |
2545 } | 2515 } |
2546 | 2516 |
2547 EmitCall(expr, convert_mode); | 2517 EmitCall(expr, convert_mode); |
2548 } | 2518 } |
2549 | 2519 |
2550 | |
2551 void FullCodeGenerator::EmitSuperCallWithLoadIC(Call* expr) { | 2520 void FullCodeGenerator::EmitSuperCallWithLoadIC(Call* expr) { |
2552 Expression* callee = expr->expression(); | 2521 Expression* callee = expr->expression(); |
2553 DCHECK(callee->IsProperty()); | 2522 DCHECK(callee->IsProperty()); |
2554 Property* prop = callee->AsProperty(); | 2523 Property* prop = callee->AsProperty(); |
2555 DCHECK(prop->IsSuperAccess()); | 2524 DCHECK(prop->IsSuperAccess()); |
2556 SetExpressionPosition(prop); | 2525 SetExpressionPosition(prop); |
2557 | 2526 |
2558 Literal* key = prop->key()->AsLiteral(); | 2527 Literal* key = prop->key()->AsLiteral(); |
2559 DCHECK(!key->value()->IsSmi()); | 2528 DCHECK(!key->value()->IsSmi()); |
2560 // Load the function from the receiver. | 2529 // Load the function from the receiver. |
2561 const Register scratch = r4; | 2530 const Register scratch = r3; |
2562 SuperPropertyReference* super_ref = prop->obj()->AsSuperPropertyReference(); | 2531 SuperPropertyReference* super_ref = prop->obj()->AsSuperPropertyReference(); |
2563 VisitForAccumulatorValue(super_ref->home_object()); | 2532 VisitForAccumulatorValue(super_ref->home_object()); |
2564 __ mr(scratch, r3); | 2533 __ LoadRR(scratch, r2); |
2565 VisitForAccumulatorValue(super_ref->this_var()); | 2534 VisitForAccumulatorValue(super_ref->this_var()); |
2566 PushOperands(scratch, r3, r3, scratch); | 2535 PushOperands(scratch, r2, r2, scratch); |
2567 PushOperand(key->value()); | 2536 PushOperand(key->value()); |
2568 | 2537 |
2569 // Stack here: | 2538 // Stack here: |
2570 // - home_object | 2539 // - home_object |
2571 // - this (receiver) | 2540 // - this (receiver) |
2572 // - this (receiver) <-- LoadFromSuper will pop here and below. | 2541 // - this (receiver) <-- LoadFromSuper will pop here and below. |
2573 // - home_object | 2542 // - home_object |
2574 // - key | 2543 // - key |
2575 CallRuntimeWithOperands(Runtime::kLoadFromSuper); | 2544 CallRuntimeWithOperands(Runtime::kLoadFromSuper); |
2576 | 2545 |
2577 // Replace home_object with target function. | 2546 // Replace home_object with target function. |
2578 __ StoreP(r3, MemOperand(sp, kPointerSize)); | 2547 __ StoreP(r2, MemOperand(sp, kPointerSize)); |
2579 | 2548 |
2580 // Stack here: | 2549 // Stack here: |
2581 // - target function | 2550 // - target function |
2582 // - this (receiver) | 2551 // - this (receiver) |
2583 EmitCall(expr); | 2552 EmitCall(expr); |
2584 } | 2553 } |
2585 | 2554 |
2586 | |
2587 // Code common for calls using the IC. | 2555 // Code common for calls using the IC. |
2588 void FullCodeGenerator::EmitKeyedCallWithLoadIC(Call* expr, Expression* key) { | 2556 void FullCodeGenerator::EmitKeyedCallWithLoadIC(Call* expr, Expression* key) { |
2589 // Load the key. | 2557 // Load the key. |
2590 VisitForAccumulatorValue(key); | 2558 VisitForAccumulatorValue(key); |
2591 | 2559 |
2592 Expression* callee = expr->expression(); | 2560 Expression* callee = expr->expression(); |
2593 | 2561 |
2594 // Load the function from the receiver. | 2562 // Load the function from the receiver. |
2595 DCHECK(callee->IsProperty()); | 2563 DCHECK(callee->IsProperty()); |
2596 __ LoadP(LoadDescriptor::ReceiverRegister(), MemOperand(sp, 0)); | 2564 __ LoadP(LoadDescriptor::ReceiverRegister(), MemOperand(sp, 0)); |
2597 __ Move(LoadDescriptor::NameRegister(), r3); | 2565 __ Move(LoadDescriptor::NameRegister(), r2); |
2598 EmitKeyedPropertyLoad(callee->AsProperty()); | 2566 EmitKeyedPropertyLoad(callee->AsProperty()); |
2599 PrepareForBailoutForId(callee->AsProperty()->LoadId(), TOS_REG); | 2567 PrepareForBailoutForId(callee->AsProperty()->LoadId(), TOS_REG); |
2600 | 2568 |
2601 // Push the target function under the receiver. | 2569 // Push the target function under the receiver. |
2602 __ LoadP(ip, MemOperand(sp, 0)); | 2570 __ LoadP(ip, MemOperand(sp, 0)); |
2603 PushOperand(ip); | 2571 PushOperand(ip); |
2604 __ StoreP(r3, MemOperand(sp, kPointerSize)); | 2572 __ StoreP(r2, MemOperand(sp, kPointerSize)); |
2605 | 2573 |
2606 EmitCall(expr, ConvertReceiverMode::kNotNullOrUndefined); | 2574 EmitCall(expr, ConvertReceiverMode::kNotNullOrUndefined); |
2607 } | 2575 } |
2608 | 2576 |
2609 | |
2610 void FullCodeGenerator::EmitKeyedSuperCallWithLoadIC(Call* expr) { | 2577 void FullCodeGenerator::EmitKeyedSuperCallWithLoadIC(Call* expr) { |
2611 Expression* callee = expr->expression(); | 2578 Expression* callee = expr->expression(); |
2612 DCHECK(callee->IsProperty()); | 2579 DCHECK(callee->IsProperty()); |
2613 Property* prop = callee->AsProperty(); | 2580 Property* prop = callee->AsProperty(); |
2614 DCHECK(prop->IsSuperAccess()); | 2581 DCHECK(prop->IsSuperAccess()); |
2615 | 2582 |
2616 SetExpressionPosition(prop); | 2583 SetExpressionPosition(prop); |
2617 // Load the function from the receiver. | 2584 // Load the function from the receiver. |
2618 const Register scratch = r4; | 2585 const Register scratch = r3; |
2619 SuperPropertyReference* super_ref = prop->obj()->AsSuperPropertyReference(); | 2586 SuperPropertyReference* super_ref = prop->obj()->AsSuperPropertyReference(); |
2620 VisitForAccumulatorValue(super_ref->home_object()); | 2587 VisitForAccumulatorValue(super_ref->home_object()); |
2621 __ mr(scratch, r3); | 2588 __ LoadRR(scratch, r2); |
2622 VisitForAccumulatorValue(super_ref->this_var()); | 2589 VisitForAccumulatorValue(super_ref->this_var()); |
2623 PushOperands(scratch, r3, r3, scratch); | 2590 PushOperands(scratch, r2, r2, scratch); |
2624 VisitForStackValue(prop->key()); | 2591 VisitForStackValue(prop->key()); |
2625 | 2592 |
2626 // Stack here: | 2593 // Stack here: |
2627 // - home_object | 2594 // - home_object |
2628 // - this (receiver) | 2595 // - this (receiver) |
2629 // - this (receiver) <-- LoadKeyedFromSuper will pop here and below. | 2596 // - this (receiver) <-- LoadKeyedFromSuper will pop here and below. |
2630 // - home_object | 2597 // - home_object |
2631 // - key | 2598 // - key |
2632 CallRuntimeWithOperands(Runtime::kLoadKeyedFromSuper); | 2599 CallRuntimeWithOperands(Runtime::kLoadKeyedFromSuper); |
2633 | 2600 |
2634 // Replace home_object with target function. | 2601 // Replace home_object with target function. |
2635 __ StoreP(r3, MemOperand(sp, kPointerSize)); | 2602 __ StoreP(r2, MemOperand(sp, kPointerSize)); |
2636 | 2603 |
2637 // Stack here: | 2604 // Stack here: |
2638 // - target function | 2605 // - target function |
2639 // - this (receiver) | 2606 // - this (receiver) |
2640 EmitCall(expr); | 2607 EmitCall(expr); |
2641 } | 2608 } |
2642 | 2609 |
2643 | |
2644 void FullCodeGenerator::EmitCall(Call* expr, ConvertReceiverMode mode) { | 2610 void FullCodeGenerator::EmitCall(Call* expr, ConvertReceiverMode mode) { |
2645 // Load the arguments. | 2611 // Load the arguments. |
2646 ZoneList<Expression*>* args = expr->arguments(); | 2612 ZoneList<Expression*>* args = expr->arguments(); |
2647 int arg_count = args->length(); | 2613 int arg_count = args->length(); |
2648 for (int i = 0; i < arg_count; i++) { | 2614 for (int i = 0; i < arg_count; i++) { |
2649 VisitForStackValue(args->at(i)); | 2615 VisitForStackValue(args->at(i)); |
2650 } | 2616 } |
2651 | 2617 |
2652 PrepareForBailoutForId(expr->CallId(), NO_REGISTERS); | 2618 PrepareForBailoutForId(expr->CallId(), NO_REGISTERS); |
2653 SetCallPosition(expr); | 2619 SetCallPosition(expr); |
2654 if (expr->tail_call_mode() == TailCallMode::kAllow) { | 2620 if (expr->tail_call_mode() == TailCallMode::kAllow) { |
2655 if (FLAG_trace) { | 2621 if (FLAG_trace) { |
2656 __ CallRuntime(Runtime::kTraceTailCall); | 2622 __ CallRuntime(Runtime::kTraceTailCall); |
2657 } | 2623 } |
2658 // Update profiling counters before the tail call since we will | 2624 // Update profiling counters before the tail call since we will |
2659 // not return to this function. | 2625 // not return to this function. |
2660 EmitProfilingCounterHandlingForReturnSequence(true); | 2626 EmitProfilingCounterHandlingForReturnSequence(true); |
2661 } | 2627 } |
2662 Handle<Code> ic = | 2628 Handle<Code> ic = |
2663 CodeFactory::CallIC(isolate(), arg_count, mode, expr->tail_call_mode()) | 2629 CodeFactory::CallIC(isolate(), arg_count, mode, expr->tail_call_mode()) |
2664 .code(); | 2630 .code(); |
2665 __ LoadSmiLiteral(r6, SmiFromSlot(expr->CallFeedbackICSlot())); | 2631 __ LoadSmiLiteral(r5, SmiFromSlot(expr->CallFeedbackICSlot())); |
2666 __ LoadP(r4, MemOperand(sp, (arg_count + 1) * kPointerSize), r0); | 2632 __ LoadP(r3, MemOperand(sp, (arg_count + 1) * kPointerSize), r0); |
2667 // Don't assign a type feedback id to the IC, since type feedback is provided | 2633 // Don't assign a type feedback id to the IC, since type feedback is provided |
2668 // by the vector above. | 2634 // by the vector above. |
2669 CallIC(ic); | 2635 CallIC(ic); |
2670 OperandStackDepthDecrement(arg_count + 1); | 2636 OperandStackDepthDecrement(arg_count + 1); |
2671 | 2637 |
2672 RecordJSReturnSite(expr); | 2638 RecordJSReturnSite(expr); |
2673 // Restore context register. | 2639 // Restore context register. |
2674 __ LoadP(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); | 2640 __ LoadP(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); |
2675 context()->DropAndPlug(1, r3); | 2641 context()->DropAndPlug(1, r2); |
2676 } | 2642 } |
2677 | 2643 |
2678 | |
2679 void FullCodeGenerator::EmitResolvePossiblyDirectEval(int arg_count) { | 2644 void FullCodeGenerator::EmitResolvePossiblyDirectEval(int arg_count) { |
2680 // r7: copy of the first argument or undefined if it doesn't exist. | 2645 // r6: copy of the first argument or undefined if it doesn't exist. |
2681 if (arg_count > 0) { | 2646 if (arg_count > 0) { |
2682 __ LoadP(r7, MemOperand(sp, arg_count * kPointerSize), r0); | 2647 __ LoadP(r6, MemOperand(sp, arg_count * kPointerSize), r0); |
2683 } else { | 2648 } else { |
2684 __ LoadRoot(r7, Heap::kUndefinedValueRootIndex); | 2649 __ LoadRoot(r6, Heap::kUndefinedValueRootIndex); |
2685 } | 2650 } |
2686 | 2651 |
2687 // r6: the receiver of the enclosing function. | 2652 // r5: the receiver of the enclosing function. |
2688 __ LoadP(r6, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset)); | 2653 __ LoadP(r5, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset)); |
2689 | 2654 |
2690 // r5: language mode. | 2655 // r4: language mode. |
2691 __ LoadSmiLiteral(r5, Smi::FromInt(language_mode())); | 2656 __ LoadSmiLiteral(r4, Smi::FromInt(language_mode())); |
2692 | 2657 |
2693 // r4: the start position of the scope the calls resides in. | 2658 // r3: the start position of the scope the calls resides in. |
2694 __ LoadSmiLiteral(r4, Smi::FromInt(scope()->start_position())); | 2659 __ LoadSmiLiteral(r3, Smi::FromInt(scope()->start_position())); |
2695 | 2660 |
2696 // Do the runtime call. | 2661 // Do the runtime call. |
2697 __ Push(r7, r6, r5, r4); | 2662 __ Push(r6, r5, r4, r3); |
2698 __ CallRuntime(Runtime::kResolvePossiblyDirectEval); | 2663 __ CallRuntime(Runtime::kResolvePossiblyDirectEval); |
2699 } | 2664 } |
2700 | 2665 |
2701 | |
2702 // See http://www.ecma-international.org/ecma-262/6.0/#sec-function-calls. | 2666 // See http://www.ecma-international.org/ecma-262/6.0/#sec-function-calls. |
2703 void FullCodeGenerator::PushCalleeAndWithBaseObject(Call* expr) { | 2667 void FullCodeGenerator::PushCalleeAndWithBaseObject(Call* expr) { |
2704 VariableProxy* callee = expr->expression()->AsVariableProxy(); | 2668 VariableProxy* callee = expr->expression()->AsVariableProxy(); |
2705 if (callee->var()->IsLookupSlot()) { | 2669 if (callee->var()->IsLookupSlot()) { |
2706 Label slow, done; | 2670 Label slow, done; |
2707 SetExpressionPosition(callee); | 2671 SetExpressionPosition(callee); |
2708 // Generate code for loading from variables potentially shadowed by | 2672 // Generate code for loading from variables potentially shadowed by |
2709 // eval-introduced variables. | 2673 // eval-introduced variables. |
2710 EmitDynamicLookupFastCase(callee, NOT_INSIDE_TYPEOF, &slow, &done); | 2674 EmitDynamicLookupFastCase(callee, NOT_INSIDE_TYPEOF, &slow, &done); |
2711 | 2675 |
2712 __ bind(&slow); | 2676 __ bind(&slow); |
2713 // Call the runtime to find the function to call (returned in r3) and | 2677 // Call the runtime to find the function to call (returned in r2) and |
2714 // the object holding it (returned in r4). | 2678 // the object holding it (returned in r3). |
2715 __ Push(callee->name()); | 2679 __ Push(callee->name()); |
2716 __ CallRuntime(Runtime::kLoadLookupSlotForCall); | 2680 __ CallRuntime(Runtime::kLoadLookupSlotForCall); |
2717 PushOperands(r3, r4); // Function, receiver. | 2681 PushOperands(r2, r3); // Function, receiver. |
2718 PrepareForBailoutForId(expr->LookupId(), NO_REGISTERS); | 2682 PrepareForBailoutForId(expr->LookupId(), NO_REGISTERS); |
2719 | 2683 |
2720 // If fast case code has been generated, emit code to push the function | 2684 // If fast case code has been generated, emit code to push the function |
2721 // and receiver and have the slow path jump around this code. | 2685 // and receiver and have the slow path jump around this code. |
2722 if (done.is_linked()) { | 2686 if (done.is_linked()) { |
2723 Label call; | 2687 Label call; |
2724 __ b(&call); | 2688 __ b(&call); |
2725 __ bind(&done); | 2689 __ bind(&done); |
2726 // Push function. | 2690 // Push function. |
2727 __ push(r3); | 2691 __ push(r2); |
2728 // Pass undefined as the receiver, which is the WithBaseObject of a | 2692 // Pass undefined as the receiver, which is the WithBaseObject of a |
2729 // non-object environment record. If the callee is sloppy, it will patch | 2693 // non-object environment record. If the callee is sloppy, it will patch |
2730 // it up to be the global receiver. | 2694 // it up to be the global receiver. |
2731 __ LoadRoot(r4, Heap::kUndefinedValueRootIndex); | 2695 __ LoadRoot(r3, Heap::kUndefinedValueRootIndex); |
2732 __ push(r4); | 2696 __ push(r3); |
2733 __ bind(&call); | 2697 __ bind(&call); |
2734 } | 2698 } |
2735 } else { | 2699 } else { |
2736 VisitForStackValue(callee); | 2700 VisitForStackValue(callee); |
2737 // refEnv.WithBaseObject() | 2701 // refEnv.WithBaseObject() |
2738 __ LoadRoot(r5, Heap::kUndefinedValueRootIndex); | 2702 __ LoadRoot(r4, Heap::kUndefinedValueRootIndex); |
2739 PushOperand(r5); // Reserved receiver slot. | 2703 PushOperand(r4); // Reserved receiver slot. |
2740 } | 2704 } |
2741 } | 2705 } |
2742 | 2706 |
2743 | |
2744 void FullCodeGenerator::EmitPossiblyEvalCall(Call* expr) { | 2707 void FullCodeGenerator::EmitPossiblyEvalCall(Call* expr) { |
2745 // In a call to eval, we first call RuntimeHidden_ResolvePossiblyDirectEval | 2708 // In a call to eval, we first call RuntimeHidden_ResolvePossiblyDirectEval |
2746 // to resolve the function we need to call. Then we call the resolved | 2709 // to resolve the function we need to call. Then we call the resolved |
2747 // function using the given arguments. | 2710 // function using the given arguments. |
2748 ZoneList<Expression*>* args = expr->arguments(); | 2711 ZoneList<Expression*>* args = expr->arguments(); |
2749 int arg_count = args->length(); | 2712 int arg_count = args->length(); |
2750 | 2713 |
2751 PushCalleeAndWithBaseObject(expr); | 2714 PushCalleeAndWithBaseObject(expr); |
2752 | 2715 |
2753 // Push the arguments. | 2716 // Push the arguments. |
2754 for (int i = 0; i < arg_count; i++) { | 2717 for (int i = 0; i < arg_count; i++) { |
2755 VisitForStackValue(args->at(i)); | 2718 VisitForStackValue(args->at(i)); |
2756 } | 2719 } |
2757 | 2720 |
2758 // Push a copy of the function (found below the arguments) and | 2721 // Push a copy of the function (found below the arguments) and |
2759 // resolve eval. | 2722 // resolve eval. |
2760 __ LoadP(r4, MemOperand(sp, (arg_count + 1) * kPointerSize), r0); | 2723 __ LoadP(r3, MemOperand(sp, (arg_count + 1) * kPointerSize), r0); |
2761 __ push(r4); | 2724 __ push(r3); |
2762 EmitResolvePossiblyDirectEval(arg_count); | 2725 EmitResolvePossiblyDirectEval(arg_count); |
2763 | 2726 |
2764 // Touch up the stack with the resolved function. | 2727 // Touch up the stack with the resolved function. |
2765 __ StoreP(r3, MemOperand(sp, (arg_count + 1) * kPointerSize), r0); | 2728 __ StoreP(r2, MemOperand(sp, (arg_count + 1) * kPointerSize), r0); |
2766 | 2729 |
2767 PrepareForBailoutForId(expr->EvalId(), NO_REGISTERS); | 2730 PrepareForBailoutForId(expr->EvalId(), NO_REGISTERS); |
2768 | 2731 |
2769 // Record source position for debugger. | 2732 // Record source position for debugger. |
2770 SetCallPosition(expr); | 2733 SetCallPosition(expr); |
2771 __ LoadP(r4, MemOperand(sp, (arg_count + 1) * kPointerSize), r0); | 2734 __ LoadP(r3, MemOperand(sp, (arg_count + 1) * kPointerSize), r0); |
2772 __ mov(r3, Operand(arg_count)); | 2735 __ mov(r2, Operand(arg_count)); |
2773 __ Call(isolate()->builtins()->Call(ConvertReceiverMode::kAny, | 2736 __ Call(isolate()->builtins()->Call(ConvertReceiverMode::kAny, |
2774 expr->tail_call_mode()), | 2737 expr->tail_call_mode()), |
2775 RelocInfo::CODE_TARGET); | 2738 RelocInfo::CODE_TARGET); |
2776 OperandStackDepthDecrement(arg_count + 1); | 2739 OperandStackDepthDecrement(arg_count + 1); |
2777 RecordJSReturnSite(expr); | 2740 RecordJSReturnSite(expr); |
2778 // Restore context register. | 2741 // Restore context register. |
2779 __ LoadP(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); | 2742 __ LoadP(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); |
2780 context()->DropAndPlug(1, r3); | 2743 context()->DropAndPlug(1, r2); |
2781 } | 2744 } |
2782 | 2745 |
2783 | |
2784 void FullCodeGenerator::VisitCallNew(CallNew* expr) { | 2746 void FullCodeGenerator::VisitCallNew(CallNew* expr) { |
2785 Comment cmnt(masm_, "[ CallNew"); | 2747 Comment cmnt(masm_, "[ CallNew"); |
2786 // According to ECMA-262, section 11.2.2, page 44, the function | 2748 // According to ECMA-262, section 11.2.2, page 44, the function |
2787 // expression in new calls must be evaluated before the | 2749 // expression in new calls must be evaluated before the |
2788 // arguments. | 2750 // arguments. |
2789 | 2751 |
2790 // Push constructor on the stack. If it's not a function it's used as | 2752 // Push constructor on the stack. If it's not a function it's used as |
2791 // receiver for CALL_NON_FUNCTION, otherwise the value on the stack is | 2753 // receiver for CALL_NON_FUNCTION, otherwise the value on the stack is |
2792 // ignored. | 2754 // ignored. |
2793 DCHECK(!expr->expression()->IsSuperPropertyReference()); | 2755 DCHECK(!expr->expression()->IsSuperPropertyReference()); |
2794 VisitForStackValue(expr->expression()); | 2756 VisitForStackValue(expr->expression()); |
2795 | 2757 |
2796 // Push the arguments ("left-to-right") on the stack. | 2758 // Push the arguments ("left-to-right") on the stack. |
2797 ZoneList<Expression*>* args = expr->arguments(); | 2759 ZoneList<Expression*>* args = expr->arguments(); |
2798 int arg_count = args->length(); | 2760 int arg_count = args->length(); |
2799 for (int i = 0; i < arg_count; i++) { | 2761 for (int i = 0; i < arg_count; i++) { |
2800 VisitForStackValue(args->at(i)); | 2762 VisitForStackValue(args->at(i)); |
2801 } | 2763 } |
2802 | 2764 |
2803 // Call the construct call builtin that handles allocation and | 2765 // Call the construct call builtin that handles allocation and |
2804 // constructor invocation. | 2766 // constructor invocation. |
2805 SetConstructCallPosition(expr); | 2767 SetConstructCallPosition(expr); |
2806 | 2768 |
2807 // Load function and argument count into r4 and r3. | 2769 // Load function and argument count into r3 and r2. |
2808 __ mov(r3, Operand(arg_count)); | 2770 __ mov(r2, Operand(arg_count)); |
2809 __ LoadP(r4, MemOperand(sp, arg_count * kPointerSize), r0); | 2771 __ LoadP(r3, MemOperand(sp, arg_count * kPointerSize), r0); |
2810 | 2772 |
2811 // Record call targets in unoptimized code. | 2773 // Record call targets in unoptimized code. |
2812 __ EmitLoadTypeFeedbackVector(r5); | 2774 __ EmitLoadTypeFeedbackVector(r4); |
2813 __ LoadSmiLiteral(r6, SmiFromSlot(expr->CallNewFeedbackSlot())); | 2775 __ LoadSmiLiteral(r5, SmiFromSlot(expr->CallNewFeedbackSlot())); |
2814 | 2776 |
2815 CallConstructStub stub(isolate()); | 2777 CallConstructStub stub(isolate()); |
2816 __ Call(stub.GetCode(), RelocInfo::CODE_TARGET); | 2778 __ Call(stub.GetCode(), RelocInfo::CODE_TARGET); |
2817 OperandStackDepthDecrement(arg_count + 1); | 2779 OperandStackDepthDecrement(arg_count + 1); |
2818 PrepareForBailoutForId(expr->ReturnId(), TOS_REG); | 2780 PrepareForBailoutForId(expr->ReturnId(), TOS_REG); |
2819 // Restore context register. | 2781 // Restore context register. |
2820 __ LoadP(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); | 2782 __ LoadP(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); |
2821 context()->Plug(r3); | 2783 context()->Plug(r2); |
2822 } | 2784 } |
2823 | 2785 |
2824 | |
2825 void FullCodeGenerator::EmitSuperConstructorCall(Call* expr) { | 2786 void FullCodeGenerator::EmitSuperConstructorCall(Call* expr) { |
2826 SuperCallReference* super_call_ref = | 2787 SuperCallReference* super_call_ref = |
2827 expr->expression()->AsSuperCallReference(); | 2788 expr->expression()->AsSuperCallReference(); |
2828 DCHECK_NOT_NULL(super_call_ref); | 2789 DCHECK_NOT_NULL(super_call_ref); |
2829 | 2790 |
2830 // Push the super constructor target on the stack (may be null, | 2791 // Push the super constructor target on the stack (may be null, |
2831 // but the Construct builtin can deal with that properly). | 2792 // but the Construct builtin can deal with that properly). |
2832 VisitForAccumulatorValue(super_call_ref->this_function_var()); | 2793 VisitForAccumulatorValue(super_call_ref->this_function_var()); |
2833 __ AssertFunction(result_register()); | 2794 __ AssertFunction(result_register()); |
2834 __ LoadP(result_register(), | 2795 __ LoadP(result_register(), |
2835 FieldMemOperand(result_register(), HeapObject::kMapOffset)); | 2796 FieldMemOperand(result_register(), HeapObject::kMapOffset)); |
2836 __ LoadP(result_register(), | 2797 __ LoadP(result_register(), |
2837 FieldMemOperand(result_register(), Map::kPrototypeOffset)); | 2798 FieldMemOperand(result_register(), Map::kPrototypeOffset)); |
2838 PushOperand(result_register()); | 2799 PushOperand(result_register()); |
2839 | 2800 |
2840 // Push the arguments ("left-to-right") on the stack. | 2801 // Push the arguments ("left-to-right") on the stack. |
2841 ZoneList<Expression*>* args = expr->arguments(); | 2802 ZoneList<Expression*>* args = expr->arguments(); |
2842 int arg_count = args->length(); | 2803 int arg_count = args->length(); |
2843 for (int i = 0; i < arg_count; i++) { | 2804 for (int i = 0; i < arg_count; i++) { |
2844 VisitForStackValue(args->at(i)); | 2805 VisitForStackValue(args->at(i)); |
2845 } | 2806 } |
2846 | 2807 |
2847 // Call the construct call builtin that handles allocation and | 2808 // Call the construct call builtin that handles allocation and |
2848 // constructor invocation. | 2809 // constructor invocation. |
2849 SetConstructCallPosition(expr); | 2810 SetConstructCallPosition(expr); |
2850 | 2811 |
2851 // Load new target into r6. | 2812 // Load new target into r5. |
2852 VisitForAccumulatorValue(super_call_ref->new_target_var()); | 2813 VisitForAccumulatorValue(super_call_ref->new_target_var()); |
2853 __ mr(r6, result_register()); | 2814 __ LoadRR(r5, result_register()); |
2854 | 2815 |
2855 // Load function and argument count into r1 and r0. | 2816 // Load function and argument count into r1 and r0. |
2856 __ mov(r3, Operand(arg_count)); | 2817 __ mov(r2, Operand(arg_count)); |
2857 __ LoadP(r4, MemOperand(sp, arg_count * kPointerSize)); | 2818 __ LoadP(r3, MemOperand(sp, arg_count * kPointerSize)); |
2858 | 2819 |
2859 __ Call(isolate()->builtins()->Construct(), RelocInfo::CODE_TARGET); | 2820 __ Call(isolate()->builtins()->Construct(), RelocInfo::CODE_TARGET); |
2860 OperandStackDepthDecrement(arg_count + 1); | 2821 OperandStackDepthDecrement(arg_count + 1); |
2861 | 2822 |
2862 RecordJSReturnSite(expr); | 2823 RecordJSReturnSite(expr); |
2863 | 2824 |
2864 // Restore context register. | 2825 // Restore context register. |
2865 __ LoadP(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); | 2826 __ LoadP(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); |
2866 context()->Plug(r3); | 2827 context()->Plug(r2); |
2867 } | 2828 } |
2868 | 2829 |
2869 | |
2870 void FullCodeGenerator::EmitIsSmi(CallRuntime* expr) { | 2830 void FullCodeGenerator::EmitIsSmi(CallRuntime* expr) { |
2871 ZoneList<Expression*>* args = expr->arguments(); | 2831 ZoneList<Expression*>* args = expr->arguments(); |
2872 DCHECK(args->length() == 1); | 2832 DCHECK(args->length() == 1); |
2873 | 2833 |
2874 VisitForAccumulatorValue(args->at(0)); | 2834 VisitForAccumulatorValue(args->at(0)); |
2875 | 2835 |
2876 Label materialize_true, materialize_false; | 2836 Label materialize_true, materialize_false, skip_lookup; |
2877 Label* if_true = NULL; | 2837 Label* if_true = NULL; |
2878 Label* if_false = NULL; | 2838 Label* if_false = NULL; |
2879 Label* fall_through = NULL; | 2839 Label* fall_through = NULL; |
2880 context()->PrepareTest(&materialize_true, &materialize_false, &if_true, | 2840 context()->PrepareTest(&materialize_true, &materialize_false, &if_true, |
2881 &if_false, &fall_through); | 2841 &if_false, &fall_through); |
2882 | 2842 |
2883 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false); | 2843 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false); |
2884 __ TestIfSmi(r3, r0); | 2844 __ TestIfSmi(r2); |
2885 Split(eq, if_true, if_false, fall_through, cr0); | 2845 Split(eq, if_true, if_false, fall_through); |
2886 | 2846 |
2887 context()->Plug(if_true, if_false); | 2847 context()->Plug(if_true, if_false); |
2888 } | 2848 } |
2889 | 2849 |
2890 | |
2891 void FullCodeGenerator::EmitIsJSReceiver(CallRuntime* expr) { | 2850 void FullCodeGenerator::EmitIsJSReceiver(CallRuntime* expr) { |
2892 ZoneList<Expression*>* args = expr->arguments(); | 2851 ZoneList<Expression*>* args = expr->arguments(); |
2893 DCHECK(args->length() == 1); | 2852 DCHECK(args->length() == 1); |
2894 | 2853 |
2895 VisitForAccumulatorValue(args->at(0)); | 2854 VisitForAccumulatorValue(args->at(0)); |
2896 | 2855 |
2897 Label materialize_true, materialize_false; | 2856 Label materialize_true, materialize_false; |
2898 Label* if_true = NULL; | 2857 Label* if_true = NULL; |
2899 Label* if_false = NULL; | 2858 Label* if_false = NULL; |
2900 Label* fall_through = NULL; | 2859 Label* fall_through = NULL; |
2901 context()->PrepareTest(&materialize_true, &materialize_false, &if_true, | 2860 context()->PrepareTest(&materialize_true, &materialize_false, &if_true, |
2902 &if_false, &fall_through); | 2861 &if_false, &fall_through); |
2903 | 2862 |
2904 __ JumpIfSmi(r3, if_false); | 2863 __ JumpIfSmi(r2, if_false); |
2905 __ CompareObjectType(r3, r4, r4, FIRST_JS_RECEIVER_TYPE); | 2864 __ CompareObjectType(r2, r3, r3, FIRST_JS_RECEIVER_TYPE); |
2906 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false); | 2865 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false); |
2907 Split(ge, if_true, if_false, fall_through); | 2866 Split(ge, if_true, if_false, fall_through); |
2908 | 2867 |
2909 context()->Plug(if_true, if_false); | 2868 context()->Plug(if_true, if_false); |
2910 } | 2869 } |
2911 | 2870 |
2912 | |
2913 void FullCodeGenerator::EmitIsArray(CallRuntime* expr) { | 2871 void FullCodeGenerator::EmitIsArray(CallRuntime* expr) { |
2914 ZoneList<Expression*>* args = expr->arguments(); | 2872 ZoneList<Expression*>* args = expr->arguments(); |
2915 DCHECK(args->length() == 1); | 2873 DCHECK(args->length() == 1); |
2916 | 2874 |
2917 VisitForAccumulatorValue(args->at(0)); | 2875 VisitForAccumulatorValue(args->at(0)); |
2918 | 2876 |
2919 Label materialize_true, materialize_false; | 2877 Label materialize_true, materialize_false; |
2920 Label* if_true = NULL; | 2878 Label* if_true = NULL; |
2921 Label* if_false = NULL; | 2879 Label* if_false = NULL; |
2922 Label* fall_through = NULL; | 2880 Label* fall_through = NULL; |
2923 context()->PrepareTest(&materialize_true, &materialize_false, &if_true, | 2881 context()->PrepareTest(&materialize_true, &materialize_false, &if_true, |
2924 &if_false, &fall_through); | 2882 &if_false, &fall_through); |
2925 | 2883 |
2926 __ JumpIfSmi(r3, if_false); | 2884 __ JumpIfSmi(r2, if_false); |
2927 __ CompareObjectType(r3, r4, r4, JS_ARRAY_TYPE); | 2885 __ CompareObjectType(r2, r3, r3, JS_ARRAY_TYPE); |
2928 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false); | 2886 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false); |
2929 Split(eq, if_true, if_false, fall_through); | 2887 Split(eq, if_true, if_false, fall_through); |
2930 | 2888 |
2931 context()->Plug(if_true, if_false); | 2889 context()->Plug(if_true, if_false); |
2932 } | 2890 } |
2933 | 2891 |
2934 | |
2935 void FullCodeGenerator::EmitIsTypedArray(CallRuntime* expr) { | 2892 void FullCodeGenerator::EmitIsTypedArray(CallRuntime* expr) { |
2936 ZoneList<Expression*>* args = expr->arguments(); | 2893 ZoneList<Expression*>* args = expr->arguments(); |
2937 DCHECK(args->length() == 1); | 2894 DCHECK(args->length() == 1); |
2938 | 2895 |
2939 VisitForAccumulatorValue(args->at(0)); | 2896 VisitForAccumulatorValue(args->at(0)); |
2940 | 2897 |
2941 Label materialize_true, materialize_false; | 2898 Label materialize_true, materialize_false; |
2942 Label* if_true = NULL; | 2899 Label* if_true = NULL; |
2943 Label* if_false = NULL; | 2900 Label* if_false = NULL; |
2944 Label* fall_through = NULL; | 2901 Label* fall_through = NULL; |
2945 context()->PrepareTest(&materialize_true, &materialize_false, &if_true, | 2902 context()->PrepareTest(&materialize_true, &materialize_false, &if_true, |
2946 &if_false, &fall_through); | 2903 &if_false, &fall_through); |
2947 | 2904 |
2948 __ JumpIfSmi(r3, if_false); | 2905 __ JumpIfSmi(r2, if_false); |
2949 __ CompareObjectType(r3, r4, r4, JS_TYPED_ARRAY_TYPE); | 2906 __ CompareObjectType(r2, r3, r3, JS_TYPED_ARRAY_TYPE); |
2950 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false); | 2907 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false); |
2951 Split(eq, if_true, if_false, fall_through); | 2908 Split(eq, if_true, if_false, fall_through); |
2952 | 2909 |
2953 context()->Plug(if_true, if_false); | 2910 context()->Plug(if_true, if_false); |
2954 } | 2911 } |
2955 | 2912 |
2956 | |
2957 void FullCodeGenerator::EmitIsRegExp(CallRuntime* expr) { | 2913 void FullCodeGenerator::EmitIsRegExp(CallRuntime* expr) { |
2958 ZoneList<Expression*>* args = expr->arguments(); | 2914 ZoneList<Expression*>* args = expr->arguments(); |
2959 DCHECK(args->length() == 1); | 2915 DCHECK(args->length() == 1); |
2960 | 2916 |
2961 VisitForAccumulatorValue(args->at(0)); | 2917 VisitForAccumulatorValue(args->at(0)); |
2962 | 2918 |
2963 Label materialize_true, materialize_false; | 2919 Label materialize_true, materialize_false; |
2964 Label* if_true = NULL; | 2920 Label* if_true = NULL; |
2965 Label* if_false = NULL; | 2921 Label* if_false = NULL; |
2966 Label* fall_through = NULL; | 2922 Label* fall_through = NULL; |
2967 context()->PrepareTest(&materialize_true, &materialize_false, &if_true, | 2923 context()->PrepareTest(&materialize_true, &materialize_false, &if_true, |
2968 &if_false, &fall_through); | 2924 &if_false, &fall_through); |
2969 | 2925 |
2970 __ JumpIfSmi(r3, if_false); | 2926 __ JumpIfSmi(r2, if_false); |
2971 __ CompareObjectType(r3, r4, r4, JS_REGEXP_TYPE); | 2927 __ CompareObjectType(r2, r3, r3, JS_REGEXP_TYPE); |
2972 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false); | 2928 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false); |
2973 Split(eq, if_true, if_false, fall_through); | 2929 Split(eq, if_true, if_false, fall_through); |
2974 | 2930 |
2975 context()->Plug(if_true, if_false); | 2931 context()->Plug(if_true, if_false); |
2976 } | 2932 } |
2977 | 2933 |
2978 | |
2979 void FullCodeGenerator::EmitIsJSProxy(CallRuntime* expr) { | 2934 void FullCodeGenerator::EmitIsJSProxy(CallRuntime* expr) { |
2980 ZoneList<Expression*>* args = expr->arguments(); | 2935 ZoneList<Expression*>* args = expr->arguments(); |
2981 DCHECK(args->length() == 1); | 2936 DCHECK(args->length() == 1); |
2982 | 2937 |
2983 VisitForAccumulatorValue(args->at(0)); | 2938 VisitForAccumulatorValue(args->at(0)); |
2984 | 2939 |
2985 Label materialize_true, materialize_false; | 2940 Label materialize_true, materialize_false; |
2986 Label* if_true = NULL; | 2941 Label* if_true = NULL; |
2987 Label* if_false = NULL; | 2942 Label* if_false = NULL; |
2988 Label* fall_through = NULL; | 2943 Label* fall_through = NULL; |
2989 context()->PrepareTest(&materialize_true, &materialize_false, &if_true, | 2944 context()->PrepareTest(&materialize_true, &materialize_false, &if_true, |
2990 &if_false, &fall_through); | 2945 &if_false, &fall_through); |
2991 | 2946 |
2992 __ JumpIfSmi(r3, if_false); | 2947 __ JumpIfSmi(r2, if_false); |
2993 __ CompareObjectType(r3, r4, r4, JS_PROXY_TYPE); | 2948 __ CompareObjectType(r2, r3, r3, JS_PROXY_TYPE); |
2994 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false); | 2949 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false); |
2995 Split(eq, if_true, if_false, fall_through); | 2950 Split(eq, if_true, if_false, fall_through); |
2996 | 2951 |
2997 context()->Plug(if_true, if_false); | 2952 context()->Plug(if_true, if_false); |
2998 } | 2953 } |
2999 | 2954 |
3000 | |
3001 void FullCodeGenerator::EmitClassOf(CallRuntime* expr) { | 2955 void FullCodeGenerator::EmitClassOf(CallRuntime* expr) { |
3002 ZoneList<Expression*>* args = expr->arguments(); | 2956 ZoneList<Expression*>* args = expr->arguments(); |
3003 DCHECK(args->length() == 1); | 2957 DCHECK(args->length() == 1); |
3004 Label done, null, function, non_function_constructor; | 2958 Label done, null, function, non_function_constructor; |
3005 | 2959 |
3006 VisitForAccumulatorValue(args->at(0)); | 2960 VisitForAccumulatorValue(args->at(0)); |
3007 | 2961 |
3008 // If the object is not a JSReceiver, we return null. | 2962 // If the object is not a JSReceiver, we return null. |
3009 __ JumpIfSmi(r3, &null); | 2963 __ JumpIfSmi(r2, &null); |
3010 STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE); | 2964 STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE); |
3011 __ CompareObjectType(r3, r3, r4, FIRST_JS_RECEIVER_TYPE); | 2965 __ CompareObjectType(r2, r2, r3, FIRST_JS_RECEIVER_TYPE); |
3012 // Map is now in r3. | 2966 // Map is now in r2. |
3013 __ blt(&null); | 2967 __ blt(&null); |
3014 | 2968 |
3015 // Return 'Function' for JSFunction objects. | 2969 // Return 'Function' for JSFunction objects. |
3016 __ cmpi(r4, Operand(JS_FUNCTION_TYPE)); | 2970 __ CmpP(r3, Operand(JS_FUNCTION_TYPE)); |
3017 __ beq(&function); | 2971 __ beq(&function); |
3018 | 2972 |
3019 // Check if the constructor in the map is a JS function. | 2973 // Check if the constructor in the map is a JS function. |
3020 Register instance_type = r5; | 2974 Register instance_type = r4; |
3021 __ GetMapConstructor(r3, r3, r4, instance_type); | 2975 __ GetMapConstructor(r2, r2, r3, instance_type); |
3022 __ cmpi(instance_type, Operand(JS_FUNCTION_TYPE)); | 2976 __ CmpP(instance_type, Operand(JS_FUNCTION_TYPE)); |
3023 __ bne(&non_function_constructor); | 2977 __ bne(&non_function_constructor, Label::kNear); |
3024 | 2978 |
3025 // r3 now contains the constructor function. Grab the | 2979 // r2 now contains the constructor function. Grab the |
3026 // instance class name from there. | 2980 // instance class name from there. |
3027 __ LoadP(r3, FieldMemOperand(r3, JSFunction::kSharedFunctionInfoOffset)); | 2981 __ LoadP(r2, FieldMemOperand(r2, JSFunction::kSharedFunctionInfoOffset)); |
3028 __ LoadP(r3, | 2982 __ LoadP(r2, |
3029 FieldMemOperand(r3, SharedFunctionInfo::kInstanceClassNameOffset)); | 2983 FieldMemOperand(r2, SharedFunctionInfo::kInstanceClassNameOffset)); |
3030 __ b(&done); | 2984 __ b(&done, Label::kNear); |
3031 | 2985 |
3032 // Functions have class 'Function'. | 2986 // Functions have class 'Function'. |
3033 __ bind(&function); | 2987 __ bind(&function); |
3034 __ LoadRoot(r3, Heap::kFunction_stringRootIndex); | 2988 __ LoadRoot(r2, Heap::kFunction_stringRootIndex); |
3035 __ b(&done); | 2989 __ b(&done, Label::kNear); |
3036 | 2990 |
3037 // Objects with a non-function constructor have class 'Object'. | 2991 // Objects with a non-function constructor have class 'Object'. |
3038 __ bind(&non_function_constructor); | 2992 __ bind(&non_function_constructor); |
3039 __ LoadRoot(r3, Heap::kObject_stringRootIndex); | 2993 __ LoadRoot(r2, Heap::kObject_stringRootIndex); |
3040 __ b(&done); | 2994 __ b(&done, Label::kNear); |
3041 | 2995 |
3042 // Non-JS objects have class null. | 2996 // Non-JS objects have class null. |
3043 __ bind(&null); | 2997 __ bind(&null); |
3044 __ LoadRoot(r3, Heap::kNullValueRootIndex); | 2998 __ LoadRoot(r2, Heap::kNullValueRootIndex); |
3045 | 2999 |
3046 // All done. | 3000 // All done. |
3047 __ bind(&done); | 3001 __ bind(&done); |
3048 | 3002 |
3049 context()->Plug(r3); | 3003 context()->Plug(r2); |
3050 } | 3004 } |
3051 | 3005 |
3052 | |
3053 void FullCodeGenerator::EmitValueOf(CallRuntime* expr) { | 3006 void FullCodeGenerator::EmitValueOf(CallRuntime* expr) { |
3054 ZoneList<Expression*>* args = expr->arguments(); | 3007 ZoneList<Expression*>* args = expr->arguments(); |
3055 DCHECK(args->length() == 1); | 3008 DCHECK(args->length() == 1); |
3056 VisitForAccumulatorValue(args->at(0)); // Load the object. | 3009 VisitForAccumulatorValue(args->at(0)); // Load the object. |
3057 | 3010 |
3058 Label done; | 3011 Label done; |
3059 // If the object is a smi return the object. | 3012 // If the object is a smi return the object. |
3060 __ JumpIfSmi(r3, &done); | 3013 __ JumpIfSmi(r2, &done); |
3061 // If the object is not a value type, return the object. | 3014 // If the object is not a value type, return the object. |
3062 __ CompareObjectType(r3, r4, r4, JS_VALUE_TYPE); | 3015 __ CompareObjectType(r2, r3, r3, JS_VALUE_TYPE); |
3063 __ bne(&done); | 3016 __ bne(&done, Label::kNear); |
3064 __ LoadP(r3, FieldMemOperand(r3, JSValue::kValueOffset)); | 3017 __ LoadP(r2, FieldMemOperand(r2, JSValue::kValueOffset)); |
3065 | 3018 |
3066 __ bind(&done); | 3019 __ bind(&done); |
3067 context()->Plug(r3); | 3020 context()->Plug(r2); |
3068 } | 3021 } |
3069 | 3022 |
3070 | |
3071 void FullCodeGenerator::EmitOneByteSeqStringSetChar(CallRuntime* expr) { | 3023 void FullCodeGenerator::EmitOneByteSeqStringSetChar(CallRuntime* expr) { |
3072 ZoneList<Expression*>* args = expr->arguments(); | 3024 ZoneList<Expression*>* args = expr->arguments(); |
3073 DCHECK_EQ(3, args->length()); | 3025 DCHECK_EQ(3, args->length()); |
3074 | 3026 |
3075 Register string = r3; | 3027 Register string = r2; |
3076 Register index = r4; | 3028 Register index = r3; |
3077 Register value = r5; | 3029 Register value = r4; |
3078 | 3030 |
3079 VisitForStackValue(args->at(0)); // index | 3031 VisitForStackValue(args->at(0)); // index |
3080 VisitForStackValue(args->at(1)); // value | 3032 VisitForStackValue(args->at(1)); // value |
3081 VisitForAccumulatorValue(args->at(2)); // string | 3033 VisitForAccumulatorValue(args->at(2)); // string |
3082 PopOperands(index, value); | 3034 PopOperands(index, value); |
3083 | 3035 |
3084 if (FLAG_debug_code) { | 3036 if (FLAG_debug_code) { |
3085 __ TestIfSmi(value, r0); | 3037 __ TestIfSmi(value); |
3086 __ Check(eq, kNonSmiValue, cr0); | 3038 __ Check(eq, kNonSmiValue, cr0); |
3087 __ TestIfSmi(index, r0); | 3039 __ TestIfSmi(index); |
3088 __ Check(eq, kNonSmiIndex, cr0); | 3040 __ Check(eq, kNonSmiIndex, cr0); |
3089 __ SmiUntag(index, index); | 3041 __ SmiUntag(index); |
3090 static const uint32_t one_byte_seq_type = kSeqStringTag | kOneByteStringTag; | 3042 static const uint32_t one_byte_seq_type = kSeqStringTag | kOneByteStringTag; |
3091 __ EmitSeqStringSetCharCheck(string, index, value, one_byte_seq_type); | 3043 __ EmitSeqStringSetCharCheck(string, index, value, one_byte_seq_type); |
3092 __ SmiTag(index, index); | 3044 __ SmiTag(index); |
3093 } | 3045 } |
3094 | 3046 |
3095 __ SmiUntag(value); | 3047 __ SmiUntag(value); |
3096 __ addi(ip, string, Operand(SeqOneByteString::kHeaderSize - kHeapObjectTag)); | 3048 __ AddP(ip, string, Operand(SeqOneByteString::kHeaderSize - kHeapObjectTag)); |
3097 __ SmiToByteArrayOffset(r0, index); | 3049 __ SmiToByteArrayOffset(r1, index); |
3098 __ stbx(value, MemOperand(ip, r0)); | 3050 __ StoreByte(value, MemOperand(ip, r1)); |
3099 context()->Plug(string); | 3051 context()->Plug(string); |
3100 } | 3052 } |
3101 | 3053 |
3102 | |
3103 void FullCodeGenerator::EmitTwoByteSeqStringSetChar(CallRuntime* expr) { | 3054 void FullCodeGenerator::EmitTwoByteSeqStringSetChar(CallRuntime* expr) { |
3104 ZoneList<Expression*>* args = expr->arguments(); | 3055 ZoneList<Expression*>* args = expr->arguments(); |
3105 DCHECK_EQ(3, args->length()); | 3056 DCHECK_EQ(3, args->length()); |
3106 | 3057 |
3107 Register string = r3; | 3058 Register string = r2; |
3108 Register index = r4; | 3059 Register index = r3; |
3109 Register value = r5; | 3060 Register value = r4; |
3110 | 3061 |
3111 VisitForStackValue(args->at(0)); // index | 3062 VisitForStackValue(args->at(0)); // index |
3112 VisitForStackValue(args->at(1)); // value | 3063 VisitForStackValue(args->at(1)); // value |
3113 VisitForAccumulatorValue(args->at(2)); // string | 3064 VisitForAccumulatorValue(args->at(2)); // string |
3114 PopOperands(index, value); | 3065 PopOperands(index, value); |
3115 | 3066 |
3116 if (FLAG_debug_code) { | 3067 if (FLAG_debug_code) { |
3117 __ TestIfSmi(value, r0); | 3068 __ TestIfSmi(value); |
3118 __ Check(eq, kNonSmiValue, cr0); | 3069 __ Check(eq, kNonSmiValue, cr0); |
3119 __ TestIfSmi(index, r0); | 3070 __ TestIfSmi(index); |
3120 __ Check(eq, kNonSmiIndex, cr0); | 3071 __ Check(eq, kNonSmiIndex, cr0); |
3121 __ SmiUntag(index, index); | 3072 __ SmiUntag(index, index); |
3122 static const uint32_t two_byte_seq_type = kSeqStringTag | kTwoByteStringTag; | 3073 static const uint32_t two_byte_seq_type = kSeqStringTag | kTwoByteStringTag; |
3123 __ EmitSeqStringSetCharCheck(string, index, value, two_byte_seq_type); | 3074 __ EmitSeqStringSetCharCheck(string, index, value, two_byte_seq_type); |
3124 __ SmiTag(index, index); | 3075 __ SmiTag(index, index); |
3125 } | 3076 } |
3126 | 3077 |
3127 __ SmiUntag(value); | 3078 __ SmiUntag(value); |
3128 __ addi(ip, string, Operand(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); | 3079 __ SmiToShortArrayOffset(r1, index); |
3129 __ SmiToShortArrayOffset(r0, index); | 3080 __ StoreHalfWord(value, MemOperand(r1, string, SeqTwoByteString::kHeaderSize - |
3130 __ sthx(value, MemOperand(ip, r0)); | 3081 kHeapObjectTag)); |
3131 context()->Plug(string); | 3082 context()->Plug(string); |
3132 } | 3083 } |
3133 | 3084 |
3134 | |
3135 void FullCodeGenerator::EmitToInteger(CallRuntime* expr) { | 3085 void FullCodeGenerator::EmitToInteger(CallRuntime* expr) { |
3136 ZoneList<Expression*>* args = expr->arguments(); | 3086 ZoneList<Expression*>* args = expr->arguments(); |
3137 DCHECK_EQ(1, args->length()); | 3087 DCHECK_EQ(1, args->length()); |
3138 | 3088 |
3139 // Load the argument into r3 and convert it. | 3089 // Load the argument into r2 and convert it. |
3140 VisitForAccumulatorValue(args->at(0)); | 3090 VisitForAccumulatorValue(args->at(0)); |
3141 | 3091 |
3142 // Convert the object to an integer. | 3092 // Convert the object to an integer. |
3143 Label done_convert; | 3093 Label done_convert; |
3144 __ JumpIfSmi(r3, &done_convert); | 3094 __ JumpIfSmi(r2, &done_convert); |
3145 __ Push(r3); | 3095 __ Push(r2); |
3146 __ CallRuntime(Runtime::kToInteger); | 3096 __ CallRuntime(Runtime::kToInteger); |
3147 __ bind(&done_convert); | 3097 __ bind(&done_convert); |
3148 context()->Plug(r3); | 3098 context()->Plug(r2); |
3149 } | 3099 } |
3150 | 3100 |
3151 | |
3152 void FullCodeGenerator::EmitStringCharFromCode(CallRuntime* expr) { | 3101 void FullCodeGenerator::EmitStringCharFromCode(CallRuntime* expr) { |
3153 ZoneList<Expression*>* args = expr->arguments(); | 3102 ZoneList<Expression*>* args = expr->arguments(); |
3154 DCHECK(args->length() == 1); | 3103 DCHECK(args->length() == 1); |
3155 VisitForAccumulatorValue(args->at(0)); | 3104 VisitForAccumulatorValue(args->at(0)); |
3156 | 3105 |
3157 Label done; | 3106 Label done; |
3158 StringCharFromCodeGenerator generator(r3, r4); | 3107 StringCharFromCodeGenerator generator(r2, r3); |
3159 generator.GenerateFast(masm_); | 3108 generator.GenerateFast(masm_); |
3160 __ b(&done); | 3109 __ b(&done); |
3161 | 3110 |
3162 NopRuntimeCallHelper call_helper; | 3111 NopRuntimeCallHelper call_helper; |
3163 generator.GenerateSlow(masm_, call_helper); | 3112 generator.GenerateSlow(masm_, call_helper); |
3164 | 3113 |
3165 __ bind(&done); | 3114 __ bind(&done); |
3166 context()->Plug(r4); | 3115 context()->Plug(r3); |
3167 } | 3116 } |
3168 | 3117 |
3169 | |
3170 void FullCodeGenerator::EmitStringCharCodeAt(CallRuntime* expr) { | 3118 void FullCodeGenerator::EmitStringCharCodeAt(CallRuntime* expr) { |
3171 ZoneList<Expression*>* args = expr->arguments(); | 3119 ZoneList<Expression*>* args = expr->arguments(); |
3172 DCHECK(args->length() == 2); | 3120 DCHECK(args->length() == 2); |
3173 VisitForStackValue(args->at(0)); | 3121 VisitForStackValue(args->at(0)); |
3174 VisitForAccumulatorValue(args->at(1)); | 3122 VisitForAccumulatorValue(args->at(1)); |
3175 | 3123 |
3176 Register object = r4; | 3124 Register object = r3; |
3177 Register index = r3; | 3125 Register index = r2; |
3178 Register result = r6; | 3126 Register result = r5; |
3179 | 3127 |
3180 PopOperand(object); | 3128 PopOperand(object); |
3181 | 3129 |
3182 Label need_conversion; | 3130 Label need_conversion; |
3183 Label index_out_of_range; | 3131 Label index_out_of_range; |
3184 Label done; | 3132 Label done; |
3185 StringCharCodeAtGenerator generator(object, index, result, &need_conversion, | 3133 StringCharCodeAtGenerator generator(object, index, result, &need_conversion, |
3186 &need_conversion, &index_out_of_range, | 3134 &need_conversion, &index_out_of_range, |
3187 STRING_INDEX_IS_NUMBER); | 3135 STRING_INDEX_IS_NUMBER); |
3188 generator.GenerateFast(masm_); | 3136 generator.GenerateFast(masm_); |
(...skipping 11 matching lines...) Expand all Loading... |
3200 __ LoadRoot(result, Heap::kUndefinedValueRootIndex); | 3148 __ LoadRoot(result, Heap::kUndefinedValueRootIndex); |
3201 __ b(&done); | 3149 __ b(&done); |
3202 | 3150 |
3203 NopRuntimeCallHelper call_helper; | 3151 NopRuntimeCallHelper call_helper; |
3204 generator.GenerateSlow(masm_, NOT_PART_OF_IC_HANDLER, call_helper); | 3152 generator.GenerateSlow(masm_, NOT_PART_OF_IC_HANDLER, call_helper); |
3205 | 3153 |
3206 __ bind(&done); | 3154 __ bind(&done); |
3207 context()->Plug(result); | 3155 context()->Plug(result); |
3208 } | 3156 } |
3209 | 3157 |
3210 | |
3211 void FullCodeGenerator::EmitStringCharAt(CallRuntime* expr) { | 3158 void FullCodeGenerator::EmitStringCharAt(CallRuntime* expr) { |
3212 ZoneList<Expression*>* args = expr->arguments(); | 3159 ZoneList<Expression*>* args = expr->arguments(); |
3213 DCHECK(args->length() == 2); | 3160 DCHECK(args->length() == 2); |
3214 VisitForStackValue(args->at(0)); | 3161 VisitForStackValue(args->at(0)); |
3215 VisitForAccumulatorValue(args->at(1)); | 3162 VisitForAccumulatorValue(args->at(1)); |
3216 | 3163 |
3217 Register object = r4; | 3164 Register object = r3; |
3218 Register index = r3; | 3165 Register index = r2; |
3219 Register scratch = r6; | 3166 Register scratch = r5; |
3220 Register result = r3; | 3167 Register result = r2; |
3221 | 3168 |
3222 PopOperand(object); | 3169 PopOperand(object); |
3223 | 3170 |
3224 Label need_conversion; | 3171 Label need_conversion; |
3225 Label index_out_of_range; | 3172 Label index_out_of_range; |
3226 Label done; | 3173 Label done; |
3227 StringCharAtGenerator generator(object, index, scratch, result, | 3174 StringCharAtGenerator generator(object, index, scratch, result, |
3228 &need_conversion, &need_conversion, | 3175 &need_conversion, &need_conversion, |
3229 &index_out_of_range, STRING_INDEX_IS_NUMBER); | 3176 &index_out_of_range, STRING_INDEX_IS_NUMBER); |
3230 generator.GenerateFast(masm_); | 3177 generator.GenerateFast(masm_); |
(...skipping 11 matching lines...) Expand all Loading... |
3242 __ LoadSmiLiteral(result, Smi::FromInt(0)); | 3189 __ LoadSmiLiteral(result, Smi::FromInt(0)); |
3243 __ b(&done); | 3190 __ b(&done); |
3244 | 3191 |
3245 NopRuntimeCallHelper call_helper; | 3192 NopRuntimeCallHelper call_helper; |
3246 generator.GenerateSlow(masm_, NOT_PART_OF_IC_HANDLER, call_helper); | 3193 generator.GenerateSlow(masm_, NOT_PART_OF_IC_HANDLER, call_helper); |
3247 | 3194 |
3248 __ bind(&done); | 3195 __ bind(&done); |
3249 context()->Plug(result); | 3196 context()->Plug(result); |
3250 } | 3197 } |
3251 | 3198 |
3252 | |
3253 void FullCodeGenerator::EmitCall(CallRuntime* expr) { | 3199 void FullCodeGenerator::EmitCall(CallRuntime* expr) { |
3254 ZoneList<Expression*>* args = expr->arguments(); | 3200 ZoneList<Expression*>* args = expr->arguments(); |
3255 DCHECK_LE(2, args->length()); | 3201 DCHECK_LE(2, args->length()); |
3256 // Push target, receiver and arguments onto the stack. | 3202 // Push target, receiver and arguments onto the stack. |
3257 for (Expression* const arg : *args) { | 3203 for (Expression* const arg : *args) { |
3258 VisitForStackValue(arg); | 3204 VisitForStackValue(arg); |
3259 } | 3205 } |
3260 PrepareForBailoutForId(expr->CallId(), NO_REGISTERS); | 3206 PrepareForBailoutForId(expr->CallId(), NO_REGISTERS); |
3261 // Move target to r4. | 3207 // Move target to r3. |
3262 int const argc = args->length() - 2; | 3208 int const argc = args->length() - 2; |
3263 __ LoadP(r4, MemOperand(sp, (argc + 1) * kPointerSize)); | 3209 __ LoadP(r3, MemOperand(sp, (argc + 1) * kPointerSize)); |
3264 // Call the target. | 3210 // Call the target. |
3265 __ mov(r3, Operand(argc)); | 3211 __ mov(r2, Operand(argc)); |
3266 __ Call(isolate()->builtins()->Call(), RelocInfo::CODE_TARGET); | 3212 __ Call(isolate()->builtins()->Call(), RelocInfo::CODE_TARGET); |
3267 OperandStackDepthDecrement(argc + 1); | 3213 OperandStackDepthDecrement(argc + 1); |
3268 // Restore context register. | 3214 // Restore context register. |
3269 __ LoadP(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); | 3215 __ LoadP(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); |
3270 // Discard the function left on TOS. | 3216 // Discard the function left on TOS. |
3271 context()->DropAndPlug(1, r3); | 3217 context()->DropAndPlug(1, r2); |
3272 } | 3218 } |
3273 | 3219 |
3274 | |
3275 void FullCodeGenerator::EmitHasCachedArrayIndex(CallRuntime* expr) { | 3220 void FullCodeGenerator::EmitHasCachedArrayIndex(CallRuntime* expr) { |
3276 ZoneList<Expression*>* args = expr->arguments(); | 3221 ZoneList<Expression*>* args = expr->arguments(); |
3277 VisitForAccumulatorValue(args->at(0)); | 3222 VisitForAccumulatorValue(args->at(0)); |
3278 | 3223 |
3279 Label materialize_true, materialize_false; | 3224 Label materialize_true, materialize_false; |
3280 Label* if_true = NULL; | 3225 Label* if_true = NULL; |
3281 Label* if_false = NULL; | 3226 Label* if_false = NULL; |
3282 Label* fall_through = NULL; | 3227 Label* fall_through = NULL; |
3283 context()->PrepareTest(&materialize_true, &materialize_false, &if_true, | 3228 context()->PrepareTest(&materialize_true, &materialize_false, &if_true, |
3284 &if_false, &fall_through); | 3229 &if_false, &fall_through); |
3285 | 3230 |
3286 __ lwz(r3, FieldMemOperand(r3, String::kHashFieldOffset)); | 3231 __ LoadlW(r2, FieldMemOperand(r2, String::kHashFieldOffset)); |
3287 // PPC - assume ip is free | 3232 __ AndP(r0, r2, Operand(String::kContainsCachedArrayIndexMask)); |
3288 __ mov(ip, Operand(String::kContainsCachedArrayIndexMask)); | |
3289 __ and_(r0, r3, ip, SetRC); | |
3290 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false); | 3233 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false); |
3291 Split(eq, if_true, if_false, fall_through, cr0); | 3234 Split(eq, if_true, if_false, fall_through); |
3292 | 3235 |
3293 context()->Plug(if_true, if_false); | 3236 context()->Plug(if_true, if_false); |
3294 } | 3237 } |
3295 | 3238 |
3296 | |
3297 void FullCodeGenerator::EmitGetCachedArrayIndex(CallRuntime* expr) { | 3239 void FullCodeGenerator::EmitGetCachedArrayIndex(CallRuntime* expr) { |
3298 ZoneList<Expression*>* args = expr->arguments(); | 3240 ZoneList<Expression*>* args = expr->arguments(); |
3299 DCHECK(args->length() == 1); | 3241 DCHECK(args->length() == 1); |
3300 VisitForAccumulatorValue(args->at(0)); | 3242 VisitForAccumulatorValue(args->at(0)); |
3301 | 3243 |
3302 __ AssertString(r3); | 3244 __ AssertString(r2); |
3303 | 3245 |
3304 __ lwz(r3, FieldMemOperand(r3, String::kHashFieldOffset)); | 3246 __ LoadlW(r2, FieldMemOperand(r2, String::kHashFieldOffset)); |
3305 __ IndexFromHash(r3, r3); | 3247 __ IndexFromHash(r2, r2); |
3306 | 3248 |
3307 context()->Plug(r3); | 3249 context()->Plug(r2); |
3308 } | 3250 } |
3309 | 3251 |
3310 | |
3311 void FullCodeGenerator::EmitGetSuperConstructor(CallRuntime* expr) { | 3252 void FullCodeGenerator::EmitGetSuperConstructor(CallRuntime* expr) { |
3312 ZoneList<Expression*>* args = expr->arguments(); | 3253 ZoneList<Expression*>* args = expr->arguments(); |
3313 DCHECK_EQ(1, args->length()); | 3254 DCHECK_EQ(1, args->length()); |
3314 VisitForAccumulatorValue(args->at(0)); | 3255 VisitForAccumulatorValue(args->at(0)); |
3315 __ AssertFunction(r3); | 3256 __ AssertFunction(r2); |
3316 __ LoadP(r3, FieldMemOperand(r3, HeapObject::kMapOffset)); | 3257 __ LoadP(r2, FieldMemOperand(r2, HeapObject::kMapOffset)); |
3317 __ LoadP(r3, FieldMemOperand(r3, Map::kPrototypeOffset)); | 3258 __ LoadP(r2, FieldMemOperand(r2, Map::kPrototypeOffset)); |
3318 context()->Plug(r3); | 3259 context()->Plug(r2); |
3319 } | 3260 } |
3320 | 3261 |
3321 | |
3322 void FullCodeGenerator::EmitDebugIsActive(CallRuntime* expr) { | 3262 void FullCodeGenerator::EmitDebugIsActive(CallRuntime* expr) { |
3323 DCHECK(expr->arguments()->length() == 0); | 3263 DCHECK(expr->arguments()->length() == 0); |
3324 ExternalReference debug_is_active = | 3264 ExternalReference debug_is_active = |
3325 ExternalReference::debug_is_active_address(isolate()); | 3265 ExternalReference::debug_is_active_address(isolate()); |
3326 __ mov(ip, Operand(debug_is_active)); | 3266 __ mov(ip, Operand(debug_is_active)); |
3327 __ lbz(r3, MemOperand(ip)); | 3267 __ LoadlB(r2, MemOperand(ip)); |
3328 __ SmiTag(r3); | 3268 __ SmiTag(r2); |
3329 context()->Plug(r3); | 3269 context()->Plug(r2); |
3330 } | 3270 } |
3331 | 3271 |
3332 | |
3333 void FullCodeGenerator::EmitCreateIterResultObject(CallRuntime* expr) { | 3272 void FullCodeGenerator::EmitCreateIterResultObject(CallRuntime* expr) { |
3334 ZoneList<Expression*>* args = expr->arguments(); | 3273 ZoneList<Expression*>* args = expr->arguments(); |
3335 DCHECK_EQ(2, args->length()); | 3274 DCHECK_EQ(2, args->length()); |
3336 VisitForStackValue(args->at(0)); | 3275 VisitForStackValue(args->at(0)); |
3337 VisitForStackValue(args->at(1)); | 3276 VisitForStackValue(args->at(1)); |
3338 | 3277 |
3339 Label runtime, done; | 3278 Label runtime, done; |
3340 | 3279 |
3341 __ Allocate(JSIteratorResult::kSize, r3, r5, r6, &runtime, TAG_OBJECT); | 3280 __ Allocate(JSIteratorResult::kSize, r2, r4, r5, &runtime, TAG_OBJECT); |
3342 __ LoadNativeContextSlot(Context::ITERATOR_RESULT_MAP_INDEX, r4); | 3281 __ LoadNativeContextSlot(Context::ITERATOR_RESULT_MAP_INDEX, r3); |
3343 __ Pop(r5, r6); | 3282 __ Pop(r4, r5); |
3344 __ LoadRoot(r7, Heap::kEmptyFixedArrayRootIndex); | 3283 __ LoadRoot(r6, Heap::kEmptyFixedArrayRootIndex); |
3345 __ StoreP(r4, FieldMemOperand(r3, HeapObject::kMapOffset), r0); | 3284 __ StoreP(r3, FieldMemOperand(r2, HeapObject::kMapOffset), r0); |
3346 __ StoreP(r7, FieldMemOperand(r3, JSObject::kPropertiesOffset), r0); | 3285 __ StoreP(r6, FieldMemOperand(r2, JSObject::kPropertiesOffset), r0); |
3347 __ StoreP(r7, FieldMemOperand(r3, JSObject::kElementsOffset), r0); | 3286 __ StoreP(r6, FieldMemOperand(r2, JSObject::kElementsOffset), r0); |
3348 __ StoreP(r5, FieldMemOperand(r3, JSIteratorResult::kValueOffset), r0); | 3287 __ StoreP(r4, FieldMemOperand(r2, JSIteratorResult::kValueOffset), r0); |
3349 __ StoreP(r6, FieldMemOperand(r3, JSIteratorResult::kDoneOffset), r0); | 3288 __ StoreP(r5, FieldMemOperand(r2, JSIteratorResult::kDoneOffset), r0); |
3350 STATIC_ASSERT(JSIteratorResult::kSize == 5 * kPointerSize); | 3289 STATIC_ASSERT(JSIteratorResult::kSize == 5 * kPointerSize); |
3351 __ b(&done); | 3290 __ b(&done); |
3352 | 3291 |
3353 __ bind(&runtime); | 3292 __ bind(&runtime); |
3354 CallRuntimeWithOperands(Runtime::kCreateIterResultObject); | 3293 CallRuntimeWithOperands(Runtime::kCreateIterResultObject); |
3355 | 3294 |
3356 __ bind(&done); | 3295 __ bind(&done); |
3357 context()->Plug(r3); | 3296 context()->Plug(r2); |
3358 } | 3297 } |
3359 | 3298 |
3360 | |
3361 void FullCodeGenerator::EmitLoadJSRuntimeFunction(CallRuntime* expr) { | 3299 void FullCodeGenerator::EmitLoadJSRuntimeFunction(CallRuntime* expr) { |
3362 // Push undefined as the receiver. | 3300 // Push undefined as the receiver. |
3363 __ LoadRoot(r3, Heap::kUndefinedValueRootIndex); | 3301 __ LoadRoot(r2, Heap::kUndefinedValueRootIndex); |
3364 PushOperand(r3); | 3302 PushOperand(r2); |
3365 | 3303 |
3366 __ LoadNativeContextSlot(expr->context_index(), r3); | 3304 __ LoadNativeContextSlot(expr->context_index(), r2); |
3367 } | 3305 } |
3368 | 3306 |
3369 | |
3370 void FullCodeGenerator::EmitCallJSRuntimeFunction(CallRuntime* expr) { | 3307 void FullCodeGenerator::EmitCallJSRuntimeFunction(CallRuntime* expr) { |
3371 ZoneList<Expression*>* args = expr->arguments(); | 3308 ZoneList<Expression*>* args = expr->arguments(); |
3372 int arg_count = args->length(); | 3309 int arg_count = args->length(); |
3373 | 3310 |
3374 SetCallPosition(expr); | 3311 SetCallPosition(expr); |
3375 __ LoadP(r4, MemOperand(sp, (arg_count + 1) * kPointerSize), r0); | 3312 __ LoadP(r3, MemOperand(sp, (arg_count + 1) * kPointerSize), r0); |
3376 __ mov(r3, Operand(arg_count)); | 3313 __ mov(r2, Operand(arg_count)); |
3377 __ Call(isolate()->builtins()->Call(ConvertReceiverMode::kNullOrUndefined), | 3314 __ Call(isolate()->builtins()->Call(ConvertReceiverMode::kNullOrUndefined), |
3378 RelocInfo::CODE_TARGET); | 3315 RelocInfo::CODE_TARGET); |
3379 OperandStackDepthDecrement(arg_count + 1); | 3316 OperandStackDepthDecrement(arg_count + 1); |
3380 } | 3317 } |
3381 | 3318 |
3382 | |
3383 void FullCodeGenerator::VisitCallRuntime(CallRuntime* expr) { | 3319 void FullCodeGenerator::VisitCallRuntime(CallRuntime* expr) { |
3384 ZoneList<Expression*>* args = expr->arguments(); | 3320 ZoneList<Expression*>* args = expr->arguments(); |
3385 int arg_count = args->length(); | 3321 int arg_count = args->length(); |
3386 | 3322 |
3387 if (expr->is_jsruntime()) { | 3323 if (expr->is_jsruntime()) { |
3388 Comment cmnt(masm_, "[ CallRuntime"); | 3324 Comment cmnt(masm_, "[ CallRuntime"); |
3389 EmitLoadJSRuntimeFunction(expr); | 3325 EmitLoadJSRuntimeFunction(expr); |
3390 | 3326 |
3391 // Push the target function under the receiver. | 3327 // Push the target function under the receiver. |
3392 __ LoadP(ip, MemOperand(sp, 0)); | 3328 __ LoadP(ip, MemOperand(sp, 0)); |
3393 PushOperand(ip); | 3329 PushOperand(ip); |
3394 __ StoreP(r3, MemOperand(sp, kPointerSize)); | 3330 __ StoreP(r2, MemOperand(sp, kPointerSize)); |
3395 | 3331 |
3396 // Push the arguments ("left-to-right"). | 3332 // Push the arguments ("left-to-right"). |
3397 for (int i = 0; i < arg_count; i++) { | 3333 for (int i = 0; i < arg_count; i++) { |
3398 VisitForStackValue(args->at(i)); | 3334 VisitForStackValue(args->at(i)); |
3399 } | 3335 } |
3400 | 3336 |
3401 PrepareForBailoutForId(expr->CallId(), NO_REGISTERS); | 3337 PrepareForBailoutForId(expr->CallId(), NO_REGISTERS); |
3402 EmitCallJSRuntimeFunction(expr); | 3338 EmitCallJSRuntimeFunction(expr); |
3403 | 3339 |
3404 // Restore context register. | 3340 // Restore context register. |
3405 __ LoadP(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); | 3341 __ LoadP(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); |
3406 | 3342 |
3407 context()->DropAndPlug(1, r3); | 3343 context()->DropAndPlug(1, r2); |
3408 | 3344 |
3409 } else { | 3345 } else { |
3410 const Runtime::Function* function = expr->function(); | 3346 const Runtime::Function* function = expr->function(); |
3411 switch (function->function_id) { | 3347 switch (function->function_id) { |
3412 #define CALL_INTRINSIC_GENERATOR(Name) \ | 3348 #define CALL_INTRINSIC_GENERATOR(Name) \ |
3413 case Runtime::kInline##Name: { \ | 3349 case Runtime::kInline##Name: { \ |
3414 Comment cmnt(masm_, "[ Inline" #Name); \ | 3350 Comment cmnt(masm_, "[ Inline" #Name); \ |
3415 return Emit##Name(expr); \ | 3351 return Emit##Name(expr); \ |
3416 } | 3352 } |
3417 FOR_EACH_FULL_CODE_INTRINSIC(CALL_INTRINSIC_GENERATOR) | 3353 FOR_EACH_FULL_CODE_INTRINSIC(CALL_INTRINSIC_GENERATOR) |
3418 #undef CALL_INTRINSIC_GENERATOR | 3354 #undef CALL_INTRINSIC_GENERATOR |
3419 default: { | 3355 default: { |
3420 Comment cmnt(masm_, "[ CallRuntime for unhandled intrinsic"); | 3356 Comment cmnt(masm_, "[ CallRuntime for unhandled intrinsic"); |
3421 // Push the arguments ("left-to-right"). | 3357 // Push the arguments ("left-to-right"). |
3422 for (int i = 0; i < arg_count; i++) { | 3358 for (int i = 0; i < arg_count; i++) { |
3423 VisitForStackValue(args->at(i)); | 3359 VisitForStackValue(args->at(i)); |
3424 } | 3360 } |
3425 | 3361 |
3426 // Call the C runtime function. | 3362 // Call the C runtime function. |
3427 PrepareForBailoutForId(expr->CallId(), NO_REGISTERS); | 3363 PrepareForBailoutForId(expr->CallId(), NO_REGISTERS); |
3428 __ CallRuntime(expr->function(), arg_count); | 3364 __ CallRuntime(expr->function(), arg_count); |
3429 OperandStackDepthDecrement(arg_count); | 3365 OperandStackDepthDecrement(arg_count); |
3430 context()->Plug(r3); | 3366 context()->Plug(r2); |
3431 } | 3367 } |
3432 } | 3368 } |
3433 } | 3369 } |
3434 } | 3370 } |
3435 | 3371 |
3436 | |
3437 void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) { | 3372 void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) { |
3438 switch (expr->op()) { | 3373 switch (expr->op()) { |
3439 case Token::DELETE: { | 3374 case Token::DELETE: { |
3440 Comment cmnt(masm_, "[ UnaryOperation (DELETE)"); | 3375 Comment cmnt(masm_, "[ UnaryOperation (DELETE)"); |
3441 Property* property = expr->expression()->AsProperty(); | 3376 Property* property = expr->expression()->AsProperty(); |
3442 VariableProxy* proxy = expr->expression()->AsVariableProxy(); | 3377 VariableProxy* proxy = expr->expression()->AsVariableProxy(); |
3443 | 3378 |
3444 if (property != NULL) { | 3379 if (property != NULL) { |
3445 VisitForStackValue(property->obj()); | 3380 VisitForStackValue(property->obj()); |
3446 VisitForStackValue(property->key()); | 3381 VisitForStackValue(property->key()); |
3447 CallRuntimeWithOperands(is_strict(language_mode()) | 3382 CallRuntimeWithOperands(is_strict(language_mode()) |
3448 ? Runtime::kDeleteProperty_Strict | 3383 ? Runtime::kDeleteProperty_Strict |
3449 : Runtime::kDeleteProperty_Sloppy); | 3384 : Runtime::kDeleteProperty_Sloppy); |
3450 context()->Plug(r3); | 3385 context()->Plug(r2); |
3451 } else if (proxy != NULL) { | 3386 } else if (proxy != NULL) { |
3452 Variable* var = proxy->var(); | 3387 Variable* var = proxy->var(); |
3453 // Delete of an unqualified identifier is disallowed in strict mode but | 3388 // Delete of an unqualified identifier is disallowed in strict mode but |
3454 // "delete this" is allowed. | 3389 // "delete this" is allowed. |
3455 bool is_this = var->HasThisName(isolate()); | 3390 bool is_this = var->HasThisName(isolate()); |
3456 DCHECK(is_sloppy(language_mode()) || is_this); | 3391 DCHECK(is_sloppy(language_mode()) || is_this); |
3457 if (var->IsUnallocatedOrGlobalSlot()) { | 3392 if (var->IsUnallocatedOrGlobalSlot()) { |
3458 __ LoadGlobalObject(r5); | 3393 __ LoadGlobalObject(r4); |
3459 __ mov(r4, Operand(var->name())); | 3394 __ mov(r3, Operand(var->name())); |
3460 __ Push(r5, r4); | 3395 __ Push(r4, r3); |
3461 __ CallRuntime(Runtime::kDeleteProperty_Sloppy); | 3396 __ CallRuntime(Runtime::kDeleteProperty_Sloppy); |
3462 context()->Plug(r3); | 3397 context()->Plug(r2); |
3463 } else if (var->IsStackAllocated() || var->IsContextSlot()) { | 3398 } else if (var->IsStackAllocated() || var->IsContextSlot()) { |
3464 // Result of deleting non-global, non-dynamic variables is false. | 3399 // Result of deleting non-global, non-dynamic variables is false. |
3465 // The subexpression does not have side effects. | 3400 // The subexpression does not have side effects. |
3466 context()->Plug(is_this); | 3401 context()->Plug(is_this); |
3467 } else { | 3402 } else { |
3468 // Non-global variable. Call the runtime to try to delete from the | 3403 // Non-global variable. Call the runtime to try to delete from the |
3469 // context where the variable was introduced. | 3404 // context where the variable was introduced. |
3470 __ Push(var->name()); | 3405 __ Push(var->name()); |
3471 __ CallRuntime(Runtime::kDeleteLookupSlot); | 3406 __ CallRuntime(Runtime::kDeleteLookupSlot); |
3472 context()->Plug(r3); | 3407 context()->Plug(r2); |
3473 } | 3408 } |
3474 } else { | 3409 } else { |
3475 // Result of deleting non-property, non-variable reference is true. | 3410 // Result of deleting non-property, non-variable reference is true. |
3476 // The subexpression may have side effects. | 3411 // The subexpression may have side effects. |
3477 VisitForEffect(expr->expression()); | 3412 VisitForEffect(expr->expression()); |
3478 context()->Plug(true); | 3413 context()->Plug(true); |
3479 } | 3414 } |
3480 break; | 3415 break; |
3481 } | 3416 } |
3482 | 3417 |
(...skipping 21 matching lines...) Expand all Loading... |
3504 // for control and plugging the control flow into the context, | 3439 // for control and plugging the control flow into the context, |
3505 // because we need to prepare a pair of extra administrative AST ids | 3440 // because we need to prepare a pair of extra administrative AST ids |
3506 // for the optimizing compiler. | 3441 // for the optimizing compiler. |
3507 DCHECK(context()->IsAccumulatorValue() || context()->IsStackValue()); | 3442 DCHECK(context()->IsAccumulatorValue() || context()->IsStackValue()); |
3508 Label materialize_true, materialize_false, done; | 3443 Label materialize_true, materialize_false, done; |
3509 VisitForControl(expr->expression(), &materialize_false, | 3444 VisitForControl(expr->expression(), &materialize_false, |
3510 &materialize_true, &materialize_true); | 3445 &materialize_true, &materialize_true); |
3511 if (!context()->IsAccumulatorValue()) OperandStackDepthIncrement(1); | 3446 if (!context()->IsAccumulatorValue()) OperandStackDepthIncrement(1); |
3512 __ bind(&materialize_true); | 3447 __ bind(&materialize_true); |
3513 PrepareForBailoutForId(expr->MaterializeTrueId(), NO_REGISTERS); | 3448 PrepareForBailoutForId(expr->MaterializeTrueId(), NO_REGISTERS); |
3514 __ LoadRoot(r3, Heap::kTrueValueRootIndex); | 3449 __ LoadRoot(r2, Heap::kTrueValueRootIndex); |
3515 if (context()->IsStackValue()) __ push(r3); | 3450 if (context()->IsStackValue()) __ push(r2); |
3516 __ b(&done); | 3451 __ b(&done); |
3517 __ bind(&materialize_false); | 3452 __ bind(&materialize_false); |
3518 PrepareForBailoutForId(expr->MaterializeFalseId(), NO_REGISTERS); | 3453 PrepareForBailoutForId(expr->MaterializeFalseId(), NO_REGISTERS); |
3519 __ LoadRoot(r3, Heap::kFalseValueRootIndex); | 3454 __ LoadRoot(r2, Heap::kFalseValueRootIndex); |
3520 if (context()->IsStackValue()) __ push(r3); | 3455 if (context()->IsStackValue()) __ push(r2); |
3521 __ bind(&done); | 3456 __ bind(&done); |
3522 } | 3457 } |
3523 break; | 3458 break; |
3524 } | 3459 } |
3525 | 3460 |
3526 case Token::TYPEOF: { | 3461 case Token::TYPEOF: { |
3527 Comment cmnt(masm_, "[ UnaryOperation (TYPEOF)"); | 3462 Comment cmnt(masm_, "[ UnaryOperation (TYPEOF)"); |
3528 { | 3463 { |
3529 AccumulatorValueContext context(this); | 3464 AccumulatorValueContext context(this); |
3530 VisitForTypeofValue(expr->expression()); | 3465 VisitForTypeofValue(expr->expression()); |
3531 } | 3466 } |
3532 __ mr(r6, r3); | 3467 __ LoadRR(r5, r2); |
3533 TypeofStub typeof_stub(isolate()); | 3468 TypeofStub typeof_stub(isolate()); |
3534 __ CallStub(&typeof_stub); | 3469 __ CallStub(&typeof_stub); |
3535 context()->Plug(r3); | 3470 context()->Plug(r2); |
3536 break; | 3471 break; |
3537 } | 3472 } |
3538 | 3473 |
3539 default: | 3474 default: |
3540 UNREACHABLE(); | 3475 UNREACHABLE(); |
3541 } | 3476 } |
3542 } | 3477 } |
3543 | 3478 |
3544 | |
3545 void FullCodeGenerator::VisitCountOperation(CountOperation* expr) { | 3479 void FullCodeGenerator::VisitCountOperation(CountOperation* expr) { |
3546 DCHECK(expr->expression()->IsValidReferenceExpressionOrThis()); | 3480 DCHECK(expr->expression()->IsValidReferenceExpressionOrThis()); |
3547 | 3481 |
3548 Comment cmnt(masm_, "[ CountOperation"); | 3482 Comment cmnt(masm_, "[ CountOperation"); |
3549 | 3483 |
3550 Property* prop = expr->expression()->AsProperty(); | 3484 Property* prop = expr->expression()->AsProperty(); |
3551 LhsKind assign_type = Property::GetAssignType(prop); | 3485 LhsKind assign_type = Property::GetAssignType(prop); |
3552 | 3486 |
3553 // Evaluate expression and get value. | 3487 // Evaluate expression and get value. |
3554 if (assign_type == VARIABLE) { | 3488 if (assign_type == VARIABLE) { |
(...skipping 13 matching lines...) Expand all Loading... |
3568 __ LoadP(LoadDescriptor::ReceiverRegister(), MemOperand(sp, 0)); | 3502 __ LoadP(LoadDescriptor::ReceiverRegister(), MemOperand(sp, 0)); |
3569 EmitNamedPropertyLoad(prop); | 3503 EmitNamedPropertyLoad(prop); |
3570 break; | 3504 break; |
3571 } | 3505 } |
3572 | 3506 |
3573 case NAMED_SUPER_PROPERTY: { | 3507 case NAMED_SUPER_PROPERTY: { |
3574 VisitForStackValue(prop->obj()->AsSuperPropertyReference()->this_var()); | 3508 VisitForStackValue(prop->obj()->AsSuperPropertyReference()->this_var()); |
3575 VisitForAccumulatorValue( | 3509 VisitForAccumulatorValue( |
3576 prop->obj()->AsSuperPropertyReference()->home_object()); | 3510 prop->obj()->AsSuperPropertyReference()->home_object()); |
3577 PushOperand(result_register()); | 3511 PushOperand(result_register()); |
3578 const Register scratch = r4; | 3512 const Register scratch = r3; |
3579 __ LoadP(scratch, MemOperand(sp, kPointerSize)); | 3513 __ LoadP(scratch, MemOperand(sp, kPointerSize)); |
3580 PushOperands(scratch, result_register()); | 3514 PushOperands(scratch, result_register()); |
3581 EmitNamedSuperPropertyLoad(prop); | 3515 EmitNamedSuperPropertyLoad(prop); |
3582 break; | 3516 break; |
3583 } | 3517 } |
3584 | 3518 |
3585 case KEYED_SUPER_PROPERTY: { | 3519 case KEYED_SUPER_PROPERTY: { |
3586 VisitForStackValue(prop->obj()->AsSuperPropertyReference()->this_var()); | 3520 VisitForStackValue(prop->obj()->AsSuperPropertyReference()->this_var()); |
3587 VisitForAccumulatorValue( | 3521 VisitForAccumulatorValue( |
3588 prop->obj()->AsSuperPropertyReference()->home_object()); | 3522 prop->obj()->AsSuperPropertyReference()->home_object()); |
3589 const Register scratch = r4; | 3523 const Register scratch = r3; |
3590 const Register scratch1 = r5; | 3524 const Register scratch1 = r4; |
3591 __ mr(scratch, result_register()); | 3525 __ LoadRR(scratch, result_register()); |
3592 VisitForAccumulatorValue(prop->key()); | 3526 VisitForAccumulatorValue(prop->key()); |
3593 PushOperands(scratch, result_register()); | 3527 PushOperands(scratch, result_register()); |
3594 __ LoadP(scratch1, MemOperand(sp, 2 * kPointerSize)); | 3528 __ LoadP(scratch1, MemOperand(sp, 2 * kPointerSize)); |
3595 PushOperands(scratch1, scratch, result_register()); | 3529 PushOperands(scratch1, scratch, result_register()); |
3596 EmitKeyedSuperPropertyLoad(prop); | 3530 EmitKeyedSuperPropertyLoad(prop); |
3597 break; | 3531 break; |
3598 } | 3532 } |
3599 | 3533 |
3600 case KEYED_PROPERTY: { | 3534 case KEYED_PROPERTY: { |
3601 VisitForStackValue(prop->obj()); | 3535 VisitForStackValue(prop->obj()); |
(...skipping 18 matching lines...) Expand all Loading... |
3620 PrepareForBailoutForId(prop->LoadId(), TOS_REG); | 3554 PrepareForBailoutForId(prop->LoadId(), TOS_REG); |
3621 } | 3555 } |
3622 | 3556 |
3623 // Inline smi case if we are in a loop. | 3557 // Inline smi case if we are in a loop. |
3624 Label stub_call, done; | 3558 Label stub_call, done; |
3625 JumpPatchSite patch_site(masm_); | 3559 JumpPatchSite patch_site(masm_); |
3626 | 3560 |
3627 int count_value = expr->op() == Token::INC ? 1 : -1; | 3561 int count_value = expr->op() == Token::INC ? 1 : -1; |
3628 if (ShouldInlineSmiCase(expr->op())) { | 3562 if (ShouldInlineSmiCase(expr->op())) { |
3629 Label slow; | 3563 Label slow; |
3630 patch_site.EmitJumpIfNotSmi(r3, &slow); | 3564 patch_site.EmitJumpIfNotSmi(r2, &slow); |
3631 | 3565 |
3632 // Save result for postfix expressions. | 3566 // Save result for postfix expressions. |
3633 if (expr->is_postfix()) { | 3567 if (expr->is_postfix()) { |
3634 if (!context()->IsEffect()) { | 3568 if (!context()->IsEffect()) { |
3635 // Save the result on the stack. If we have a named or keyed property | 3569 // Save the result on the stack. If we have a named or keyed property |
3636 // we store the result under the receiver that is currently on top | 3570 // we store the result under the receiver that is currently on top |
3637 // of the stack. | 3571 // of the stack. |
3638 switch (assign_type) { | 3572 switch (assign_type) { |
3639 case VARIABLE: | 3573 case VARIABLE: |
3640 __ push(r3); | 3574 __ push(r2); |
3641 break; | 3575 break; |
3642 case NAMED_PROPERTY: | 3576 case NAMED_PROPERTY: |
3643 __ StoreP(r3, MemOperand(sp, kPointerSize)); | 3577 __ StoreP(r2, MemOperand(sp, kPointerSize)); |
3644 break; | 3578 break; |
3645 case NAMED_SUPER_PROPERTY: | 3579 case NAMED_SUPER_PROPERTY: |
3646 __ StoreP(r3, MemOperand(sp, 2 * kPointerSize)); | 3580 __ StoreP(r2, MemOperand(sp, 2 * kPointerSize)); |
3647 break; | 3581 break; |
3648 case KEYED_PROPERTY: | 3582 case KEYED_PROPERTY: |
3649 __ StoreP(r3, MemOperand(sp, 2 * kPointerSize)); | 3583 __ StoreP(r2, MemOperand(sp, 2 * kPointerSize)); |
3650 break; | 3584 break; |
3651 case KEYED_SUPER_PROPERTY: | 3585 case KEYED_SUPER_PROPERTY: |
3652 __ StoreP(r3, MemOperand(sp, 3 * kPointerSize)); | 3586 __ StoreP(r2, MemOperand(sp, 3 * kPointerSize)); |
3653 break; | 3587 break; |
3654 } | 3588 } |
3655 } | 3589 } |
3656 } | 3590 } |
3657 | 3591 |
3658 Register scratch1 = r4; | 3592 Register scratch1 = r3; |
3659 Register scratch2 = r5; | 3593 Register scratch2 = r4; |
3660 __ LoadSmiLiteral(scratch1, Smi::FromInt(count_value)); | 3594 __ LoadSmiLiteral(scratch1, Smi::FromInt(count_value)); |
3661 __ AddAndCheckForOverflow(r3, r3, scratch1, scratch2, r0); | 3595 __ AddAndCheckForOverflow(r2, r2, scratch1, scratch2, r0); |
3662 __ BranchOnNoOverflow(&done); | 3596 __ BranchOnNoOverflow(&done); |
3663 // Call stub. Undo operation first. | 3597 // Call stub. Undo operation first. |
3664 __ sub(r3, r3, scratch1); | 3598 __ SubP(r2, r2, scratch1); |
3665 __ b(&stub_call); | 3599 __ b(&stub_call); |
3666 __ bind(&slow); | 3600 __ bind(&slow); |
3667 } | 3601 } |
3668 | 3602 |
3669 // Convert old value into a number. | 3603 // Convert old value into a number. |
3670 ToNumberStub convert_stub(isolate()); | 3604 ToNumberStub convert_stub(isolate()); |
3671 __ CallStub(&convert_stub); | 3605 __ CallStub(&convert_stub); |
3672 PrepareForBailoutForId(expr->ToNumberId(), TOS_REG); | 3606 PrepareForBailoutForId(expr->ToNumberId(), TOS_REG); |
3673 | 3607 |
3674 // Save result for postfix expressions. | 3608 // Save result for postfix expressions. |
3675 if (expr->is_postfix()) { | 3609 if (expr->is_postfix()) { |
3676 if (!context()->IsEffect()) { | 3610 if (!context()->IsEffect()) { |
3677 // Save the result on the stack. If we have a named or keyed property | 3611 // Save the result on the stack. If we have a named or keyed property |
3678 // we store the result under the receiver that is currently on top | 3612 // we store the result under the receiver that is currently on top |
3679 // of the stack. | 3613 // of the stack. |
3680 switch (assign_type) { | 3614 switch (assign_type) { |
3681 case VARIABLE: | 3615 case VARIABLE: |
3682 PushOperand(r3); | 3616 PushOperand(r2); |
3683 break; | 3617 break; |
3684 case NAMED_PROPERTY: | 3618 case NAMED_PROPERTY: |
3685 __ StoreP(r3, MemOperand(sp, kPointerSize)); | 3619 __ StoreP(r2, MemOperand(sp, kPointerSize)); |
3686 break; | 3620 break; |
3687 case NAMED_SUPER_PROPERTY: | 3621 case NAMED_SUPER_PROPERTY: |
3688 __ StoreP(r3, MemOperand(sp, 2 * kPointerSize)); | 3622 __ StoreP(r2, MemOperand(sp, 2 * kPointerSize)); |
3689 break; | 3623 break; |
3690 case KEYED_PROPERTY: | 3624 case KEYED_PROPERTY: |
3691 __ StoreP(r3, MemOperand(sp, 2 * kPointerSize)); | 3625 __ StoreP(r2, MemOperand(sp, 2 * kPointerSize)); |
3692 break; | 3626 break; |
3693 case KEYED_SUPER_PROPERTY: | 3627 case KEYED_SUPER_PROPERTY: |
3694 __ StoreP(r3, MemOperand(sp, 3 * kPointerSize)); | 3628 __ StoreP(r2, MemOperand(sp, 3 * kPointerSize)); |
3695 break; | 3629 break; |
3696 } | 3630 } |
3697 } | 3631 } |
3698 } | 3632 } |
3699 | 3633 |
3700 __ bind(&stub_call); | 3634 __ bind(&stub_call); |
3701 __ mr(r4, r3); | 3635 __ LoadRR(r3, r2); |
3702 __ LoadSmiLiteral(r3, Smi::FromInt(count_value)); | 3636 __ LoadSmiLiteral(r2, Smi::FromInt(count_value)); |
3703 | 3637 |
3704 SetExpressionPosition(expr); | 3638 SetExpressionPosition(expr); |
3705 | 3639 |
3706 Handle<Code> code = CodeFactory::BinaryOpIC(isolate(), Token::ADD).code(); | 3640 Handle<Code> code = CodeFactory::BinaryOpIC(isolate(), Token::ADD).code(); |
3707 CallIC(code, expr->CountBinOpFeedbackId()); | 3641 CallIC(code, expr->CountBinOpFeedbackId()); |
3708 patch_site.EmitPatchInfo(); | 3642 patch_site.EmitPatchInfo(); |
3709 __ bind(&done); | 3643 __ bind(&done); |
3710 | 3644 |
3711 // Store the value returned in r3. | 3645 // Store the value returned in r2. |
3712 switch (assign_type) { | 3646 switch (assign_type) { |
3713 case VARIABLE: | 3647 case VARIABLE: |
3714 if (expr->is_postfix()) { | 3648 if (expr->is_postfix()) { |
3715 { | 3649 { |
3716 EffectContext context(this); | 3650 EffectContext context(this); |
3717 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(), | 3651 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(), |
3718 Token::ASSIGN, expr->CountSlot()); | 3652 Token::ASSIGN, expr->CountSlot()); |
3719 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); | 3653 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); |
3720 context.Plug(r3); | 3654 context.Plug(r2); |
3721 } | 3655 } |
3722 // For all contexts except EffectConstant We have the result on | 3656 // For all contexts except EffectConstant We have the result on |
3723 // top of the stack. | 3657 // top of the stack. |
3724 if (!context()->IsEffect()) { | 3658 if (!context()->IsEffect()) { |
3725 context()->PlugTOS(); | 3659 context()->PlugTOS(); |
3726 } | 3660 } |
3727 } else { | 3661 } else { |
3728 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(), | 3662 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(), |
3729 Token::ASSIGN, expr->CountSlot()); | 3663 Token::ASSIGN, expr->CountSlot()); |
3730 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); | 3664 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); |
3731 context()->Plug(r3); | 3665 context()->Plug(r2); |
3732 } | 3666 } |
3733 break; | 3667 break; |
3734 case NAMED_PROPERTY: { | 3668 case NAMED_PROPERTY: { |
3735 __ mov(StoreDescriptor::NameRegister(), | 3669 __ mov(StoreDescriptor::NameRegister(), |
3736 Operand(prop->key()->AsLiteral()->value())); | 3670 Operand(prop->key()->AsLiteral()->value())); |
3737 PopOperand(StoreDescriptor::ReceiverRegister()); | 3671 PopOperand(StoreDescriptor::ReceiverRegister()); |
3738 EmitLoadStoreICSlot(expr->CountSlot()); | 3672 EmitLoadStoreICSlot(expr->CountSlot()); |
3739 CallStoreIC(); | 3673 CallStoreIC(); |
3740 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); | 3674 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); |
3741 if (expr->is_postfix()) { | 3675 if (expr->is_postfix()) { |
3742 if (!context()->IsEffect()) { | 3676 if (!context()->IsEffect()) { |
3743 context()->PlugTOS(); | 3677 context()->PlugTOS(); |
3744 } | 3678 } |
3745 } else { | 3679 } else { |
3746 context()->Plug(r3); | 3680 context()->Plug(r2); |
3747 } | 3681 } |
3748 break; | 3682 break; |
3749 } | 3683 } |
3750 case NAMED_SUPER_PROPERTY: { | 3684 case NAMED_SUPER_PROPERTY: { |
3751 EmitNamedSuperPropertyStore(prop); | 3685 EmitNamedSuperPropertyStore(prop); |
3752 if (expr->is_postfix()) { | 3686 if (expr->is_postfix()) { |
3753 if (!context()->IsEffect()) { | 3687 if (!context()->IsEffect()) { |
3754 context()->PlugTOS(); | 3688 context()->PlugTOS(); |
3755 } | 3689 } |
3756 } else { | 3690 } else { |
3757 context()->Plug(r3); | 3691 context()->Plug(r2); |
3758 } | 3692 } |
3759 break; | 3693 break; |
3760 } | 3694 } |
3761 case KEYED_SUPER_PROPERTY: { | 3695 case KEYED_SUPER_PROPERTY: { |
3762 EmitKeyedSuperPropertyStore(prop); | 3696 EmitKeyedSuperPropertyStore(prop); |
3763 if (expr->is_postfix()) { | 3697 if (expr->is_postfix()) { |
3764 if (!context()->IsEffect()) { | 3698 if (!context()->IsEffect()) { |
3765 context()->PlugTOS(); | 3699 context()->PlugTOS(); |
3766 } | 3700 } |
3767 } else { | 3701 } else { |
3768 context()->Plug(r3); | 3702 context()->Plug(r2); |
3769 } | 3703 } |
3770 break; | 3704 break; |
3771 } | 3705 } |
3772 case KEYED_PROPERTY: { | 3706 case KEYED_PROPERTY: { |
3773 PopOperands(StoreDescriptor::ReceiverRegister(), | 3707 PopOperands(StoreDescriptor::ReceiverRegister(), |
3774 StoreDescriptor::NameRegister()); | 3708 StoreDescriptor::NameRegister()); |
3775 Handle<Code> ic = | 3709 Handle<Code> ic = |
3776 CodeFactory::KeyedStoreIC(isolate(), language_mode()).code(); | 3710 CodeFactory::KeyedStoreIC(isolate(), language_mode()).code(); |
3777 EmitLoadStoreICSlot(expr->CountSlot()); | 3711 EmitLoadStoreICSlot(expr->CountSlot()); |
3778 CallIC(ic); | 3712 CallIC(ic); |
3779 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); | 3713 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); |
3780 if (expr->is_postfix()) { | 3714 if (expr->is_postfix()) { |
3781 if (!context()->IsEffect()) { | 3715 if (!context()->IsEffect()) { |
3782 context()->PlugTOS(); | 3716 context()->PlugTOS(); |
3783 } | 3717 } |
3784 } else { | 3718 } else { |
3785 context()->Plug(r3); | 3719 context()->Plug(r2); |
3786 } | 3720 } |
3787 break; | 3721 break; |
3788 } | 3722 } |
3789 } | 3723 } |
3790 } | 3724 } |
3791 | 3725 |
3792 | |
3793 void FullCodeGenerator::EmitLiteralCompareTypeof(Expression* expr, | 3726 void FullCodeGenerator::EmitLiteralCompareTypeof(Expression* expr, |
3794 Expression* sub_expr, | 3727 Expression* sub_expr, |
3795 Handle<String> check) { | 3728 Handle<String> check) { |
3796 Label materialize_true, materialize_false; | 3729 Label materialize_true, materialize_false; |
3797 Label* if_true = NULL; | 3730 Label* if_true = NULL; |
3798 Label* if_false = NULL; | 3731 Label* if_false = NULL; |
3799 Label* fall_through = NULL; | 3732 Label* fall_through = NULL; |
3800 context()->PrepareTest(&materialize_true, &materialize_false, &if_true, | 3733 context()->PrepareTest(&materialize_true, &materialize_false, &if_true, |
3801 &if_false, &fall_through); | 3734 &if_false, &fall_through); |
3802 | 3735 |
3803 { | 3736 { |
3804 AccumulatorValueContext context(this); | 3737 AccumulatorValueContext context(this); |
3805 VisitForTypeofValue(sub_expr); | 3738 VisitForTypeofValue(sub_expr); |
3806 } | 3739 } |
3807 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false); | 3740 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false); |
3808 | 3741 |
3809 Factory* factory = isolate()->factory(); | 3742 Factory* factory = isolate()->factory(); |
3810 if (String::Equals(check, factory->number_string())) { | 3743 if (String::Equals(check, factory->number_string())) { |
3811 __ JumpIfSmi(r3, if_true); | 3744 __ JumpIfSmi(r2, if_true); |
3812 __ LoadP(r3, FieldMemOperand(r3, HeapObject::kMapOffset)); | 3745 __ LoadP(r2, FieldMemOperand(r2, HeapObject::kMapOffset)); |
3813 __ LoadRoot(ip, Heap::kHeapNumberMapRootIndex); | 3746 __ CompareRoot(r2, Heap::kHeapNumberMapRootIndex); |
3814 __ cmp(r3, ip); | |
3815 Split(eq, if_true, if_false, fall_through); | 3747 Split(eq, if_true, if_false, fall_through); |
3816 } else if (String::Equals(check, factory->string_string())) { | 3748 } else if (String::Equals(check, factory->string_string())) { |
3817 __ JumpIfSmi(r3, if_false); | 3749 __ JumpIfSmi(r2, if_false); |
3818 __ CompareObjectType(r3, r3, r4, FIRST_NONSTRING_TYPE); | 3750 __ CompareObjectType(r2, r2, r3, FIRST_NONSTRING_TYPE); |
3819 Split(lt, if_true, if_false, fall_through); | 3751 Split(lt, if_true, if_false, fall_through); |
3820 } else if (String::Equals(check, factory->symbol_string())) { | 3752 } else if (String::Equals(check, factory->symbol_string())) { |
3821 __ JumpIfSmi(r3, if_false); | 3753 __ JumpIfSmi(r2, if_false); |
3822 __ CompareObjectType(r3, r3, r4, SYMBOL_TYPE); | 3754 __ CompareObjectType(r2, r2, r3, SYMBOL_TYPE); |
3823 Split(eq, if_true, if_false, fall_through); | 3755 Split(eq, if_true, if_false, fall_through); |
3824 } else if (String::Equals(check, factory->boolean_string())) { | 3756 } else if (String::Equals(check, factory->boolean_string())) { |
3825 __ CompareRoot(r3, Heap::kTrueValueRootIndex); | 3757 __ CompareRoot(r2, Heap::kTrueValueRootIndex); |
3826 __ beq(if_true); | 3758 __ beq(if_true); |
3827 __ CompareRoot(r3, Heap::kFalseValueRootIndex); | 3759 __ CompareRoot(r2, Heap::kFalseValueRootIndex); |
3828 Split(eq, if_true, if_false, fall_through); | 3760 Split(eq, if_true, if_false, fall_through); |
3829 } else if (String::Equals(check, factory->undefined_string())) { | 3761 } else if (String::Equals(check, factory->undefined_string())) { |
3830 __ CompareRoot(r3, Heap::kNullValueRootIndex); | 3762 __ CompareRoot(r2, Heap::kNullValueRootIndex); |
3831 __ beq(if_false); | 3763 __ beq(if_false); |
3832 __ JumpIfSmi(r3, if_false); | 3764 __ JumpIfSmi(r2, if_false); |
3833 // Check for undetectable objects => true. | 3765 // Check for undetectable objects => true. |
3834 __ LoadP(r3, FieldMemOperand(r3, HeapObject::kMapOffset)); | 3766 __ LoadP(r2, FieldMemOperand(r2, HeapObject::kMapOffset)); |
3835 __ lbz(r4, FieldMemOperand(r3, Map::kBitFieldOffset)); | 3767 __ tm(FieldMemOperand(r2, Map::kBitFieldOffset), |
3836 __ andi(r0, r4, Operand(1 << Map::kIsUndetectable)); | 3768 Operand(1 << Map::kIsUndetectable)); |
3837 Split(ne, if_true, if_false, fall_through, cr0); | 3769 Split(ne, if_true, if_false, fall_through); |
3838 | 3770 |
3839 } else if (String::Equals(check, factory->function_string())) { | 3771 } else if (String::Equals(check, factory->function_string())) { |
3840 __ JumpIfSmi(r3, if_false); | 3772 __ JumpIfSmi(r2, if_false); |
3841 __ LoadP(r3, FieldMemOperand(r3, HeapObject::kMapOffset)); | 3773 __ LoadP(r2, FieldMemOperand(r2, HeapObject::kMapOffset)); |
3842 __ lbz(r4, FieldMemOperand(r3, Map::kBitFieldOffset)); | 3774 __ LoadlB(r3, FieldMemOperand(r2, Map::kBitFieldOffset)); |
3843 __ andi(r4, r4, | 3775 __ AndP(r3, r3, |
3844 Operand((1 << Map::kIsCallable) | (1 << Map::kIsUndetectable))); | 3776 Operand((1 << Map::kIsCallable) | (1 << Map::kIsUndetectable))); |
3845 __ cmpi(r4, Operand(1 << Map::kIsCallable)); | 3777 __ CmpP(r3, Operand(1 << Map::kIsCallable)); |
3846 Split(eq, if_true, if_false, fall_through); | 3778 Split(eq, if_true, if_false, fall_through); |
3847 } else if (String::Equals(check, factory->object_string())) { | 3779 } else if (String::Equals(check, factory->object_string())) { |
3848 __ JumpIfSmi(r3, if_false); | 3780 __ JumpIfSmi(r2, if_false); |
3849 __ CompareRoot(r3, Heap::kNullValueRootIndex); | 3781 __ CompareRoot(r2, Heap::kNullValueRootIndex); |
3850 __ beq(if_true); | 3782 __ beq(if_true); |
3851 STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE); | 3783 STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE); |
3852 __ CompareObjectType(r3, r3, r4, FIRST_JS_RECEIVER_TYPE); | 3784 __ CompareObjectType(r2, r2, r3, FIRST_JS_RECEIVER_TYPE); |
3853 __ blt(if_false); | 3785 __ blt(if_false); |
3854 // Check for callable or undetectable objects => false. | 3786 __ tm(FieldMemOperand(r2, Map::kBitFieldOffset), |
3855 __ lbz(r4, FieldMemOperand(r3, Map::kBitFieldOffset)); | 3787 Operand((1 << Map::kIsCallable) | (1 << Map::kIsUndetectable))); |
3856 __ andi(r0, r4, | 3788 Split(eq, if_true, if_false, fall_through); |
3857 Operand((1 << Map::kIsCallable) | (1 << Map::kIsUndetectable))); | |
3858 Split(eq, if_true, if_false, fall_through, cr0); | |
3859 // clang-format off | 3789 // clang-format off |
3860 #define SIMD128_TYPE(TYPE, Type, type, lane_count, lane_type) \ | 3790 #define SIMD128_TYPE(TYPE, Type, type, lane_count, lane_type) \ |
3861 } else if (String::Equals(check, factory->type##_string())) { \ | 3791 } else if (String::Equals(check, factory->type##_string())) { \ |
3862 __ JumpIfSmi(r3, if_false); \ | 3792 __ JumpIfSmi(r2, if_false); \ |
3863 __ LoadP(r3, FieldMemOperand(r3, HeapObject::kMapOffset)); \ | 3793 __ LoadP(r2, FieldMemOperand(r2, HeapObject::kMapOffset)); \ |
3864 __ CompareRoot(r3, Heap::k##Type##MapRootIndex); \ | 3794 __ CompareRoot(r2, Heap::k##Type##MapRootIndex); \ |
3865 Split(eq, if_true, if_false, fall_through); | 3795 Split(eq, if_true, if_false, fall_through); |
3866 SIMD128_TYPES(SIMD128_TYPE) | 3796 SIMD128_TYPES(SIMD128_TYPE) |
3867 #undef SIMD128_TYPE | 3797 #undef SIMD128_TYPE |
3868 // clang-format on | 3798 // clang-format on |
3869 } else { | 3799 } else { |
3870 if (if_false != fall_through) __ b(if_false); | 3800 if (if_false != fall_through) __ b(if_false); |
3871 } | 3801 } |
3872 context()->Plug(if_true, if_false); | 3802 context()->Plug(if_true, if_false); |
3873 } | 3803 } |
3874 | 3804 |
3875 | |
3876 void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) { | 3805 void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) { |
3877 Comment cmnt(masm_, "[ CompareOperation"); | 3806 Comment cmnt(masm_, "[ CompareOperation"); |
3878 SetExpressionPosition(expr); | 3807 SetExpressionPosition(expr); |
3879 | 3808 |
3880 // First we try a fast inlined version of the compare when one of | 3809 // First we try a fast inlined version of the compare when one of |
3881 // the operands is a literal. | 3810 // the operands is a literal. |
3882 if (TryLiteralCompare(expr)) return; | 3811 if (TryLiteralCompare(expr)) return; |
3883 | 3812 |
3884 // Always perform the comparison for its control flow. Pack the result | 3813 // Always perform the comparison for its control flow. Pack the result |
3885 // into the expression's context after the comparison is performed. | 3814 // into the expression's context after the comparison is performed. |
3886 Label materialize_true, materialize_false; | 3815 Label materialize_true, materialize_false; |
3887 Label* if_true = NULL; | 3816 Label* if_true = NULL; |
3888 Label* if_false = NULL; | 3817 Label* if_false = NULL; |
3889 Label* fall_through = NULL; | 3818 Label* fall_through = NULL; |
3890 context()->PrepareTest(&materialize_true, &materialize_false, &if_true, | 3819 context()->PrepareTest(&materialize_true, &materialize_false, &if_true, |
3891 &if_false, &fall_through); | 3820 &if_false, &fall_through); |
3892 | 3821 |
3893 Token::Value op = expr->op(); | 3822 Token::Value op = expr->op(); |
3894 VisitForStackValue(expr->left()); | 3823 VisitForStackValue(expr->left()); |
3895 switch (op) { | 3824 switch (op) { |
3896 case Token::IN: | 3825 case Token::IN: |
3897 VisitForStackValue(expr->right()); | 3826 VisitForStackValue(expr->right()); |
3898 CallRuntimeWithOperands(Runtime::kHasProperty); | 3827 CallRuntimeWithOperands(Runtime::kHasProperty); |
3899 PrepareForBailoutBeforeSplit(expr, false, NULL, NULL); | 3828 PrepareForBailoutBeforeSplit(expr, false, NULL, NULL); |
3900 __ CompareRoot(r3, Heap::kTrueValueRootIndex); | 3829 __ CompareRoot(r2, Heap::kTrueValueRootIndex); |
3901 Split(eq, if_true, if_false, fall_through); | 3830 Split(eq, if_true, if_false, fall_through); |
3902 break; | 3831 break; |
3903 | 3832 |
3904 case Token::INSTANCEOF: { | 3833 case Token::INSTANCEOF: { |
3905 VisitForAccumulatorValue(expr->right()); | 3834 VisitForAccumulatorValue(expr->right()); |
3906 PopOperand(r4); | 3835 PopOperand(r3); |
3907 InstanceOfStub stub(isolate()); | 3836 InstanceOfStub stub(isolate()); |
3908 __ CallStub(&stub); | 3837 __ CallStub(&stub); |
3909 PrepareForBailoutBeforeSplit(expr, false, NULL, NULL); | 3838 PrepareForBailoutBeforeSplit(expr, false, NULL, NULL); |
3910 __ CompareRoot(r3, Heap::kTrueValueRootIndex); | 3839 __ CompareRoot(r2, Heap::kTrueValueRootIndex); |
3911 Split(eq, if_true, if_false, fall_through); | 3840 Split(eq, if_true, if_false, fall_through); |
3912 break; | 3841 break; |
3913 } | 3842 } |
3914 | 3843 |
3915 default: { | 3844 default: { |
3916 VisitForAccumulatorValue(expr->right()); | 3845 VisitForAccumulatorValue(expr->right()); |
3917 Condition cond = CompareIC::ComputeCondition(op); | 3846 Condition cond = CompareIC::ComputeCondition(op); |
3918 PopOperand(r4); | 3847 PopOperand(r3); |
3919 | 3848 |
3920 bool inline_smi_code = ShouldInlineSmiCase(op); | 3849 bool inline_smi_code = ShouldInlineSmiCase(op); |
3921 JumpPatchSite patch_site(masm_); | 3850 JumpPatchSite patch_site(masm_); |
3922 if (inline_smi_code) { | 3851 if (inline_smi_code) { |
3923 Label slow_case; | 3852 Label slow_case; |
3924 __ orx(r5, r3, r4); | 3853 __ LoadRR(r4, r3); |
3925 patch_site.EmitJumpIfNotSmi(r5, &slow_case); | 3854 __ OrP(r4, r2); |
3926 __ cmp(r4, r3); | 3855 patch_site.EmitJumpIfNotSmi(r4, &slow_case); |
| 3856 __ CmpP(r3, r2); |
3927 Split(cond, if_true, if_false, NULL); | 3857 Split(cond, if_true, if_false, NULL); |
3928 __ bind(&slow_case); | 3858 __ bind(&slow_case); |
3929 } | 3859 } |
3930 | 3860 |
3931 Handle<Code> ic = CodeFactory::CompareIC(isolate(), op).code(); | 3861 Handle<Code> ic = CodeFactory::CompareIC(isolate(), op).code(); |
3932 CallIC(ic, expr->CompareOperationFeedbackId()); | 3862 CallIC(ic, expr->CompareOperationFeedbackId()); |
3933 patch_site.EmitPatchInfo(); | 3863 patch_site.EmitPatchInfo(); |
3934 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false); | 3864 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false); |
3935 __ cmpi(r3, Operand::Zero()); | 3865 __ CmpP(r2, Operand::Zero()); |
3936 Split(cond, if_true, if_false, fall_through); | 3866 Split(cond, if_true, if_false, fall_through); |
3937 } | 3867 } |
3938 } | 3868 } |
3939 | 3869 |
3940 // Convert the result of the comparison into one expected for this | 3870 // Convert the result of the comparison into one expected for this |
3941 // expression's context. | 3871 // expression's context. |
3942 context()->Plug(if_true, if_false); | 3872 context()->Plug(if_true, if_false); |
3943 } | 3873 } |
3944 | 3874 |
3945 | |
3946 void FullCodeGenerator::EmitLiteralCompareNil(CompareOperation* expr, | 3875 void FullCodeGenerator::EmitLiteralCompareNil(CompareOperation* expr, |
3947 Expression* sub_expr, | 3876 Expression* sub_expr, |
3948 NilValue nil) { | 3877 NilValue nil) { |
3949 Label materialize_true, materialize_false; | 3878 Label materialize_true, materialize_false; |
3950 Label* if_true = NULL; | 3879 Label* if_true = NULL; |
3951 Label* if_false = NULL; | 3880 Label* if_false = NULL; |
3952 Label* fall_through = NULL; | 3881 Label* fall_through = NULL; |
3953 context()->PrepareTest(&materialize_true, &materialize_false, &if_true, | 3882 context()->PrepareTest(&materialize_true, &materialize_false, &if_true, |
3954 &if_false, &fall_through); | 3883 &if_false, &fall_through); |
3955 | 3884 |
3956 VisitForAccumulatorValue(sub_expr); | 3885 VisitForAccumulatorValue(sub_expr); |
3957 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false); | 3886 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false); |
3958 if (expr->op() == Token::EQ_STRICT) { | 3887 if (expr->op() == Token::EQ_STRICT) { |
3959 Heap::RootListIndex nil_value = nil == kNullValue | 3888 Heap::RootListIndex nil_value = nil == kNullValue |
3960 ? Heap::kNullValueRootIndex | 3889 ? Heap::kNullValueRootIndex |
3961 : Heap::kUndefinedValueRootIndex; | 3890 : Heap::kUndefinedValueRootIndex; |
3962 __ LoadRoot(r4, nil_value); | 3891 __ CompareRoot(r2, nil_value); |
3963 __ cmp(r3, r4); | |
3964 Split(eq, if_true, if_false, fall_through); | 3892 Split(eq, if_true, if_false, fall_through); |
3965 } else { | 3893 } else { |
3966 __ JumpIfSmi(r3, if_false); | 3894 Handle<Code> ic = CompareNilICStub::GetUninitialized(isolate(), nil); |
3967 __ LoadP(r3, FieldMemOperand(r3, HeapObject::kMapOffset)); | 3895 CallIC(ic, expr->CompareOperationFeedbackId()); |
3968 __ lbz(r4, FieldMemOperand(r3, Map::kBitFieldOffset)); | 3896 __ CompareRoot(r2, Heap::kTrueValueRootIndex); |
3969 __ andi(r0, r4, Operand(1 << Map::kIsUndetectable)); | 3897 Split(eq, if_true, if_false, fall_through); |
3970 Split(ne, if_true, if_false, fall_through, cr0); | |
3971 } | 3898 } |
3972 context()->Plug(if_true, if_false); | 3899 context()->Plug(if_true, if_false); |
3973 } | 3900 } |
3974 | 3901 |
3975 | |
3976 void FullCodeGenerator::VisitThisFunction(ThisFunction* expr) { | 3902 void FullCodeGenerator::VisitThisFunction(ThisFunction* expr) { |
3977 __ LoadP(r3, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset)); | 3903 __ LoadP(r2, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset)); |
3978 context()->Plug(r3); | 3904 context()->Plug(r2); |
3979 } | 3905 } |
3980 | 3906 |
3981 | 3907 Register FullCodeGenerator::result_register() { return r2; } |
3982 Register FullCodeGenerator::result_register() { return r3; } | |
3983 | |
3984 | 3908 |
3985 Register FullCodeGenerator::context_register() { return cp; } | 3909 Register FullCodeGenerator::context_register() { return cp; } |
3986 | 3910 |
3987 | |
3988 void FullCodeGenerator::StoreToFrameField(int frame_offset, Register value) { | 3911 void FullCodeGenerator::StoreToFrameField(int frame_offset, Register value) { |
3989 DCHECK_EQ(static_cast<int>(POINTER_SIZE_ALIGN(frame_offset)), frame_offset); | 3912 DCHECK_EQ(static_cast<int>(POINTER_SIZE_ALIGN(frame_offset)), frame_offset); |
3990 __ StoreP(value, MemOperand(fp, frame_offset), r0); | 3913 __ StoreP(value, MemOperand(fp, frame_offset)); |
3991 } | 3914 } |
3992 | 3915 |
3993 | |
3994 void FullCodeGenerator::LoadContextField(Register dst, int context_index) { | 3916 void FullCodeGenerator::LoadContextField(Register dst, int context_index) { |
3995 __ LoadP(dst, ContextMemOperand(cp, context_index), r0); | 3917 __ LoadP(dst, ContextMemOperand(cp, context_index), r0); |
3996 } | 3918 } |
3997 | 3919 |
3998 | |
3999 void FullCodeGenerator::PushFunctionArgumentForContextAllocation() { | 3920 void FullCodeGenerator::PushFunctionArgumentForContextAllocation() { |
4000 Scope* closure_scope = scope()->ClosureScope(); | 3921 Scope* closure_scope = scope()->ClosureScope(); |
4001 if (closure_scope->is_script_scope() || | 3922 if (closure_scope->is_script_scope() || closure_scope->is_module_scope()) { |
4002 closure_scope->is_module_scope()) { | |
4003 // Contexts nested in the native context have a canonical empty function | 3923 // Contexts nested in the native context have a canonical empty function |
4004 // as their closure, not the anonymous closure containing the global | 3924 // as their closure, not the anonymous closure containing the global |
4005 // code. | 3925 // code. |
4006 __ LoadNativeContextSlot(Context::CLOSURE_INDEX, ip); | 3926 __ LoadNativeContextSlot(Context::CLOSURE_INDEX, ip); |
4007 } else if (closure_scope->is_eval_scope()) { | 3927 } else if (closure_scope->is_eval_scope()) { |
4008 // Contexts created by a call to eval have the same closure as the | 3928 // Contexts created by a call to eval have the same closure as the |
4009 // context calling eval, not the anonymous closure containing the eval | 3929 // context calling eval, not the anonymous closure containing the eval |
4010 // code. Fetch it from the context. | 3930 // code. Fetch it from the context. |
4011 __ LoadP(ip, ContextMemOperand(cp, Context::CLOSURE_INDEX)); | 3931 __ LoadP(ip, ContextMemOperand(cp, Context::CLOSURE_INDEX)); |
4012 } else { | 3932 } else { |
4013 DCHECK(closure_scope->is_function_scope()); | 3933 DCHECK(closure_scope->is_function_scope()); |
4014 __ LoadP(ip, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset)); | 3934 __ LoadP(ip, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset)); |
4015 } | 3935 } |
4016 PushOperand(ip); | 3936 PushOperand(ip); |
4017 } | 3937 } |
4018 | 3938 |
4019 | |
4020 // ---------------------------------------------------------------------------- | 3939 // ---------------------------------------------------------------------------- |
4021 // Non-local control flow support. | 3940 // Non-local control flow support. |
4022 | 3941 |
4023 void FullCodeGenerator::EnterFinallyBlock() { | 3942 void FullCodeGenerator::EnterFinallyBlock() { |
4024 DCHECK(!result_register().is(r4)); | 3943 DCHECK(!result_register().is(r3)); |
4025 // Store pending message while executing finally block. | 3944 // Store pending message while executing finally block. |
4026 ExternalReference pending_message_obj = | 3945 ExternalReference pending_message_obj = |
4027 ExternalReference::address_of_pending_message_obj(isolate()); | 3946 ExternalReference::address_of_pending_message_obj(isolate()); |
4028 __ mov(ip, Operand(pending_message_obj)); | 3947 __ mov(ip, Operand(pending_message_obj)); |
4029 __ LoadP(r4, MemOperand(ip)); | 3948 __ LoadP(r3, MemOperand(ip)); |
4030 PushOperand(r4); | 3949 PushOperand(r3); |
4031 | 3950 |
4032 ClearPendingMessage(); | 3951 ClearPendingMessage(); |
4033 } | 3952 } |
4034 | 3953 |
4035 | |
4036 void FullCodeGenerator::ExitFinallyBlock() { | 3954 void FullCodeGenerator::ExitFinallyBlock() { |
4037 DCHECK(!result_register().is(r4)); | 3955 DCHECK(!result_register().is(r3)); |
4038 // Restore pending message from stack. | 3956 // Restore pending message from stack. |
4039 PopOperand(r4); | 3957 PopOperand(r3); |
4040 ExternalReference pending_message_obj = | 3958 ExternalReference pending_message_obj = |
4041 ExternalReference::address_of_pending_message_obj(isolate()); | 3959 ExternalReference::address_of_pending_message_obj(isolate()); |
4042 __ mov(ip, Operand(pending_message_obj)); | 3960 __ mov(ip, Operand(pending_message_obj)); |
4043 __ StoreP(r4, MemOperand(ip)); | 3961 __ StoreP(r3, MemOperand(ip)); |
4044 } | 3962 } |
4045 | 3963 |
4046 | |
4047 void FullCodeGenerator::ClearPendingMessage() { | 3964 void FullCodeGenerator::ClearPendingMessage() { |
4048 DCHECK(!result_register().is(r4)); | 3965 DCHECK(!result_register().is(r3)); |
4049 ExternalReference pending_message_obj = | 3966 ExternalReference pending_message_obj = |
4050 ExternalReference::address_of_pending_message_obj(isolate()); | 3967 ExternalReference::address_of_pending_message_obj(isolate()); |
4051 __ LoadRoot(r4, Heap::kTheHoleValueRootIndex); | 3968 __ LoadRoot(r3, Heap::kTheHoleValueRootIndex); |
4052 __ mov(ip, Operand(pending_message_obj)); | 3969 __ mov(ip, Operand(pending_message_obj)); |
4053 __ StoreP(r4, MemOperand(ip)); | 3970 __ StoreP(r3, MemOperand(ip)); |
4054 } | 3971 } |
4055 | 3972 |
| 3973 void FullCodeGenerator::EmitLoadStoreICSlot(FeedbackVectorSlot slot) { |
| 3974 DCHECK(!slot.IsInvalid()); |
| 3975 __ mov(VectorStoreICTrampolineDescriptor::SlotRegister(), |
| 3976 Operand(SmiFromSlot(slot))); |
| 3977 } |
4056 | 3978 |
4057 void FullCodeGenerator::DeferredCommands::EmitCommands() { | 3979 void FullCodeGenerator::DeferredCommands::EmitCommands() { |
4058 DCHECK(!result_register().is(r4)); | 3980 DCHECK(!result_register().is(r3)); |
4059 // Restore the accumulator (r3) and token (r4). | 3981 // Restore the accumulator (r2) and token (r3). |
4060 __ Pop(r4, result_register()); | 3982 __ Pop(r3, result_register()); |
4061 for (DeferredCommand cmd : commands_) { | 3983 for (DeferredCommand cmd : commands_) { |
4062 Label skip; | 3984 Label skip; |
4063 __ CmpSmiLiteral(r4, Smi::FromInt(cmd.token), r0); | 3985 __ CmpSmiLiteral(r3, Smi::FromInt(cmd.token), r0); |
4064 __ bne(&skip); | 3986 __ bne(&skip); |
4065 switch (cmd.command) { | 3987 switch (cmd.command) { |
4066 case kReturn: | 3988 case kReturn: |
4067 codegen_->EmitUnwindAndReturn(); | 3989 codegen_->EmitUnwindAndReturn(); |
4068 break; | 3990 break; |
4069 case kThrow: | 3991 case kThrow: |
4070 __ Push(result_register()); | 3992 __ Push(result_register()); |
4071 __ CallRuntime(Runtime::kReThrow); | 3993 __ CallRuntime(Runtime::kReThrow); |
4072 break; | 3994 break; |
4073 case kContinue: | 3995 case kContinue: |
4074 codegen_->EmitContinue(cmd.target); | 3996 codegen_->EmitContinue(cmd.target); |
4075 break; | 3997 break; |
4076 case kBreak: | 3998 case kBreak: |
4077 codegen_->EmitBreak(cmd.target); | 3999 codegen_->EmitBreak(cmd.target); |
4078 break; | 4000 break; |
4079 } | 4001 } |
4080 __ bind(&skip); | 4002 __ bind(&skip); |
4081 } | 4003 } |
4082 } | 4004 } |
4083 | 4005 |
4084 #undef __ | 4006 #undef __ |
4085 | 4007 |
| 4008 #if V8_TARGET_ARCH_S390X |
| 4009 static const FourByteInstr kInterruptBranchInstruction = 0xA7A40011; |
| 4010 static const FourByteInstr kOSRBranchInstruction = 0xA7040011; |
| 4011 static const int16_t kBackEdgeBranchOffset = 0x11 * 2; |
| 4012 #else |
| 4013 static const FourByteInstr kInterruptBranchInstruction = 0xA7A4000D; |
| 4014 static const FourByteInstr kOSRBranchInstruction = 0xA704000D; |
| 4015 static const int16_t kBackEdgeBranchOffset = 0xD * 2; |
| 4016 #endif |
4086 | 4017 |
4087 void BackEdgeTable::PatchAt(Code* unoptimized_code, Address pc, | 4018 void BackEdgeTable::PatchAt(Code* unoptimized_code, Address pc, |
4088 BackEdgeState target_state, | 4019 BackEdgeState target_state, |
4089 Code* replacement_code) { | 4020 Code* replacement_code) { |
4090 Address mov_address = Assembler::target_address_from_return_address(pc); | 4021 Address call_address = Assembler::target_address_from_return_address(pc); |
4091 Address cmp_address = mov_address - 2 * Assembler::kInstrSize; | 4022 Address branch_address = call_address - 4; |
4092 Isolate* isolate = unoptimized_code->GetIsolate(); | 4023 Isolate* isolate = unoptimized_code->GetIsolate(); |
4093 CodePatcher patcher(isolate, cmp_address, 1); | 4024 CodePatcher patcher(isolate, branch_address, 4); |
4094 | 4025 |
4095 switch (target_state) { | 4026 switch (target_state) { |
4096 case INTERRUPT: { | 4027 case INTERRUPT: { |
4097 // <decrement profiling counter> | 4028 // <decrement profiling counter> |
4098 // cmpi r6, 0 | 4029 // bge <ok> ;; patched to GE BRC |
4099 // bge <ok> ;; not changed | 4030 // brasrl r14, <interrupt stub address> |
4100 // mov r12, <interrupt stub address> | |
4101 // mtlr r12 | |
4102 // blrl | |
4103 // <reset profiling counter> | 4031 // <reset profiling counter> |
4104 // ok-label | 4032 // ok-label |
4105 patcher.masm()->cmpi(r6, Operand::Zero()); | 4033 patcher.masm()->brc(ge, Operand(kBackEdgeBranchOffset)); |
4106 break; | 4034 break; |
4107 } | 4035 } |
4108 case ON_STACK_REPLACEMENT: | 4036 case ON_STACK_REPLACEMENT: |
4109 case OSR_AFTER_STACK_CHECK: | 4037 case OSR_AFTER_STACK_CHECK: |
4110 // <decrement profiling counter> | 4038 // <decrement profiling counter> |
4111 // crset | 4039 // brc 0x0, <ok> ;; patched to NOP BRC |
4112 // bge <ok> ;; not changed | 4040 // brasrl r14, <interrupt stub address> |
4113 // mov r12, <on-stack replacement address> | |
4114 // mtlr r12 | |
4115 // blrl | |
4116 // <reset profiling counter> | 4041 // <reset profiling counter> |
4117 // ok-label ----- pc_after points here | 4042 // ok-label ----- pc_after points here |
4118 | 4043 patcher.masm()->brc(CC_NOP, Operand(kBackEdgeBranchOffset)); |
4119 // Set the LT bit such that bge is a NOP | |
4120 patcher.masm()->crset(Assembler::encode_crbit(cr7, CR_LT)); | |
4121 break; | 4044 break; |
4122 } | 4045 } |
4123 | 4046 |
4124 // Replace the stack check address in the mov sequence with the | 4047 // Replace the stack check address in the mov sequence with the |
4125 // entry address of the replacement code. | 4048 // entry address of the replacement code. |
4126 Assembler::set_target_address_at(isolate, mov_address, unoptimized_code, | 4049 Assembler::set_target_address_at(isolate, call_address, unoptimized_code, |
4127 replacement_code->entry()); | 4050 replacement_code->entry()); |
4128 | 4051 |
4129 unoptimized_code->GetHeap()->incremental_marking()->RecordCodeTargetPatch( | 4052 unoptimized_code->GetHeap()->incremental_marking()->RecordCodeTargetPatch( |
4130 unoptimized_code, mov_address, replacement_code); | 4053 unoptimized_code, call_address, replacement_code); |
4131 } | 4054 } |
4132 | 4055 |
4133 | |
4134 BackEdgeTable::BackEdgeState BackEdgeTable::GetBackEdgeState( | 4056 BackEdgeTable::BackEdgeState BackEdgeTable::GetBackEdgeState( |
4135 Isolate* isolate, Code* unoptimized_code, Address pc) { | 4057 Isolate* isolate, Code* unoptimized_code, Address pc) { |
4136 Address mov_address = Assembler::target_address_from_return_address(pc); | 4058 Address call_address = Assembler::target_address_from_return_address(pc); |
4137 Address cmp_address = mov_address - 2 * Assembler::kInstrSize; | 4059 Address branch_address = call_address - 4; |
4138 Address interrupt_address = | 4060 Address interrupt_address = |
4139 Assembler::target_address_at(mov_address, unoptimized_code); | 4061 Assembler::target_address_at(call_address, unoptimized_code); |
4140 | 4062 |
4141 if (Assembler::IsCmpImmediate(Assembler::instr_at(cmp_address))) { | 4063 DCHECK(BRC == Instruction::S390OpcodeValue(branch_address)); |
| 4064 // For interrupt, we expect a branch greater than or equal |
| 4065 // i.e. BRC 0xa, +XXXX (0xA7A4XXXX) |
| 4066 FourByteInstr br_instr = Instruction::InstructionBits( |
| 4067 reinterpret_cast<const byte*>(branch_address)); |
| 4068 if (kInterruptBranchInstruction == br_instr) { |
4142 DCHECK(interrupt_address == isolate->builtins()->InterruptCheck()->entry()); | 4069 DCHECK(interrupt_address == isolate->builtins()->InterruptCheck()->entry()); |
4143 return INTERRUPT; | 4070 return INTERRUPT; |
4144 } | 4071 } |
4145 | 4072 |
4146 DCHECK(Assembler::IsCrSet(Assembler::instr_at(cmp_address))); | 4073 // Expect BRC to be patched to NOP branch. |
| 4074 // i.e. BRC 0x0, +XXXX (0xA704XXXX) |
| 4075 USE(kOSRBranchInstruction); |
| 4076 DCHECK(kOSRBranchInstruction == br_instr); |
4147 | 4077 |
4148 if (interrupt_address == isolate->builtins()->OnStackReplacement()->entry()) { | 4078 if (interrupt_address == isolate->builtins()->OnStackReplacement()->entry()) { |
4149 return ON_STACK_REPLACEMENT; | 4079 return ON_STACK_REPLACEMENT; |
4150 } | 4080 } |
4151 | 4081 |
4152 DCHECK(interrupt_address == | 4082 DCHECK(interrupt_address == |
4153 isolate->builtins()->OsrAfterStackCheck()->entry()); | 4083 isolate->builtins()->OsrAfterStackCheck()->entry()); |
4154 return OSR_AFTER_STACK_CHECK; | 4084 return OSR_AFTER_STACK_CHECK; |
4155 } | 4085 } |
| 4086 |
4156 } // namespace internal | 4087 } // namespace internal |
4157 } // namespace v8 | 4088 } // namespace v8 |
4158 #endif // V8_TARGET_ARCH_PPC | 4089 #endif // V8_TARGET_ARCH_S390 |
OLD | NEW |