Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(563)

Side by Side Diff: src/compiler/ia32/code-generator-ia32.cc

Issue 1259203002: [turbofan] Implement tail calls with differing stack parameter counts (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Fix bugs in frameless tail calls Created 5 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2013 the V8 project authors. All rights reserved. 1 // Copyright 2013 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 #include "src/compiler/code-generator.h" 5 #include "src/compiler/code-generator.h"
6 6
7 #include "src/compiler/code-generator-impl.h" 7 #include "src/compiler/code-generator-impl.h"
8 #include "src/compiler/gap-resolver.h" 8 #include "src/compiler/gap-resolver.h"
9 #include "src/compiler/node-matchers.h" 9 #include "src/compiler/node-matchers.h"
10 #include "src/ia32/assembler-ia32.h" 10 #include "src/ia32/assembler-ia32.h"
(...skipping 266 matching lines...) Expand 10 before | Expand all | Expand 10 after
277 __ j(above_equal, &done, Label::kNear); \ 277 __ j(above_equal, &done, Label::kNear); \
278 if (instr->InputAt(2)->IsRegister()) { \ 278 if (instr->InputAt(2)->IsRegister()) { \
279 __ asm_instr(i.MemoryOperand(3), i.InputRegister(2)); \ 279 __ asm_instr(i.MemoryOperand(3), i.InputRegister(2)); \
280 } else { \ 280 } else { \
281 __ asm_instr(i.MemoryOperand(3), i.InputImmediate(2)); \ 281 __ asm_instr(i.MemoryOperand(3), i.InputImmediate(2)); \
282 } \ 282 } \
283 __ bind(&done); \ 283 __ bind(&done); \
284 } while (false) 284 } while (false)
285 285
286 286
287 void CodeGenerator::AssembleDeconstructActivationRecord() { 287 void CodeGenerator::AssembleTailCallSetup(Instruction* instr) {
Benedikt Meurer 2015/07/30 06:47:24 This is quite a lot of (complex) per-architecture
288 CallDescriptor* descriptor = linkage()->GetIncomingDescriptor(); 288 IA32OperandConverter i(this, instr);
289 int stack_slots = frame()->GetSpillSlotCount(); 289 size_t current_argument = instr->InputCount() - 1;
290 if (descriptor->IsJSFunctionCall() || stack_slots > 0) { 290 int stack_delta = ImmediateOperand::cast(instr->InputAt(current_argument--))
291 __ mov(esp, ebp); 291 ->inline_value();
292 __ pop(ebp); 292 int pushed_parameters =
293 ImmediateOperand::cast(instr->InputAt(current_argument--))
294 ->inline_value();
295 int base_offset = pushed_parameters * kPointerSize;
296 int frame_size = (StandardFrameConstants::kCallerPCOffset -
297 StandardFrameConstants::kMarkerOffset) +
298 frame()->GetFrameSlotCount() * kPointerSize;
299 if (frame()->NeedsFrame()) {
300 base_offset += frame_size;
293 } 301 }
302
303 if (frame()->NeedsFrame() && stack_delta != 0) {
304 __ mov(ebp, Operand(ebp, 0));
305 }
306
307 bool done = false;
308 Register return_reg = no_reg;
309 while (!done) {
310 TailCallOpcode opcode = static_cast<TailCallOpcode>(
311 ImmediateOperand::cast(instr->InputAt(current_argument--))
312 ->inline_value());
313 switch (opcode) {
314 case kPopAndStore: {
315 int location =
316 ImmediateOperand::cast(instr->InputAt(current_argument--))
317 ->inline_value();
318 DCHECK(location != 0);
319 DCHECK(frame()->NeedsFrame()); // Tail calls from elided frames that
320 // require pushing arguments are not
321 // supported.
322 base_offset -= kPointerSize;
323 __ pop(Operand(esp, base_offset + location * kPointerSize));
324 break;
325 }
326 case kStore: {
327 size_t arg = current_argument--;
328 if (HasImmediateInput(instr, arg)) {
329 Immediate value_immediate = i.InputImmediate(arg);
330 int location =
331 ImmediateOperand::cast(instr->InputAt(current_argument--))
332 ->inline_value();
333 DCHECK(location != 0);
334 __ mov(Operand(esp, base_offset + location * kPointerSize),
335 value_immediate);
336 } else {
337 Register value_reg = i.InputRegister(arg);
338 int location =
339 ImmediateOperand::cast(instr->InputAt(current_argument--))
340 ->inline_value();
341 DCHECK(location != 0);
342 __ mov(Operand(esp, base_offset + location * kPointerSize),
343 value_reg);
344 }
345 break;
346 }
347 case kReplaceReturn: {
348 return_reg = i.InputRegister(current_argument--);
349 DCHECK(return_reg.is_valid());
350 __ xchg(return_reg, Operand(esp, base_offset));
351 break;
352 }
353 case kDeconstructFrame: {
354 if (stack_delta > 0) {
355 int delta = (frame()->NeedsFrame() ? frame_size : 0) -
356 (stack_delta - 1) * kPointerSize;
357 if (delta != 0) {
358 if (delta < 0) {
359 __ sub(esp, Immediate(-delta));
360 } else {
361 __ add(esp, Immediate(delta));
362 }
363 base_offset -= delta;
364 }
365 } else if (stack_delta < 0) {
366 if (frame()->NeedsFrame()) {
367 __ add(esp, Immediate(frame_size));
368 base_offset -= frame_size;
369 }
370 int delta = (-stack_delta - 1) * kPointerSize;
371 base_offset -= kPointerSize;
372 __ pop(Operand(esp, delta));
373 if (stack_delta != -1) {
374 if (delta < 0) {
375 __ sub(esp, Immediate(-delta));
376 } else {
377 __ add(esp, Immediate(delta));
378 }
379 base_offset -= delta;
380 }
381 } else {
382 if (frame()->NeedsFrame()) {
383 __ mov(esp, ebp);
384 __ pop(ebp);
385 base_offset -= frame_size;
386 }
387 }
388 break;
389 }
390 case kParametersReady: {
391 if (stack_delta > 0) {
392 __ push(return_reg);
393 base_offset += kPointerSize;
394 }
395 done = true;
396 break;
397 }
398 }
399 }
400
401 // Ensure all of the stack tracking math ends up at the end matching the
402 // predicted delta.
403 DCHECK_EQ(stack_delta * kPointerSize, base_offset);
294 } 404 }
295 405
296 406
297 // Assembles an instruction after register allocation, producing machine code. 407 // Assembles an instruction after register allocation, producing machine code.
298 void CodeGenerator::AssembleArchInstruction(Instruction* instr) { 408 void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
299 IA32OperandConverter i(this, instr); 409 IA32OperandConverter i(this, instr);
300 410
301 switch (ArchOpcodeField::decode(instr->opcode())) { 411 switch (ArchOpcodeField::decode(instr->opcode())) {
302 case kArchCallCodeObject: { 412 case kArchCallCodeObject: {
303 EnsureSpaceForLazyDeopt(); 413 EnsureSpaceForLazyDeopt();
304 if (HasImmediateInput(instr, 0)) { 414 if (HasImmediateInput(instr, 0)) {
305 Handle<Code> code = Handle<Code>::cast(i.InputHeapObject(0)); 415 Handle<Code> code = Handle<Code>::cast(i.InputHeapObject(0));
306 __ call(code, RelocInfo::CODE_TARGET); 416 __ call(code, RelocInfo::CODE_TARGET);
307 } else { 417 } else {
308 Register reg = i.InputRegister(0); 418 Register reg = i.InputRegister(0);
309 __ call(Operand(reg, Code::kHeaderSize - kHeapObjectTag)); 419 __ call(Operand(reg, Code::kHeaderSize - kHeapObjectTag));
310 } 420 }
311 RecordCallPosition(instr); 421 RecordCallPosition(instr);
312 break; 422 break;
313 } 423 }
314 case kArchTailCallCodeObject: { 424 case kArchTailCallCodeObject: {
315 AssembleDeconstructActivationRecord(); 425 AssembleTailCallSetup(instr);
316 if (HasImmediateInput(instr, 0)) { 426 if (HasImmediateInput(instr, 0)) {
317 Handle<Code> code = Handle<Code>::cast(i.InputHeapObject(0)); 427 Handle<Code> code = Handle<Code>::cast(i.InputHeapObject(0));
318 __ jmp(code, RelocInfo::CODE_TARGET); 428 __ jmp(code, RelocInfo::CODE_TARGET);
319 } else { 429 } else {
320 Register reg = i.InputRegister(0); 430 Register reg = i.InputRegister(0);
321 __ jmp(Operand(reg, Code::kHeaderSize - kHeapObjectTag)); 431 __ jmp(Operand(reg, Code::kHeaderSize - kHeapObjectTag));
322 } 432 }
323 break; 433 break;
324 } 434 }
325 case kArchCallJSFunction: { 435 case kArchCallJSFunction: {
326 EnsureSpaceForLazyDeopt(); 436 EnsureSpaceForLazyDeopt();
327 Register func = i.InputRegister(0); 437 Register func = i.InputRegister(0);
328 if (FLAG_debug_code) { 438 if (FLAG_debug_code) {
329 // Check the function's context matches the context argument. 439 // Check the function's context matches the context argument.
330 __ cmp(esi, FieldOperand(func, JSFunction::kContextOffset)); 440 __ cmp(esi, FieldOperand(func, JSFunction::kContextOffset));
331 __ Assert(equal, kWrongFunctionContext); 441 __ Assert(equal, kWrongFunctionContext);
332 } 442 }
333 __ call(FieldOperand(func, JSFunction::kCodeEntryOffset)); 443 __ call(FieldOperand(func, JSFunction::kCodeEntryOffset));
334 RecordCallPosition(instr); 444 RecordCallPosition(instr);
335 break; 445 break;
336 } 446 }
337 case kArchTailCallJSFunction: { 447 case kArchTailCallJSFunction: {
338 Register func = i.InputRegister(0); 448 Register func = i.InputRegister(0);
339 if (FLAG_debug_code) { 449 if (FLAG_debug_code) {
340 // Check the function's context matches the context argument. 450 // Check the function's context matches the context argument.
341 __ cmp(esi, FieldOperand(func, JSFunction::kContextOffset)); 451 __ cmp(esi, FieldOperand(func, JSFunction::kContextOffset));
342 __ Assert(equal, kWrongFunctionContext); 452 __ Assert(equal, kWrongFunctionContext);
343 } 453 }
344 AssembleDeconstructActivationRecord(); 454 AssembleTailCallSetup(instr);
345 __ jmp(FieldOperand(func, JSFunction::kCodeEntryOffset)); 455 __ jmp(FieldOperand(func, JSFunction::kCodeEntryOffset));
346 break; 456 break;
347 } 457 }
348 case kArchPrepareCallCFunction: { 458 case kArchPrepareCallCFunction: {
349 int const num_parameters = MiscField::decode(instr->opcode()); 459 int const num_parameters = MiscField::decode(instr->opcode());
350 __ PrepareCallCFunction(num_parameters, i.TempRegister(0)); 460 __ PrepareCallCFunction(num_parameters, i.TempRegister(0));
351 break; 461 break;
352 } 462 }
353 case kArchCallCFunction: { 463 case kArchCallCFunction: {
354 int const num_parameters = MiscField::decode(instr->opcode()); 464 int const num_parameters = MiscField::decode(instr->opcode());
(...skipping 511 matching lines...) Expand 10 before | Expand all | Expand 10 after
866 __ shl(i.OutputRegister(), 3); 976 __ shl(i.OutputRegister(), 3);
867 } else { 977 } else {
868 __ lea(i.OutputRegister(), i.MemoryOperand()); 978 __ lea(i.OutputRegister(), i.MemoryOperand());
869 } 979 }
870 } else { 980 } else {
871 __ lea(i.OutputRegister(), i.MemoryOperand()); 981 __ lea(i.OutputRegister(), i.MemoryOperand());
872 } 982 }
873 break; 983 break;
874 } 984 }
875 case kIA32Push: 985 case kIA32Push:
986 // Pushes and pops require a frame, otherwise parameter access, which is
987 // esp-relative would be off.
988 DCHECK(frame()->NeedsFrame());
876 if (HasImmediateInput(instr, 0)) { 989 if (HasImmediateInput(instr, 0)) {
877 __ push(i.InputImmediate(0)); 990 __ push(i.InputImmediate(0));
878 } else { 991 } else {
879 __ push(i.InputOperand(0)); 992 __ push(i.InputOperand(0));
880 } 993 }
881 break; 994 break;
882 case kIA32Poke: { 995 case kIA32Poke: {
883 int const slot = MiscField::decode(instr->opcode()); 996 int const slot = MiscField::decode(instr->opcode());
884 if (HasImmediateInput(instr, 0)) { 997 if (HasImmediateInput(instr, 0)) {
885 __ mov(Operand(esp, slot * kPointerSize), i.InputImmediate(0)); 998 __ mov(Operand(esp, slot * kPointerSize), i.InputImmediate(0));
(...skipping 362 matching lines...) Expand 10 before | Expand all | Expand 10 after
1248 // | FP | RET | args | caller frame | 1361 // | FP | RET | args | caller frame |
1249 // ^ esp,ebp 1362 // ^ esp,ebp
1250 1363
1251 // --{ pop ebp }---------------------------------------------------------------- 1364 // --{ pop ebp }----------------------------------------------------------------
1252 // | RET | args | caller frame | 1365 // | RET | args | caller frame |
1253 // ^ esp ^ ebp 1366 // ^ esp ^ ebp
1254 1367
1255 1368
1256 void CodeGenerator::AssemblePrologue() { 1369 void CodeGenerator::AssemblePrologue() {
1257 CallDescriptor* descriptor = linkage()->GetIncomingDescriptor(); 1370 CallDescriptor* descriptor = linkage()->GetIncomingDescriptor();
1258 int stack_slots = frame()->GetSpillSlotCount(); 1371 int stack_slots = frame()->GetFrameSlotCount();
1259 if (descriptor->kind() == CallDescriptor::kCallAddress) { 1372 if (descriptor->kind() == CallDescriptor::kCallAddress) {
1260 // Assemble a prologue similar the to cdecl calling convention. 1373 // Assemble a prologue similar the to cdecl calling convention.
1261 __ push(ebp); 1374 __ push(ebp);
1262 __ mov(ebp, esp); 1375 __ mov(ebp, esp);
1263 const RegList saves = descriptor->CalleeSavedRegisters(); 1376 const RegList saves = descriptor->CalleeSavedRegisters();
1264 if (saves != 0) { // Save callee-saved registers. 1377 if (saves != 0) { // Save callee-saved registers.
1265 int register_save_area_size = 0; 1378 int register_save_area_size = 0;
1266 for (int i = Register::kNumRegisters - 1; i >= 0; i--) { 1379 for (int i = Register::kNumRegisters - 1; i >= 0; i--) {
1267 if (!((1 << i) & saves)) continue; 1380 if (!((1 << i) & saves)) continue;
1268 __ push(Register::from_code(i)); 1381 __ push(Register::from_code(i));
1269 register_save_area_size += kPointerSize; 1382 register_save_area_size += kPointerSize;
1270 } 1383 }
1271 frame()->SetRegisterSaveAreaSize(register_save_area_size); 1384 frame()->SetRegisterSaveAreaSize(register_save_area_size);
1272 } 1385 }
1273 } else if (descriptor->IsJSFunctionCall()) { 1386 } else if (frame()->NeedsFrame()) {
1274 // TODO(turbofan): this prologue is redundant with OSR, but needed for 1387 // TODO(turbofan): this prologue is redundant with OSR, but needed for
1275 // code aging. 1388 // code aging.
1276 CompilationInfo* info = this->info(); 1389 CompilationInfo* info = this->info();
1277 __ Prologue(info->IsCodePreAgingActive()); 1390 if (descriptor->IsJSFunctionCall()) {
1278 frame()->SetRegisterSaveAreaSize( 1391 __ Prologue(info->IsCodePreAgingActive());
1279 StandardFrameConstants::kFixedFrameSizeFromFp); 1392 } else {
1280 } else if (needs_frame_) { 1393 __ StubPrologue();
1281 __ StubPrologue(); 1394 }
1282 frame()->SetRegisterSaveAreaSize( 1395 frame()->SetRegisterSaveAreaSize(
1283 StandardFrameConstants::kFixedFrameSizeFromFp); 1396 StandardFrameConstants::kFixedFrameSizeFromFp);
1284 } 1397 }
1285 1398
1286 if (info()->is_osr()) { 1399 if (info()->is_osr()) {
1287 // TurboFan OSR-compiled functions cannot be entered directly. 1400 // TurboFan OSR-compiled functions cannot be entered directly.
1288 __ Abort(kShouldNotDirectlyEnterOsrFunction); 1401 __ Abort(kShouldNotDirectlyEnterOsrFunction);
1289 1402
1290 // Unoptimized code jumps directly to this entrypoint while the unoptimized 1403 // Unoptimized code jumps directly to this entrypoint while the unoptimized
1291 // frame is still on the stack. Optimized code uses OSR values directly from 1404 // frame is still on the stack. Optimized code uses OSR values directly from
1292 // the unoptimized frame. Thus, all that needs to be done is to allocate the 1405 // the unoptimized frame. Thus, all that needs to be done is to allocate the
1293 // remaining stack slots. 1406 // remaining stack slots.
1294 if (FLAG_code_comments) __ RecordComment("-- OSR entrypoint --"); 1407 if (FLAG_code_comments) __ RecordComment("-- OSR entrypoint --");
1295 osr_pc_offset_ = __ pc_offset(); 1408 osr_pc_offset_ = __ pc_offset();
1296 // TODO(titzer): cannot address target function == local #-1 1409 // TODO(titzer): cannot address target function == local #-1
1297 __ mov(edi, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset)); 1410 __ mov(edi, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
1298 DCHECK(stack_slots >= frame()->GetOsrStackSlotCount()); 1411 DCHECK(stack_slots >= frame()->GetOsrStackSlotCount());
1299 stack_slots -= frame()->GetOsrStackSlotCount(); 1412 stack_slots -= frame()->GetOsrStackSlotCount();
1300 } 1413 }
1301 1414
1302 if (stack_slots > 0) { 1415 if (stack_slots > 0) {
1303 // Allocate the stack slots used by this frame. 1416 // Allocate the stack slots used by this frame.
1304 __ sub(esp, Immediate(stack_slots * kPointerSize)); 1417 __ sub(esp, Immediate(stack_slots * kPointerSize));
1305 } 1418 }
1306 } 1419 }
1307 1420
1308 1421
1309 void CodeGenerator::AssembleReturn() { 1422 void CodeGenerator::AssembleReturn() {
1310 CallDescriptor* descriptor = linkage()->GetIncomingDescriptor(); 1423 CallDescriptor* descriptor = linkage()->GetIncomingDescriptor();
1311 int stack_slots = frame()->GetSpillSlotCount(); 1424 int stack_slots = frame()->GetFrameSlotCount();
1312 if (descriptor->kind() == CallDescriptor::kCallAddress) { 1425 if (descriptor->kind() == CallDescriptor::kCallAddress) {
1313 const RegList saves = descriptor->CalleeSavedRegisters(); 1426 const RegList saves = descriptor->CalleeSavedRegisters();
1314 if (frame()->GetRegisterSaveAreaSize() > 0) { 1427 if (frame()->GetRegisterSaveAreaSize() > 0) {
1315 // Remove this frame's spill slots first. 1428 // Remove this frame's spill slots first.
1316 if (stack_slots > 0) { 1429 if (stack_slots > 0) {
1317 __ add(esp, Immediate(stack_slots * kPointerSize)); 1430 __ add(esp, Immediate(stack_slots * kPointerSize));
1318 } 1431 }
1319 // Restore registers. 1432 // Restore registers.
1320 if (saves != 0) { 1433 if (saves != 0) {
1321 for (int i = 0; i < Register::kNumRegisters; i++) { 1434 for (int i = 0; i < Register::kNumRegisters; i++) {
1322 if (!((1 << i) & saves)) continue; 1435 if (!((1 << i) & saves)) continue;
1323 __ pop(Register::from_code(i)); 1436 __ pop(Register::from_code(i));
1324 } 1437 }
1325 } 1438 }
1326 __ pop(ebp); // Pop caller's frame pointer. 1439 __ pop(ebp); // Pop caller's frame pointer.
1327 __ ret(0); 1440 __ ret(0);
1328 } else { 1441 } else {
1329 // No saved registers. 1442 // No saved registers.
1330 __ mov(esp, ebp); // Move stack pointer back to frame pointer. 1443 __ mov(esp, ebp); // Move stack pointer back to frame pointer.
1331 __ pop(ebp); // Pop caller's frame pointer. 1444 __ pop(ebp); // Pop caller's frame pointer.
1332 __ ret(0); 1445 __ ret(0);
1333 } 1446 }
1334 } else if (descriptor->IsJSFunctionCall() || needs_frame_) { 1447 } else if (frame()->NeedsFrame()) {
1335 // Canonicalize JSFunction return sites for now. 1448 // Canonicalize JSFunction return sites for now.
1336 if (return_label_.is_bound()) { 1449 if (return_label_.is_bound()) {
1337 __ jmp(&return_label_); 1450 __ jmp(&return_label_);
1338 } else { 1451 } else {
1339 __ bind(&return_label_); 1452 __ bind(&return_label_);
1340 __ mov(esp, ebp); // Move stack pointer back to frame pointer. 1453 __ mov(esp, ebp); // Move stack pointer back to frame pointer.
1341 __ pop(ebp); // Pop caller's frame pointer. 1454 __ pop(ebp); // Pop caller's frame pointer.
1342 int pop_count = descriptor->IsJSFunctionCall() 1455 int pop_count = descriptor->IsJSFunctionCall()
1343 ? static_cast<int>(descriptor->JSParameterCount()) 1456 ? static_cast<int>(descriptor->JSParameterCount())
1344 : (info()->IsStub() 1457 : (info()->IsStub()
(...skipping 196 matching lines...) Expand 10 before | Expand all | Expand 10 after
1541 __ Nop(padding_size); 1654 __ Nop(padding_size);
1542 } 1655 }
1543 } 1656 }
1544 } 1657 }
1545 1658
1546 #undef __ 1659 #undef __
1547 1660
1548 } // namespace compiler 1661 } // namespace compiler
1549 } // namespace internal 1662 } // namespace internal
1550 } // namespace v8 1663 } // namespace v8
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698