📄 codegen-ia32.cc.svn-base
字号:
// The value to convert should be popped from the stack. __ pop(eax); // Fast case checks. // 'false' => false. __ cmp(eax, Factory::false_value()); __ j(equal, false_target); // 'true' => true. __ cmp(eax, Factory::true_value()); __ j(equal, true_target); // 'undefined' => false. __ cmp(eax, Factory::undefined_value()); __ j(equal, false_target); // Smi => false iff zero. ASSERT(kSmiTag == 0); __ test(eax, Operand(eax)); __ j(zero, false_target); __ test(eax, Immediate(kSmiTagMask)); __ j(zero, true_target); // Call the stub for all other cases. __ push(eax); // Undo the pop(eax) from above. ToBooleanStub stub; __ CallStub(&stub); // Convert result (eax) to condition code. __ test(eax, Operand(eax)); ASSERT(not_equal == not_zero); cc_reg_ = not_equal;}void Ia32CodeGenerator::GetReferenceProperty(Expression* key) { ASSERT(!ref()->is_illegal()); Reference::Type type = ref()->type(); // TODO(1241834): Make sure that this it is safe to ignore the distinction // between access types LOAD and LOAD_TYPEOF_EXPR. If there is a chance // that reference errors can be thrown below, we must distinguish between // the two kinds of loads (typeof expression loads must not throw a // reference error). if (type == Reference::NAMED) { // Compute the name of the property. Literal* literal = key->AsLiteral(); Handle<String> name(String::cast(*literal->handle())); Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize)); Variable* var = ref()->expression()->AsVariableProxy()->AsVariable(); // Setup the name register. __ Set(ecx, Immediate(name)); if (var != NULL) { ASSERT(var->is_global()); __ call(ic, RelocInfo::CODE_TARGET_CONTEXT); } else { __ call(ic, RelocInfo::CODE_TARGET); } } else { // Access keyed property. ASSERT(type == Reference::KEYED); // Call IC code. Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize)); Variable* var = ref()->expression()->AsVariableProxy()->AsVariable(); if (var != NULL) { ASSERT(var->is_global()); __ call(ic, RelocInfo::CODE_TARGET_CONTEXT); } else { __ call(ic, RelocInfo::CODE_TARGET); } } __ push(eax); // IC call leaves result in eax, push it out}void Ia32CodeGenerator::SetReferenceProperty(MacroAssembler* masm, Reference* ref, Expression* key) { ASSERT(!ref->is_illegal()); Reference::Type type = ref->type(); if (type == Reference::NAMED) { // Compute the name of the property. Literal* literal = key->AsLiteral(); Handle<String> name(String::cast(*literal->handle())); // Call the appropriate IC code. Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); // TODO(1222589): Make the IC grab the values from the stack. masm->pop(eax); // Setup the name register. masm->Set(ecx, Immediate(name)); masm->call(ic, RelocInfo::CODE_TARGET); } else { // Access keyed property. ASSERT(type == Reference::KEYED); // Call IC code. Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize)); // TODO(1222589): Make the IC grab the values from the stack. masm->pop(eax); masm->call(ic, RelocInfo::CODE_TARGET); } masm->push(eax); // IC call leaves result in eax, push it out}#undef __#define __ masm->class FloatingPointHelper : public AllStatic { public: // Code pattern for loading floating point values. Input values must // be either smi or heap number objects (fp values). Requirements: // operand_1 on TOS+1 , operand_2 on TOS+2; Returns operands as // floating point numbers on FPU stack. static void LoadFloatOperands(MacroAssembler* masm, Register scratch); // Test if operands are smi or number objects (fp). Requirements: // operand_1 in eax, operand_2 in edx; falls through on float // operands, jumps to the non_float label otherwise. static void CheckFloatOperands(MacroAssembler* masm, Label* non_float, Register scratch); // Allocate a heap number in new space with undefined value. // Returns tagged pointer in eax, or jumps to need_gc if new space is full. static void AllocateHeapNumber(MacroAssembler* masm, Label* need_gc, Register scratch1, Register scratch2);};class GenericBinaryOpStub: public CodeStub { public: GenericBinaryOpStub(Token::Value op, OverwriteMode mode) : op_(op), mode_(mode) { } private: Token::Value op_; OverwriteMode mode_; const char* GetName();#ifdef DEBUG void Print() { PrintF("GenericBinaryOpStub (op %s), (mode %d)\n", Token::String(op_), static_cast<int>(mode_)); }#endif // Minor key encoding in 16 bits OOOOOOOOOOOOOOMM. class ModeBits: public BitField<OverwriteMode, 0, 2> {}; class OpBits: public BitField<Token::Value, 2, 14> {}; Major MajorKey() { return GenericBinaryOp; } int MinorKey() { // Encode the parameters in a unique 16 bit value. return OpBits::encode(op_) | ModeBits::encode(mode_); } void Generate(MacroAssembler* masm);};const char* GenericBinaryOpStub::GetName() { switch (op_) { case Token::ADD: return "GenericBinaryOpStub_ADD"; case Token::SUB: return "GenericBinaryOpStub_SUB"; case Token::MUL: return "GenericBinaryOpStub_MUL"; case Token::DIV: return "GenericBinaryOpStub_DIV"; case Token::BIT_OR: return "GenericBinaryOpStub_BIT_OR"; case Token::BIT_AND: return "GenericBinaryOpStub_BIT_AND"; case Token::BIT_XOR: return "GenericBinaryOpStub_BIT_XOR"; case Token::SAR: return "GenericBinaryOpStub_SAR"; case Token::SHL: return "GenericBinaryOpStub_SHL"; case Token::SHR: return "GenericBinaryOpStub_SHR"; default: return "GenericBinaryOpStub"; }}void GenericBinaryOpStub::Generate(MacroAssembler* masm) { Label call_runtime; __ mov(eax, Operand(esp, 1 * kPointerSize)); // Get y. __ mov(edx, Operand(esp, 2 * kPointerSize)); // Get x. // 1. Smi case. switch (op_) { case Token::ADD: { // eax: y. // edx: x. Label revert; __ mov(ecx, Operand(eax)); __ or_(ecx, Operand(edx)); // ecx = x | y. __ add(eax, Operand(edx)); // Add y optimistically. // Go slow-path in case of overflow. __ j(overflow, &revert, not_taken); // Go slow-path in case of non-smi operands. ASSERT(kSmiTag == 0); // adjust code below __ test(ecx, Immediate(kSmiTagMask)); __ j(not_zero, &revert, not_taken); __ ret(2 * kPointerSize); // Remove all operands. // Revert optimistic add. __ bind(&revert); __ sub(eax, Operand(edx)); break; } case Token::SUB: { // eax: y. // edx: x. Label revert; __ mov(ecx, Operand(edx)); __ or_(ecx, Operand(eax)); // ecx = x | y. __ sub(edx, Operand(eax)); // Subtract y optimistically. // Go slow-path in case of overflow. __ j(overflow, &revert, not_taken); // Go slow-path in case of non-smi operands. ASSERT(kSmiTag == 0); // adjust code below __ test(ecx, Immediate(kSmiTagMask)); __ j(not_zero, &revert, not_taken); __ mov(eax, Operand(edx)); __ ret(2 * kPointerSize); // Remove all operands. // Revert optimistic sub. __ bind(&revert); __ add(edx, Operand(eax)); break; } case Token::MUL: { // eax: y // edx: x // a) both operands smi and result fits into a smi -> return. // b) at least one of operands non-smi -> non_smi_operands. // c) result does not fit in a smi -> non_smi_result. Label non_smi_operands, non_smi_result; // Tag check. __ mov(ecx, Operand(edx)); __ or_(ecx, Operand(eax)); // ecx = x | y. ASSERT(kSmiTag == 0); // Adjust code below. __ test(ecx, Immediate(kSmiTagMask)); // Jump if not both smi; check if float numbers. __ j(not_zero, &non_smi_operands, not_taken); // Get copies of operands. __ mov(ebx, Operand(eax)); __ mov(ecx, Operand(edx)); // If the smi tag is 0 we can just leave the tag on one operand. ASSERT(kSmiTag == 0); // adjust code below // Remove tag from one of the operands (but keep sign). __ sar(ecx, kSmiTagSize); // Do multiplication. __ imul(eax, Operand(ecx)); // Multiplication of Smis; result in eax. // Go slow on overflows. __ j(overflow, &non_smi_result, not_taken); // ...but operands OK for float arithmetic. // If the result is +0 we may need to check if the result should // really be -0. Welcome to the -0 fan club. __ NegativeZeroTest(eax, ebx, edx, ecx, &non_smi_result); __ ret(2 * kPointerSize); __ bind(&non_smi_result); // TODO(1243132): Do not check float operands here. __ bind(&non_smi_operands); __ mov(eax, Operand(esp, 1 * kPointerSize)); __ mov(edx, Operand(esp, 2 * kPointerSize)); break; } case Token::DIV: { // eax: y // edx: x Label non_smi_operands, non_smi_result, division_by_zero; __ mov(ebx, Operand(eax)); // Get y __ mov(eax, Operand(edx)); // Get x __ cdq(); // Sign extend eax into edx:eax. // Tag check. __ mov(ecx, Operand(ebx)); __ or_(ecx, Operand(eax)); // ecx = x | y. ASSERT(kSmiTag == 0); // Adjust code below. __ test(ecx, Immediate(kSmiTagMask)); // Jump if not both smi; check if float numbers. __ j(not_zero, &non_smi_operands, not_taken); __ test(ebx, Operand(ebx)); // Check for 0 divisor. __ j(zero, &division_by_zero, not_taken); __ idiv(ebx); // Check for the corner case of dividing the most negative smi by -1. // (We cannot use the overflow flag, since it is not set by idiv.) ASSERT(kSmiTag == 0 && kSmiTagSize == 1); __ cmp(eax, 0x40000000); __ j(equal, &non_smi_result); // If the result is +0 we may need to check if the result should // really be -0. Welcome to the -0 fan club. __ NegativeZeroTest(eax, ecx, &non_smi_result); // Use ecx = x | y. __ test(edx, Operand(edx)); // Use floats if there's a remainder. __ j(not_zero, &non_smi_result, not_taken); __ shl(eax, kSmiTagSize); __ ret(2 * kPointerSize); // Remove all operands. __ bind(&division_by_zero); __ mov(eax, Operand(esp, 1 * kPointerSize)); __ mov(edx, Operand(esp, 2 * kPointerSize)); __ jmp(&call_runtime); // Division by zero must go through runtime. __ bind(&non_smi_result); // TODO(1243132): Do not check float operands here. __ bind(&non_smi_operands); __ mov(eax, Operand(esp, 1 * kPointerSize)); __ mov(edx, Operand(esp, 2 * kPointerSize)); break; } case Token::MOD: { Label slow; __ mov(ebx, Operand(eax)); // get y __ mov(eax, Operand(edx)); // get x __ cdq(); // sign extend eax into edx:eax // tag check __ mov(ecx, Operand(ebx)); __ or_(ecx, Operand(eax)); // ecx = x | y; ASSERT(kSmiTag == 0); // adjust code below __ test(ecx, Immediate(kSmiTagMask)); __ j(not_zero, &slow, not_taken); __ test(ebx, Operand(ebx)); // test for y == 0 __ j(zero, &slow); // Fast case: Do integer division and use remainder. __ idiv(ebx); __ NegativeZeroTest(edx, ecx, &slow); // use ecx = x | y __ mov(eax, Operand(edx)); __ ret(2 * kPointerSize); // Slow case: Call runtime operator implementation. __ bind(&slow); __ mov(eax, Operand(esp, 1 * kPointerSize)); __ mov(edx, Operand(esp, 2 * kPointerSize)); __ jmp(&call_runtime); break; } case Token::BIT_OR: case Token::BIT_AND: case Token::BIT_XOR: case Token::SAR: case Token::SHL: case Token::SHR: { // Smi-case for bitops should already have been inlined. break; } default: { UNREACHABLE(); } } // 2. Floating point case. switch (op_) { case Token::ADD: case Token::SUB: case Token::MUL: case Token::DIV: { // eax: y // edx: x FloatingPointHelper::CheckFloatOperands(masm, &call_runtime, ebx); // Fast-case: Both operands are numbers. // Allocate a heap number, if needed. Label skip_allocation; switch (mode_) { case OVERWRITE_LEFT: __ mov(eax, Operand(edx)); // Fall through! case OVERWRITE_RIGHT: // If the argument in eax is already an object, we skip the // allocation of a heap number. __ test(eax, Immediate(kSmiTagMask)); __ j(not_zero, &skip_allocation, not_taken);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -