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 2226 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2237 | 2237 |
2238 #endif // ENABLE_DEBUGGER_SUPPORT | 2238 #endif // ENABLE_DEBUGGER_SUPPORT |
2239 | 2239 |
2240 | 2240 |
2241 // --------------------------------------------------------------------------- | 2241 // --------------------------------------------------------------------------- |
2242 // Exception handling. | 2242 // Exception handling. |
2243 | 2243 |
2244 void MacroAssembler::PushTryHandler(CodeLocation try_location, | 2244 void MacroAssembler::PushTryHandler(CodeLocation try_location, |
2245 HandlerType type) { | 2245 HandlerType type) { |
2246 // Adjust this code if not the case. | 2246 // Adjust this code if not the case. |
2247 ASSERT(StackHandlerConstants::kSize == 4 * kPointerSize); | 2247 STATIC_ASSERT(StackHandlerConstants::kSize == 5 * kPointerSize); |
2248 STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0 * kPointerSize); | |
2249 STATIC_ASSERT(StackHandlerConstants::kStateOffset == 1 * kPointerSize); | |
2250 STATIC_ASSERT(StackHandlerConstants::kContextOffset == 2 * kPointerSize); | |
2251 STATIC_ASSERT(StackHandlerConstants::kFPOffset == 3 * kPointerSize); | |
2252 STATIC_ASSERT(StackHandlerConstants::kPCOffset == 4 * kPointerSize); | |
2253 | |
2248 // The return address is passed in register ra. | 2254 // The return address is passed in register ra. |
2249 if (try_location == IN_JAVASCRIPT) { | 2255 if (try_location == IN_JAVASCRIPT) { |
2250 if (type == TRY_CATCH_HANDLER) { | 2256 if (type == TRY_CATCH_HANDLER) { |
2251 li(t0, Operand(StackHandler::TRY_CATCH)); | 2257 li(t0, Operand(StackHandler::TRY_CATCH)); |
2252 } else { | 2258 } else { |
2253 li(t0, Operand(StackHandler::TRY_FINALLY)); | 2259 li(t0, Operand(StackHandler::TRY_FINALLY)); |
2254 } | 2260 } |
2255 ASSERT(StackHandlerConstants::kStateOffset == 1 * kPointerSize | |
2256 && StackHandlerConstants::kFPOffset == 2 * kPointerSize | |
2257 && StackHandlerConstants::kPCOffset == 3 * kPointerSize | |
2258 && StackHandlerConstants::kNextOffset == 0 * kPointerSize); | |
2259 // Save the current handler as the next handler. | 2261 // Save the current handler as the next handler. |
2260 li(t2, Operand(ExternalReference(Isolate::k_handler_address, isolate()))); | 2262 li(t2, Operand(ExternalReference(Isolate::k_handler_address, isolate()))); |
2261 lw(t1, MemOperand(t2)); | 2263 lw(t1, MemOperand(t2)); |
2262 | 2264 |
2263 addiu(sp, sp, -StackHandlerConstants::kSize); | 2265 addiu(sp, sp, -StackHandlerConstants::kSize); |
2264 sw(ra, MemOperand(sp, 12)); | 2266 sw(ra, MemOperand(sp, StackHandlerConstants::kPCOffset)); |
2265 sw(fp, MemOperand(sp, 8)); | 2267 sw(fp, MemOperand(sp, StackHandlerConstants::kFPOffset)); |
2266 sw(t0, MemOperand(sp, 4)); | 2268 sw(cp, MemOperand(sp, StackHandlerConstants::kContextOffset)); |
2267 sw(t1, MemOperand(sp, 0)); | 2269 sw(t0, MemOperand(sp, StackHandlerConstants::kStateOffset)); |
2270 sw(t1, MemOperand(sp, StackHandlerConstants::kNextOffset)); | |
2268 | 2271 |
2269 // Link this handler as the new current one. | 2272 // Link this handler as the new current one. |
2270 sw(sp, MemOperand(t2)); | 2273 sw(sp, MemOperand(t2)); |
2271 | 2274 |
2272 } else { | 2275 } else { |
2273 // Must preserve a0-a3, and s0 (argv). | 2276 // Must preserve a0-a3, and s0 (argv). |
2274 ASSERT(try_location == IN_JS_ENTRY); | 2277 ASSERT(try_location == IN_JS_ENTRY); |
2275 ASSERT(StackHandlerConstants::kStateOffset == 1 * kPointerSize | |
2276 && StackHandlerConstants::kFPOffset == 2 * kPointerSize | |
2277 && StackHandlerConstants::kPCOffset == 3 * kPointerSize | |
2278 && StackHandlerConstants::kNextOffset == 0 * kPointerSize); | |
2279 | |
2280 // The frame pointer does not point to a JS frame so we save NULL | 2278 // The frame pointer does not point to a JS frame so we save NULL |
2281 // for fp. We expect the code throwing an exception to check fp | 2279 // for fp. We expect the code throwing an exception to check fp |
2282 // before dereferencing it to restore the context. | 2280 // before dereferencing it to restore the context. |
2283 li(t0, Operand(StackHandler::ENTRY)); | 2281 li(t0, Operand(StackHandler::ENTRY)); |
Kevin Millikin (Chromium)
2011/08/16 08:42:14
StackHandler::ENTRY is zero. If you wanted to rel
| |
2284 | 2282 |
2285 // Save the current handler as the next handler. | 2283 // Save the current handler as the next handler. |
2286 li(t2, Operand(ExternalReference(Isolate::k_handler_address, isolate()))); | 2284 li(t2, Operand(ExternalReference(Isolate::k_handler_address, isolate()))); |
2287 lw(t1, MemOperand(t2)); | 2285 lw(t1, MemOperand(t2)); |
2288 | 2286 |
2287 ASSERT(Smi::FromInt(0) == 0); // Used for no context. | |
2288 | |
2289 addiu(sp, sp, -StackHandlerConstants::kSize); | 2289 addiu(sp, sp, -StackHandlerConstants::kSize); |
2290 sw(ra, MemOperand(sp, 12)); | 2290 sw(ra, MemOperand(sp, StackHandlerConstants::kPCOffset)); |
2291 sw(zero_reg, MemOperand(sp, 8)); | 2291 sw(zero_reg, MemOperand(sp, StackHandlerConstants::kFPOffset)); |
2292 sw(t0, MemOperand(sp, 4)); | 2292 sw(zero_reg, MemOperand(sp, StackHandlerConstants::kContextOffset)); |
2293 sw(t1, MemOperand(sp, 0)); | 2293 sw(t0, MemOperand(sp, StackHandlerConstants::kStateOffset)); |
2294 sw(t1, MemOperand(sp, StackHandlerConstants::kNextOffset)); | |
2294 | 2295 |
2295 // Link this handler as the new current one. | 2296 // Link this handler as the new current one. |
2296 sw(sp, MemOperand(t2)); | 2297 sw(sp, MemOperand(t2)); |
2297 } | 2298 } |
2298 } | 2299 } |
2299 | 2300 |
2300 | 2301 |
2301 void MacroAssembler::PopTryHandler() { | 2302 void MacroAssembler::PopTryHandler() { |
2302 ASSERT_EQ(0, StackHandlerConstants::kNextOffset); | 2303 STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0); |
2303 pop(a1); | 2304 pop(a1); |
2304 Addu(sp, sp, Operand(StackHandlerConstants::kSize - kPointerSize)); | 2305 Addu(sp, sp, Operand(StackHandlerConstants::kSize - kPointerSize)); |
2305 li(at, Operand(ExternalReference(Isolate::k_handler_address, isolate()))); | 2306 li(at, Operand(ExternalReference(Isolate::k_handler_address, isolate()))); |
2306 sw(a1, MemOperand(at)); | 2307 sw(a1, MemOperand(at)); |
2307 } | 2308 } |
2308 | 2309 |
2309 | 2310 |
2310 void MacroAssembler::Throw(Register value) { | 2311 void MacroAssembler::Throw(Register value) { |
2311 // v0 is expected to hold the exception. | 2312 // v0 is expected to hold the exception. |
2312 Move(v0, value); | 2313 Move(v0, value); |
2313 | 2314 |
2314 // Adjust this code if not the case. | 2315 // Adjust this code if not the case. |
2315 STATIC_ASSERT(StackHandlerConstants::kSize == 4 * kPointerSize); | 2316 STATIC_ASSERT(StackHandlerConstants::kSize == 5 * kPointerSize); |
2317 STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0 * kPointerSize); | |
2318 STATIC_ASSERT(StackHandlerConstants::kStateOffset == 1 * kPointerSize); | |
2319 STATIC_ASSERT(StackHandlerConstants::kContextOffset == 2 * kPointerSize); | |
2320 STATIC_ASSERT(StackHandlerConstants::kFPOffset == 3 * kPointerSize); | |
2321 STATIC_ASSERT(StackHandlerConstants::kPCOffset == 4 * kPointerSize); | |
2316 | 2322 |
2317 // Drop the sp to the top of the handler. | 2323 // Drop the sp to the top of the handler. |
2318 li(a3, Operand(ExternalReference(Isolate::k_handler_address, | 2324 li(a3, Operand(ExternalReference(Isolate::k_handler_address, |
2319 isolate()))); | 2325 isolate()))); |
2320 lw(sp, MemOperand(a3)); | 2326 lw(sp, MemOperand(a3)); |
2321 | 2327 |
2322 // Restore the next handler and frame pointer, discard handler state. | 2328 // Restore the next handler. |
2323 STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0); | |
2324 pop(a2); | 2329 pop(a2); |
2325 sw(a2, MemOperand(a3)); | 2330 sw(a2, MemOperand(a3)); |
2326 STATIC_ASSERT(StackHandlerConstants::kFPOffset == 2 * kPointerSize); | |
2327 MultiPop(a3.bit() | fp.bit()); | |
2328 | 2331 |
2329 // Before returning we restore the context from the frame pointer if | 2332 // Restore context and frame pointer, discard state (a3). |
2330 // not NULL. The frame pointer is NULL in the exception handler of a | 2333 MultiPop(a3.bit() | cp.bit() | fp.bit()); |
2331 // JS entry frame. | 2334 |
2332 // Set cp to NULL if fp is NULL. | 2335 // If the handler is a JS frame, restore the context to the frame. |
2336 // (a3 == ENTRY) == (fp == 0) == (cp == 0), so we could test any | |
2337 // of them. | |
2333 Label done; | 2338 Label done; |
2334 Branch(USE_DELAY_SLOT, &done, eq, fp, Operand(zero_reg)); | 2339 Branch(&done, eq, fp, Operand(zero_reg)); |
2335 mov(cp, zero_reg); // In branch delay slot. | 2340 sw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); |
2336 lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); | |
2337 bind(&done); | 2341 bind(&done); |
2338 | 2342 |
2339 #ifdef DEBUG | 2343 #ifdef DEBUG |
2340 // When emitting debug_code, set ra as return address for the jump. | 2344 // When emitting debug_code, set ra as return address for the jump. |
2341 // 5 instructions: add: 1, pop: 2, jump: 2. | 2345 // 5 instructions: add: 1, pop: 2, jump: 2. |
2342 const int kOffsetRaInstructions = 5; | 2346 const int kOffsetRaInstructions = 5; |
2343 Label find_ra; | 2347 Label find_ra; |
2344 | 2348 |
2345 if (emit_debug_code()) { | 2349 if (emit_debug_code()) { |
2346 // Compute ra for the Jump(t9). | 2350 // Compute ra for the Jump(t9). |
2347 const int kOffsetRaBytes = kOffsetRaInstructions * Assembler::kInstrSize; | 2351 const int kOffsetRaBytes = kOffsetRaInstructions * Assembler::kInstrSize; |
2348 | 2352 |
2349 // This branch-and-link sequence is needed to get the current PC on mips, | 2353 // This branch-and-link sequence is needed to get the current PC on mips, |
2350 // saved to the ra register. Then adjusted for instruction count. | 2354 // saved to the ra register. Then adjusted for instruction count. |
2351 bal(&find_ra); // bal exposes branch-delay. | 2355 bal(&find_ra); // bal exposes branch-delay. |
2352 nop(); // Branch delay slot nop. | 2356 nop(); // Branch delay slot nop. |
2353 bind(&find_ra); | 2357 bind(&find_ra); |
2354 addiu(ra, ra, kOffsetRaBytes); | 2358 addiu(ra, ra, kOffsetRaBytes); |
2355 } | 2359 } |
2356 #endif | 2360 #endif |
2357 | 2361 |
2358 STATIC_ASSERT(StackHandlerConstants::kPCOffset == 3 * kPointerSize); | |
2359 pop(t9); // 2 instructions: lw, add sp. | 2362 pop(t9); // 2 instructions: lw, add sp. |
2360 Jump(t9); // 2 instructions: jr, nop (in delay slot). | 2363 Jump(t9); // 2 instructions: jr, nop (in delay slot). |
2361 | 2364 |
2362 if (emit_debug_code()) { | 2365 if (emit_debug_code()) { |
2363 // Make sure that the expected number of instructions were generated. | 2366 // Make sure that the expected number of instructions were generated. |
2364 ASSERT_EQ(kOffsetRaInstructions, | 2367 ASSERT_EQ(kOffsetRaInstructions, |
2365 InstructionsGeneratedSince(&find_ra)); | 2368 InstructionsGeneratedSince(&find_ra)); |
2366 } | 2369 } |
2367 } | 2370 } |
2368 | 2371 |
2369 | 2372 |
2370 void MacroAssembler::ThrowUncatchable(UncatchableExceptionType type, | 2373 void MacroAssembler::ThrowUncatchable(UncatchableExceptionType type, |
2371 Register value) { | 2374 Register value) { |
2372 // Adjust this code if not the case. | 2375 // Adjust this code if not the case. |
2373 STATIC_ASSERT(StackHandlerConstants::kSize == 4 * kPointerSize); | 2376 STATIC_ASSERT(StackHandlerConstants::kSize == 5 * kPointerSize); |
2377 STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0 * kPointerSize); | |
2378 STATIC_ASSERT(StackHandlerConstants::kStateOffset == 1 * kPointerSize); | |
2379 STATIC_ASSERT(StackHandlerConstants::kContextOffset == 2 * kPointerSize); | |
2380 STATIC_ASSERT(StackHandlerConstants::kFPOffset == 3 * kPointerSize); | |
2381 STATIC_ASSERT(StackHandlerConstants::kPCOffset == 4 * kPointerSize); | |
2374 | 2382 |
2375 // v0 is expected to hold the exception. | 2383 // v0 is expected to hold the exception. |
2376 Move(v0, value); | 2384 Move(v0, value); |
2377 | 2385 |
2378 // Drop sp to the top stack handler. | 2386 // Drop sp to the top stack handler. |
2379 li(a3, Operand(ExternalReference(Isolate::k_handler_address, isolate()))); | 2387 li(a3, Operand(ExternalReference(Isolate::k_handler_address, isolate()))); |
2380 lw(sp, MemOperand(a3)); | 2388 lw(sp, MemOperand(a3)); |
2381 | 2389 |
2382 // Unwind the handlers until the ENTRY handler is found. | 2390 // Unwind the handlers until the ENTRY handler is found. |
2383 Label loop, done; | 2391 Label loop, done; |
2384 bind(&loop); | 2392 bind(&loop); |
2385 // Load the type of the current stack handler. | 2393 // Load the type of the current stack handler. |
2386 const int kStateOffset = StackHandlerConstants::kStateOffset; | 2394 const int kStateOffset = StackHandlerConstants::kStateOffset; |
2387 lw(a2, MemOperand(sp, kStateOffset)); | 2395 lw(a2, MemOperand(sp, kStateOffset)); |
2388 Branch(&done, eq, a2, Operand(StackHandler::ENTRY)); | 2396 Branch(&done, eq, a2, Operand(StackHandler::ENTRY)); |
2389 // Fetch the next handler in the list. | 2397 // Fetch the next handler in the list. |
2390 const int kNextOffset = StackHandlerConstants::kNextOffset; | 2398 const int kNextOffset = StackHandlerConstants::kNextOffset; |
2391 lw(sp, MemOperand(sp, kNextOffset)); | 2399 lw(sp, MemOperand(sp, kNextOffset)); |
2392 jmp(&loop); | 2400 jmp(&loop); |
2393 bind(&done); | 2401 bind(&done); |
2394 | 2402 |
2395 // Set the top handler address to next handler past the current ENTRY handler. | 2403 // Set the top handler address to next handler past the current ENTRY handler. |
2396 STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0); | |
2397 pop(a2); | 2404 pop(a2); |
2398 sw(a2, MemOperand(a3)); | 2405 sw(a2, MemOperand(a3)); |
2399 | 2406 |
2400 if (type == OUT_OF_MEMORY) { | 2407 if (type == OUT_OF_MEMORY) { |
2401 // Set external caught exception to false. | 2408 // Set external caught exception to false. |
2402 ExternalReference external_caught( | 2409 ExternalReference external_caught( |
2403 Isolate::k_external_caught_exception_address, isolate()); | 2410 Isolate::k_external_caught_exception_address, isolate()); |
2404 li(a0, Operand(false, RelocInfo::NONE)); | 2411 li(a0, Operand(false, RelocInfo::NONE)); |
2405 li(a2, Operand(external_caught)); | 2412 li(a2, Operand(external_caught)); |
2406 sw(a0, MemOperand(a2)); | 2413 sw(a0, MemOperand(a2)); |
2407 | 2414 |
2408 // Set pending exception and v0 to out of memory exception. | 2415 // Set pending exception and v0 to out of memory exception. |
2409 Failure* out_of_memory = Failure::OutOfMemoryException(); | 2416 Failure* out_of_memory = Failure::OutOfMemoryException(); |
2410 li(v0, Operand(reinterpret_cast<int32_t>(out_of_memory))); | 2417 li(v0, Operand(reinterpret_cast<int32_t>(out_of_memory))); |
2411 li(a2, Operand(ExternalReference(Isolate::k_pending_exception_address, | 2418 li(a2, Operand(ExternalReference(Isolate::k_pending_exception_address, |
2412 isolate()))); | 2419 isolate()))); |
2413 sw(v0, MemOperand(a2)); | 2420 sw(v0, MemOperand(a2)); |
2414 } | 2421 } |
2415 | 2422 |
2416 // Stack layout at this point. See also StackHandlerConstants. | 2423 // Stack layout at this point. See also StackHandlerConstants. |
2417 // sp -> state (ENTRY) | 2424 // sp -> state (ENTRY) |
2425 // cp | |
2418 // fp | 2426 // fp |
2419 // ra | 2427 // ra |
2420 | 2428 |
2421 // Discard handler state (a2 is not used) and restore frame pointer. | 2429 // Restore context and frame pointer, discard state (r2). |
2422 STATIC_ASSERT(StackHandlerConstants::kFPOffset == 2 * kPointerSize); | 2430 MultiPop(a2.bit() | cp.bit() | fp.bit()); |
2423 MultiPop(a2.bit() | fp.bit()); // a2: discarded state. | |
2424 // Before returning we restore the context from the frame pointer if | |
2425 // not NULL. The frame pointer is NULL in the exception handler of a | |
2426 // JS entry frame. | |
2427 Label cp_null; | |
2428 Branch(USE_DELAY_SLOT, &cp_null, eq, fp, Operand(zero_reg)); | |
2429 mov(cp, zero_reg); // In the branch delay slot. | |
2430 lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); | |
2431 bind(&cp_null); | |
2432 | 2431 |
2433 #ifdef DEBUG | 2432 #ifdef DEBUG |
2434 // When emitting debug_code, set ra as return address for the jump. | 2433 // When emitting debug_code, set ra as return address for the jump. |
2435 // 5 instructions: add: 1, pop: 2, jump: 2. | 2434 // 5 instructions: add: 1, pop: 2, jump: 2. |
2436 const int kOffsetRaInstructions = 5; | 2435 const int kOffsetRaInstructions = 5; |
2437 Label find_ra; | 2436 Label find_ra; |
2438 | 2437 |
2439 if (emit_debug_code()) { | 2438 if (emit_debug_code()) { |
2440 // Compute ra for the Jump(t9). | 2439 // Compute ra for the Jump(t9). |
2441 const int kOffsetRaBytes = kOffsetRaInstructions * Assembler::kInstrSize; | 2440 const int kOffsetRaBytes = kOffsetRaInstructions * Assembler::kInstrSize; |
2442 | 2441 |
2443 // This branch-and-link sequence is needed to get the current PC on mips, | 2442 // This branch-and-link sequence is needed to get the current PC on mips, |
2444 // saved to the ra register. Then adjusted for instruction count. | 2443 // saved to the ra register. Then adjusted for instruction count. |
2445 bal(&find_ra); // bal exposes branch-delay slot. | 2444 bal(&find_ra); // bal exposes branch-delay slot. |
2446 nop(); // Branch delay slot nop. | 2445 nop(); // Branch delay slot nop. |
2447 bind(&find_ra); | 2446 bind(&find_ra); |
2448 addiu(ra, ra, kOffsetRaBytes); | 2447 addiu(ra, ra, kOffsetRaBytes); |
2449 } | 2448 } |
2450 #endif | 2449 #endif |
2451 STATIC_ASSERT(StackHandlerConstants::kPCOffset == 3 * kPointerSize); | |
2452 pop(t9); // 2 instructions: lw, add sp. | 2450 pop(t9); // 2 instructions: lw, add sp. |
2453 Jump(t9); // 2 instructions: jr, nop (in delay slot). | 2451 Jump(t9); // 2 instructions: jr, nop (in delay slot). |
2454 | 2452 |
2455 if (emit_debug_code()) { | 2453 if (emit_debug_code()) { |
2456 // Make sure that the expected number of instructions were generated. | 2454 // Make sure that the expected number of instructions were generated. |
2457 ASSERT_EQ(kOffsetRaInstructions, | 2455 ASSERT_EQ(kOffsetRaInstructions, |
2458 InstructionsGeneratedSince(&find_ra)); | 2456 InstructionsGeneratedSince(&find_ra)); |
2459 } | 2457 } |
2460 } | 2458 } |
2461 | 2459 |
(...skipping 1829 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
4291 opcode == BGTZL); | 4289 opcode == BGTZL); |
4292 opcode = (cond == eq) ? BEQ : BNE; | 4290 opcode = (cond == eq) ? BEQ : BNE; |
4293 instr = (instr & ~kOpcodeMask) | opcode; | 4291 instr = (instr & ~kOpcodeMask) | opcode; |
4294 masm_.emit(instr); | 4292 masm_.emit(instr); |
4295 } | 4293 } |
4296 | 4294 |
4297 | 4295 |
4298 } } // namespace v8::internal | 4296 } } // namespace v8::internal |
4299 | 4297 |
4300 #endif // V8_TARGET_ARCH_MIPS | 4298 #endif // V8_TARGET_ARCH_MIPS |
OLD | NEW |