Chromium Code Reviews| 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 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 101 __ RecordJSReturn(); | 101 __ RecordJSReturn(); |
| 102 // Do not use the leave instruction here because it is too short to | 102 // Do not use the leave instruction here because it is too short to |
| 103 // patch with the code required by the debugger. | 103 // patch with the code required by the debugger. |
| 104 __ mov(esp, ebp); | 104 __ mov(esp, ebp); |
| 105 __ pop(ebp); | 105 __ pop(ebp); |
| 106 __ ret((fun->scope()->num_parameters() + 1) * kPointerSize); | 106 __ ret((fun->scope()->num_parameters() + 1) * kPointerSize); |
| 107 } | 107 } |
| 108 } | 108 } |
| 109 | 109 |
| 110 | 110 |
| 111 void FastCodeGenerator::Move(Location destination, Slot* source) { | 111 void FastCodeGenerator::Move(Expression::Context context, Slot* source) { |
| 112 switch (destination.type()) { | 112 switch (context) { |
| 113 case Location::kUninitialized: | 113 case Expression::kUninitialized: |
| 114 UNREACHABLE(); | 114 UNREACHABLE(); |
| 115 case Location::kEffect: | 115 case Expression::kEffect: |
| 116 break; | 116 break; |
| 117 case Location::kValue: | 117 case Expression::kValue: |
| 118 __ push(Operand(ebp, SlotOffset(source))); | 118 __ push(Operand(ebp, SlotOffset(source))); |
| 119 break; | 119 break; |
| 120 } | 120 } |
| 121 } | 121 } |
| 122 | 122 |
| 123 | 123 |
| 124 void FastCodeGenerator::Move(Location destination, Literal* expr) { | 124 void FastCodeGenerator::Move(Expression::Context context, Literal* expr) { |
| 125 switch (destination.type()) { | 125 switch (context) { |
| 126 case Location::kUninitialized: | 126 case Expression::kUninitialized: |
| 127 UNREACHABLE(); | 127 UNREACHABLE(); |
| 128 case Location::kEffect: | 128 case Expression::kEffect: |
| 129 break; | 129 break; |
| 130 case Location::kValue: | 130 case Expression::kValue: |
| 131 __ push(Immediate(expr->handle())); | 131 __ push(Immediate(expr->handle())); |
| 132 break; | 132 break; |
| 133 } | 133 } |
| 134 } | 134 } |
| 135 | 135 |
| 136 | 136 |
| 137 void FastCodeGenerator::Move(Slot* destination, Location source) { | 137 void FastCodeGenerator::DropAndMove(Expression::Context context, |
| 138 switch (source.type()) { | 138 Register source) { |
| 139 case Location::kUninitialized: // Fall through. | 139 switch (context) { |
| 140 case Location::kEffect: | 140 case Expression::kUninitialized: |
| 141 UNREACHABLE(); | 141 UNREACHABLE(); |
| 142 case Location::kValue: | 142 case Expression::kEffect: |
| 143 __ pop(Operand(ebp, SlotOffset(destination))); | |
| 144 break; | |
| 145 } | |
| 146 } | |
| 147 | |
| 148 | |
| 149 void FastCodeGenerator::DropAndMove(Location destination, Register source) { | |
| 150 switch (destination.type()) { | |
| 151 case Location::kUninitialized: | |
| 152 UNREACHABLE(); | |
| 153 case Location::kEffect: | |
| 154 __ add(Operand(esp), Immediate(kPointerSize)); | 143 __ add(Operand(esp), Immediate(kPointerSize)); |
| 155 break; | 144 break; |
| 156 case Location::kValue: | 145 case Expression::kValue: |
| 157 __ mov(Operand(esp, 0), source); | 146 __ mov(Operand(esp, 0), source); |
| 158 break; | 147 break; |
| 159 } | 148 } |
| 160 } | 149 } |
| 161 | 150 |
| 162 | 151 |
| 163 void FastCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) { | 152 void FastCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) { |
| 164 // Call the runtime to declare the globals. | 153 // Call the runtime to declare the globals. |
| 165 __ push(esi); // The context is the first argument. | 154 __ push(esi); // The context is the first argument. |
| 166 __ push(Immediate(pairs)); | 155 __ push(Immediate(pairs)); |
| 167 __ push(Immediate(Smi::FromInt(is_eval_ ? 1 : 0))); | 156 __ push(Immediate(Smi::FromInt(is_eval_ ? 1 : 0))); |
| 168 __ CallRuntime(Runtime::kDeclareGlobals, 3); | 157 __ CallRuntime(Runtime::kDeclareGlobals, 3); |
| 169 // Return value is ignored. | 158 // Return value is ignored. |
| 170 } | 159 } |
| 171 | 160 |
| 172 | 161 |
| 173 void FastCodeGenerator::VisitReturnStatement(ReturnStatement* stmt) { | 162 void FastCodeGenerator::VisitReturnStatement(ReturnStatement* stmt) { |
| 174 Comment cmnt(masm_, "[ ReturnStatement"); | 163 Comment cmnt(masm_, "[ ReturnStatement"); |
| 175 SetStatementPosition(stmt); | 164 SetStatementPosition(stmt); |
| 176 Expression* expr = stmt->expression(); | 165 Expression* expr = stmt->expression(); |
| 177 // Complete the statement based on the type of the subexpression. | 166 Visit(expr); |
| 178 if (expr->AsLiteral() != NULL) { | 167 ASSERT_EQ(Expression::kValue, expr->context()); |
| 179 __ mov(eax, expr->AsLiteral()->handle()); | 168 __ pop(eax); |
|
William Hesse
2009/10/29 15:15:25
Restore optimization?
Kevin Millikin (Chromium)
2009/10/29 16:36:10
Done.
| |
| 180 } else { | |
| 181 Visit(expr); | |
| 182 Move(eax, expr->location()); | |
| 183 } | |
| 184 | 169 |
| 185 if (FLAG_trace) { | 170 if (FLAG_trace) { |
| 186 __ push(eax); | 171 __ push(eax); |
| 187 __ CallRuntime(Runtime::kTraceExit, 1); | 172 __ CallRuntime(Runtime::kTraceExit, 1); |
| 188 } | 173 } |
| 189 __ RecordJSReturn(); | 174 __ RecordJSReturn(); |
| 190 | 175 |
| 191 // Do not use the leave instruction here because it is too short to | 176 // Do not use the leave instruction here because it is too short to |
| 192 // patch with the code required by the debugger. | 177 // patch with the code required by the debugger. |
| 193 __ mov(esp, ebp); | 178 __ mov(esp, ebp); |
| 194 __ pop(ebp); | 179 __ pop(ebp); |
| 195 __ ret((function_->scope()->num_parameters() + 1) * kPointerSize); | 180 __ ret((function_->scope()->num_parameters() + 1) * kPointerSize); |
| 196 } | 181 } |
| 197 | 182 |
| 198 | 183 |
| 199 void FastCodeGenerator::VisitFunctionLiteral(FunctionLiteral* expr) { | 184 void FastCodeGenerator::VisitFunctionLiteral(FunctionLiteral* expr) { |
| 200 Comment cmnt(masm_, "[ FunctionLiteral"); | 185 Comment cmnt(masm_, "[ FunctionLiteral"); |
| 201 | 186 |
| 202 // Build the function boilerplate and instantiate it. | 187 // Build the function boilerplate and instantiate it. |
| 203 Handle<JSFunction> boilerplate = BuildBoilerplate(expr); | 188 Handle<JSFunction> boilerplate = BuildBoilerplate(expr); |
| 204 if (HasStackOverflow()) return; | 189 if (HasStackOverflow()) return; |
| 205 | 190 |
| 206 ASSERT(boilerplate->IsBoilerplate()); | 191 ASSERT(boilerplate->IsBoilerplate()); |
| 207 | 192 |
| 208 // Create a new closure. | 193 // Create a new closure. |
| 209 __ push(esi); | 194 __ push(esi); |
| 210 __ push(Immediate(boilerplate)); | 195 __ push(Immediate(boilerplate)); |
| 211 __ CallRuntime(Runtime::kNewClosure, 2); | 196 __ CallRuntime(Runtime::kNewClosure, 2); |
| 212 Move(expr->location(), eax); | 197 Move(expr->context(), eax); |
| 213 } | 198 } |
| 214 | 199 |
| 215 | 200 |
| 216 void FastCodeGenerator::VisitVariableProxy(VariableProxy* expr) { | 201 void FastCodeGenerator::VisitVariableProxy(VariableProxy* expr) { |
| 217 Comment cmnt(masm_, "[ VariableProxy"); | 202 Comment cmnt(masm_, "[ VariableProxy"); |
| 218 Expression* rewrite = expr->var()->rewrite(); | 203 Expression* rewrite = expr->var()->rewrite(); |
| 219 if (rewrite == NULL) { | 204 if (rewrite == NULL) { |
| 220 Comment cmnt(masm_, "Global variable"); | 205 Comment cmnt(masm_, "Global variable"); |
| 221 // Use inline caching. Variable name is passed in ecx and the global | 206 // Use inline caching. Variable name is passed in ecx and the global |
| 222 // object on the stack. | 207 // object on the stack. |
| 223 __ push(CodeGenerator::GlobalObject()); | 208 __ push(CodeGenerator::GlobalObject()); |
| 224 __ mov(ecx, expr->name()); | 209 __ mov(ecx, expr->name()); |
| 225 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize)); | 210 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize)); |
| 226 __ call(ic, RelocInfo::CODE_TARGET_CONTEXT); | 211 __ call(ic, RelocInfo::CODE_TARGET_CONTEXT); |
| 227 // By emitting a nop we make sure that we do not have a test eax | 212 // By emitting a nop we make sure that we do not have a test eax |
| 228 // instruction after the call it is treated specially by the LoadIC code | 213 // instruction after the call it is treated specially by the LoadIC code |
| 229 // Remember that the assembler may choose to do peephole optimization | 214 // Remember that the assembler may choose to do peephole optimization |
| 230 // (eg, push/pop elimination). | 215 // (eg, push/pop elimination). |
| 231 __ nop(); | 216 __ nop(); |
| 232 | 217 |
| 233 DropAndMove(expr->location(), eax); | 218 DropAndMove(expr->context(), eax); |
| 234 } else { | 219 } else { |
| 235 Comment cmnt(masm_, "Stack slot"); | 220 Comment cmnt(masm_, "Stack slot"); |
| 236 Move(expr->location(), rewrite->AsSlot()); | 221 Move(expr->context(), rewrite->AsSlot()); |
| 237 } | 222 } |
| 238 } | 223 } |
| 239 | 224 |
| 240 | 225 |
| 241 void FastCodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) { | 226 void FastCodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) { |
| 242 Comment cmnt(masm_, "[ RegExp Literal"); | 227 Comment cmnt(masm_, "[ RegExp Literal"); |
| 243 Label done; | 228 Label done; |
| 244 // Registers will be used as follows: | 229 // Registers will be used as follows: |
| 245 // edi = JS function. | 230 // edi = JS function. |
| 246 // ebx = literals array. | 231 // ebx = literals array. |
| 247 // eax = regexp literal. | 232 // eax = regexp literal. |
| 248 __ mov(edi, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset)); | 233 __ mov(edi, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset)); |
| 249 __ mov(ebx, FieldOperand(edi, JSFunction::kLiteralsOffset)); | 234 __ mov(ebx, FieldOperand(edi, JSFunction::kLiteralsOffset)); |
| 250 int literal_offset = | 235 int literal_offset = |
| 251 FixedArray::kHeaderSize + expr->literal_index() * kPointerSize; | 236 FixedArray::kHeaderSize + expr->literal_index() * kPointerSize; |
| 252 __ mov(eax, FieldOperand(ebx, literal_offset)); | 237 __ mov(eax, FieldOperand(ebx, literal_offset)); |
| 253 __ cmp(eax, Factory::undefined_value()); | 238 __ cmp(eax, Factory::undefined_value()); |
| 254 __ j(not_equal, &done); | 239 __ j(not_equal, &done); |
| 255 // Create regexp literal using runtime function | 240 // Create regexp literal using runtime function |
| 256 // Result will be in eax. | 241 // Result will be in eax. |
| 257 __ push(ebx); | 242 __ push(ebx); |
| 258 __ push(Immediate(Smi::FromInt(expr->literal_index()))); | 243 __ push(Immediate(Smi::FromInt(expr->literal_index()))); |
| 259 __ push(Immediate(expr->pattern())); | 244 __ push(Immediate(expr->pattern())); |
| 260 __ push(Immediate(expr->flags())); | 245 __ push(Immediate(expr->flags())); |
| 261 __ CallRuntime(Runtime::kMaterializeRegExpLiteral, 4); | 246 __ CallRuntime(Runtime::kMaterializeRegExpLiteral, 4); |
| 262 // Label done: | 247 // Label done: |
| 263 __ bind(&done); | 248 __ bind(&done); |
| 264 Move(expr->location(), eax); | 249 Move(expr->context(), eax); |
| 265 } | 250 } |
| 266 | 251 |
| 267 | 252 |
| 268 void FastCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { | 253 void FastCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { |
| 269 Comment cmnt(masm_, "[ ObjectLiteral"); | 254 Comment cmnt(masm_, "[ ObjectLiteral"); |
| 270 Label exists; | 255 Label exists; |
| 271 // Registers will be used as follows: | 256 // Registers will be used as follows: |
| 272 // edi = JS function. | 257 // edi = JS function. |
| 273 // ebx = literals array. | 258 // ebx = literals array. |
| 274 // eax = boilerplate | 259 // eax = boilerplate |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 311 if (!result_saved) { | 296 if (!result_saved) { |
| 312 __ push(eax); // Save result on the stack | 297 __ push(eax); // Save result on the stack |
| 313 result_saved = true; | 298 result_saved = true; |
| 314 } | 299 } |
| 315 switch (property->kind()) { | 300 switch (property->kind()) { |
| 316 case ObjectLiteral::Property::MATERIALIZED_LITERAL: // fall through | 301 case ObjectLiteral::Property::MATERIALIZED_LITERAL: // fall through |
| 317 ASSERT(!CompileTimeValue::IsCompileTimeValue(value)); | 302 ASSERT(!CompileTimeValue::IsCompileTimeValue(value)); |
| 318 case ObjectLiteral::Property::COMPUTED: | 303 case ObjectLiteral::Property::COMPUTED: |
| 319 if (key->handle()->IsSymbol()) { | 304 if (key->handle()->IsSymbol()) { |
| 320 Visit(value); | 305 Visit(value); |
| 321 Move(eax, value->location()); | 306 ASSERT_EQ(Expression::kValue, value->context()); |
| 307 __ pop(eax); | |
| 322 __ mov(ecx, Immediate(key->handle())); | 308 __ mov(ecx, Immediate(key->handle())); |
| 323 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); | 309 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); |
| 324 __ call(ic, RelocInfo::CODE_TARGET); | 310 __ call(ic, RelocInfo::CODE_TARGET); |
| 325 // StoreIC leaves the receiver on the stack. | 311 // StoreIC leaves the receiver on the stack. |
| 326 break; | 312 break; |
| 327 } | 313 } |
| 328 // fall through | 314 // fall through |
| 329 case ObjectLiteral::Property::PROTOTYPE: | 315 case ObjectLiteral::Property::PROTOTYPE: |
| 330 __ push(eax); | 316 __ push(eax); |
| 331 Visit(key); | 317 Visit(key); |
| 332 ASSERT(key->location().is_value()); | 318 ASSERT_EQ(Expression::kValue, key->context()); |
| 333 Visit(value); | 319 Visit(value); |
| 334 ASSERT(value->location().is_value()); | 320 ASSERT_EQ(Expression::kValue, value->context()); |
| 335 __ CallRuntime(Runtime::kSetProperty, 3); | 321 __ CallRuntime(Runtime::kSetProperty, 3); |
| 336 __ mov(eax, Operand(esp, 0)); // Restore result into eax. | 322 __ mov(eax, Operand(esp, 0)); // Restore result into eax. |
| 337 break; | 323 break; |
| 338 case ObjectLiteral::Property::SETTER: // fall through | 324 case ObjectLiteral::Property::SETTER: // fall through |
| 339 case ObjectLiteral::Property::GETTER: | 325 case ObjectLiteral::Property::GETTER: |
| 340 __ push(eax); | 326 __ push(eax); |
| 341 Visit(key); | 327 Visit(key); |
| 342 ASSERT(key->location().is_value()); | 328 ASSERT_EQ(Expression::kValue, key->context()); |
| 343 __ push(Immediate(property->kind() == ObjectLiteral::Property::SETTER ? | 329 __ push(Immediate(property->kind() == ObjectLiteral::Property::SETTER ? |
| 344 Smi::FromInt(1) : | 330 Smi::FromInt(1) : |
| 345 Smi::FromInt(0))); | 331 Smi::FromInt(0))); |
| 346 Visit(value); | 332 Visit(value); |
| 347 ASSERT(value->location().is_value()); | 333 ASSERT_EQ(Expression::kValue, value->context()); |
| 348 __ CallRuntime(Runtime::kDefineAccessor, 4); | 334 __ CallRuntime(Runtime::kDefineAccessor, 4); |
| 349 __ mov(eax, Operand(esp, 0)); // Restore result into eax. | 335 __ mov(eax, Operand(esp, 0)); // Restore result into eax. |
| 350 break; | 336 break; |
| 351 default: UNREACHABLE(); | 337 default: UNREACHABLE(); |
| 352 } | 338 } |
| 353 } | 339 } |
| 354 switch (expr->location().type()) { | 340 switch (expr->context()) { |
| 355 case Location::kUninitialized: | 341 case Expression::kUninitialized: |
| 356 UNREACHABLE(); | 342 UNREACHABLE(); |
| 357 case Location::kEffect: | 343 case Expression::kEffect: |
| 358 if (result_saved) __ add(Operand(esp), Immediate(kPointerSize)); | 344 if (result_saved) __ add(Operand(esp), Immediate(kPointerSize)); |
| 359 break; | 345 break; |
| 360 case Location::kValue: | 346 case Expression::kValue: |
| 361 if (!result_saved) __ push(eax); | 347 if (!result_saved) __ push(eax); |
| 362 break; | 348 break; |
| 363 } | 349 } |
| 364 } | 350 } |
| 365 | 351 |
| 366 | 352 |
| 367 void FastCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { | 353 void FastCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { |
| 368 Comment cmnt(masm_, "[ ArrayLiteral"); | 354 Comment cmnt(masm_, "[ ArrayLiteral"); |
| 369 Label make_clone; | 355 Label make_clone; |
| 370 | 356 |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 405 if (subexpr->AsLiteral() != NULL || | 391 if (subexpr->AsLiteral() != NULL || |
| 406 CompileTimeValue::IsCompileTimeValue(subexpr)) { | 392 CompileTimeValue::IsCompileTimeValue(subexpr)) { |
| 407 continue; | 393 continue; |
| 408 } | 394 } |
| 409 | 395 |
| 410 if (!result_saved) { | 396 if (!result_saved) { |
| 411 __ push(eax); | 397 __ push(eax); |
| 412 result_saved = true; | 398 result_saved = true; |
| 413 } | 399 } |
| 414 Visit(subexpr); | 400 Visit(subexpr); |
| 415 ASSERT(subexpr->location().is_value()); | 401 ASSERT_EQ(Expression::kValue, subexpr->context()); |
| 416 | 402 |
| 417 // Store the subexpression value in the array's elements. | 403 // Store the subexpression value in the array's elements. |
| 418 __ pop(eax); // Subexpression value. | 404 __ pop(eax); // Subexpression value. |
| 419 __ mov(ebx, Operand(esp, 0)); // Copy of array literal. | 405 __ mov(ebx, Operand(esp, 0)); // Copy of array literal. |
| 420 __ mov(ebx, FieldOperand(ebx, JSObject::kElementsOffset)); | 406 __ mov(ebx, FieldOperand(ebx, JSObject::kElementsOffset)); |
| 421 int offset = FixedArray::kHeaderSize + (i * kPointerSize); | 407 int offset = FixedArray::kHeaderSize + (i * kPointerSize); |
| 422 __ mov(FieldOperand(ebx, offset), eax); | 408 __ mov(FieldOperand(ebx, offset), eax); |
| 423 | 409 |
| 424 // Update the write barrier for the array store. | 410 // Update the write barrier for the array store. |
| 425 __ RecordWrite(ebx, offset, eax, ecx); | 411 __ RecordWrite(ebx, offset, eax, ecx); |
| 426 } | 412 } |
| 427 | 413 |
| 428 switch (expr->location().type()) { | 414 switch (expr->context()) { |
| 429 case Location::kUninitialized: | 415 case Expression::kUninitialized: |
| 430 UNREACHABLE(); | 416 UNREACHABLE(); |
| 431 case Location::kEffect: | 417 case Expression::kEffect: |
| 432 if (result_saved) __ add(Operand(esp), Immediate(kPointerSize)); | 418 if (result_saved) __ add(Operand(esp), Immediate(kPointerSize)); |
| 433 break; | 419 break; |
| 434 case Location::kValue: | 420 case Expression::kValue: |
| 435 if (!result_saved) __ push(eax); | 421 if (!result_saved) __ push(eax); |
| 436 break; | 422 break; |
| 437 } | 423 } |
| 438 } | 424 } |
| 439 | 425 |
| 440 | 426 |
| 441 void FastCodeGenerator::VisitAssignment(Assignment* expr) { | 427 void FastCodeGenerator::VisitAssignment(Assignment* expr) { |
| 442 Comment cmnt(masm_, "[ Assignment"); | 428 Comment cmnt(masm_, "[ Assignment"); |
| 443 ASSERT(expr->op() == Token::ASSIGN || expr->op() == Token::INIT_VAR); | 429 ASSERT(expr->op() == Token::ASSIGN || expr->op() == Token::INIT_VAR); |
| 444 | 430 |
| 445 // Left-hand side can only be a global or a (parameter or local) slot. | 431 // Left-hand side can only be a global or a (parameter or local) slot. |
| 446 Variable* var = expr->target()->AsVariableProxy()->AsVariable(); | 432 Variable* var = expr->target()->AsVariableProxy()->AsVariable(); |
| 447 ASSERT(var != NULL); | 433 ASSERT(var != NULL); |
| 448 ASSERT(var->is_global() || var->slot() != NULL); | 434 ASSERT(var->is_global() || var->slot() != NULL); |
| 449 | 435 |
| 450 Expression* rhs = expr->value(); | 436 Expression* rhs = expr->value(); |
| 451 if (var->is_global()) { | 437 if (var->is_global()) { |
| 452 // Assignment to a global variable, use inline caching. Right-hand-side | 438 // Assignment to a global variable, use inline caching. Right-hand-side |
| 453 // value is passed in eax, variable name in ecx, and the global object | 439 // value is passed in eax, variable name in ecx, and the global object |
| 454 // on the stack. | 440 // on the stack. |
| 455 | 441 |
| 456 // Code for the right-hand-side expression depends on its type. | 442 // Code for the right-hand-side expression depends on its type. |
| 457 if (rhs->AsLiteral() != NULL) { | 443 if (rhs->AsLiteral() != NULL) { |
| 458 __ mov(eax, rhs->AsLiteral()->handle()); | 444 __ mov(eax, rhs->AsLiteral()->handle()); |
| 459 } else { | 445 } else { |
| 460 ASSERT(rhs->location().is_value()); | 446 ASSERT_EQ(Expression::kValue, rhs->context()); |
| 461 Visit(rhs); | 447 Visit(rhs); |
| 462 __ pop(eax); | 448 __ pop(eax); |
| 463 } | 449 } |
| 464 __ mov(ecx, var->name()); | 450 __ mov(ecx, var->name()); |
| 465 __ push(CodeGenerator::GlobalObject()); | 451 __ push(CodeGenerator::GlobalObject()); |
| 466 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); | 452 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); |
| 467 __ call(ic, RelocInfo::CODE_TARGET); | 453 __ call(ic, RelocInfo::CODE_TARGET); |
| 468 // Overwrite the global object on the stack with the result if needed. | 454 // Overwrite the global object on the stack with the result if needed. |
| 469 DropAndMove(expr->location(), eax); | 455 DropAndMove(expr->context(), eax); |
| 470 } else { | 456 } else { |
| 471 // Local or parameter assignment. | 457 // Local or parameter assignment. |
| 472 | 458 |
| 473 // Code for the right-hand side expression depends on its type. | 459 // Code for the right-hand side expression depends on its type. |
| 474 if (rhs->AsLiteral() != NULL) { | 460 if (rhs->AsLiteral() != NULL) { |
| 475 // Two cases: 'temp <- (var = constant)', or 'var = constant' with a | 461 // Two cases: 'temp <- (var = constant)', or 'var = constant' with a |
| 476 // discarded result. Always perform the assignment. | 462 // discarded result. Always perform the assignment. |
| 477 __ mov(eax, rhs->AsLiteral()->handle()); | 463 __ mov(eax, rhs->AsLiteral()->handle()); |
| 478 __ mov(Operand(ebp, SlotOffset(var->slot())), eax); | 464 __ mov(Operand(ebp, SlotOffset(var->slot())), eax); |
| 479 Move(expr->location(), eax); | 465 Move(expr->context(), eax); |
| 480 } else { | 466 } else { |
| 481 ASSERT(rhs->location().is_value()); | 467 ASSERT_EQ(Expression::kValue, rhs->context()); |
| 482 Visit(rhs); | 468 Visit(rhs); |
| 483 switch (expr->location().type()) { | 469 switch (expr->context()) { |
| 484 case Location::kUninitialized: | 470 case Expression::kUninitialized: |
| 485 UNREACHABLE(); | 471 UNREACHABLE(); |
| 486 case Location::kEffect: | 472 case Expression::kEffect: |
| 487 // Case 'var = temp'. Discard right-hand-side temporary. | 473 // Case 'var = temp'. Discard right-hand-side temporary. |
| 488 Move(var->slot(), rhs->location()); | 474 __ pop(Operand(ebp, SlotOffset(var->slot()))); |
| 489 break; | 475 break; |
| 490 case Location::kValue: | 476 case Expression::kValue: |
| 491 // Case 'temp1 <- (var = temp0)'. Preserve right-hand-side | 477 // Case 'temp1 <- (var = temp0)'. Preserve right-hand-side |
| 492 // temporary on the stack. | 478 // temporary on the stack. |
| 493 __ mov(eax, Operand(esp, 0)); | 479 __ mov(eax, Operand(esp, 0)); |
| 494 __ mov(Operand(ebp, SlotOffset(var->slot())), eax); | 480 __ mov(Operand(ebp, SlotOffset(var->slot())), eax); |
| 495 break; | 481 break; |
| 496 } | 482 } |
| 497 } | 483 } |
| 498 } | 484 } |
| 499 } | 485 } |
| 500 | 486 |
| (...skipping 23 matching lines...) Expand all Loading... | |
| 524 // Do a KEYED property load. | 510 // Do a KEYED property load. |
| 525 Visit(expr->key()); | 511 Visit(expr->key()); |
| 526 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize)); | 512 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize)); |
| 527 __ call(ic, RelocInfo::CODE_TARGET); | 513 __ call(ic, RelocInfo::CODE_TARGET); |
| 528 // By emitting a nop we make sure that we do not have a "test eax,..." | 514 // By emitting a nop we make sure that we do not have a "test eax,..." |
| 529 // instruction after the call it is treated specially by the LoadIC code. | 515 // instruction after the call it is treated specially by the LoadIC code. |
| 530 __ nop(); | 516 __ nop(); |
| 531 // Drop key left on the stack by IC. | 517 // Drop key left on the stack by IC. |
| 532 __ add(Operand(esp), Immediate(kPointerSize)); | 518 __ add(Operand(esp), Immediate(kPointerSize)); |
| 533 } | 519 } |
| 534 switch (expr->location().type()) { | 520 DropAndMove(expr->context(), eax); |
| 535 case Location::kUninitialized: | |
| 536 UNREACHABLE(); | |
| 537 case Location::kValue: | |
| 538 __ mov(Operand(esp, 0), eax); | |
| 539 break; | |
| 540 case Location::kEffect: | |
| 541 __ add(Operand(esp), Immediate(kPointerSize)); | |
| 542 break; | |
| 543 } | |
| 544 } | 521 } |
| 545 | 522 |
| 546 | 523 |
| 547 void FastCodeGenerator::VisitCall(Call* expr) { | 524 void FastCodeGenerator::VisitCall(Call* expr) { |
| 548 Expression* fun = expr->expression(); | 525 Expression* fun = expr->expression(); |
| 549 ZoneList<Expression*>* args = expr->arguments(); | 526 ZoneList<Expression*>* args = expr->arguments(); |
| 550 Variable* var = fun->AsVariableProxy()->AsVariable(); | 527 Variable* var = fun->AsVariableProxy()->AsVariable(); |
| 551 ASSERT(var != NULL && !var->is_this() && var->is_global()); | 528 ASSERT(var != NULL && !var->is_this() && var->is_global()); |
| 552 ASSERT(!var->is_possibly_eval()); | 529 ASSERT(!var->is_possibly_eval()); |
| 553 | 530 |
| 554 __ push(Immediate(var->name())); | 531 __ push(Immediate(var->name())); |
| 555 // Push global object (receiver). | 532 // Push global object (receiver). |
| 556 __ push(CodeGenerator::GlobalObject()); | 533 __ push(CodeGenerator::GlobalObject()); |
| 557 int arg_count = args->length(); | 534 int arg_count = args->length(); |
| 558 for (int i = 0; i < arg_count; i++) { | 535 for (int i = 0; i < arg_count; i++) { |
| 559 Visit(args->at(i)); | 536 Visit(args->at(i)); |
| 560 ASSERT(args->at(i)->location().is_value()); | 537 ASSERT_EQ(Expression::kValue, args->at(i)->context()); |
| 561 } | 538 } |
| 562 // Record source position for debugger | 539 // Record source position for debugger |
| 563 SetSourcePosition(expr->position()); | 540 SetSourcePosition(expr->position()); |
| 564 // Call the IC initialization code. | 541 // Call the IC initialization code. |
| 565 Handle<Code> ic = CodeGenerator::ComputeCallInitialize(arg_count, | 542 Handle<Code> ic = CodeGenerator::ComputeCallInitialize(arg_count, |
| 566 NOT_IN_LOOP); | 543 NOT_IN_LOOP); |
| 567 __ call(ic, RelocInfo::CODE_TARGET_CONTEXT); | 544 __ call(ic, RelocInfo::CODE_TARGET_CONTEXT); |
| 568 // Restore context register. | 545 // Restore context register. |
| 569 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); | 546 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); |
| 570 // Discard the function left on TOS. | 547 // Discard the function left on TOS. |
| 571 DropAndMove(expr->location(), eax); | 548 DropAndMove(expr->context(), eax); |
| 572 } | 549 } |
| 573 | 550 |
| 574 | 551 |
| 575 void FastCodeGenerator::VisitCallNew(CallNew* node) { | 552 void FastCodeGenerator::VisitCallNew(CallNew* expr) { |
| 576 Comment cmnt(masm_, "[ CallNew"); | 553 Comment cmnt(masm_, "[ CallNew"); |
| 577 // According to ECMA-262, section 11.2.2, page 44, the function | 554 // According to ECMA-262, section 11.2.2, page 44, the function |
| 578 // expression in new calls must be evaluated before the | 555 // expression in new calls must be evaluated before the |
| 579 // arguments. | 556 // arguments. |
| 580 // Push function on the stack. | 557 // Push function on the stack. |
| 581 Visit(node->expression()); | 558 Visit(expr->expression()); |
| 582 ASSERT(node->expression()->location().is_value()); | 559 ASSERT_EQ(Expression::kValue, expr->expression()->context()); |
| 583 | 560 |
| 584 // Push global object (receiver). | 561 // Push global object (receiver). |
| 585 __ push(CodeGenerator::GlobalObject()); | 562 __ push(CodeGenerator::GlobalObject()); |
| 586 | 563 |
| 587 // Push the arguments ("left-to-right") on the stack. | 564 // Push the arguments ("left-to-right") on the stack. |
| 588 ZoneList<Expression*>* args = node->arguments(); | 565 ZoneList<Expression*>* args = expr->arguments(); |
| 589 int arg_count = args->length(); | 566 int arg_count = args->length(); |
| 590 for (int i = 0; i < arg_count; i++) { | 567 for (int i = 0; i < arg_count; i++) { |
| 591 Visit(args->at(i)); | 568 Visit(args->at(i)); |
| 592 ASSERT(args->at(i)->location().is_value()); | 569 ASSERT_EQ(Expression::kValue, args->at(i)->context()); |
| 593 // If location is value, it is already on the stack, | 570 // If location is value, it is already on the stack, |
| 594 // so nothing to do here. | 571 // so nothing to do here. |
| 595 } | 572 } |
| 596 | 573 |
| 597 // Call the construct call builtin that handles allocation and | 574 // Call the construct call builtin that handles allocation and |
| 598 // constructor invocation. | 575 // constructor invocation. |
| 599 SetSourcePosition(node->position()); | 576 SetSourcePosition(expr->position()); |
| 600 | 577 |
| 601 // Load function, arg_count into edi and eax. | 578 // Load function, arg_count into edi and eax. |
| 602 __ Set(eax, Immediate(arg_count)); | 579 __ Set(eax, Immediate(arg_count)); |
| 603 // Function is in esp[arg_count + 1]. | 580 // Function is in esp[arg_count + 1]. |
| 604 __ mov(edi, Operand(esp, eax, times_pointer_size, kPointerSize)); | 581 __ mov(edi, Operand(esp, eax, times_pointer_size, kPointerSize)); |
| 605 | 582 |
| 606 Handle<Code> construct_builtin(Builtins::builtin(Builtins::JSConstructCall)); | 583 Handle<Code> construct_builtin(Builtins::builtin(Builtins::JSConstructCall)); |
| 607 __ call(construct_builtin, RelocInfo::CONSTRUCT_CALL); | 584 __ call(construct_builtin, RelocInfo::CONSTRUCT_CALL); |
| 608 | 585 |
| 609 // Replace function on TOS with result in eax, or pop it. | 586 // Replace function on TOS with result in eax, or pop it. |
| 610 DropAndMove(node->location(), eax); | 587 DropAndMove(expr->context(), eax); |
| 611 } | 588 } |
| 612 | 589 |
| 613 | 590 |
| 614 void FastCodeGenerator::VisitCallRuntime(CallRuntime* expr) { | 591 void FastCodeGenerator::VisitCallRuntime(CallRuntime* expr) { |
| 615 Comment cmnt(masm_, "[ CallRuntime"); | 592 Comment cmnt(masm_, "[ CallRuntime"); |
| 616 ZoneList<Expression*>* args = expr->arguments(); | 593 ZoneList<Expression*>* args = expr->arguments(); |
| 617 Runtime::Function* function = expr->function(); | 594 Runtime::Function* function = expr->function(); |
| 618 | 595 |
| 619 ASSERT(function != NULL); | 596 ASSERT(function != NULL); |
| 620 | 597 |
| 621 // Push the arguments ("left-to-right"). | 598 // Push the arguments ("left-to-right"). |
| 622 int arg_count = args->length(); | 599 int arg_count = args->length(); |
| 623 for (int i = 0; i < arg_count; i++) { | 600 for (int i = 0; i < arg_count; i++) { |
| 624 Visit(args->at(i)); | 601 Visit(args->at(i)); |
| 625 ASSERT(args->at(i)->location().is_value()); | 602 ASSERT_EQ(Expression::kValue, args->at(i)->context()); |
| 626 } | 603 } |
| 627 | 604 |
| 628 __ CallRuntime(function, arg_count); | 605 __ CallRuntime(function, arg_count); |
| 629 Move(expr->location(), eax); | 606 Move(expr->context(), eax); |
| 630 } | 607 } |
| 631 | 608 |
| 632 | 609 |
| 633 void FastCodeGenerator::VisitBinaryOperation(BinaryOperation* expr) { | 610 void FastCodeGenerator::VisitBinaryOperation(BinaryOperation* expr) { |
| 634 switch (expr->op()) { | 611 switch (expr->op()) { |
| 635 case Token::COMMA: | 612 case Token::COMMA: |
| 636 ASSERT(expr->left()->location().is_effect()); | 613 ASSERT_EQ(Expression::kValue, expr->left()->context()); |
| 637 ASSERT_EQ(expr->right()->location().type(), expr->location().type()); | 614 ASSERT_EQ(expr->context(), expr->right()->context()); |
| 638 Visit(expr->left()); | 615 Visit(expr->left()); |
| 639 Visit(expr->right()); | 616 Visit(expr->right()); |
| 640 break; | 617 break; |
| 641 | 618 |
| 642 case Token::OR: | 619 case Token::OR: |
| 643 case Token::AND: | 620 case Token::AND: |
| 644 EmitLogicalOperation(expr); | 621 EmitLogicalOperation(expr); |
| 645 break; | 622 break; |
| 646 | 623 |
| 647 case Token::ADD: | 624 case Token::ADD: |
| 648 case Token::SUB: | 625 case Token::SUB: |
| 649 case Token::DIV: | 626 case Token::DIV: |
| 650 case Token::MOD: | 627 case Token::MOD: |
| 651 case Token::MUL: | 628 case Token::MUL: |
| 652 case Token::BIT_OR: | 629 case Token::BIT_OR: |
| 653 case Token::BIT_AND: | 630 case Token::BIT_AND: |
| 654 case Token::BIT_XOR: | 631 case Token::BIT_XOR: |
| 655 case Token::SHL: | 632 case Token::SHL: |
| 656 case Token::SHR: | 633 case Token::SHR: |
| 657 case Token::SAR: { | 634 case Token::SAR: { |
| 658 ASSERT(expr->left()->location().is_value()); | 635 ASSERT_EQ(Expression::kValue, expr->left()->context()); |
| 659 ASSERT(expr->right()->location().is_value()); | 636 ASSERT_EQ(Expression::kValue, expr->right()->context()); |
| 660 | 637 |
| 661 Visit(expr->left()); | 638 Visit(expr->left()); |
| 662 Visit(expr->right()); | 639 Visit(expr->right()); |
| 663 GenericBinaryOpStub stub(expr->op(), | 640 GenericBinaryOpStub stub(expr->op(), |
| 664 NO_OVERWRITE, | 641 NO_OVERWRITE, |
| 665 NO_GENERIC_BINARY_FLAGS); | 642 NO_GENERIC_BINARY_FLAGS); |
| 666 __ CallStub(&stub); | 643 __ CallStub(&stub); |
| 667 Move(expr->location(), eax); | 644 Move(expr->context(), eax); |
| 668 | 645 |
| 669 break; | 646 break; |
| 670 } | 647 } |
| 671 default: | 648 default: |
| 672 UNREACHABLE(); | 649 UNREACHABLE(); |
| 673 } | 650 } |
| 674 } | 651 } |
| 675 | 652 |
| 676 | 653 |
| 677 void FastCodeGenerator::EmitLogicalOperation(BinaryOperation* expr) { | 654 void FastCodeGenerator::EmitLogicalOperation(BinaryOperation* expr) { |
| 678 // Compile a short-circuited boolean operation in a non-test context. | 655 // Compile a short-circuited boolean operation in a non-test context. |
| 679 | 656 |
| 680 // Compile (e0 || e1) or (e0 && e1) as if it were | 657 // Compile (e0 || e1) or (e0 && e1) as if it were |
| 681 // (let (temp = e0) temp [or !temp, for &&] ? temp : e1). | 658 // (let (temp = e0) temp [or !temp, for &&] ? temp : e1). |
| 682 | 659 |
| 683 Label eval_right, done; | 660 Label eval_right, done; |
| 684 Label *left_true, *left_false; // Where to branch to if lhs has that value. | 661 Label *left_true, *left_false; // Where to branch to if lhs has that value. |
| 685 if (expr->op() == Token::OR) { | 662 if (expr->op() == Token::OR) { |
| 686 left_true = &done; | 663 left_true = &done; |
| 687 left_false = &eval_right; | 664 left_false = &eval_right; |
| 688 } else { | 665 } else { |
| 689 left_true = &eval_right; | 666 left_true = &eval_right; |
| 690 left_false = &done; | 667 left_false = &done; |
| 691 } | 668 } |
| 692 Location destination = expr->location(); | 669 Expression::Context context = expr->context(); |
| 693 Expression* left = expr->left(); | 670 Expression* left = expr->left(); |
| 694 Expression* right = expr->right(); | 671 Expression* right = expr->right(); |
| 695 | 672 |
| 696 // Use the shared ToBoolean stub to find the boolean value of the | 673 // Use the shared ToBoolean stub to find the boolean value of the |
| 697 // left-hand subexpression. Load the value into eax to perform some | 674 // left-hand subexpression. Load the value into eax to perform some |
| 698 // inlined checks assumed by the stub. | 675 // inlined checks assumed by the stub. |
| 699 | 676 |
| 700 // Compile the left-hand value into eax. Put it on the stack if we may | 677 // Compile the left-hand value into eax. Put it on the stack if we may |
| 701 // need it as the value of the whole expression. | 678 // need it as the value of the whole expression. |
| 702 if (left->AsLiteral() != NULL) { | 679 if (left->AsLiteral() != NULL) { |
| 703 __ mov(eax, left->AsLiteral()->handle()); | 680 __ mov(eax, left->AsLiteral()->handle()); |
| 704 if (destination.is_value()) __ push(eax); | 681 if (context == Expression::kValue) __ push(eax); |
| 705 } else { | 682 } else { |
| 706 Visit(left); | 683 Visit(left); |
| 707 ASSERT(left->location().is_value()); | 684 ASSERT_EQ(Expression::kValue, left->context()); |
| 708 switch (destination.type()) { | 685 switch (context) { |
| 709 case Location::kUninitialized: | 686 case Expression::kUninitialized: |
| 710 UNREACHABLE(); | 687 UNREACHABLE(); |
| 711 case Location::kEffect: | 688 case Expression::kEffect: |
| 712 // Pop the left-hand value into eax because we will not need it as the | 689 // Pop the left-hand value into eax because we will not need it as the |
| 713 // final result. | 690 // final result. |
| 714 __ pop(eax); | 691 __ pop(eax); |
| 715 break; | 692 break; |
| 716 case Location::kValue: | 693 case Expression::kValue: |
| 717 // Copy the left-hand value into eax because we may need it as the | 694 // Copy the left-hand value into eax because we may need it as the |
| 718 // final result. | 695 // final result. |
| 719 __ mov(eax, Operand(esp, 0)); | 696 __ mov(eax, Operand(esp, 0)); |
| 720 break; | 697 break; |
| 721 } | 698 } |
| 722 } | 699 } |
| 723 // The left-hand value is in eax. It is also on the stack iff the | 700 // The left-hand value is in eax. It is also on the stack iff the |
| 724 // destination location is value. | 701 // destination location is value. |
| 725 | 702 |
| 726 // Perform fast checks assumed by the stub. | 703 // Perform fast checks assumed by the stub. |
| 727 __ cmp(eax, Factory::undefined_value()); // The undefined value is false. | 704 __ cmp(eax, Factory::undefined_value()); // The undefined value is false. |
| 728 __ j(equal, left_false); | 705 __ j(equal, left_false); |
| 729 __ cmp(eax, Factory::true_value()); // True is true. | 706 __ cmp(eax, Factory::true_value()); // True is true. |
| 730 __ j(equal, left_true); | 707 __ j(equal, left_true); |
| 731 __ cmp(eax, Factory::false_value()); // False is false. | 708 __ cmp(eax, Factory::false_value()); // False is false. |
| 732 __ j(equal, left_false); | 709 __ j(equal, left_false); |
| 733 ASSERT(kSmiTag == 0); | 710 ASSERT_EQ(0, kSmiTag); |
| 734 __ test(eax, Operand(eax)); // The smi zero is false. | 711 __ test(eax, Operand(eax)); // The smi zero is false. |
| 735 __ j(zero, left_false); | 712 __ j(zero, left_false); |
| 736 __ test(eax, Immediate(kSmiTagMask)); // All other smis are true. | 713 __ test(eax, Immediate(kSmiTagMask)); // All other smis are true. |
| 737 __ j(zero, left_true); | 714 __ j(zero, left_true); |
| 738 | 715 |
| 739 // Call the stub for all other cases. | 716 // Call the stub for all other cases. |
| 740 __ push(eax); | 717 __ push(eax); |
| 741 ToBooleanStub stub; | 718 ToBooleanStub stub; |
| 742 __ CallStub(&stub); | 719 __ CallStub(&stub); |
| 743 __ test(eax, Operand(eax)); // The stub returns nonzero for true. | 720 __ test(eax, Operand(eax)); // The stub returns nonzero for true. |
| 744 if (expr->op() == Token::OR) { | 721 if (expr->op() == Token::OR) { |
| 745 __ j(not_zero, &done); | 722 __ j(not_zero, &done); |
| 746 } else { | 723 } else { |
| 747 __ j(zero, &done); | 724 __ j(zero, &done); |
| 748 } | 725 } |
| 749 | 726 |
| 750 __ bind(&eval_right); | 727 __ bind(&eval_right); |
| 751 // Discard the left-hand value if present on the stack. | 728 // Discard the left-hand value if present on the stack. |
| 752 if (destination.is_value()) { | 729 if (context == Expression::kValue) { |
| 753 __ add(Operand(esp), Immediate(kPointerSize)); | 730 __ add(Operand(esp), Immediate(kPointerSize)); |
| 754 } | 731 } |
| 755 // Save or discard the right-hand value as needed. | 732 // Save or discard the right-hand value as needed. |
| 756 Visit(right); | 733 Visit(right); |
| 757 ASSERT_EQ(destination.type(), right->location().type()); | 734 ASSERT_EQ(context, right->context()); |
| 758 | 735 |
| 759 __ bind(&done); | 736 __ bind(&done); |
| 760 } | 737 } |
| 761 | 738 |
| 762 | 739 |
| 763 } } // namespace v8::internal | 740 } } // namespace v8::internal |
| OLD | NEW |