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 451 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
462 Register reg = object_reg; | 462 Register reg = object_reg; |
463 int depth = 1; | 463 int depth = 1; |
464 | 464 |
465 // Check the maps in the prototype chain. | 465 // Check the maps in the prototype chain. |
466 // Traverse the prototype chain from the object and do map checks. | 466 // Traverse the prototype chain from the object and do map checks. |
467 while (object != holder) { | 467 while (object != holder) { |
468 depth++; | 468 depth++; |
469 | 469 |
470 // Only global objects and objects that do not require access | 470 // Only global objects and objects that do not require access |
471 // checks are allowed in stubs. | 471 // checks are allowed in stubs. |
472 ASSERT(object->IsJSGlobalObject() || !object->IsAccessCheckNeeded()); | 472 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded()); |
473 | 473 |
474 JSObject* prototype = JSObject::cast(object->GetPrototype()); | 474 JSObject* prototype = JSObject::cast(object->GetPrototype()); |
475 if (Heap::InNewSpace(prototype)) { | 475 if (Heap::InNewSpace(prototype)) { |
476 // Get the map of the current object. | 476 // Get the map of the current object. |
477 mov(scratch, FieldOperand(reg, HeapObject::kMapOffset)); | 477 mov(scratch, FieldOperand(reg, HeapObject::kMapOffset)); |
478 cmp(Operand(scratch), Immediate(Handle<Map>(object->map()))); | 478 cmp(Operand(scratch), Immediate(Handle<Map>(object->map()))); |
479 // Branch on the result of the map check. | 479 // Branch on the result of the map check. |
480 j(not_equal, miss, not_taken); | 480 j(not_equal, miss, not_taken); |
481 // Check access rights to the global object. This has to happen | 481 // Check access rights to the global object. This has to happen |
482 // after the map check so that we know that the object is | 482 // after the map check so that we know that the object is |
483 // actually a global object. | 483 // actually a global object. |
484 if (object->IsJSGlobalObject()) { | 484 if (object->IsJSGlobalProxy()) { |
485 CheckAccessGlobal(reg, scratch, miss); | 485 CheckAccessGlobalProxy(reg, scratch, miss); |
486 // Restore scratch register to be the map of the object. We | 486 |
487 // load the prototype from the map in the scratch register. | 487 // Restore scratch register to be the map of the object. |
| 488 // We load the prototype from the map in the scratch register. |
488 mov(scratch, FieldOperand(reg, HeapObject::kMapOffset)); | 489 mov(scratch, FieldOperand(reg, HeapObject::kMapOffset)); |
489 } | 490 } |
490 // The prototype is in new space; we cannot store a reference | 491 // The prototype is in new space; we cannot store a reference |
491 // to it in the code. Load it from the map. | 492 // to it in the code. Load it from the map. |
492 reg = holder_reg; // from now the object is in holder_reg | 493 reg = holder_reg; // from now the object is in holder_reg |
493 mov(reg, FieldOperand(scratch, Map::kPrototypeOffset)); | 494 mov(reg, FieldOperand(scratch, Map::kPrototypeOffset)); |
| 495 |
494 } else { | 496 } else { |
495 // Check the map of the current object. | 497 // Check the map of the current object. |
496 cmp(FieldOperand(reg, HeapObject::kMapOffset), | 498 cmp(FieldOperand(reg, HeapObject::kMapOffset), |
497 Immediate(Handle<Map>(object->map()))); | 499 Immediate(Handle<Map>(object->map()))); |
498 // Branch on the result of the map check. | 500 // Branch on the result of the map check. |
499 j(not_equal, miss, not_taken); | 501 j(not_equal, miss, not_taken); |
500 // Check access rights to the global object. This has to happen | 502 // Check access rights to the global object. This has to happen |
501 // after the map check so that we know that the object is | 503 // after the map check so that we know that the object is |
502 // actually a global object. | 504 // actually a global object. |
503 if (object->IsJSGlobalObject()) { | 505 if (object->IsJSGlobalProxy()) { |
504 CheckAccessGlobal(reg, scratch, miss); | 506 CheckAccessGlobalProxy(reg, scratch, miss); |
505 } | 507 } |
506 // The prototype is in old space; load it directly. | 508 // The prototype is in old space; load it directly. |
507 reg = holder_reg; // from now the object is in holder_reg | 509 reg = holder_reg; // from now the object is in holder_reg |
508 mov(reg, Handle<JSObject>(prototype)); | 510 mov(reg, Handle<JSObject>(prototype)); |
509 } | 511 } |
510 | 512 |
511 // Go to the next object in the prototype chain. | 513 // Go to the next object in the prototype chain. |
512 object = prototype; | 514 object = prototype; |
513 } | 515 } |
514 | 516 |
515 // Check the holder map. | 517 // Check the holder map. |
516 cmp(FieldOperand(reg, HeapObject::kMapOffset), | 518 cmp(FieldOperand(reg, HeapObject::kMapOffset), |
517 Immediate(Handle<Map>(holder->map()))); | 519 Immediate(Handle<Map>(holder->map()))); |
518 j(not_equal, miss, not_taken); | 520 j(not_equal, miss, not_taken); |
519 | 521 |
520 // Log the check depth. | 522 // Log the check depth. |
521 LOG(IntEvent("check-maps-depth", depth)); | 523 LOG(IntEvent("check-maps-depth", depth)); |
522 | 524 |
523 // Perform security check for access to the global object and return | 525 // Perform security check for access to the global object and return |
524 // the holder register. | 526 // the holder register. |
525 ASSERT(object == holder); | 527 ASSERT(object == holder); |
526 ASSERT(object->IsJSGlobalObject() || !object->IsAccessCheckNeeded()); | 528 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded()); |
527 if (object->IsJSGlobalObject()) { | 529 if (object->IsJSGlobalProxy()) { |
528 CheckAccessGlobal(reg, scratch, miss); | 530 CheckAccessGlobalProxy(reg, scratch, miss); |
529 } | 531 } |
530 return reg; | 532 return reg; |
531 } | 533 } |
532 | 534 |
533 | 535 |
534 void MacroAssembler::CheckAccessGlobal(Register holder_reg, | 536 void MacroAssembler::CheckAccessGlobalProxy(Register holder_reg, |
535 Register scratch, | 537 Register scratch, |
536 Label* miss) { | 538 Label* miss) { |
| 539 Label same_contexts; |
| 540 |
537 ASSERT(!holder_reg.is(scratch)); | 541 ASSERT(!holder_reg.is(scratch)); |
538 | 542 |
539 // Load the security context. | 543 // Load current lexical context from the stack frame. |
540 ExternalReference security_context = | 544 mov(scratch, Operand(ebp, StandardFrameConstants::kContextOffset)); |
541 ExternalReference(Top::k_security_context_address); | 545 |
542 mov(scratch, Operand::StaticVariable(security_context)); | 546 // When generating debug code, make sure the lexical context is set. |
543 // When generating debug code, make sure the security context is set. | |
544 if (FLAG_debug_code) { | 547 if (FLAG_debug_code) { |
545 cmp(Operand(scratch), Immediate(0)); | 548 cmp(Operand(scratch), Immediate(0)); |
546 Check(not_equal, "we should not have an empty security context"); | 549 Check(not_equal, "we should not have an empty lexical context"); |
547 } | 550 } |
548 // Load the global object of the security context. | 551 // Load the global context of the current context. |
549 int offset = Context::kHeaderSize + Context::GLOBAL_INDEX * kPointerSize; | 552 int offset = Context::kHeaderSize + Context::GLOBAL_INDEX * kPointerSize; |
550 mov(scratch, FieldOperand(scratch, offset)); | 553 mov(scratch, FieldOperand(scratch, offset)); |
| 554 mov(scratch, FieldOperand(scratch, GlobalObject::kGlobalContextOffset)); |
| 555 |
| 556 // Check the context is a global context. |
| 557 if (FLAG_debug_code) { |
| 558 push(scratch); |
| 559 // Read the first word and compare to global_context_map. |
| 560 mov(scratch, FieldOperand(scratch, HeapObject::kMapOffset)); |
| 561 cmp(scratch, Factory::global_context_map()); |
| 562 Check(equal, "JSGlobalObject::global_context should be a global context."); |
| 563 pop(scratch); |
| 564 } |
| 565 |
| 566 // Check if both contexts are the same. |
| 567 cmp(scratch, FieldOperand(holder_reg, JSGlobalProxy::kContextOffset)); |
| 568 j(equal, &same_contexts, taken); |
| 569 |
| 570 // Compare security tokens, save holder_reg on the stack so we can use it |
| 571 // as a temporary register. |
| 572 // |
| 573 // TODO(119): avoid push(holder_reg)/pop(holder_reg) |
| 574 push(holder_reg); |
551 // Check that the security token in the calling global object is | 575 // Check that the security token in the calling global object is |
552 // compatible with the security token in the receiving global | 576 // compatible with the security token in the receiving global |
553 // object. | 577 // object. |
554 mov(scratch, FieldOperand(scratch, JSGlobalObject::kSecurityTokenOffset)); | 578 mov(holder_reg, FieldOperand(holder_reg, JSGlobalProxy::kContextOffset)); |
555 cmp(scratch, FieldOperand(holder_reg, JSGlobalObject::kSecurityTokenOffset)); | 579 |
| 580 // Check the context is a global context. |
| 581 if (FLAG_debug_code) { |
| 582 cmp(holder_reg, Factory::null_value()); |
| 583 Check(not_equal, "JSGlobalProxy::context() should not be null."); |
| 584 |
| 585 push(holder_reg); |
| 586 // Read the first word and compare to global_context_map(), |
| 587 mov(holder_reg, FieldOperand(holder_reg, HeapObject::kMapOffset)); |
| 588 cmp(holder_reg, Factory::global_context_map()); |
| 589 Check(equal, "JSGlobalObject::global_context should be a global context."); |
| 590 pop(holder_reg); |
| 591 } |
| 592 |
| 593 int token_offset = Context::kHeaderSize + |
| 594 Context::SECURITY_TOKEN_INDEX * kPointerSize; |
| 595 mov(scratch, FieldOperand(scratch, token_offset)); |
| 596 cmp(scratch, FieldOperand(holder_reg, token_offset)); |
| 597 pop(holder_reg); |
556 j(not_equal, miss, not_taken); | 598 j(not_equal, miss, not_taken); |
| 599 |
| 600 bind(&same_contexts); |
557 } | 601 } |
558 | 602 |
559 | 603 |
560 void MacroAssembler::NegativeZeroTest(Register result, | 604 void MacroAssembler::NegativeZeroTest(Register result, |
561 Register op, | 605 Register op, |
562 Label* then_label) { | 606 Label* then_label) { |
563 Label ok; | 607 Label ok; |
564 test(result, Operand(result)); | 608 test(result, Operand(result)); |
565 j(not_zero, &ok, taken); | 609 j(not_zero, &ok, taken); |
566 test(op, Operand(op)); | 610 test(op, Operand(op)); |
(...skipping 394 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
961 // Indicate that code has changed. | 1005 // Indicate that code has changed. |
962 CPU::FlushICache(address_, size_); | 1006 CPU::FlushICache(address_, size_); |
963 | 1007 |
964 // Check that the code was patched as expected. | 1008 // Check that the code was patched as expected. |
965 ASSERT(masm_.pc_ == address_ + size_); | 1009 ASSERT(masm_.pc_ == address_ + size_); |
966 ASSERT(masm_.reloc_info_writer.pos() == address_ + size_ + Assembler::kGap); | 1010 ASSERT(masm_.reloc_info_writer.pos() == address_ + size_ + Assembler::kGap); |
967 } | 1011 } |
968 | 1012 |
969 | 1013 |
970 } } // namespace v8::internal | 1014 } } // namespace v8::internal |
OLD | NEW |