 Chromium Code Reviews
 Chromium Code Reviews Issue 8462010:
  Add a level of indirection to exception handler addresses.  (Closed) 
  Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
    
  
    Issue 8462010:
  Add a level of indirection to exception handler addresses.  (Closed) 
  Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge| OLD | NEW | 
|---|---|
| 1 // Copyright 2011 the V8 project authors. All rights reserved. | 1 // Copyright 2011 the V8 project authors. All rights reserved. | 
| 2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without | 
| 3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are | 
| 4 // met: | 4 // met: | 
| 5 // | 5 // | 
| 6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright | 
| 7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. | 
| 8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above | 
| 9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following | 
| 10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided | 
| (...skipping 2399 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2410 movq(dst, SafepointRegisterSlot(src)); | 2410 movq(dst, SafepointRegisterSlot(src)); | 
| 2411 } | 2411 } | 
| 2412 | 2412 | 
| 2413 | 2413 | 
| 2414 Operand MacroAssembler::SafepointRegisterSlot(Register reg) { | 2414 Operand MacroAssembler::SafepointRegisterSlot(Register reg) { | 
| 2415 return Operand(rsp, SafepointRegisterStackIndex(reg.code()) * kPointerSize); | 2415 return Operand(rsp, SafepointRegisterStackIndex(reg.code()) * kPointerSize); | 
| 2416 } | 2416 } | 
| 2417 | 2417 | 
| 2418 | 2418 | 
| 2419 void MacroAssembler::PushTryHandler(CodeLocation try_location, | 2419 void MacroAssembler::PushTryHandler(CodeLocation try_location, | 
| 2420 HandlerType type) { | 2420 HandlerType type, | 
| 2421 int handler_index) { | |
| 2421 // Adjust this code if not the case. | 2422 // Adjust this code if not the case. | 
| 2422 STATIC_ASSERT(StackHandlerConstants::kSize == 5 * kPointerSize); | 2423 STATIC_ASSERT(StackHandlerConstants::kSize == 5 * kPointerSize); | 
| 2423 STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0 * kPointerSize); | 2424 STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0); | 
| 2424 STATIC_ASSERT(StackHandlerConstants::kContextOffset == 1 * kPointerSize); | 2425 STATIC_ASSERT(StackHandlerConstants::kCodeOffset == 1 * kPointerSize); | 
| 2425 STATIC_ASSERT(StackHandlerConstants::kFPOffset == 2 * kPointerSize); | 2426 STATIC_ASSERT(StackHandlerConstants::kStateOffset == 2 * kPointerSize); | 
| 2426 STATIC_ASSERT(StackHandlerConstants::kStateOffset == 3 * kPointerSize); | 2427 STATIC_ASSERT(StackHandlerConstants::kContextOffset == 3 * kPointerSize); | 
| 2427 STATIC_ASSERT(StackHandlerConstants::kPCOffset == 4 * kPointerSize); | 2428 STATIC_ASSERT(StackHandlerConstants::kFPOffset == 4 * kPointerSize); | 
| 2428 | 2429 | 
| 2429 // The pc (return address) is already on TOS. This code pushes state, | 2430 // We will build up the handler from the bottom by pushing on the stack. | 
| 2430 // frame pointer, context, and current handler. | 2431 // First compute the state and push the frame pointer and context. | 
| 2432 unsigned state = StackHandler::OffsetField::encode(handler_index); | |
| 2431 if (try_location == IN_JAVASCRIPT) { | 2433 if (try_location == IN_JAVASCRIPT) { | 
| 2432 if (type == TRY_CATCH_HANDLER) { | |
| 2433 push(Immediate(StackHandler::TRY_CATCH)); | |
| 2434 } else { | |
| 2435 push(Immediate(StackHandler::TRY_FINALLY)); | |
| 2436 } | |
| 2437 push(rbp); | 2434 push(rbp); | 
| 2438 push(rsi); | 2435 push(rsi); | 
| 2436 state |= (type == TRY_CATCH_HANDLER) | |
| 2437 ? StackHandler::KindField::encode(StackHandler::TRY_CATCH) | |
| 2438 : StackHandler::KindField::encode(StackHandler::TRY_FINALLY); | |
| 2439 } else { | 2439 } else { | 
| 2440 ASSERT(try_location == IN_JS_ENTRY); | 2440 ASSERT(try_location == IN_JS_ENTRY); | 
| 2441 // The frame pointer does not point to a JS frame so we save NULL | 2441 // The frame pointer does not point to a JS frame so we save NULL for | 
| 2442 // for rbp. We expect the code throwing an exception to check rbp | 2442 // rbp. We expect the code throwing an exception to check rbp before | 
| 2443 // before dereferencing it to restore the context. | 2443 // dereferencing it to restore the context. | 
| 2444 push(Immediate(StackHandler::ENTRY)); | |
| 2445 push(Immediate(0)); // NULL frame pointer. | 2444 push(Immediate(0)); // NULL frame pointer. | 
| 2446 Push(Smi::FromInt(0)); // No context. | 2445 Push(Smi::FromInt(0)); // No context. | 
| 2446 state |= StackHandler::KindField::encode(StackHandler::ENTRY); | |
| 2447 } | 2447 } | 
| 2448 // Save the current handler. | 2448 | 
| 2449 Operand handler_operand = | 2449 // Push the state and the code object. | 
| 2450 ExternalOperand(ExternalReference(Isolate::kHandlerAddress, isolate())); | 2450 push(Immediate(state)); | 
| 2451 push(handler_operand); | 2451 Push(CodeObject()); | 
| 2452 // Link this handler. | 2452 | 
| 2453 movq(handler_operand, rsp); | 2453 // Link the current handler as the next handler. | 
| 2454 ExternalReference handler_address(Isolate::kHandlerAddress, isolate()); | |
| 2455 push(ExternalOperand(handler_address)); | |
| 2456 // Set this new handler as the current one. | |
| 2457 movq(ExternalOperand(handler_address), rsp); | |
| 2454 } | 2458 } | 
| 2455 | 2459 | 
| 2456 | 2460 | 
| 2457 void MacroAssembler::PopTryHandler() { | 2461 void MacroAssembler::PopTryHandler() { | 
| 2458 ASSERT_EQ(0, StackHandlerConstants::kNextOffset); | 2462 STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0); | 
| 2459 // Unlink this handler. | 2463 ExternalReference handler_address(Isolate::kHandlerAddress, isolate()); | 
| 2460 Operand handler_operand = | 2464 pop(ExternalOperand(handler_address)); | 
| 2461 ExternalOperand(ExternalReference(Isolate::kHandlerAddress, isolate())); | |
| 2462 pop(handler_operand); | |
| 2463 // Remove the remaining fields. | |
| 2464 addq(rsp, Immediate(StackHandlerConstants::kSize - kPointerSize)); | 2465 addq(rsp, Immediate(StackHandlerConstants::kSize - kPointerSize)); | 
| 2465 } | 2466 } | 
| 2466 | 2467 | 
| 2467 | 2468 | 
| 2468 void MacroAssembler::Throw(Register value) { | 2469 void MacroAssembler::Throw(Register value) { | 
| 2469 // Adjust this code if not the case. | 2470 // Adjust this code if not the case. | 
| 2470 STATIC_ASSERT(StackHandlerConstants::kSize == 5 * kPointerSize); | 2471 STATIC_ASSERT(StackHandlerConstants::kSize == 5 * kPointerSize); | 
| 2471 STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0 * kPointerSize); | 2472 STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0); | 
| 2472 STATIC_ASSERT(StackHandlerConstants::kContextOffset == 1 * kPointerSize); | 2473 STATIC_ASSERT(StackHandlerConstants::kCodeOffset == 1 * kPointerSize); | 
| 2473 STATIC_ASSERT(StackHandlerConstants::kFPOffset == 2 * kPointerSize); | 2474 STATIC_ASSERT(StackHandlerConstants::kStateOffset == 2 * kPointerSize); | 
| 2474 STATIC_ASSERT(StackHandlerConstants::kStateOffset == 3 * kPointerSize); | 2475 STATIC_ASSERT(StackHandlerConstants::kContextOffset == 3 * kPointerSize); | 
| 2475 STATIC_ASSERT(StackHandlerConstants::kPCOffset == 4 * kPointerSize); | 2476 STATIC_ASSERT(StackHandlerConstants::kFPOffset == 4 * kPointerSize); | 
| 2476 // Keep thrown value in rax. | 2477 | 
| 2478 // The exception is expected in rax. | |
| 2477 if (!value.is(rax)) { | 2479 if (!value.is(rax)) { | 
| 2478 movq(rax, value); | 2480 movq(rax, value); | 
| 2479 } | 2481 } | 
| 2482 // Drop the stack pointer to the top of the top handler. | |
| 2483 ExternalReference handler_address(Isolate::kHandlerAddress, isolate()); | |
| 2484 movq(rsp, ExternalOperand(handler_address)); | |
| 2485 // Restore the next handler. | |
| 2486 pop(ExternalOperand(handler_address)); | |
| 2480 | 2487 | 
| 2481 ExternalReference handler_address(Isolate::kHandlerAddress, isolate()); | 2488 // Remove the code object and state, compute the handler address in rdi. | 
| 2482 Operand handler_operand = ExternalOperand(handler_address); | 2489 pop(rdi); // Code object. | 
| 2483 movq(rsp, handler_operand); | 2490 pop(rdx); // Offset and state. | 
| 2484 // get next in chain | 2491 // The handler table is a fixed array of (smi-tagged) code offsets. | 
| 2485 pop(handler_operand); | 2492 movq(rbx, FieldOperand(rdi, Code::kHandlerTableOffset)); | 
| 2493 shr(rdx, Immediate(StackHandler::kKindWidth)); | |
| 2494 movq(rdx, FieldOperand(rbx, rdx, times_8, FixedArray::kHeaderSize)); | |
| 2495 SmiToInteger64(rdx, rdx); | |
| 2496 lea(rdi, FieldOperand(rdi, rdx, times_1, Code::kHeaderSize)); | |
| 2497 | |
| 2498 // Restore the context and frame pointer. | |
| 2486 pop(rsi); // Context. | 2499 pop(rsi); // Context. | 
| 2487 pop(rbp); // Frame pointer. | 2500 pop(rbp); // Frame pointer. | 
| 2488 pop(rdx); // State. | |
| 2489 | 2501 | 
| 2490 // If the handler is a JS frame, restore the context to the frame. | 2502 // If the handler is a JS frame, restore the context to the frame. | 
| 2491 // (rdx == ENTRY) == (rbp == 0) == (rsi == 0), so we could test any | 2503 // (kind == ENTRY) == (rbp == 0) == (rsi == 0), so we could test either | 
| 2492 // of them. | 2504 // rbp or rsi. | 
| 2493 Label skip; | 2505 Label skip; | 
| 2494 cmpq(rdx, Immediate(StackHandler::ENTRY)); | 2506 testq(rsi, rsi); | 
| 2495 j(equal, &skip, Label::kNear); | 2507 j(zero, &skip, Label::kNear); | 
| 2496 movq(Operand(rbp, StandardFrameConstants::kContextOffset), rsi); | 2508 movq(Operand(rbp, StandardFrameConstants::kContextOffset), rsi); | 
| 2497 bind(&skip); | 2509 bind(&skip); | 
| 2498 | 2510 | 
| 2499 ret(0); | 2511 // Jump to the handler code. | 
| 2512 jmp(rdi); | |
| 2500 } | 2513 } | 
| 2501 | 2514 | 
| 2502 | 2515 | 
| 2503 void MacroAssembler::ThrowUncatchable(UncatchableExceptionType type, | 2516 void MacroAssembler::ThrowUncatchable(UncatchableExceptionType type, | 
| 2504 Register value) { | 2517 Register value) { | 
| 2505 // Adjust this code if not the case. | 2518 // Adjust this code if not the case. | 
| 2506 STATIC_ASSERT(StackHandlerConstants::kSize == 5 * kPointerSize); | 2519 STATIC_ASSERT(StackHandlerConstants::kSize == 5 * kPointerSize); | 
| 2507 STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0 * kPointerSize); | 2520 STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0); | 
| 2508 STATIC_ASSERT(StackHandlerConstants::kContextOffset == 1 * kPointerSize); | 2521 STATIC_ASSERT(StackHandlerConstants::kCodeOffset == 1 * kPointerSize); | 
| 2509 STATIC_ASSERT(StackHandlerConstants::kFPOffset == 2 * kPointerSize); | 2522 STATIC_ASSERT(StackHandlerConstants::kStateOffset == 2 * kPointerSize); | 
| 2510 STATIC_ASSERT(StackHandlerConstants::kStateOffset == 3 * kPointerSize); | 2523 STATIC_ASSERT(StackHandlerConstants::kContextOffset == 3 * kPointerSize); | 
| 2511 STATIC_ASSERT(StackHandlerConstants::kPCOffset == 4 * kPointerSize); | 2524 STATIC_ASSERT(StackHandlerConstants::kFPOffset == 4 * kPointerSize); | 
| 2512 | 2525 | 
| 2513 // The exception is expected in rax. | 2526 // The exception is expected in rax. | 
| 2514 if (type == OUT_OF_MEMORY) { | 2527 if (type == OUT_OF_MEMORY) { | 
| 2515 // Set external caught exception to false. | 2528 // Set external caught exception to false. | 
| 2516 ExternalReference external_caught(Isolate::kExternalCaughtExceptionAddress, | 2529 ExternalReference external_caught(Isolate::kExternalCaughtExceptionAddress, | 
| 2517 isolate()); | 2530 isolate()); | 
| 2518 Set(rax, static_cast<int64_t>(false)); | 2531 Set(rax, static_cast<int64_t>(false)); | 
| 2519 Store(external_caught, rax); | 2532 Store(external_caught, rax); | 
| 2520 | 2533 | 
| 2521 // Set pending exception and rax to out of memory exception. | 2534 // Set pending exception and rax to out of memory exception. | 
| 2522 ExternalReference pending_exception(Isolate::kPendingExceptionAddress, | 2535 ExternalReference pending_exception(Isolate::kPendingExceptionAddress, | 
| 2523 isolate()); | 2536 isolate()); | 
| 2524 movq(rax, Failure::OutOfMemoryException(), RelocInfo::NONE); | 2537 movq(rax, Failure::OutOfMemoryException(), RelocInfo::NONE); | 
| 2525 Store(pending_exception, rax); | 2538 Store(pending_exception, rax); | 
| 2526 } else if (!value.is(rax)) { | 2539 } else if (!value.is(rax)) { | 
| 2527 movq(rax, value); | 2540 movq(rax, value); | 
| 2528 } | 2541 } | 
| 2529 | 2542 | 
| 2530 // Drop the stack pointer to the top of the top stack handler. | 2543 // Drop the stack pointer to the top of the top stack handler. | 
| 2531 ExternalReference handler_address(Isolate::kHandlerAddress, isolate()); | 2544 ExternalReference handler_address(Isolate::kHandlerAddress, isolate()); | 
| 2532 Load(rsp, handler_address); | 2545 Load(rsp, handler_address); | 
| 2533 | 2546 | 
| 2534 // Unwind the handlers until the top ENTRY handler is found. | 2547 // Unwind the handlers until the top ENTRY handler is found. | 
| 2535 Label fetch_next, check_kind; | 2548 Label fetch_next, check_kind; | 
| 2536 jmp(&check_kind, Label::kNear); | 2549 jmp(&check_kind, Label::kNear); | 
| 2537 bind(&fetch_next); | 2550 bind(&fetch_next); | 
| 2538 movq(rsp, Operand(rsp, StackHandlerConstants::kNextOffset)); | 2551 movq(rsp, Operand(rsp, StackHandlerConstants::kNextOffset)); | 
| 2539 | 2552 | 
| 2540 bind(&check_kind); | 2553 bind(&check_kind); | 
| 2541 cmpq(Operand(rsp, StackHandlerConstants::kStateOffset), | 2554 STATIC_ASSERT(StackHandler::ENTRY == 0); | 
| 2542 Immediate(StackHandler::ENTRY)); | 2555 testl(Operand(rsp, StackHandlerConstants::kStateOffset), | 
| 2543 j(not_equal, &fetch_next); | 2556 Immediate(StackHandler::KindField::kMask)); | 
| 2557 j(not_zero, &fetch_next); | |
| 2544 | 2558 | 
| 2545 // Set the top handler address to next handler past the top ENTRY handler. | 2559 // Set the top handler address to next handler past the top ENTRY handler. | 
| 2546 pop(ExternalOperand(handler_address)); | 2560 pop(ExternalOperand(handler_address)); | 
| 2547 | 2561 | 
| 2548 // Clear the context and frame pointer (0 was saved in the handler), and | 2562 // Remove the code object and state, compute the handler address in rdi. | 
| 2549 // discard the state. | 2563 pop(rdi); // Code object. | 
| 2564 pop(rdx); // Offset and state. | |
| 2565 // The handler table is a fixed array of (smi-tagged) code offsets. | |
| 2566 movq(rbx, FieldOperand(rdi, Code::kHandlerTableOffset)); | |
| 2567 shr(rdx, Immediate(StackHandler::kKindWidth)); | |
| 2568 movq(rdx, FieldOperand(rbx, rdx, times_8, FixedArray::kHeaderSize)); | |
| 2569 SmiToInteger64(rdx, rdx); | |
| 2570 lea(rdi, FieldOperand(rdi, rdx, times_1, Code::kHeaderSize)); | |
| 2571 | |
| 2572 // Clear the context pointer and frame pointer (0 was saved in the handler). | |
| 2550 pop(rsi); | 2573 pop(rsi); | 
| 2551 pop(rbp); | 2574 pop(rbp); | 
| 2552 pop(rdx); // State. | |
| 2553 | 2575 | 
| 2554 ret(0); | 2576 // Jump to the handler code. | 
| 2577 jmp(rdi); | |
| 
Vyacheslav Egorov (Chromium)
2011/11/10 19:01:04
Try to share code with throw.
 | |
