| OLD | NEW |
| 1 // Copyright 2006-2008 the V8 project authors. All rights reserved. | 1 // Copyright 2006-2008 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 2007 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2018 | 2018 |
| 2019 // Shadow the labels for all escapes from the try block, including | 2019 // Shadow the labels for all escapes from the try block, including |
| 2020 // returns. During shadowing, the original label is hidden as the | 2020 // returns. During shadowing, the original label is hidden as the |
| 2021 // LabelShadow and operations on the original actually affect the | 2021 // LabelShadow and operations on the original actually affect the |
| 2022 // shadowing label. | 2022 // shadowing label. |
| 2023 // | 2023 // |
| 2024 // We should probably try to unify the escaping labels and the return | 2024 // We should probably try to unify the escaping labels and the return |
| 2025 // label. | 2025 // label. |
| 2026 int nof_escapes = node->escaping_targets()->length(); | 2026 int nof_escapes = node->escaping_targets()->length(); |
| 2027 List<ShadowTarget*> shadows(1 + nof_escapes); | 2027 List<ShadowTarget*> shadows(1 + nof_escapes); |
| 2028 |
| 2029 // Add the shadow target for the function return. |
| 2030 static const int kReturnShadowIndex = 0; |
| 2028 shadows.Add(new ShadowTarget(&function_return_)); | 2031 shadows.Add(new ShadowTarget(&function_return_)); |
| 2032 bool function_return_was_shadowed = function_return_is_shadowed_; |
| 2033 function_return_is_shadowed_ = true; |
| 2034 ASSERT(shadows[kReturnShadowIndex]->other_target() == &function_return_); |
| 2035 |
| 2036 // Add the remaining shadow targets. |
| 2029 for (int i = 0; i < nof_escapes; i++) { | 2037 for (int i = 0; i < nof_escapes; i++) { |
| 2030 shadows.Add(new ShadowTarget(node->escaping_targets()->at(i))); | 2038 shadows.Add(new ShadowTarget(node->escaping_targets()->at(i))); |
| 2031 } | 2039 } |
| 2032 bool function_return_was_shadowed = function_return_is_shadowed_; | |
| 2033 function_return_is_shadowed_ = true; | |
| 2034 | 2040 |
| 2035 // Generate code for the statements in the try block. | 2041 // Generate code for the statements in the try block. |
| 2036 VisitStatementsAndSpill(node->try_block()->statements()); | 2042 VisitStatementsAndSpill(node->try_block()->statements()); |
| 2037 if (frame_ != NULL) { | |
| 2038 frame_->Drop(); // Discard the result. | |
| 2039 } | |
| 2040 | 2043 |
| 2041 // Stop the introduced shadowing and count the number of required unlinks. | 2044 // Stop the introduced shadowing and count the number of required unlinks. |
| 2042 // After shadowing stops, the original labels are unshadowed and the | 2045 // After shadowing stops, the original labels are unshadowed and the |
| 2043 // LabelShadows represent the formerly shadowing labels. | 2046 // LabelShadows represent the formerly shadowing labels. |
| 2044 int nof_unlinks = 0; | 2047 int nof_unlinks = 0; |
| 2045 for (int i = 0; i <= nof_escapes; i++) { | 2048 for (int i = 0; i <= nof_escapes; i++) { |
| 2046 shadows[i]->StopShadowing(); | 2049 shadows[i]->StopShadowing(); |
| 2047 if (shadows[i]->is_linked()) nof_unlinks++; | 2050 if (shadows[i]->is_linked()) nof_unlinks++; |
| 2048 } | 2051 } |
| 2049 function_return_is_shadowed_ = function_return_was_shadowed; | 2052 function_return_is_shadowed_ = function_return_was_shadowed; |
| 2050 | 2053 |
| 2051 const int kNextIndex = (StackHandlerConstants::kNextOffset | 2054 const int kNextIndex = StackHandlerConstants::kNextOffset / kPointerSize; |
| 2052 + StackHandlerConstants::kAddressDisplacement) | |
| 2053 / kPointerSize; | |
| 2054 // If we can fall off the end of the try block, unlink from try chain. | 2055 // If we can fall off the end of the try block, unlink from try chain. |
| 2055 if (frame_ != NULL) { | 2056 if (has_valid_frame()) { |
| 2056 __ ldr(r1, frame_->ElementAt(kNextIndex)); // read next_sp | 2057 // The next handler address is at kNextIndex in the stack. |
| 2058 __ ldr(r1, frame_->ElementAt(kNextIndex)); |
| 2057 __ mov(r3, Operand(ExternalReference(Top::k_handler_address))); | 2059 __ mov(r3, Operand(ExternalReference(Top::k_handler_address))); |
| 2058 __ str(r1, MemOperand(r3)); | 2060 __ str(r1, MemOperand(r3)); |
| 2059 ASSERT(StackHandlerConstants::kCodeOffset == 0); // first field is code | 2061 frame_->Drop(StackHandlerConstants::kSize / kPointerSize); |
| 2060 frame_->Drop(StackHandlerConstants::kSize / kPointerSize - 1); | |
| 2061 // Code slot popped. | |
| 2062 if (nof_unlinks > 0) { | 2062 if (nof_unlinks > 0) { |
| 2063 exit.Jump(); | 2063 exit.Jump(); |
| 2064 } | 2064 } |
| 2065 } | 2065 } |
| 2066 | 2066 |
| 2067 // Generate unlink code for the (formerly) shadowing labels that have been | 2067 // Generate unlink code for the (formerly) shadowing labels that have been |
| 2068 // jumped to. | 2068 // jumped to. |
| 2069 for (int i = 0; i <= nof_escapes; i++) { | 2069 for (int i = 0; i <= nof_escapes; i++) { |
| 2070 if (shadows[i]->is_linked()) { | 2070 if (shadows[i]->is_linked()) { |
| 2071 // Unlink from try chain; | 2071 // Unlink from try chain; |
| 2072 shadows[i]->Bind(); | 2072 shadows[i]->Bind(); |
| 2073 // Because we can be jumping here (to spilled code) from unspilled |
| 2074 // code, we need to reestablish a spilled frame at this block. |
| 2075 frame_->SpillAll(); |
| 2073 | 2076 |
| 2074 // Reload sp from the top handler, because some statements that we | 2077 // Reload sp from the top handler, because some statements that we |
| 2075 // break from (eg, for...in) may have left stuff on the stack. | 2078 // break from (eg, for...in) may have left stuff on the stack. |
| 2076 __ mov(r3, Operand(ExternalReference(Top::k_handler_address))); | 2079 __ mov(r3, Operand(ExternalReference(Top::k_handler_address))); |
| 2077 __ ldr(sp, MemOperand(r3)); | 2080 __ ldr(sp, MemOperand(r3)); |
| 2078 frame_->Forget(frame_->height() - handler_height); | 2081 // The stack pointer was restored to just below the code slot |
| 2082 // (the topmost slot) in the handler. |
| 2083 frame_->Forget(frame_->height() - handler_height + 1); |
| 2079 | 2084 |
| 2080 __ ldr(r1, frame_->ElementAt(kNextIndex)); | 2085 // kNextIndex is off by one because the code slot has already |
| 2086 // been dropped. |
| 2087 __ ldr(r1, frame_->ElementAt(kNextIndex - 1)); |
| 2081 __ str(r1, MemOperand(r3)); | 2088 __ str(r1, MemOperand(r3)); |
| 2082 ASSERT(StackHandlerConstants::kCodeOffset == 0); // first field is code | |
| 2083 frame_->Drop(StackHandlerConstants::kSize / kPointerSize - 1); | 2089 frame_->Drop(StackHandlerConstants::kSize / kPointerSize - 1); |
| 2084 // Code slot popped. | 2090 |
| 2085 frame_->Forget(1); | 2091 if (!function_return_is_shadowed_ && i == kReturnShadowIndex) { |
| 2092 frame_->PrepareForReturn(); |
| 2093 } |
| 2086 shadows[i]->other_target()->Jump(); | 2094 shadows[i]->other_target()->Jump(); |
| 2087 } | 2095 } |
| 2088 } | 2096 } |
| 2089 | 2097 |
| 2090 exit.Bind(); | 2098 exit.Bind(); |
| 2091 ASSERT(!has_valid_frame() || frame_->height() == original_height); | 2099 ASSERT(!has_valid_frame() || frame_->height() == original_height); |
| 2092 } | 2100 } |
| 2093 | 2101 |
| 2094 | 2102 |
| 2095 void CodeGenerator::VisitTryFinally(TryFinally* node) { | 2103 void CodeGenerator::VisitTryFinally(TryFinally* node) { |
| (...skipping 13 matching lines...) Expand all Loading... |
| 2109 JumpTarget try_block(this); | 2117 JumpTarget try_block(this); |
| 2110 JumpTarget finally_block(this); | 2118 JumpTarget finally_block(this); |
| 2111 | 2119 |
| 2112 try_block.Call(); | 2120 try_block.Call(); |
| 2113 | 2121 |
| 2114 frame_->EmitPush(r0); // save exception object on the stack | 2122 frame_->EmitPush(r0); // save exception object on the stack |
| 2115 // In case of thrown exceptions, this is where we continue. | 2123 // In case of thrown exceptions, this is where we continue. |
| 2116 __ mov(r2, Operand(Smi::FromInt(THROWING))); | 2124 __ mov(r2, Operand(Smi::FromInt(THROWING))); |
| 2117 finally_block.Jump(); | 2125 finally_block.Jump(); |
| 2118 | 2126 |
| 2119 | |
| 2120 // --- Try block --- | 2127 // --- Try block --- |
| 2121 try_block.Bind(); | 2128 try_block.Bind(); |
| 2122 | 2129 |
| 2123 frame_->PushTryHandler(TRY_FINALLY_HANDLER); | 2130 frame_->PushTryHandler(TRY_FINALLY_HANDLER); |
| 2124 int handler_height = frame_->height(); | 2131 int handler_height = frame_->height(); |
| 2125 | 2132 |
| 2126 // Shadow the labels for all escapes from the try block, including | 2133 // Shadow the labels for all escapes from the try block, including |
| 2127 // returns. Shadowing hides the original label as the LabelShadow and | 2134 // returns. Shadowing hides the original label as the LabelShadow and |
| 2128 // operations on the original actually affect the shadowing label. | 2135 // operations on the original actually affect the shadowing label. |
| 2129 // | 2136 // |
| 2130 // We should probably try to unify the escaping labels and the return | 2137 // We should probably try to unify the escaping labels and the return |
| 2131 // label. | 2138 // label. |
| 2132 int nof_escapes = node->escaping_targets()->length(); | 2139 int nof_escapes = node->escaping_targets()->length(); |
| 2133 List<ShadowTarget*> shadows(1 + nof_escapes); | 2140 List<ShadowTarget*> shadows(1 + nof_escapes); |
| 2141 |
| 2142 // Add the shadow target for the function return. |
| 2143 static const int kReturnShadowIndex = 0; |
| 2134 shadows.Add(new ShadowTarget(&function_return_)); | 2144 shadows.Add(new ShadowTarget(&function_return_)); |
| 2145 bool function_return_was_shadowed = function_return_is_shadowed_; |
| 2146 function_return_is_shadowed_ = true; |
| 2147 ASSERT(shadows[kReturnShadowIndex]->other_target() == &function_return_); |
| 2148 |
| 2149 // Add the remaining shadow targets. |
| 2135 for (int i = 0; i < nof_escapes; i++) { | 2150 for (int i = 0; i < nof_escapes; i++) { |
| 2136 shadows.Add(new ShadowTarget(node->escaping_targets()->at(i))); | 2151 shadows.Add(new ShadowTarget(node->escaping_targets()->at(i))); |
| 2137 } | 2152 } |
| 2138 bool function_return_was_shadowed = function_return_is_shadowed_; | |
| 2139 function_return_is_shadowed_ = true; | |
| 2140 | 2153 |
| 2141 // Generate code for the statements in the try block. | 2154 // Generate code for the statements in the try block. |
| 2142 VisitStatementsAndSpill(node->try_block()->statements()); | 2155 VisitStatementsAndSpill(node->try_block()->statements()); |
| 2143 | 2156 |
| 2144 // Stop the introduced shadowing and count the number of required unlinks. | 2157 // Stop the introduced shadowing and count the number of required unlinks. |
| 2145 // After shadowing stops, the original labels are unshadowed and the | 2158 // After shadowing stops, the original labels are unshadowed and the |
| 2146 // LabelShadows represent the formerly shadowing labels. | 2159 // LabelShadows represent the formerly shadowing labels. |
| 2147 int nof_unlinks = 0; | 2160 int nof_unlinks = 0; |
| 2148 for (int i = 0; i <= nof_escapes; i++) { | 2161 for (int i = 0; i <= nof_escapes; i++) { |
| 2149 shadows[i]->StopShadowing(); | 2162 shadows[i]->StopShadowing(); |
| 2150 if (shadows[i]->is_linked()) nof_unlinks++; | 2163 if (shadows[i]->is_linked()) nof_unlinks++; |
| 2151 } | 2164 } |
| 2152 function_return_is_shadowed_ = function_return_was_shadowed; | 2165 function_return_is_shadowed_ = function_return_was_shadowed; |
| 2153 | 2166 |
| 2154 // If we can fall off the end of the try block, set the state on the stack | 2167 // If we can fall off the end of the try block, set the state on the stack |
| 2155 // to FALLING. | 2168 // to FALLING. |
| 2156 if (frame_ != NULL) { | 2169 if (has_valid_frame()) { |
| 2157 __ mov(r0, Operand(Factory::undefined_value())); // fake TOS | 2170 __ mov(r0, Operand(Factory::undefined_value())); // fake TOS |
| 2158 frame_->EmitPush(r0); | 2171 frame_->EmitPush(r0); |
| 2159 __ mov(r2, Operand(Smi::FromInt(FALLING))); | 2172 __ mov(r2, Operand(Smi::FromInt(FALLING))); |
| 2160 if (nof_unlinks > 0) { | 2173 if (nof_unlinks > 0) { |
| 2161 unlink.Jump(); | 2174 unlink.Jump(); |
| 2162 } | 2175 } |
| 2163 } | 2176 } |
| 2164 | 2177 |
| 2165 // Generate code to set the state for the (formerly) shadowing labels that | 2178 // Generate code to set the state for the (formerly) shadowing labels that |
| 2166 // have been jumped to. | 2179 // have been jumped to. |
| 2167 for (int i = 0; i <= nof_escapes; i++) { | 2180 for (int i = 0; i <= nof_escapes; i++) { |
| 2168 if (shadows[i]->is_linked()) { | 2181 if (shadows[i]->is_linked()) { |
| 2182 // Because we can be jumping here (to spilled code) from |
| 2183 // unspilled code, we need to reestablish a spilled frame at |
| 2184 // this block. |
| 2169 shadows[i]->Bind(); | 2185 shadows[i]->Bind(); |
| 2170 if (shadows[i]->other_target() == &function_return_) { | 2186 frame_->SpillAll(); |
| 2187 if (i == kReturnShadowIndex) { |
| 2171 // If this label shadowed the function return, materialize the | 2188 // If this label shadowed the function return, materialize the |
| 2172 // return value on the stack. | 2189 // return value on the stack. |
| 2173 frame_->EmitPush(r0); | 2190 frame_->EmitPush(r0); |
| 2174 } else { | 2191 } else { |
| 2175 // Fake TOS for labels that shadowed breaks and continues. | 2192 // Fake TOS for targets that shadowed breaks and continues. |
| 2176 __ mov(r0, Operand(Factory::undefined_value())); | 2193 __ mov(r0, Operand(Factory::undefined_value())); |
| 2177 frame_->EmitPush(r0); | 2194 frame_->EmitPush(r0); |
| 2178 } | 2195 } |
| 2179 __ mov(r2, Operand(Smi::FromInt(JUMPING + i))); | 2196 __ mov(r2, Operand(Smi::FromInt(JUMPING + i))); |
| 2180 unlink.Jump(); | 2197 unlink.Jump(); |
| 2181 } | 2198 } |
| 2182 } | 2199 } |
| 2183 | 2200 |
| 2184 // Unlink from try chain; | 2201 // Unlink from try chain; |
| 2185 unlink.Bind(); | 2202 unlink.Bind(); |
| 2186 | 2203 |
| 2187 frame_->EmitPop(r0); // Store TOS in r0 across stack manipulation | 2204 // Preserve TOS result in r0 across stack manipulation. |
| 2205 frame_->EmitPop(r0); |
| 2188 // Reload sp from the top handler, because some statements that we | 2206 // Reload sp from the top handler, because some statements that we |
| 2189 // break from (eg, for...in) may have left stuff on the stack. | 2207 // break from (eg, for...in) may have left stuff on the stack. |
| 2190 __ mov(r3, Operand(ExternalReference(Top::k_handler_address))); | 2208 __ mov(r3, Operand(ExternalReference(Top::k_handler_address))); |
| 2191 __ ldr(sp, MemOperand(r3)); | 2209 __ ldr(sp, MemOperand(r3)); |
| 2192 frame_->Forget(frame_->height() - handler_height); | 2210 // The stack pointer was restored to just below the code slot |
| 2211 // (the topmost slot) in the handler. |
| 2212 frame_->Forget(frame_->height() - handler_height + 1); |
| 2193 const int kNextIndex = (StackHandlerConstants::kNextOffset | 2213 const int kNextIndex = (StackHandlerConstants::kNextOffset |
| 2194 + StackHandlerConstants::kAddressDisplacement) | 2214 + StackHandlerConstants::kAddressDisplacement) |
| 2195 / kPointerSize; | 2215 / kPointerSize; |
| 2196 __ ldr(r1, frame_->ElementAt(kNextIndex)); | 2216 __ ldr(r1, frame_->ElementAt(kNextIndex)); |
| 2197 __ str(r1, MemOperand(r3)); | 2217 __ str(r1, MemOperand(r3)); |
| 2198 ASSERT(StackHandlerConstants::kCodeOffset == 0); // first field is code | 2218 ASSERT(StackHandlerConstants::kCodeOffset == 0); // first field is code |
| 2219 // Drop the rest of the handler (not including the already dropped |
| 2220 // code slot). |
| 2199 frame_->Drop(StackHandlerConstants::kSize / kPointerSize - 1); | 2221 frame_->Drop(StackHandlerConstants::kSize / kPointerSize - 1); |
| 2200 // Code slot popped. | 2222 // Restore the result to TOS. |
| 2201 frame_->Forget(1); | |
| 2202 frame_->EmitPush(r0); | 2223 frame_->EmitPush(r0); |
| 2203 | 2224 |
| 2204 // --- Finally block --- | 2225 // --- Finally block --- |
| 2205 finally_block.Bind(); | 2226 finally_block.Bind(); |
| 2206 | 2227 |
| 2207 // Push the state on the stack. | 2228 // Push the state on the stack. |
| 2208 frame_->EmitPush(r2); | 2229 frame_->EmitPush(r2); |
| 2209 | 2230 |
| 2210 // We keep two elements on the stack - the (possibly faked) result | 2231 // We keep two elements on the stack - the (possibly faked) result |
| 2211 // and the state - while evaluating the finally block. Record it, so | 2232 // and the state - while evaluating the finally block. Record it, so |
| 2212 // that a break/continue crossing this statement can restore the | 2233 // that a break/continue crossing this statement can restore the |
| 2213 // stack. | 2234 // stack. |
| 2214 const int kFinallyStackSize = 2 * kPointerSize; | 2235 const int kFinallyStackSize = 2 * kPointerSize; |
| 2215 break_stack_height_ += kFinallyStackSize; | 2236 break_stack_height_ += kFinallyStackSize; |
| 2216 | 2237 |
| 2217 // Generate code for the statements in the finally block. | 2238 // Generate code for the statements in the finally block. |
| 2218 VisitStatementsAndSpill(node->finally_block()->statements()); | 2239 VisitStatementsAndSpill(node->finally_block()->statements()); |
| 2219 | 2240 |
| 2220 break_stack_height_ -= kFinallyStackSize; | 2241 break_stack_height_ -= kFinallyStackSize; |
| 2221 if (frame_ != NULL) { | 2242 if (has_valid_frame()) { |
| 2222 JumpTarget exit(this); | 2243 JumpTarget exit(this); |
| 2223 // Restore state and return value or faked TOS. | 2244 // Restore state and return value or faked TOS. |
| 2224 frame_->EmitPop(r2); | 2245 frame_->EmitPop(r2); |
| 2225 frame_->EmitPop(r0); | 2246 frame_->EmitPop(r0); |
| 2226 | 2247 |
| 2227 // Generate code to jump to the right destination for all used (formerly) | 2248 // Generate code to jump to the right destination for all used (formerly) |
| 2228 // shadowing labels. | 2249 // shadowing labels. |
| 2229 for (int i = 0; i <= nof_escapes; i++) { | 2250 for (int i = 0; i <= nof_escapes; i++) { |
| 2230 if (shadows[i]->is_bound()) { | 2251 if (shadows[i]->is_bound()) { |
| 2252 JumpTarget* original = shadows[i]->other_target(); |
| 2231 __ cmp(r2, Operand(Smi::FromInt(JUMPING + i))); | 2253 __ cmp(r2, Operand(Smi::FromInt(JUMPING + i))); |
| 2232 if (shadows[i]->other_target() != &function_return_) { | 2254 if (!function_return_is_shadowed_ && i == kReturnShadowIndex) { |
| 2233 JumpTarget next(this); | 2255 JumpTarget skip(this); |
| 2234 next.Branch(ne); | 2256 skip.Branch(ne); |
| 2235 shadows[i]->other_target()->Jump(); | 2257 frame_->PrepareForReturn(); |
| 2236 next.Bind(); | 2258 original->Jump(); |
| 2259 skip.Bind(); |
| 2237 } else { | 2260 } else { |
| 2238 shadows[i]->other_target()->Branch(eq); | 2261 original->Branch(eq); |
| 2239 } | 2262 } |
| 2240 } | 2263 } |
| 2241 } | 2264 } |
| 2242 | 2265 |
| 2243 // Check if we need to rethrow the exception. | 2266 // Check if we need to rethrow the exception. |
| 2244 __ cmp(r2, Operand(Smi::FromInt(THROWING))); | 2267 __ cmp(r2, Operand(Smi::FromInt(THROWING))); |
| 2245 exit.Branch(ne); | 2268 exit.Branch(ne); |
| 2246 | 2269 |
| 2247 // Rethrow exception. | 2270 // Rethrow exception. |
| 2248 frame_->EmitPush(r0); | 2271 frame_->EmitPush(r0); |
| (...skipping 2766 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5015 __ mov(r2, Operand(0)); | 5038 __ mov(r2, Operand(0)); |
| 5016 __ GetBuiltinEntry(r3, Builtins::CALL_NON_FUNCTION); | 5039 __ GetBuiltinEntry(r3, Builtins::CALL_NON_FUNCTION); |
| 5017 __ Jump(Handle<Code>(Builtins::builtin(Builtins::ArgumentsAdaptorTrampoline)), | 5040 __ Jump(Handle<Code>(Builtins::builtin(Builtins::ArgumentsAdaptorTrampoline)), |
| 5018 RelocInfo::CODE_TARGET); | 5041 RelocInfo::CODE_TARGET); |
| 5019 } | 5042 } |
| 5020 | 5043 |
| 5021 | 5044 |
| 5022 #undef __ | 5045 #undef __ |
| 5023 | 5046 |
| 5024 } } // namespace v8::internal | 5047 } } // namespace v8::internal |
| OLD | NEW |