| 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 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 111 for (int i = 0; i < kPadding; ++i) { | 111 for (int i = 0; i < kPadding; ++i) { |
| 112 masm_->int3(); | 112 masm_->int3(); |
| 113 } | 113 } |
| 114 #endif | 114 #endif |
| 115 } | 115 } |
| 116 } | 116 } |
| 117 | 117 |
| 118 | 118 |
| 119 void FastCodeGenerator::Move(Location destination, Slot* source) { | 119 void FastCodeGenerator::Move(Location destination, Slot* source) { |
| 120 switch (destination.type()) { | 120 switch (destination.type()) { |
| 121 case Location::NOWHERE: | 121 case Location::UNINITIALIZED: |
| 122 UNREACHABLE(); |
| 123 case Location::EFFECT: |
| 122 break; | 124 break; |
| 123 case Location::TEMP: | 125 case Location::VALUE: |
| 124 __ push(Operand(rbp, SlotOffset(source))); | 126 __ push(Operand(rbp, SlotOffset(source))); |
| 125 break; | 127 break; |
| 126 } | 128 } |
| 127 } | 129 } |
| 128 | 130 |
| 129 | 131 |
| 130 void FastCodeGenerator::Move(Location destination, Literal* expr) { | 132 void FastCodeGenerator::Move(Location destination, Literal* expr) { |
| 131 switch (destination.type()) { | 133 switch (destination.type()) { |
| 132 case Location::NOWHERE: | 134 case Location::UNINITIALIZED: |
| 135 UNREACHABLE(); |
| 136 case Location::EFFECT: |
| 133 break; | 137 break; |
| 134 case Location::TEMP: | 138 case Location::VALUE: |
| 135 __ Push(expr->handle()); | 139 __ Push(expr->handle()); |
| 136 break; | 140 break; |
| 137 } | 141 } |
| 138 } | 142 } |
| 139 | 143 |
| 140 | 144 |
| 141 void FastCodeGenerator::Move(Slot* destination, Location source) { | 145 void FastCodeGenerator::Move(Slot* destination, Location source) { |
| 142 switch (source.type()) { | 146 switch (source.type()) { |
| 143 case Location::NOWHERE: | 147 case Location::UNINITIALIZED: // Fall through. |
| 148 case Location::EFFECT: |
| 144 UNREACHABLE(); | 149 UNREACHABLE(); |
| 145 case Location::TEMP: | 150 case Location::VALUE: |
| 146 __ pop(Operand(rbp, SlotOffset(destination))); | 151 __ pop(Operand(rbp, SlotOffset(destination))); |
| 147 break; | 152 break; |
| 148 } | 153 } |
| 149 } | 154 } |
| 150 | 155 |
| 151 | 156 |
| 152 void FastCodeGenerator::DropAndMove(Location destination, Register source) { | 157 void FastCodeGenerator::DropAndMove(Location destination, Register source) { |
| 153 switch (destination.type()) { | 158 switch (destination.type()) { |
| 154 case Location::NOWHERE: | 159 case Location::UNINITIALIZED: |
| 160 UNREACHABLE(); |
| 161 case Location::EFFECT: |
| 155 __ addq(rsp, Immediate(kPointerSize)); | 162 __ addq(rsp, Immediate(kPointerSize)); |
| 156 break; | 163 break; |
| 157 case Location::TEMP: | 164 case Location::VALUE: |
| 158 __ movq(Operand(rsp, 0), source); | 165 __ movq(Operand(rsp, 0), source); |
| 159 break; | 166 break; |
| 160 } | 167 } |
| 161 } | 168 } |
| 162 | 169 |
| 163 | 170 |
| 164 void FastCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) { | 171 void FastCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) { |
| 165 // Call the runtime to declare the globals. | 172 // Call the runtime to declare the globals. |
| 166 __ push(rsi); // The context is the first argument. | 173 __ push(rsi); // The context is the first argument. |
| 167 __ Push(pairs); | 174 __ Push(pairs); |
| (...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 239 // indicate that the inobject property case was inlined. Ensure there | 246 // indicate that the inobject property case was inlined. Ensure there |
| 240 // is no test rax instruction here. | 247 // is no test rax instruction here. |
| 241 DropAndMove(expr->location(), rax); | 248 DropAndMove(expr->location(), rax); |
| 242 } else { | 249 } else { |
| 243 Comment cmnt(masm_, "Stack slot"); | 250 Comment cmnt(masm_, "Stack slot"); |
| 244 Move(expr->location(), rewrite->AsSlot()); | 251 Move(expr->location(), rewrite->AsSlot()); |
| 245 } | 252 } |
| 246 } | 253 } |
| 247 | 254 |
| 248 | 255 |
| 256 void FastCodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) { |
| 257 Comment cmnt(masm_, "[ RegExp Literal"); |
| 258 Label done; |
| 259 // Registers will be used as follows: |
| 260 // rdi = JS function. |
| 261 // rbx = literals array. |
| 262 // rax = regexp literal. |
| 263 __ movq(rdi, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset)); |
| 264 __ movq(rbx, FieldOperand(rdi, JSFunction::kLiteralsOffset)); |
| 265 int literal_offset = |
| 266 FixedArray::kHeaderSize + expr->literal_index() * kPointerSize; |
| 267 __ movq(rax, FieldOperand(rbx, literal_offset)); |
| 268 __ CompareRoot(rax, Heap::kUndefinedValueRootIndex); |
| 269 __ j(not_equal, &done); |
| 270 // Create regexp literal using runtime function |
| 271 // Result will be in rax. |
| 272 __ push(rbx); |
| 273 __ Push(Smi::FromInt(expr->literal_index())); |
| 274 __ Push(expr->pattern()); |
| 275 __ Push(expr->flags()); |
| 276 __ CallRuntime(Runtime::kMaterializeRegExpLiteral, 4); |
| 277 // Label done: |
| 278 __ bind(&done); |
| 279 Move(expr->location(), rax); |
| 280 } |
| 281 |
| 282 |
| 249 void FastCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { | 283 void FastCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { |
| 250 Comment cmnt(masm_, "[ ObjectLiteral"); | 284 Comment cmnt(masm_, "[ ObjectLiteral"); |
| 251 Label boilerplate_exists; | 285 Label boilerplate_exists; |
| 252 | 286 |
| 253 __ movq(rdi, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset)); | 287 __ movq(rdi, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset)); |
| 254 __ movq(rbx, FieldOperand(rdi, JSFunction::kLiteralsOffset)); | 288 __ movq(rbx, FieldOperand(rdi, JSFunction::kLiteralsOffset)); |
| 255 int literal_offset = | 289 int literal_offset = |
| 256 FixedArray::kHeaderSize + expr->literal_index() * kPointerSize; | 290 FixedArray::kHeaderSize + expr->literal_index() * kPointerSize; |
| 257 __ movq(rax, FieldOperand(rbx, literal_offset)); | 291 __ movq(rax, FieldOperand(rbx, literal_offset)); |
| 258 __ CompareRoot(rax, Heap::kUndefinedValueRootIndex); | 292 __ CompareRoot(rax, Heap::kUndefinedValueRootIndex); |
| (...skipping 29 matching lines...) Expand all Loading... |
| 288 if (!result_saved) { | 322 if (!result_saved) { |
| 289 __ push(rax); // Save result on the stack | 323 __ push(rax); // Save result on the stack |
| 290 result_saved = true; | 324 result_saved = true; |
| 291 } | 325 } |
| 292 switch (property->kind()) { | 326 switch (property->kind()) { |
| 293 case ObjectLiteral::Property::MATERIALIZED_LITERAL: // fall through | 327 case ObjectLiteral::Property::MATERIALIZED_LITERAL: // fall through |
| 294 ASSERT(!CompileTimeValue::IsCompileTimeValue(value)); | 328 ASSERT(!CompileTimeValue::IsCompileTimeValue(value)); |
| 295 case ObjectLiteral::Property::COMPUTED: | 329 case ObjectLiteral::Property::COMPUTED: |
| 296 if (key->handle()->IsSymbol()) { | 330 if (key->handle()->IsSymbol()) { |
| 297 Visit(value); | 331 Visit(value); |
| 298 ASSERT(value->location().is_temporary()); | 332 ASSERT(value->location().is_value()); |
| 299 __ pop(rax); | 333 __ pop(rax); |
| 300 __ Move(rcx, key->handle()); | 334 __ Move(rcx, key->handle()); |
| 301 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); | 335 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); |
| 302 __ call(ic, RelocInfo::CODE_TARGET); | 336 __ call(ic, RelocInfo::CODE_TARGET); |
| 303 // StoreIC leaves the receiver on the stack. | 337 // StoreIC leaves the receiver on the stack. |
| 304 break; | 338 break; |
| 305 } | 339 } |
| 306 // fall through | 340 // fall through |
| 307 case ObjectLiteral::Property::PROTOTYPE: | 341 case ObjectLiteral::Property::PROTOTYPE: |
| 308 __ push(rax); | 342 __ push(rax); |
| 309 Visit(key); | 343 Visit(key); |
| 310 ASSERT(key->location().is_temporary()); | 344 ASSERT(key->location().is_value()); |
| 311 Visit(value); | 345 Visit(value); |
| 312 ASSERT(value->location().is_temporary()); | 346 ASSERT(value->location().is_value()); |
| 313 __ CallRuntime(Runtime::kSetProperty, 3); | 347 __ CallRuntime(Runtime::kSetProperty, 3); |
| 314 __ movq(rax, Operand(rsp, 0)); // Restore result into rax. | 348 __ movq(rax, Operand(rsp, 0)); // Restore result into rax. |
| 315 break; | 349 break; |
| 316 case ObjectLiteral::Property::SETTER: // fall through | 350 case ObjectLiteral::Property::SETTER: // fall through |
| 317 case ObjectLiteral::Property::GETTER: | 351 case ObjectLiteral::Property::GETTER: |
| 318 __ push(rax); | 352 __ push(rax); |
| 319 Visit(key); | 353 Visit(key); |
| 320 ASSERT(key->location().is_temporary()); | 354 ASSERT(key->location().is_value()); |
| 321 __ Push(property->kind() == ObjectLiteral::Property::SETTER ? | 355 __ Push(property->kind() == ObjectLiteral::Property::SETTER ? |
| 322 Smi::FromInt(1) : | 356 Smi::FromInt(1) : |
| 323 Smi::FromInt(0)); | 357 Smi::FromInt(0)); |
| 324 Visit(value); | 358 Visit(value); |
| 325 ASSERT(value->location().is_temporary()); | 359 ASSERT(value->location().is_value()); |
| 326 __ CallRuntime(Runtime::kDefineAccessor, 4); | 360 __ CallRuntime(Runtime::kDefineAccessor, 4); |
| 327 __ movq(rax, Operand(rsp, 0)); // Restore result into rax. | 361 __ movq(rax, Operand(rsp, 0)); // Restore result into rax. |
| 328 break; | 362 break; |
| 329 default: UNREACHABLE(); | 363 default: UNREACHABLE(); |
| 330 } | 364 } |
| 331 } | 365 } |
| 332 switch (expr->location().type()) { | 366 switch (expr->location().type()) { |
| 333 case Location::NOWHERE: | 367 case Location::UNINITIALIZED: |
| 368 UNREACHABLE(); |
| 369 case Location::EFFECT: |
| 334 if (result_saved) __ addq(rsp, Immediate(kPointerSize)); | 370 if (result_saved) __ addq(rsp, Immediate(kPointerSize)); |
| 335 break; | 371 break; |
| 336 case Location::TEMP: | 372 case Location::VALUE: |
| 337 if (!result_saved) __ push(rax); | 373 if (!result_saved) __ push(rax); |
| 338 break; | 374 break; |
| 339 } | 375 } |
| 340 } | 376 } |
| 341 | 377 |
| 342 | 378 |
| 343 void FastCodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) { | |
| 344 Comment cmnt(masm_, "[ RegExp Literal"); | |
| 345 Label done; | |
| 346 // Registers will be used as follows: | |
| 347 // rdi = JS function. | |
| 348 // rbx = literals array. | |
| 349 // rax = regexp literal. | |
| 350 __ movq(rdi, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset)); | |
| 351 __ movq(rbx, FieldOperand(rdi, JSFunction::kLiteralsOffset)); | |
| 352 int literal_offset = | |
| 353 FixedArray::kHeaderSize + expr->literal_index() * kPointerSize; | |
| 354 __ movq(rax, FieldOperand(rbx, literal_offset)); | |
| 355 __ CompareRoot(rax, Heap::kUndefinedValueRootIndex); | |
| 356 __ j(not_equal, &done); | |
| 357 // Create regexp literal using runtime function | |
| 358 // Result will be in rax. | |
| 359 __ push(rbx); | |
| 360 __ Push(Smi::FromInt(expr->literal_index())); | |
| 361 __ Push(expr->pattern()); | |
| 362 __ Push(expr->flags()); | |
| 363 __ CallRuntime(Runtime::kMaterializeRegExpLiteral, 4); | |
| 364 // Label done: | |
| 365 __ bind(&done); | |
| 366 Move(expr->location(), rax); | |
| 367 } | |
| 368 | |
| 369 | |
| 370 void FastCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { | 379 void FastCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { |
| 371 Comment cmnt(masm_, "[ ArrayLiteral"); | 380 Comment cmnt(masm_, "[ ArrayLiteral"); |
| 372 Label make_clone; | 381 Label make_clone; |
| 373 | 382 |
| 374 // Fetch the function's literals array. | 383 // Fetch the function's literals array. |
| 375 __ movq(rbx, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset)); | 384 __ movq(rbx, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset)); |
| 376 __ movq(rbx, FieldOperand(rbx, JSFunction::kLiteralsOffset)); | 385 __ movq(rbx, FieldOperand(rbx, JSFunction::kLiteralsOffset)); |
| 377 // Check if the literal's boilerplate has been instantiated. | 386 // Check if the literal's boilerplate has been instantiated. |
| 378 int offset = | 387 int offset = |
| 379 FixedArray::kHeaderSize + (expr->literal_index() * kPointerSize); | 388 FixedArray::kHeaderSize + (expr->literal_index() * kPointerSize); |
| (...skipping 28 matching lines...) Expand all Loading... |
| 408 if (subexpr->AsLiteral() != NULL || | 417 if (subexpr->AsLiteral() != NULL || |
| 409 CompileTimeValue::IsCompileTimeValue(subexpr)) { | 418 CompileTimeValue::IsCompileTimeValue(subexpr)) { |
| 410 continue; | 419 continue; |
| 411 } | 420 } |
| 412 | 421 |
| 413 if (!result_saved) { | 422 if (!result_saved) { |
| 414 __ push(rax); | 423 __ push(rax); |
| 415 result_saved = true; | 424 result_saved = true; |
| 416 } | 425 } |
| 417 Visit(subexpr); | 426 Visit(subexpr); |
| 418 ASSERT(subexpr->location().is_temporary()); | 427 ASSERT(subexpr->location().is_value()); |
| 419 | 428 |
| 420 // Store the subexpression value in the array's elements. | 429 // Store the subexpression value in the array's elements. |
| 421 __ pop(rax); // Subexpression value. | 430 __ pop(rax); // Subexpression value. |
| 422 __ movq(rbx, Operand(rsp, 0)); // Copy of array literal. | 431 __ movq(rbx, Operand(rsp, 0)); // Copy of array literal. |
| 423 __ movq(rbx, FieldOperand(rbx, JSObject::kElementsOffset)); | 432 __ movq(rbx, FieldOperand(rbx, JSObject::kElementsOffset)); |
| 424 int offset = FixedArray::kHeaderSize + (i * kPointerSize); | 433 int offset = FixedArray::kHeaderSize + (i * kPointerSize); |
| 425 __ movq(FieldOperand(rbx, offset), rax); | 434 __ movq(FieldOperand(rbx, offset), rax); |
| 426 | 435 |
| 427 // Update the write barrier for the array store. | 436 // Update the write barrier for the array store. |
| 428 __ RecordWrite(rbx, offset, rax, rcx); | 437 __ RecordWrite(rbx, offset, rax, rcx); |
| 429 } | 438 } |
| 430 | 439 |
| 431 switch (expr->location().type()) { | 440 switch (expr->location().type()) { |
| 432 case Location::NOWHERE: | 441 case Location::UNINITIALIZED: |
| 442 UNREACHABLE(); |
| 443 case Location::EFFECT: |
| 433 if (result_saved) __ addq(rsp, Immediate(kPointerSize)); | 444 if (result_saved) __ addq(rsp, Immediate(kPointerSize)); |
| 434 break; | 445 break; |
| 435 case Location::TEMP: | 446 case Location::VALUE: |
| 436 if (!result_saved) __ push(rax); | 447 if (!result_saved) __ push(rax); |
| 437 break; | 448 break; |
| 438 } | 449 } |
| 439 } | 450 } |
| 440 | 451 |
| 441 | 452 |
| 442 void FastCodeGenerator::VisitAssignment(Assignment* expr) { | 453 void FastCodeGenerator::VisitAssignment(Assignment* expr) { |
| 443 Comment cmnt(masm_, "[ Assignment"); | 454 Comment cmnt(masm_, "[ Assignment"); |
| 444 ASSERT(expr->op() == Token::ASSIGN || expr->op() == Token::INIT_VAR); | 455 ASSERT(expr->op() == Token::ASSIGN || expr->op() == Token::INIT_VAR); |
| 445 | 456 |
| 446 // Left-hand side can only be a global or a (parameter or local) slot. | 457 // Left-hand side can only be a global or a (parameter or local) slot. |
| 447 Variable* var = expr->target()->AsVariableProxy()->AsVariable(); | 458 Variable* var = expr->target()->AsVariableProxy()->AsVariable(); |
| 448 ASSERT(var != NULL); | 459 ASSERT(var != NULL); |
| 449 ASSERT(var->is_global() || var->slot() != NULL); | 460 ASSERT(var->is_global() || var->slot() != NULL); |
| 450 | 461 |
| 451 Expression* rhs = expr->value(); | 462 Expression* rhs = expr->value(); |
| 452 Location destination = expr->location(); | 463 Location destination = expr->location(); |
| 453 if (var->is_global()) { | 464 if (var->is_global()) { |
| 454 // Assignment to a global variable, use inline caching. Right-hand-side | 465 // Assignment to a global variable, use inline caching. Right-hand-side |
| 455 // value is passed in rax, variable name in rcx, and the global object | 466 // value is passed in rax, variable name in rcx, and the global object |
| 456 // on the stack. | 467 // on the stack. |
| 457 | 468 |
| 458 // Code for the right-hand-side expression depends on its type. | 469 // Code for the right-hand-side expression depends on its type. |
| 459 if (rhs->AsLiteral() != NULL) { | 470 if (rhs->AsLiteral() != NULL) { |
| 460 __ Move(rax, rhs->AsLiteral()->handle()); | 471 __ Move(rax, rhs->AsLiteral()->handle()); |
| 461 } else { | 472 } else { |
| 462 ASSERT(rhs->location().is_temporary()); | 473 ASSERT(rhs->location().is_value()); |
| 463 Visit(rhs); | 474 Visit(rhs); |
| 464 __ pop(rax); | 475 __ pop(rax); |
| 465 } | 476 } |
| 466 __ Move(rcx, var->name()); | 477 __ Move(rcx, var->name()); |
| 467 __ push(CodeGenerator::GlobalObject()); | 478 __ push(CodeGenerator::GlobalObject()); |
| 468 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); | 479 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); |
| 469 __ Call(ic, RelocInfo::CODE_TARGET); | 480 __ Call(ic, RelocInfo::CODE_TARGET); |
| 470 // Overwrite the global object on the stack with the result if needed. | 481 // Overwrite the global object on the stack with the result if needed. |
| 471 DropAndMove(expr->location(), rax); | 482 DropAndMove(expr->location(), rax); |
| 472 } else { | 483 } else { |
| 473 // Local or parameter assignment. | 484 // Local or parameter assignment. |
| 474 | 485 |
| 475 // Code for the right-hand-side expression depends on its type. | 486 // Code for the right-hand-side expression depends on its type. |
| 476 if (rhs->AsLiteral() != NULL) { | 487 if (rhs->AsLiteral() != NULL) { |
| 477 // Two cases: 'temp <- (var = constant)', or 'var = constant' with a | 488 // Two cases: 'temp <- (var = constant)', or 'var = constant' with a |
| 478 // discarded result. Always perform the assignment. | 489 // discarded result. Always perform the assignment. |
| 479 __ Move(kScratchRegister, rhs->AsLiteral()->handle()); | 490 __ Move(kScratchRegister, rhs->AsLiteral()->handle()); |
| 480 __ movq(Operand(rbp, SlotOffset(var->slot())), kScratchRegister); | 491 __ movq(Operand(rbp, SlotOffset(var->slot())), kScratchRegister); |
| 481 Move(expr->location(), kScratchRegister); | 492 Move(expr->location(), kScratchRegister); |
| 482 } else { | 493 } else { |
| 483 ASSERT(rhs->location().is_temporary()); | 494 ASSERT(rhs->location().is_value()); |
| 484 Visit(rhs); | 495 Visit(rhs); |
| 485 switch (expr->location().type()) { | 496 switch (expr->location().type()) { |
| 486 case Location::NOWHERE: | 497 case Location::UNINITIALIZED: |
| 498 UNREACHABLE(); |
| 499 case Location::EFFECT: |
| 487 // Case 'var = temp'. Discard right-hand-side temporary. | 500 // Case 'var = temp'. Discard right-hand-side temporary. |
| 488 Move(var->slot(), rhs->location()); | 501 Move(var->slot(), rhs->location()); |
| 489 break; | 502 break; |
| 490 case Location::TEMP: | 503 case Location::VALUE: |
| 491 // Case 'temp1 <- (var = temp0)'. Preserve right-hand-side | 504 // Case 'temp1 <- (var = temp0)'. Preserve right-hand-side |
| 492 // temporary on the stack. | 505 // temporary on the stack. |
| 493 __ movq(kScratchRegister, Operand(rsp, 0)); | 506 __ movq(kScratchRegister, Operand(rsp, 0)); |
| 494 __ movq(Operand(rbp, SlotOffset(var->slot())), kScratchRegister); | 507 __ movq(Operand(rbp, SlotOffset(var->slot())), kScratchRegister); |
| 495 break; | 508 break; |
| 496 } | 509 } |
| 497 } | 510 } |
| 498 } | 511 } |
| 499 } | 512 } |
| 500 | 513 |
| (...skipping 24 matching lines...) Expand all Loading... |
| 525 Visit(expr->key()); | 538 Visit(expr->key()); |
| 526 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize)); | 539 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize)); |
| 527 __ call(ic, RelocInfo::CODE_TARGET); | 540 __ call(ic, RelocInfo::CODE_TARGET); |
| 528 // By emitting a nop we make sure that we do not have a "test ..." | 541 // By emitting a nop we make sure that we do not have a "test ..." |
| 529 // instruction after the call it is treated specially by the LoadIC code. | 542 // instruction after the call it is treated specially by the LoadIC code. |
| 530 __ nop(); | 543 __ nop(); |
| 531 // Drop key left on the stack by IC. | 544 // Drop key left on the stack by IC. |
| 532 __ addq(rsp, Immediate(kPointerSize)); | 545 __ addq(rsp, Immediate(kPointerSize)); |
| 533 } | 546 } |
| 534 switch (expr->location().type()) { | 547 switch (expr->location().type()) { |
| 535 case Location::TEMP: | 548 case Location::UNINITIALIZED: |
| 549 UNREACHABLE(); |
| 550 case Location::VALUE: |
| 536 __ movq(Operand(rsp, 0), rax); | 551 __ movq(Operand(rsp, 0), rax); |
| 537 break; | 552 break; |
| 538 case Location::NOWHERE: | 553 case Location::EFFECT: |
| 539 __ addq(rsp, Immediate(kPointerSize)); | 554 __ addq(rsp, Immediate(kPointerSize)); |
| 540 break; | 555 break; |
| 541 } | 556 } |
| 542 } | 557 } |
| 543 | 558 |
| 544 | 559 |
| 545 void FastCodeGenerator::VisitCall(Call* expr) { | 560 void FastCodeGenerator::VisitCall(Call* expr) { |
| 546 Expression* fun = expr->expression(); | 561 Expression* fun = expr->expression(); |
| 547 ZoneList<Expression*>* args = expr->arguments(); | 562 ZoneList<Expression*>* args = expr->arguments(); |
| 548 Variable* var = fun->AsVariableProxy()->AsVariable(); | 563 Variable* var = fun->AsVariableProxy()->AsVariable(); |
| 549 ASSERT(var != NULL && !var->is_this() && var->is_global()); | 564 ASSERT(var != NULL && !var->is_this() && var->is_global()); |
| 550 ASSERT(!var->is_possibly_eval()); | 565 ASSERT(!var->is_possibly_eval()); |
| 551 | 566 |
| 552 __ Push(var->name()); | 567 __ Push(var->name()); |
| 553 // Push global object (receiver). | 568 // Push global object (receiver). |
| 554 __ push(CodeGenerator::GlobalObject()); | 569 __ push(CodeGenerator::GlobalObject()); |
| 555 int arg_count = args->length(); | 570 int arg_count = args->length(); |
| 556 for (int i = 0; i < arg_count; i++) { | 571 for (int i = 0; i < arg_count; i++) { |
| 557 Visit(args->at(i)); | 572 Visit(args->at(i)); |
| 558 ASSERT(args->at(i)->location().is_temporary()); | 573 ASSERT(args->at(i)->location().is_value()); |
| 559 } | 574 } |
| 560 // Record source position for debugger | 575 // Record source position for debugger |
| 561 SetSourcePosition(expr->position()); | 576 SetSourcePosition(expr->position()); |
| 562 // Call the IC initialization code. | 577 // Call the IC initialization code. |
| 563 Handle<Code> ic = CodeGenerator::ComputeCallInitialize(arg_count, | 578 Handle<Code> ic = CodeGenerator::ComputeCallInitialize(arg_count, |
| 564 NOT_IN_LOOP); | 579 NOT_IN_LOOP); |
| 565 __ call(ic, RelocInfo::CODE_TARGET_CONTEXT); | 580 __ call(ic, RelocInfo::CODE_TARGET_CONTEXT); |
| 566 // Restore context register. | 581 // Restore context register. |
| 567 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); | 582 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); |
| 568 // Discard the function left on TOS. | 583 // Discard the function left on TOS. |
| 569 DropAndMove(expr->location(), rax); | 584 DropAndMove(expr->location(), rax); |
| 570 } | 585 } |
| 571 | 586 |
| 572 | 587 |
| 573 void FastCodeGenerator::VisitCallNew(CallNew* node) { | 588 void FastCodeGenerator::VisitCallNew(CallNew* node) { |
| 574 Comment cmnt(masm_, "[ CallNew"); | 589 Comment cmnt(masm_, "[ CallNew"); |
| 575 // According to ECMA-262, section 11.2.2, page 44, the function | 590 // According to ECMA-262, section 11.2.2, page 44, the function |
| 576 // expression in new calls must be evaluated before the | 591 // expression in new calls must be evaluated before the |
| 577 // arguments. | 592 // arguments. |
| 578 // Push function on the stack. | 593 // Push function on the stack. |
| 579 Visit(node->expression()); | 594 Visit(node->expression()); |
| 580 ASSERT(node->expression()->location().is_temporary()); | 595 ASSERT(node->expression()->location().is_value()); |
| 581 // If location is temporary, already on the stack, | 596 // If location is temporary, already on the stack, |
| 582 | 597 |
| 583 // Push global object (receiver). | 598 // Push global object (receiver). |
| 584 __ push(CodeGenerator::GlobalObject()); | 599 __ push(CodeGenerator::GlobalObject()); |
| 585 | 600 |
| 586 // Push the arguments ("left-to-right") on the stack. | 601 // Push the arguments ("left-to-right") on the stack. |
| 587 ZoneList<Expression*>* args = node->arguments(); | 602 ZoneList<Expression*>* args = node->arguments(); |
| 588 int arg_count = args->length(); | 603 int arg_count = args->length(); |
| 589 for (int i = 0; i < arg_count; i++) { | 604 for (int i = 0; i < arg_count; i++) { |
| 590 Visit(args->at(i)); | 605 Visit(args->at(i)); |
| 591 ASSERT(args->at(i)->location().is_temporary()); | 606 ASSERT(args->at(i)->location().is_value()); |
| 592 // If location is temporary, it is already on the stack, | 607 // If location is temporary, it is already on the stack, |
| 593 // so nothing to do here. | 608 // so nothing to do here. |
| 594 } | 609 } |
| 595 | 610 |
| 596 // Call the construct call builtin that handles allocation and | 611 // Call the construct call builtin that handles allocation and |
| 597 // constructor invocation. | 612 // constructor invocation. |
| 598 SetSourcePosition(node->position()); | 613 SetSourcePosition(node->position()); |
| 599 | 614 |
| 600 // Load function, arg_count into rdi and rax. | 615 // Load function, arg_count into rdi and rax. |
| 601 __ Set(rax, arg_count); | 616 __ Set(rax, arg_count); |
| (...skipping 12 matching lines...) Expand all Loading... |
| 614 Comment cmnt(masm_, "[ CallRuntime"); | 629 Comment cmnt(masm_, "[ CallRuntime"); |
| 615 ZoneList<Expression*>* args = expr->arguments(); | 630 ZoneList<Expression*>* args = expr->arguments(); |
| 616 Runtime::Function* function = expr->function(); | 631 Runtime::Function* function = expr->function(); |
| 617 | 632 |
| 618 ASSERT(function != NULL); | 633 ASSERT(function != NULL); |
| 619 | 634 |
| 620 // Push the arguments ("left-to-right"). | 635 // Push the arguments ("left-to-right"). |
| 621 int arg_count = args->length(); | 636 int arg_count = args->length(); |
| 622 for (int i = 0; i < arg_count; i++) { | 637 for (int i = 0; i < arg_count; i++) { |
| 623 Visit(args->at(i)); | 638 Visit(args->at(i)); |
| 624 ASSERT(args->at(i)->location().is_temporary()); | 639 ASSERT(args->at(i)->location().is_value()); |
| 625 } | 640 } |
| 626 | 641 |
| 627 __ CallRuntime(function, arg_count); | 642 __ CallRuntime(function, arg_count); |
| 628 Move(expr->location(), rax); | 643 Move(expr->location(), rax); |
| 629 } | 644 } |
| 630 | 645 |
| 631 | 646 |
| 632 void FastCodeGenerator::VisitBinaryOperation(BinaryOperation* expr) { | 647 void FastCodeGenerator::VisitBinaryOperation(BinaryOperation* expr) { |
| 633 // Compile a short-circuited boolean or operation in a non-test | 648 // Compile a short-circuited boolean or operation in a non-test |
| 634 // context. | 649 // context. |
| 635 ASSERT(expr->op() == Token::OR); | 650 ASSERT(expr->op() == Token::OR); |
| 636 // Compile (e0 || e1) as if it were | 651 // Compile (e0 || e1) as if it were |
| 637 // (let (temp = e0) temp ? temp : e1). | 652 // (let (temp = e0) temp ? temp : e1). |
| 638 | 653 |
| 639 Label eval_right, done; | 654 Label eval_right, done; |
| 640 Location destination = expr->location(); | 655 Location destination = expr->location(); |
| 641 Expression* left = expr->left(); | 656 Expression* left = expr->left(); |
| 642 Expression* right = expr->right(); | 657 Expression* right = expr->right(); |
| 643 | 658 |
| 644 // Use the shared ToBoolean stub to find the boolean value of the | 659 // Use the shared ToBoolean stub to find the boolean value of the |
| 645 // left-hand subexpression. Load the value into rax to perform some | 660 // left-hand subexpression. Load the value into rax to perform some |
| 646 // inlined checks assumed by the stub. | 661 // inlined checks assumed by the stub. |
| 647 | 662 |
| 648 // Compile the left-hand value into rax. Put it on the stack if we may | 663 // Compile the left-hand value into rax. Put it on the stack if we may |
| 649 // need it as the value of the whole expression. | 664 // need it as the value of the whole expression. |
| 650 if (left->AsLiteral() != NULL) { | 665 if (left->AsLiteral() != NULL) { |
| 651 __ Move(rax, left->AsLiteral()->handle()); | 666 __ Move(rax, left->AsLiteral()->handle()); |
| 652 if (destination.is_temporary()) __ push(rax); | 667 if (destination.is_value()) __ push(rax); |
| 653 } else { | 668 } else { |
| 654 Visit(left); | 669 Visit(left); |
| 655 ASSERT(left->location().is_temporary()); | 670 ASSERT(left->location().is_value()); |
| 656 switch (destination.type()) { | 671 switch (destination.type()) { |
| 657 case Location::NOWHERE: | 672 case Location::UNINITIALIZED: |
| 673 UNREACHABLE(); |
| 674 case Location::EFFECT: |
| 658 // Pop the left-hand value into rax because we will not need it as the | 675 // Pop the left-hand value into rax because we will not need it as the |
| 659 // final result. | 676 // final result. |
| 660 __ pop(rax); | 677 __ pop(rax); |
| 661 break; | 678 break; |
| 662 case Location::TEMP: | 679 case Location::VALUE: |
| 663 // Copy the left-hand value into rax because we may need it as the | 680 // Copy the left-hand value into rax because we may need it as the |
| 664 // final result. | 681 // final result. |
| 665 __ movq(rax, Operand(rsp, 0)); | 682 __ movq(rax, Operand(rsp, 0)); |
| 666 break; | 683 break; |
| 667 } | 684 } |
| 668 } | 685 } |
| 669 // The left-hand value is in rax. It is also on the stack iff the | 686 // The left-hand value is in rax. It is also on the stack iff the |
| 670 // destination location is temporary. | 687 // destination location is temporary. |
| 671 | 688 |
| 672 // Perform fast checks assumed by the stub. | 689 // Perform fast checks assumed by the stub. |
| (...skipping 12 matching lines...) Expand all Loading... |
| 685 | 702 |
| 686 // Call the stub for all other cases. | 703 // Call the stub for all other cases. |
| 687 __ push(rax); | 704 __ push(rax); |
| 688 ToBooleanStub stub; | 705 ToBooleanStub stub; |
| 689 __ CallStub(&stub); | 706 __ CallStub(&stub); |
| 690 __ testq(rax, rax); // The stub returns nonzero for true. | 707 __ testq(rax, rax); // The stub returns nonzero for true. |
| 691 __ j(not_zero, &done); | 708 __ j(not_zero, &done); |
| 692 | 709 |
| 693 __ bind(&eval_right); | 710 __ bind(&eval_right); |
| 694 // Discard the left-hand value if present on the stack. | 711 // Discard the left-hand value if present on the stack. |
| 695 if (destination.is_temporary()) { | 712 if (destination.is_value()) { |
| 696 __ addq(rsp, Immediate(kPointerSize)); | 713 __ addq(rsp, Immediate(kPointerSize)); |
| 697 } | 714 } |
| 698 // Save or discard the right-hand value as needed. | 715 // Save or discard the right-hand value as needed. |
| 699 if (right->AsLiteral() != NULL) { | 716 if (right->AsLiteral() != NULL) { |
| 700 Move(destination, right->AsLiteral()); | 717 Move(destination, right->AsLiteral()); |
| 701 } else { | 718 } else { |
| 702 Visit(right); | 719 Visit(right); |
| 703 Move(destination, right->location()); | 720 Move(destination, right->location()); |
| 704 } | 721 } |
| 705 | 722 |
| 706 __ bind(&done); | 723 __ bind(&done); |
| 707 } | 724 } |
| 708 | 725 |
| 709 | 726 |
| 710 } } // namespace v8::internal | 727 } } // namespace v8::internal |
| OLD | NEW |