| 2555 } | 2578 } | 
| 2556 | 2579 | 
| 2557 | 2580 | 
| 2558 void MacroAssembler::Ret() { | 2581 void MacroAssembler::Ret() { | 
| 2559 ret(0); | 2582 ret(0); | 
| 2560 } | 2583 } | 
| 2561 | 2584 | 
| 2562 | 2585 | 
| 2563 void MacroAssembler::Ret(int bytes_dropped, Register scratch) { | 2586 void MacroAssembler::Ret(int bytes_dropped, Register scratch) { | 
| 2564 if (is_uint16(bytes_dropped)) { | 2587 if (is_uint16(bytes_dropped)) { | 
| (...skipping 1655 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 4220 | 4243 | 
| 4221 and_(bitmap_scratch, Immediate(~Page::kPageAlignmentMask)); | 4244 and_(bitmap_scratch, Immediate(~Page::kPageAlignmentMask)); | 
| 4222 addl(Operand(bitmap_scratch, MemoryChunk::kLiveBytesOffset), length); | 4245 addl(Operand(bitmap_scratch, MemoryChunk::kLiveBytesOffset), length); | 
| 4223 | 4246 | 
| 4224 bind(&done); | 4247 bind(&done); | 
| 4225 } | 4248 } | 
| 4226 | 4249 | 
| 4227 } } // namespace v8::internal | 4250 } } // namespace v8::internal | 
| 4228 | 4251 | 
| 4229 #endif // V8_TARGET_ARCH_X64 | 4252 #endif // V8_TARGET_ARCH_X64 | 
| OLD | NEW |