OLD | NEW |
1 // Copyright 2014 the V8 project authors. All rights reserved. | 1 // Copyright 2014 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_PPC |
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" |
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
82 }; | 82 }; |
83 | 83 |
84 | 84 |
85 // Generate code for a JS function. On entry to the function the receiver | 85 // Generate code for a JS function. On entry to the function the receiver |
86 // and arguments have been pushed on the stack left to right. The actual | 86 // and arguments have been pushed on the stack left to right. The actual |
87 // argument count matches the formal parameter count expected by the | 87 // argument count matches the formal parameter count expected by the |
88 // function. | 88 // function. |
89 // | 89 // |
90 // The live registers are: | 90 // The live registers are: |
91 // o r4: the JS function object being called (i.e., ourselves) | 91 // o r4: the JS function object being called (i.e., ourselves) |
| 92 // o r6: the new target value |
92 // o cp: our context | 93 // o cp: our context |
93 // o fp: our caller's frame pointer (aka r31) | 94 // o fp: our caller's frame pointer (aka r31) |
94 // o sp: stack pointer | 95 // o sp: stack pointer |
95 // o lr: return address | 96 // o lr: return address |
96 // o ip: our own function entry (required by the prologue) | 97 // o ip: our own function entry (required by the prologue) |
97 // | 98 // |
98 // The function builds a JS frame. Please see JavaScriptFrameConstants in | 99 // The function builds a JS frame. Please see JavaScriptFrameConstants in |
99 // frames-ppc.h for its layout. | 100 // frames-ppc.h for its layout. |
100 void FullCodeGenerator::Generate() { | 101 void FullCodeGenerator::Generate() { |
101 CompilationInfo* info = info_; | 102 CompilationInfo* info = info_; |
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
180 if (info->scope()->num_heap_slots() > 0) { | 181 if (info->scope()->num_heap_slots() > 0) { |
181 // Argument to NewContext is the function, which is still in r4. | 182 // Argument to NewContext is the function, which is still in r4. |
182 Comment cmnt(masm_, "[ Allocate context"); | 183 Comment cmnt(masm_, "[ Allocate context"); |
183 bool need_write_barrier = true; | 184 bool need_write_barrier = true; |
184 int slots = info->scope()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS; | 185 int slots = info->scope()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS; |
185 if (info->scope()->is_script_scope()) { | 186 if (info->scope()->is_script_scope()) { |
186 __ push(r4); | 187 __ push(r4); |
187 __ Push(info->scope()->GetScopeInfo(info->isolate())); | 188 __ Push(info->scope()->GetScopeInfo(info->isolate())); |
188 __ CallRuntime(Runtime::kNewScriptContext, 2); | 189 __ CallRuntime(Runtime::kNewScriptContext, 2); |
189 PrepareForBailoutForId(BailoutId::ScriptContext(), TOS_REG); | 190 PrepareForBailoutForId(BailoutId::ScriptContext(), TOS_REG); |
190 } else if (slots <= FastNewContextStub::kMaximumSlots) { | 191 // The new target value is not used, clobbering is safe. |
191 FastNewContextStub stub(isolate(), slots); | 192 DCHECK_NULL(info->scope()->new_target_var()); |
192 __ CallStub(&stub); | |
193 // Result of FastNewContextStub is always in new space. | |
194 need_write_barrier = false; | |
195 } else { | 193 } else { |
196 __ push(r4); | 194 if (info->scope()->new_target_var() != nullptr) { |
197 __ CallRuntime(Runtime::kNewFunctionContext, 1); | 195 __ push(r6); // Preserve new target. |
| 196 } |
| 197 if (slots <= FastNewContextStub::kMaximumSlots) { |
| 198 FastNewContextStub stub(isolate(), slots); |
| 199 __ CallStub(&stub); |
| 200 // Result of FastNewContextStub is always in new space. |
| 201 need_write_barrier = false; |
| 202 } else { |
| 203 __ push(r4); |
| 204 __ CallRuntime(Runtime::kNewFunctionContext, 1); |
| 205 } |
| 206 if (info->scope()->new_target_var() != nullptr) { |
| 207 __ pop(r6); // Preserve new target. |
| 208 } |
198 } | 209 } |
199 function_in_register_r4 = false; | 210 function_in_register_r4 = false; |
200 // Context is returned in r3. It replaces the context passed to us. | 211 // Context is returned in r3. It replaces the context passed to us. |
201 // It's saved in the stack and kept live in cp. | 212 // It's saved in the stack and kept live in cp. |
202 __ mr(cp, r3); | 213 __ mr(cp, r3); |
203 __ StoreP(r3, MemOperand(fp, StandardFrameConstants::kContextOffset)); | 214 __ StoreP(r3, MemOperand(fp, StandardFrameConstants::kContextOffset)); |
204 // Copy any necessary parameters into the context. | 215 // Copy any necessary parameters into the context. |
205 int num_parameters = info->scope()->num_parameters(); | 216 int num_parameters = info->scope()->num_parameters(); |
206 int first_parameter = info->scope()->has_this_declaration() ? -1 : 0; | 217 int first_parameter = info->scope()->has_this_declaration() ? -1 : 0; |
207 for (int i = first_parameter; i < num_parameters; i++) { | 218 for (int i = first_parameter; i < num_parameters; i++) { |
208 Variable* var = (i == -1) ? scope()->receiver() : scope()->parameter(i); | 219 Variable* var = (i == -1) ? scope()->receiver() : scope()->parameter(i); |
209 if (var->IsContextSlot()) { | 220 if (var->IsContextSlot()) { |
210 int parameter_offset = StandardFrameConstants::kCallerSPOffset + | 221 int parameter_offset = StandardFrameConstants::kCallerSPOffset + |
211 (num_parameters - 1 - i) * kPointerSize; | 222 (num_parameters - 1 - i) * kPointerSize; |
212 // Load parameter from stack. | 223 // Load parameter from stack. |
213 __ LoadP(r3, MemOperand(fp, parameter_offset), r0); | 224 __ LoadP(r3, MemOperand(fp, parameter_offset), r0); |
214 // Store it in the context. | 225 // Store it in the context. |
215 MemOperand target = ContextMemOperand(cp, var->index()); | 226 MemOperand target = ContextMemOperand(cp, var->index()); |
216 __ StoreP(r3, target, r0); | 227 __ StoreP(r3, target, r0); |
217 | 228 |
218 // Update the write barrier. | 229 // Update the write barrier. |
219 if (need_write_barrier) { | 230 if (need_write_barrier) { |
220 __ RecordWriteContextSlot(cp, target.offset(), r3, r6, | 231 __ RecordWriteContextSlot(cp, target.offset(), r3, r5, |
221 kLRHasBeenSaved, kDontSaveFPRegs); | 232 kLRHasBeenSaved, kDontSaveFPRegs); |
222 } else if (FLAG_debug_code) { | 233 } else if (FLAG_debug_code) { |
223 Label done; | 234 Label done; |
224 __ JumpIfInNewSpace(cp, r3, &done); | 235 __ JumpIfInNewSpace(cp, r3, &done); |
225 __ Abort(kExpectedNewSpaceObject); | 236 __ Abort(kExpectedNewSpaceObject); |
226 __ bind(&done); | 237 __ bind(&done); |
227 } | 238 } |
228 } | 239 } |
229 } | 240 } |
230 } | 241 } |
| 242 |
| 243 // Register holding this function and new target are both trashed in case we |
| 244 // bailout here. But since that can happen only when new target is not used |
| 245 // and we allocate a context, the value of |function_in_register| is correct. |
231 PrepareForBailoutForId(BailoutId::FunctionContext(), NO_REGISTERS); | 246 PrepareForBailoutForId(BailoutId::FunctionContext(), NO_REGISTERS); |
232 | 247 |
233 // Function register is trashed in case we bailout here. But since that | |
234 // could happen only when we allocate a context the value of | |
235 // |function_in_register_r4| is correct. | |
236 | |
237 // 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 |
238 // derived constructors with super calls. | 249 // derived constructors with super calls. |
239 Variable* this_function_var = scope()->this_function_var(); | 250 Variable* this_function_var = scope()->this_function_var(); |
240 if (this_function_var != nullptr) { | 251 if (this_function_var != nullptr) { |
241 Comment cmnt(masm_, "[ This function"); | 252 Comment cmnt(masm_, "[ This function"); |
242 if (!function_in_register_r4) { | 253 if (!function_in_register_r4) { |
243 __ LoadP(r4, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset)); | 254 __ LoadP(r4, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset)); |
244 // The write barrier clobbers register again, keep it marked as such. | 255 // The write barrier clobbers register again, keep it marked as such. |
245 } | 256 } |
246 SetVar(this_function_var, r4, r3, r5); | 257 SetVar(this_function_var, r4, r3, r5); |
247 } | 258 } |
248 | 259 |
| 260 // Possibly set up a local binding to the new target value. |
249 Variable* new_target_var = scope()->new_target_var(); | 261 Variable* new_target_var = scope()->new_target_var(); |
250 if (new_target_var != nullptr) { | 262 if (new_target_var != nullptr) { |
251 Comment cmnt(masm_, "[ new.target"); | 263 Comment cmnt(masm_, "[ new.target"); |
252 | 264 SetVar(new_target_var, r6, r3, r5); |
253 // Get the frame pointer for the calling frame. | |
254 __ LoadP(r5, MemOperand(fp, StandardFrameConstants::kCallerFPOffset)); | |
255 | |
256 // Skip the arguments adaptor frame if it exists. | |
257 __ LoadP(r4, MemOperand(r5, StandardFrameConstants::kContextOffset)); | |
258 __ CmpSmiLiteral(r4, Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR), r0); | |
259 Label skip; | |
260 __ bne(&skip); | |
261 __ LoadP(r5, MemOperand(r5, StandardFrameConstants::kCallerFPOffset)); | |
262 __ bind(&skip); | |
263 | |
264 // Check the marker in the calling frame. | |
265 __ LoadP(r4, MemOperand(r5, StandardFrameConstants::kMarkerOffset)); | |
266 __ CmpSmiLiteral(r4, Smi::FromInt(StackFrame::CONSTRUCT), r0); | |
267 Label non_construct_frame, done; | |
268 function_in_register_r4 = false; | |
269 | |
270 __ bne(&non_construct_frame); | |
271 __ LoadP(r3, MemOperand(r5, ConstructFrameConstants::kNewTargetOffset)); | |
272 __ b(&done); | |
273 | |
274 __ bind(&non_construct_frame); | |
275 __ LoadRoot(r3, Heap::kUndefinedValueRootIndex); | |
276 __ bind(&done); | |
277 | |
278 SetVar(new_target_var, r3, r5, r6); | |
279 } | 265 } |
280 | 266 |
281 Variable* arguments = scope()->arguments(); | 267 Variable* arguments = scope()->arguments(); |
282 if (arguments != NULL) { | 268 if (arguments != NULL) { |
283 // Function uses arguments object. | 269 // Function uses arguments object. |
284 Comment cmnt(masm_, "[ Allocate arguments object"); | 270 Comment cmnt(masm_, "[ Allocate arguments object"); |
285 DCHECK(r4.is(ArgumentsAccessNewDescriptor::function())); | 271 DCHECK(r4.is(ArgumentsAccessNewDescriptor::function())); |
286 if (!function_in_register_r4) { | 272 if (!function_in_register_r4) { |
287 // Load this again, if it's used by the local context below. | 273 // Load this again, if it's used by the local context below. |
288 __ LoadP(r4, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset)); | 274 __ LoadP(r4, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset)); |
(...skipping 4630 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4919 return ON_STACK_REPLACEMENT; | 4905 return ON_STACK_REPLACEMENT; |
4920 } | 4906 } |
4921 | 4907 |
4922 DCHECK(interrupt_address == | 4908 DCHECK(interrupt_address == |
4923 isolate->builtins()->OsrAfterStackCheck()->entry()); | 4909 isolate->builtins()->OsrAfterStackCheck()->entry()); |
4924 return OSR_AFTER_STACK_CHECK; | 4910 return OSR_AFTER_STACK_CHECK; |
4925 } | 4911 } |
4926 } // namespace internal | 4912 } // namespace internal |
4927 } // namespace v8 | 4913 } // namespace v8 |
4928 #endif // V8_TARGET_ARCH_PPC | 4914 #endif // V8_TARGET_ARCH_PPC |
OLD | NEW |