| OLD | NEW |
| 1 // Copyright 2009 the V8 project authors. All rights reserved. | 1 // Copyright 2009 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 11 matching lines...) Expand all Loading... |
| 22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | 22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 27 | 27 |
| 28 #include "v8.h" | 28 #include "v8.h" |
| 29 | 29 |
| 30 #include "codegen-inl.h" | 30 #include "codegen-inl.h" |
| 31 #include "fast-codegen.h" | 31 #include "fast-codegen.h" |
| 32 #include "parser.h" |
| 32 | 33 |
| 33 namespace v8 { | 34 namespace v8 { |
| 34 namespace internal { | 35 namespace internal { |
| 35 | 36 |
| 36 #define __ ACCESS_MASM(masm_) | 37 #define __ ACCESS_MASM(masm_) |
| 37 | 38 |
| 38 // Generate code for a JS function. On entry to the function the receiver | 39 // Generate code for a JS function. On entry to the function the receiver |
| 39 // and arguments have been pushed on the stack left to right, with the | 40 // and arguments have been pushed on the stack left to right, with the |
| 40 // return address on top of them. The actual argument count matches the | 41 // return address on top of them. The actual argument count matches the |
| 41 // formal parameter count expected by the function. | 42 // formal parameter count expected by the function. |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 93 // patch with the code required by the debugger. | 94 // patch with the code required by the debugger. |
| 94 __ mov(esp, ebp); | 95 __ mov(esp, ebp); |
| 95 __ pop(ebp); | 96 __ pop(ebp); |
| 96 __ ret((fun->scope()->num_parameters() + 1) * kPointerSize); | 97 __ ret((fun->scope()->num_parameters() + 1) * kPointerSize); |
| 97 } | 98 } |
| 98 } | 99 } |
| 99 | 100 |
| 100 | 101 |
| 101 void FastCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) { | 102 void FastCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) { |
| 102 // Call the runtime to declare the globals. | 103 // Call the runtime to declare the globals. |
| 104 __ push(esi); // The context is the first argument. |
| 103 __ push(Immediate(pairs)); | 105 __ push(Immediate(pairs)); |
| 104 __ push(esi); // The context is the second argument. | |
| 105 __ push(Immediate(Smi::FromInt(is_eval_ ? 1 : 0))); | 106 __ push(Immediate(Smi::FromInt(is_eval_ ? 1 : 0))); |
| 106 __ CallRuntime(Runtime::kDeclareGlobals, 3); | 107 __ CallRuntime(Runtime::kDeclareGlobals, 3); |
| 107 // Return value is ignored. | 108 // Return value is ignored. |
| 108 } | 109 } |
| 109 | 110 |
| 110 | 111 |
| 111 void FastCodeGenerator::VisitBlock(Block* stmt) { | 112 void FastCodeGenerator::VisitBlock(Block* stmt) { |
| 112 Comment cmnt(masm_, "[ Block"); | 113 Comment cmnt(masm_, "[ Block"); |
| 113 SetStatementPosition(stmt); | 114 SetStatementPosition(stmt); |
| 114 VisitStatements(stmt->statements()); | 115 VisitStatements(stmt->statements()); |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 150 void FastCodeGenerator::VisitFunctionLiteral(FunctionLiteral* expr) { | 151 void FastCodeGenerator::VisitFunctionLiteral(FunctionLiteral* expr) { |
| 151 Comment cmnt(masm_, "[ FunctionLiteral"); | 152 Comment cmnt(masm_, "[ FunctionLiteral"); |
| 152 | 153 |
| 153 // Build the function boilerplate and instantiate it. | 154 // Build the function boilerplate and instantiate it. |
| 154 Handle<JSFunction> boilerplate = BuildBoilerplate(expr); | 155 Handle<JSFunction> boilerplate = BuildBoilerplate(expr); |
| 155 if (HasStackOverflow()) return; | 156 if (HasStackOverflow()) return; |
| 156 | 157 |
| 157 ASSERT(boilerplate->IsBoilerplate()); | 158 ASSERT(boilerplate->IsBoilerplate()); |
| 158 | 159 |
| 159 // Create a new closure. | 160 // Create a new closure. |
| 161 __ push(esi); |
| 160 __ push(Immediate(boilerplate)); | 162 __ push(Immediate(boilerplate)); |
| 161 __ push(esi); | |
| 162 __ CallRuntime(Runtime::kNewClosure, 2); | 163 __ CallRuntime(Runtime::kNewClosure, 2); |
| 163 | 164 |
| 164 if (expr->location().is_temporary()) { | 165 if (expr->location().is_temporary()) { |
| 165 __ push(eax); | 166 __ push(eax); |
| 166 } else { | 167 } else { |
| 167 ASSERT(expr->location().is_nowhere()); | 168 ASSERT(expr->location().is_nowhere()); |
| 168 } | 169 } |
| 169 } | 170 } |
| 170 | 171 |
| 171 | 172 |
| (...skipping 11 matching lines...) Expand all Loading... |
| 183 | 184 |
| 184 // A test eax instruction following the call is used by the IC to | 185 // A test eax instruction following the call is used by the IC to |
| 185 // indicate that the inobject property case was inlined. Ensure there | 186 // indicate that the inobject property case was inlined. Ensure there |
| 186 // is no test eax instruction here. Remember that the assembler may | 187 // is no test eax instruction here. Remember that the assembler may |
| 187 // choose to do peephole optimization (eg, push/pop elimination). | 188 // choose to do peephole optimization (eg, push/pop elimination). |
| 188 if (expr->location().is_temporary()) { | 189 if (expr->location().is_temporary()) { |
| 189 // Replace the global object with the result. | 190 // Replace the global object with the result. |
| 190 __ mov(Operand(esp, 0), eax); | 191 __ mov(Operand(esp, 0), eax); |
| 191 } else { | 192 } else { |
| 192 ASSERT(expr->location().is_nowhere()); | 193 ASSERT(expr->location().is_nowhere()); |
| 193 __ pop(eax); | 194 __ add(Operand(esp), Immediate(kPointerSize)); |
| 194 } | 195 } |
| 195 | 196 |
| 196 } else { | 197 } else { |
| 197 Comment cmnt(masm_, "Stack slot"); | 198 Comment cmnt(masm_, "Stack slot"); |
| 198 Slot* slot = rewrite->AsSlot(); | 199 Slot* slot = rewrite->AsSlot(); |
| 199 ASSERT(slot != NULL); | 200 ASSERT(slot != NULL); |
| 200 if (expr->location().is_temporary()) { | 201 if (expr->location().is_temporary()) { |
| 201 __ push(Operand(ebp, SlotOffset(slot))); | 202 __ push(Operand(ebp, SlotOffset(slot))); |
| 202 } else { | 203 } else { |
| 203 ASSERT(expr->location().is_nowhere()); | 204 ASSERT(expr->location().is_nowhere()); |
| 204 } | 205 } |
| 205 } | 206 } |
| 206 } | 207 } |
| 207 | 208 |
| 208 | 209 |
| 210 void FastCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { |
| 211 Comment cmnt(masm_, "[ ArrayLiteral"); |
| 212 Label make_clone; |
| 213 |
| 214 // Fetch the function's literals array. |
| 215 __ mov(ebx, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset)); |
| 216 __ mov(ebx, FieldOperand(ebx, JSFunction::kLiteralsOffset)); |
| 217 // Check if the literal's boilerplate has been instantiated. |
| 218 int offset = |
| 219 FixedArray::kHeaderSize + (expr->literal_index() * kPointerSize); |
| 220 __ mov(eax, FieldOperand(ebx, offset)); |
| 221 __ cmp(eax, Factory::undefined_value()); |
| 222 __ j(not_equal, &make_clone); |
| 223 |
| 224 // Instantiate the boilerplate. |
| 225 __ push(ebx); |
| 226 __ push(Immediate(Smi::FromInt(expr->literal_index()))); |
| 227 __ push(Immediate(expr->literals())); |
| 228 __ CallRuntime(Runtime::kCreateArrayLiteralBoilerplate, 3); |
| 229 |
| 230 __ bind(&make_clone); |
| 231 // Clone the boilerplate. |
| 232 __ push(eax); |
| 233 if (expr->depth() > 1) { |
| 234 __ CallRuntime(Runtime::kCloneLiteralBoilerplate, 1); |
| 235 } else { |
| 236 __ CallRuntime(Runtime::kCloneShallowLiteralBoilerplate, 1); |
| 237 } |
| 238 |
| 239 bool result_saved = false; // Is the result saved to the stack? |
| 240 |
| 241 // Emit code to evaluate all the non-constant subexpressions and to store |
| 242 // them into the newly cloned array. |
| 243 ZoneList<Expression*>* subexprs = expr->values(); |
| 244 for (int i = 0, len = subexprs->length(); i < len; i++) { |
| 245 Expression* subexpr = subexprs->at(i); |
| 246 // If the subexpression is a literal or a simple materialized literal it |
| 247 // is already set in the cloned array. |
| 248 if (subexpr->AsLiteral() != NULL || |
| 249 CompileTimeValue::IsCompileTimeValue(subexpr)) { |
| 250 continue; |
| 251 } |
| 252 |
| 253 if (!result_saved) { |
| 254 __ push(eax); |
| 255 result_saved = true; |
| 256 } |
| 257 Visit(subexpr); |
| 258 ASSERT(subexpr->location().is_temporary()); |
| 259 |
| 260 // Store the subexpression value in the array's elements. |
| 261 __ pop(eax); // Subexpression value. |
| 262 __ mov(ebx, Operand(esp, 0)); // Copy of array literal. |
| 263 __ mov(ebx, FieldOperand(ebx, JSObject::kElementsOffset)); |
| 264 int offset = FixedArray::kHeaderSize + (i * kPointerSize); |
| 265 __ mov(FieldOperand(ebx, offset), eax); |
| 266 |
| 267 // Update the write barrier for the array store. |
| 268 __ RecordWrite(ebx, offset, eax, ecx); |
| 269 } |
| 270 |
| 271 Location destination = expr->location(); |
| 272 if (destination.is_nowhere() && result_saved) { |
| 273 __ add(Operand(esp), Immediate(kPointerSize)); |
| 274 } else if (destination.is_temporary() && !result_saved) { |
| 275 __ push(eax); |
| 276 } |
| 277 } |
| 278 |
| 279 |
| 209 void FastCodeGenerator::VisitAssignment(Assignment* expr) { | 280 void FastCodeGenerator::VisitAssignment(Assignment* expr) { |
| 210 Comment cmnt(masm_, "[ Assignment"); | 281 Comment cmnt(masm_, "[ Assignment"); |
| 211 ASSERT(expr->op() == Token::ASSIGN || expr->op() == Token::INIT_VAR); | 282 ASSERT(expr->op() == Token::ASSIGN || expr->op() == Token::INIT_VAR); |
| 212 Expression* rhs = expr->value(); | 283 Expression* rhs = expr->value(); |
| 213 Visit(rhs); | 284 Visit(rhs); |
| 214 | 285 |
| 215 // Left-hand side can only be a global or a (parameter or local) slot. | 286 // Left-hand side can only be a global or a (parameter or local) slot. |
| 216 Variable* var = expr->target()->AsVariableProxy()->AsVariable(); | 287 Variable* var = expr->target()->AsVariableProxy()->AsVariable(); |
| 217 ASSERT(var != NULL); | 288 ASSERT(var != NULL); |
| 218 ASSERT(var->is_global() || var->slot() != NULL); | 289 ASSERT(var->is_global() || var->slot() != NULL); |
| (...skipping 18 matching lines...) Expand all Loading... |
| 237 } | 308 } |
| 238 __ mov(ecx, var->name()); | 309 __ mov(ecx, var->name()); |
| 239 __ push(CodeGenerator::GlobalObject()); | 310 __ push(CodeGenerator::GlobalObject()); |
| 240 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); | 311 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); |
| 241 __ call(ic, RelocInfo::CODE_TARGET); | 312 __ call(ic, RelocInfo::CODE_TARGET); |
| 242 // Overwrite the global object on the stack with the result if needed. | 313 // Overwrite the global object on the stack with the result if needed. |
| 243 if (destination.is_temporary()) { | 314 if (destination.is_temporary()) { |
| 244 __ mov(Operand(esp, 0), eax); | 315 __ mov(Operand(esp, 0), eax); |
| 245 } else { | 316 } else { |
| 246 ASSERT(destination.is_nowhere()); | 317 ASSERT(destination.is_nowhere()); |
| 247 __ pop(eax); | 318 __ add(Operand(esp), Immediate(kPointerSize)); |
| 248 } | 319 } |
| 249 | 320 |
| 250 } else { | 321 } else { |
| 251 // Local or parameter assignment. | 322 // Local or parameter assignment. |
| 252 if (source.is_temporary()) { | 323 if (source.is_temporary()) { |
| 253 if (destination.is_temporary()) { | 324 if (destination.is_temporary()) { |
| 254 // Case 'temp1 <- (var = temp0)'. Preserve right-hand-side | 325 // Case 'temp1 <- (var = temp0)'. Preserve right-hand-side |
| 255 // temporary on the stack. | 326 // temporary on the stack. |
| 256 __ mov(eax, Operand(esp, 0)); | 327 __ mov(eax, Operand(esp, 0)); |
| 257 __ mov(Operand(ebp, SlotOffset(var->slot())), eax); | 328 __ mov(Operand(ebp, SlotOffset(var->slot())), eax); |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 301 Handle<Code> ic = CodeGenerator::ComputeCallInitialize(arg_count, | 372 Handle<Code> ic = CodeGenerator::ComputeCallInitialize(arg_count, |
| 302 NOT_IN_LOOP); | 373 NOT_IN_LOOP); |
| 303 __ call(ic, RelocInfo::CODE_TARGET_CONTEXT); | 374 __ call(ic, RelocInfo::CODE_TARGET_CONTEXT); |
| 304 // Restore context register. | 375 // Restore context register. |
| 305 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); | 376 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); |
| 306 // Discard the function left on TOS. | 377 // Discard the function left on TOS. |
| 307 if (expr->location().is_temporary()) { | 378 if (expr->location().is_temporary()) { |
| 308 __ mov(Operand(esp, 0), eax); | 379 __ mov(Operand(esp, 0), eax); |
| 309 } else { | 380 } else { |
| 310 ASSERT(expr->location().is_nowhere()); | 381 ASSERT(expr->location().is_nowhere()); |
| 311 __ pop(eax); | 382 __ add(Operand(esp), Immediate(kPointerSize)); |
| 312 } | 383 } |
| 313 } | 384 } |
| 314 | 385 |
| 315 | 386 |
| 316 void FastCodeGenerator::VisitCallRuntime(CallRuntime* expr) { | 387 void FastCodeGenerator::VisitCallRuntime(CallRuntime* expr) { |
| 317 Comment cmnt(masm_, "[ CallRuntime"); | 388 Comment cmnt(masm_, "[ CallRuntime"); |
| 318 ZoneList<Expression*>* args = expr->arguments(); | 389 ZoneList<Expression*>* args = expr->arguments(); |
| 319 Runtime::Function* function = expr->function(); | 390 Runtime::Function* function = expr->function(); |
| 320 | 391 |
| 321 ASSERT(function != NULL); | 392 ASSERT(function != NULL); |
| (...skipping 12 matching lines...) Expand all Loading... |
| 334 __ CallRuntime(function, arg_count); | 405 __ CallRuntime(function, arg_count); |
| 335 if (expr->location().is_temporary()) { | 406 if (expr->location().is_temporary()) { |
| 336 __ push(eax); | 407 __ push(eax); |
| 337 } else { | 408 } else { |
| 338 ASSERT(expr->location().is_nowhere()); | 409 ASSERT(expr->location().is_nowhere()); |
| 339 } | 410 } |
| 340 } | 411 } |
| 341 | 412 |
| 342 | 413 |
| 343 } } // namespace v8::internal | 414 } } // namespace v8::internal |
| OLD | NEW |