| Index: src/codegen-ia32.cc
|
| ===================================================================
|
| --- src/codegen-ia32.cc (revision 746)
|
| +++ src/codegen-ia32.cc (working copy)
|
| @@ -99,9 +99,7 @@
|
| }
|
|
|
|
|
| -void VirtualFrame::Pop() {
|
| - __ add(Operand(esp), Immediate(kPointerSize));
|
| -}
|
| +void VirtualFrame::Pop() { Drop(1); }
|
|
|
|
|
| void VirtualFrame::Pop(Register reg) {
|
| @@ -267,10 +265,8 @@
|
| __ int3();
|
| __ bind(&verified_true);
|
| }
|
| -
|
| // Update context local.
|
| __ mov(frame_->Context(), esi);
|
| - // Restore the arguments array pointer, if any.
|
| }
|
|
|
| // TODO(1241774): Improve this code:
|
| @@ -310,10 +306,10 @@
|
| // This section stores the pointer to the arguments object that
|
| // was allocated and copied into above. If the address was not
|
| // saved to TOS, we push ecx onto the stack.
|
| -
|
| - // Store the arguments object.
|
| - // This must happen after context initialization because
|
| - // the arguments object may be stored in the context
|
| + //
|
| + // Store the arguments object. This must happen after context
|
| + // initialization because the arguments object may be stored in the
|
| + // context.
|
| if (arguments_object_allocated) {
|
| ASSERT(scope_->arguments() != NULL);
|
| ASSERT(scope_->arguments_shadow() != NULL);
|
| @@ -341,18 +337,17 @@
|
| frame_->Pop(); // Value is no longer needed.
|
| }
|
|
|
| - // Generate code to 'execute' declarations and initialize
|
| - // functions (source elements). In case of an illegal
|
| - // redeclaration we need to handle that instead of processing the
|
| - // declarations.
|
| + // Generate code to 'execute' declarations and initialize functions
|
| + // (source elements). In case of an illegal redeclaration we need to
|
| + // handle that instead of processing the declarations.
|
| if (scope_->HasIllegalRedeclaration()) {
|
| Comment cmnt(masm_, "[ illegal redeclarations");
|
| scope_->VisitIllegalRedeclaration(this);
|
| } else {
|
| Comment cmnt(masm_, "[ declarations");
|
| ProcessDeclarations(scope_->declarations());
|
| - // Bail out if a stack-overflow exception occurred when
|
| - // processing declarations.
|
| + // Bail out if a stack-overflow exception occurred when processing
|
| + // declarations.
|
| if (HasStackOverflow()) return;
|
| }
|
|
|
| @@ -448,10 +443,11 @@
|
|
|
|
|
| // Loads a value on TOS. If it is a boolean value, the result may have been
|
| -// (partially) translated into branches, or it may have set the condition code
|
| -// register. If force_cc is set, the value is forced to set the condition code
|
| -// register and no value is pushed. If the condition code register was set,
|
| -// has_cc() is true and cc_reg_ contains the condition to test for 'true'.
|
| +// (partially) translated into branches, or it may have set the condition
|
| +// code register. If force_cc is set, the value is forced to set the
|
| +// condition code register and no value is pushed. If the condition code
|
| +// register was set, has_cc() is true and cc_reg_ contains the condition to
|
| +// test for 'true'.
|
| void CodeGenerator::LoadCondition(Expression* x,
|
| TypeofState typeof_state,
|
| Label* true_target,
|
| @@ -463,6 +459,14 @@
|
| Visit(x);
|
| }
|
| if (force_cc && !has_cc()) {
|
| + // Convert the TOS value to a boolean in the condition code register.
|
| + // Visiting an expression may possibly choose neither (a) to leave a
|
| + // value in the condition code register nor (b) to leave a value in TOS
|
| + // (eg, by compiling to only jumps to the targets). In that case the
|
| + // code generated by ToBoolean is wrong because it assumes the value of
|
| + // the expression in TOS. So long as there is always a value in TOS or
|
| + // the condition code register when control falls through to here (there
|
| + // is), the code generated by ToBoolean is dead and therefore safe.
|
| ToBoolean(true_target, false_target);
|
| }
|
| ASSERT(has_cc() || !force_cc);
|
| @@ -476,7 +480,6 @@
|
|
|
| if (has_cc()) {
|
| // convert cc_reg_ into a bool
|
| -
|
| Label loaded, materialize_true;
|
| __ j(cc_reg_, &materialize_true);
|
| frame_->Push(Immediate(Factory::false_value()));
|
| @@ -604,12 +607,10 @@
|
| // Pop a reference from the stack while preserving TOS.
|
| Comment cmnt(masm_, "[ UnloadReference");
|
| int size = ref->size();
|
| - if (size <= 0) {
|
| - // Do nothing. No popping is necessary.
|
| - } else if (size == 1) {
|
| + if (size == 1) {
|
| frame_->Pop(eax);
|
| __ mov(frame_->Top(), eax);
|
| - } else {
|
| + } else if (size > 1) {
|
| frame_->Pop(eax);
|
| frame_->Drop(size);
|
| frame_->Push(eax);
|
| @@ -663,7 +664,7 @@
|
| frame_->Push(eax); // Undo the pop(eax) from above.
|
| ToBooleanStub stub;
|
| __ CallStub(&stub);
|
| - // Convert result (eax) to condition code.
|
| + // Convert the result (eax) to condition code.
|
| __ test(eax, Operand(eax));
|
|
|
| ASSERT(not_equal == not_zero);
|
| @@ -1040,7 +1041,7 @@
|
| } else {
|
| deferred = new DeferredInlinedSmiSubReversed(this, edx, overwrite_mode);
|
| __ mov(edx, Operand(eax));
|
| - __ mov(Operand(eax), Immediate(value));
|
| + __ mov(eax, Immediate(value));
|
| __ sub(eax, Operand(edx));
|
| }
|
| __ j(overflow, deferred->enter(), not_taken);
|
| @@ -1094,7 +1095,7 @@
|
| __ j(not_zero, deferred->enter(), not_taken);
|
| // tag result and store it in TOS (eax)
|
| ASSERT(kSmiTagSize == times_2); // adjust code if not the case
|
| - __ lea(eax, Operand(ebx, times_2, kSmiTag));
|
| + __ lea(eax, Operand(ebx, ebx, times_1, kSmiTag));
|
| __ bind(deferred->exit());
|
| frame_->Push(eax);
|
| }
|
| @@ -1123,7 +1124,7 @@
|
| __ j(not_zero, deferred->enter(), not_taken);
|
| // tag result and store it in TOS (eax)
|
| ASSERT(kSmiTagSize == times_2); // adjust code if not the case
|
| - __ lea(eax, Operand(ebx, times_2, kSmiTag));
|
| + __ lea(eax, Operand(ebx, ebx, times_1, kSmiTag));
|
| __ bind(deferred->exit());
|
| frame_->Push(eax);
|
| }
|
| @@ -1264,7 +1265,7 @@
|
| CompareStub stub(cc_, strict_);
|
| // Setup parameters and call stub.
|
| __ mov(edx, Operand(eax));
|
| - __ mov(Operand(eax), Immediate(Smi::FromInt(value_)));
|
| + __ Set(eax, Immediate(Smi::FromInt(value_)));
|
| __ CallStub(&stub);
|
| __ cmp(eax, 0);
|
| // "result" is returned in the flags
|
| @@ -1650,7 +1651,7 @@
|
| __ j(greater_equal, fail_label, not_taken);
|
|
|
| // 0 is placeholder.
|
| - __ jmp(Operand(eax, times_2, 0x0, RelocInfo::INTERNAL_REFERENCE));
|
| + __ jmp(Operand(eax, eax, times_1, 0x0, RelocInfo::INTERNAL_REFERENCE));
|
| // calculate address to overwrite later with actual address of table.
|
| int32_t jump_table_ref = __ pc_offset() - sizeof(int32_t);
|
|
|
| @@ -2198,7 +2199,6 @@
|
| frame_->Pop(Operand::StaticVariable(handler_address));
|
| frame_->Drop(StackHandlerConstants::kSize / kPointerSize - 1);
|
| // Next_sp popped.
|
| - // Preserve the TOS in a register across stack manipulation.
|
| frame_->Push(eax);
|
|
|
| // --- Finally block ---
|
| @@ -3522,54 +3522,47 @@
|
| Expression* right = node->right();
|
| Token::Value op = node->op();
|
|
|
| - // NOTE: To make null checks efficient, we check if either left or
|
| - // right is the literal 'null'. If so, we optimize the code by
|
| - // inlining a null check instead of calling the (very) general
|
| - // runtime routine for checking equality.
|
| -
|
| + // To make null checks efficient, we check if either left or right is the
|
| + // literal 'null'. If so, we optimize the code by inlining a null check
|
| + // instead of calling the (very) general runtime routine for checking
|
| + // equality.
|
| if (op == Token::EQ || op == Token::EQ_STRICT) {
|
| bool left_is_null =
|
| - left->AsLiteral() != NULL && left->AsLiteral()->IsNull();
|
| + left->AsLiteral() != NULL && left->AsLiteral()->IsNull();
|
| bool right_is_null =
|
| - right->AsLiteral() != NULL && right->AsLiteral()->IsNull();
|
| - // The 'null' value is only equal to 'null' or 'undefined'.
|
| + right->AsLiteral() != NULL && right->AsLiteral()->IsNull();
|
| + // The 'null' value can only be equal to 'null' or 'undefined'.
|
| if (left_is_null || right_is_null) {
|
| Load(left_is_null ? right : left);
|
| - Label exit, undetectable;
|
| frame_->Pop(eax);
|
| __ cmp(eax, Factory::null_value());
|
|
|
| - // The 'null' value is only equal to 'undefined' if using
|
| - // non-strict comparisons.
|
| + // The 'null' value is only equal to 'undefined' if using non-strict
|
| + // comparisons.
|
| if (op != Token::EQ_STRICT) {
|
| - __ j(equal, &exit);
|
| + __ j(equal, true_target());
|
| +
|
| __ cmp(eax, Factory::undefined_value());
|
| + __ j(equal, true_target());
|
|
|
| - // NOTE: it can be an undetectable object.
|
| - __ j(equal, &exit);
|
| __ test(eax, Immediate(kSmiTagMask));
|
| + __ j(equal, false_target());
|
|
|
| - __ j(not_equal, &undetectable);
|
| - __ jmp(false_target());
|
| -
|
| - __ bind(&undetectable);
|
| - __ mov(edx, FieldOperand(eax, HeapObject::kMapOffset));
|
| - __ movzx_b(ecx, FieldOperand(edx, Map::kBitFieldOffset));
|
| - __ and_(ecx, 1 << Map::kIsUndetectable);
|
| - __ cmp(ecx, 1 << Map::kIsUndetectable);
|
| + // It can be an undetectable object.
|
| + __ mov(eax, FieldOperand(eax, HeapObject::kMapOffset));
|
| + __ movzx_b(eax, FieldOperand(eax, Map::kBitFieldOffset));
|
| + __ and_(eax, 1 << Map::kIsUndetectable);
|
| + __ cmp(eax, 1 << Map::kIsUndetectable);
|
| }
|
|
|
| - __ bind(&exit);
|
| -
|
| cc_reg_ = equal;
|
| return;
|
| }
|
| }
|
|
|
| - // NOTE: To make typeof testing for natives implemented in
|
| - // JavaScript really efficient, we generate special code for
|
| - // expressions of the form: 'typeof <expression> == <string>'.
|
| -
|
| + // To make typeof testing for natives implemented in JavaScript really
|
| + // efficient, we generate special code for expressions of the form:
|
| + // 'typeof <expression> == <string>'.
|
| UnaryOperation* operation = left->AsUnaryOperation();
|
| if ((op == Token::EQ || op == Token::EQ_STRICT) &&
|
| (operation != NULL && operation->op() == Token::TYPEOF) &&
|
| @@ -3577,7 +3570,7 @@
|
| right->AsLiteral()->handle()->IsString())) {
|
| Handle<String> check(String::cast(*right->AsLiteral()->handle()));
|
|
|
| - // Load the operand, move it to register edx, and restore TOS.
|
| + // Load the operand and move it to register edx.
|
| LoadTypeofExpression(operation->expression());
|
| frame_->Pop(edx);
|
|
|
| @@ -3594,7 +3587,7 @@
|
|
|
| __ mov(edx, FieldOperand(edx, HeapObject::kMapOffset));
|
|
|
| - // NOTE: it might be an undetectable string object
|
| + // It can be an undetectable string object.
|
| __ movzx_b(ecx, FieldOperand(edx, Map::kBitFieldOffset));
|
| __ and_(ecx, 1 << Map::kIsUndetectable);
|
| __ cmp(ecx, 1 << Map::kIsUndetectable);
|
| @@ -3617,7 +3610,7 @@
|
| __ test(edx, Immediate(kSmiTagMask));
|
| __ j(zero, false_target());
|
|
|
| - // NOTE: it can be an undetectable object.
|
| + // It can be an undetectable object.
|
| __ mov(edx, FieldOperand(edx, HeapObject::kMapOffset));
|
| __ movzx_b(ecx, FieldOperand(edx, Map::kBitFieldOffset));
|
| __ and_(ecx, 1 << Map::kIsUndetectable);
|
| @@ -3641,7 +3634,7 @@
|
| __ cmp(edx, Factory::null_value());
|
| __ j(equal, true_target());
|
|
|
| - // NOTE: it might be an undetectable object
|
| + // It can be an undetectable object.
|
| __ movzx_b(edx, FieldOperand(ecx, Map::kBitFieldOffset));
|
| __ and_(edx, 1 << Map::kIsUndetectable);
|
| __ cmp(edx, 1 << Map::kIsUndetectable);
|
| @@ -3654,8 +3647,8 @@
|
| cc_reg_ = less_equal;
|
|
|
| } else {
|
| - // Uncommon case: Typeof testing against a string literal that
|
| - // is never returned from the typeof operator.
|
| + // Uncommon case: typeof testing against a string literal that is
|
| + // never returned from the typeof operator.
|
| __ jmp(false_target());
|
| }
|
| return;
|
| @@ -4062,7 +4055,7 @@
|
| __ j(not_zero, slow);
|
| // Tag the result and store it in register eax.
|
| ASSERT(kSmiTagSize == times_2); // adjust code if not the case
|
| - __ lea(eax, Operand(eax, times_2, kSmiTag));
|
| + __ lea(eax, Operand(eax, eax, times_1, kSmiTag));
|
| break;
|
|
|
| case Token::MOD:
|
| @@ -4123,7 +4116,7 @@
|
| }
|
| // Tag the result and store it in register eax.
|
| ASSERT(kSmiTagSize == times_2); // adjust code if not the case
|
| - __ lea(eax, Operand(eax, times_2, kSmiTag));
|
| + __ lea(eax, Operand(eax, eax, times_1, kSmiTag));
|
| break;
|
|
|
| default:
|
| @@ -4250,7 +4243,7 @@
|
|
|
| // Tag smi result and return.
|
| ASSERT(kSmiTagSize == times_2); // adjust code if not the case
|
| - __ lea(eax, Operand(eax, times_2, kSmiTag));
|
| + __ lea(eax, Operand(eax, eax, times_1, kSmiTag));
|
| __ ret(2 * kPointerSize);
|
|
|
| // All ops except SHR return a signed int32 that we load in a HeapNumber.
|
| @@ -4984,7 +4977,7 @@
|
| // running with --gc-greedy set.
|
| if (FLAG_gc_greedy) {
|
| Failure* failure = Failure::RetryAfterGC(0);
|
| - __ mov(Operand(eax), Immediate(reinterpret_cast<int32_t>(failure)));
|
| + __ mov(eax, Immediate(reinterpret_cast<int32_t>(failure)));
|
| }
|
| GenerateCore(masm, &throw_normal_exception,
|
| &throw_out_of_memory_exception,
|
| @@ -5002,7 +4995,7 @@
|
|
|
| // Do full GC and retry runtime call one final time.
|
| Failure* failure = Failure::InternalError();
|
| - __ mov(Operand(eax), Immediate(reinterpret_cast<int32_t>(failure)));
|
| + __ mov(eax, Immediate(reinterpret_cast<int32_t>(failure)));
|
| GenerateCore(masm,
|
| &throw_normal_exception,
|
| &throw_out_of_memory_exception,
|
| @@ -5046,7 +5039,7 @@
|
| // exception field in the JSEnv and return a failure sentinel.
|
| ExternalReference pending_exception(Top::k_pending_exception_address);
|
| __ mov(Operand::StaticVariable(pending_exception), eax);
|
| - __ mov(eax, Handle<Failure>(Failure::Exception()));
|
| + __ mov(eax, reinterpret_cast<int32_t>(Failure::Exception()));
|
| __ jmp(&exit);
|
|
|
| // Invoke: Link this frame into the handler chain.
|
| @@ -5068,10 +5061,10 @@
|
| // stub, because the builtin stubs may not have been generated yet.
|
| if (is_construct) {
|
| ExternalReference construct_entry(Builtins::JSConstructEntryTrampoline);
|
| - __ mov(Operand(edx), Immediate(construct_entry));
|
| + __ mov(edx, Immediate(construct_entry));
|
| } else {
|
| ExternalReference entry(Builtins::JSEntryTrampoline);
|
| - __ mov(Operand(edx), Immediate(entry));
|
| + __ mov(edx, Immediate(entry));
|
| }
|
| __ mov(edx, Operand(edx, 0)); // deref address
|
| __ lea(edx, FieldOperand(edx, Code::kHeaderSize));
|
|
|