📄 codegen-arm.cc.svn-base
字号:
// Object case: Check key against length in the elements array. __ ldr(r3, FieldMemOperand(r3, JSObject::kElementsOffset)); // Check that the object is in fast mode (not dictionary). __ ldr(r2, FieldMemOperand(r3, HeapObject::kMapOffset)); __ cmp(r2, Operand(Factory::hash_table_map())); __ b(eq, &slow); // Untag the key (for checking against untagged length in the fixed array). __ mov(r1, Operand(r1, ASR, kSmiTagSize)); // Compute address to store into and check array bounds. __ add(r2, r3, Operand(Array::kHeaderSize - kHeapObjectTag)); __ add(r2, r2, Operand(r1, LSL, kPointerSizeLog2)); __ ldr(ip, FieldMemOperand(r3, Array::kLengthOffset)); __ cmp(r1, Operand(ip)); __ b(lo, &fast); // Slow case: Push extra copies of the arguments (3). __ bind(&slow); __ ldm(ia, sp, r1.bit() | r3.bit()); // r0 == value, r1 == key, r3 == object __ stm(db_w, sp, r0.bit() | r1.bit() | r3.bit()); // Do tail-call to runtime routine. __ TailCallRuntime(ExternalReference(Runtime::kSetProperty), 3); // Extra capacity case: Check if there is extra capacity to // perform the store and update the length. Used for adding one // element to the array by writing to array[array.length]. // r0 == value, r1 == key, r2 == elements, r3 == object __ bind(&extra); __ b(ne, &slow); // do not leave holes in the array __ mov(r1, Operand(r1, ASR, kSmiTagSize)); // untag __ ldr(ip, FieldMemOperand(r2, Array::kLengthOffset)); __ cmp(r1, Operand(ip)); __ b(hs, &slow); __ mov(r1, Operand(r1, LSL, kSmiTagSize)); // restore tag __ add(r1, r1, Operand(1 << kSmiTagSize)); // and increment __ str(r1, FieldMemOperand(r3, JSArray::kLengthOffset)); __ mov(r3, Operand(r2)); // NOTE: Computing the address to store into must take the fact // that the key has been incremented into account. int displacement = Array::kHeaderSize - kHeapObjectTag - ((1 << kSmiTagSize) * 2); __ add(r2, r2, Operand(displacement)); __ add(r2, r2, Operand(r1, LSL, kPointerSizeLog2 - kSmiTagSize)); __ b(&fast); // Array case: Get the length and the elements array from the JS // array. Check that the array is in fast mode; if it is the // length is always a smi. // r0 == value, r3 == object __ bind(&array); __ ldr(r2, FieldMemOperand(r3, JSObject::kElementsOffset)); __ ldr(r1, FieldMemOperand(r2, HeapObject::kMapOffset)); __ cmp(r1, Operand(Factory::hash_table_map())); __ b(eq, &slow); // Check the key against the length in the array, compute the // address to store into and fall through to fast case. __ ldr(r1, MemOperand(sp)); // r0 == value, r1 == key, r2 == elements, r3 == object. __ ldr(ip, FieldMemOperand(r3, JSArray::kLengthOffset)); __ cmp(r1, Operand(ip)); __ b(hs, &extra); __ mov(r3, Operand(r2)); __ add(r2, r2, Operand(Array::kHeaderSize - kHeapObjectTag)); __ add(r2, r2, Operand(r1, LSL, kPointerSizeLog2 - kSmiTagSize)); // Fast case: Do the store. // r0 == value, r2 == address to store into, r3 == elements __ bind(&fast); __ str(r0, MemOperand(r2)); // Skip write barrier if the written value is a smi. __ tst(r0, Operand(kSmiTagMask)); __ b(eq, &exit); // Update write barrier for the elements array address. __ sub(r1, r2, Operand(r3)); __ RecordWrite(r3, r1, r2); __ bind(&exit); masm->StubReturn(1);}class GenericBinaryOpStub : public CodeStub { public: explicit GenericBinaryOpStub(Token::Value op) : op_(op) { } private: Token::Value op_; Major MajorKey() { return GenericBinaryOp; } int MinorKey() { return static_cast<int>(op_); } void Generate(MacroAssembler* masm); const char* 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"; } }#ifdef DEBUG void Print() { PrintF("GenericBinaryOpStub (%s)\n", Token::String(op_)); }#endif};void GenericBinaryOpStub::Generate(MacroAssembler* masm) { // r1 : x // r0 : y // result : r0 switch (op_) { case Token::ADD: { Label slow, exit; // fast path __ orr(r2, r1, Operand(r0)); // r2 = x | y; __ add(r0, r1, Operand(r0), SetCC); // add y optimistically // go slow-path in case of overflow __ b(vs, &slow); // go slow-path in case of non-smi operands ASSERT(kSmiTag == 0); // adjust code below __ tst(r2, Operand(kSmiTagMask)); __ b(eq, &exit); // slow path __ bind(&slow); __ sub(r0, r0, Operand(r1)); // revert optimistic add __ push(r1); __ push(r0); __ mov(r0, Operand(1)); // set number of arguments __ InvokeBuiltin(Builtins::ADD, JUMP_JS); // done __ bind(&exit); break; } case Token::SUB: { Label slow, exit; // fast path __ orr(r2, r1, Operand(r0)); // r2 = x | y; __ sub(r3, r1, Operand(r0), SetCC); // subtract y optimistically // go slow-path in case of overflow __ b(vs, &slow); // go slow-path in case of non-smi operands ASSERT(kSmiTag == 0); // adjust code below __ tst(r2, Operand(kSmiTagMask)); __ mov(r0, Operand(r3), LeaveCC, eq); // conditionally set r0 to result __ b(eq, &exit); // slow path __ bind(&slow); __ push(r1); __ push(r0); __ mov(r0, Operand(1)); // set number of arguments __ InvokeBuiltin(Builtins::SUB, JUMP_JS); // done __ bind(&exit); break; } case Token::MUL: { Label slow, exit; // tag check __ orr(r2, r1, Operand(r0)); // r2 = x | y; ASSERT(kSmiTag == 0); // adjust code below __ tst(r2, Operand(kSmiTagMask)); __ b(ne, &slow); // remove tag from one operand (but keep sign), so that result is smi __ mov(ip, Operand(r0, ASR, kSmiTagSize)); // do multiplication __ smull(r3, r2, r1, ip); // r3 = lower 32 bits of ip*r1 // go slow on overflows (overflow bit is not set) __ mov(ip, Operand(r3, ASR, 31)); __ cmp(ip, Operand(r2)); // no overflow if higher 33 bits are identical __ b(ne, &slow); // go slow on zero result to handle -0 __ tst(r3, Operand(r3)); __ mov(r0, Operand(r3), LeaveCC, ne); __ b(ne, &exit); // slow case __ bind(&slow); __ push(r1); __ push(r0); __ mov(r0, Operand(1)); // set number of arguments __ InvokeBuiltin(Builtins::MUL, JUMP_JS); // done __ bind(&exit); break; } case Token::BIT_OR: case Token::BIT_AND: case Token::BIT_XOR: { Label slow, exit; // tag check __ orr(r2, r1, Operand(r0)); // r2 = x | y; ASSERT(kSmiTag == 0); // adjust code below __ tst(r2, Operand(kSmiTagMask)); __ b(ne, &slow); switch (op_) { case Token::BIT_OR: __ orr(r0, r0, Operand(r1)); break; case Token::BIT_AND: __ and_(r0, r0, Operand(r1)); break; case Token::BIT_XOR: __ eor(r0, r0, Operand(r1)); break; default: UNREACHABLE(); } __ b(&exit); __ bind(&slow); __ push(r1); // restore stack __ push(r0); __ mov(r0, Operand(1)); // 1 argument (not counting receiver). switch (op_) { case Token::BIT_OR: __ InvokeBuiltin(Builtins::BIT_OR, JUMP_JS); break; case Token::BIT_AND: __ InvokeBuiltin(Builtins::BIT_AND, JUMP_JS); break; case Token::BIT_XOR: __ InvokeBuiltin(Builtins::BIT_XOR, JUMP_JS); break; default: UNREACHABLE(); } __ bind(&exit); break; } case Token::SHL: case Token::SHR: case Token::SAR: { Label slow, exit; // tag check __ orr(r2, r1, Operand(r0)); // r2 = x | y; ASSERT(kSmiTag == 0); // adjust code below __ tst(r2, Operand(kSmiTagMask)); __ b(ne, &slow); // remove tags from operands (but keep sign) __ mov(r3, Operand(r1, ASR, kSmiTagSize)); // x __ mov(r2, Operand(r0, ASR, kSmiTagSize)); // y // use only the 5 least significant bits of the shift count __ and_(r2, r2, Operand(0x1f)); // perform operation switch (op_) { case Token::SAR: __ mov(r3, Operand(r3, ASR, r2)); // no checks of result necessary break; case Token::SHR: __ mov(r3, Operand(r3, LSR, r2)); // check that the *unsigned* result fits in a smi // neither of the two high-order bits can be set: // - 0x80000000: high bit would be lost when smi tagging // - 0x40000000: this number would convert to negative when // smi tagging these two cases can only happen with shifts // by 0 or 1 when handed a valid smi __ and_(r2, r3, Operand(0xc0000000), SetCC); __ b(ne, &slow); break; case Token::SHL: __ mov(r3, Operand(r3, LSL, r2)); // check that the *signed* result fits in a smi __ add(r2, r3, Operand(0x40000000), SetCC); __ b(mi, &slow); break; default: UNREACHABLE(); } // tag result and store it in r0 ASSERT(kSmiTag == 0); // adjust code below __ mov(r0, Operand(r3, LSL, kSmiTagSize)); __ b(&exit); // slow case __ bind(&slow); __ push(r1); // restore stack __ push(r0); __ mov(r0, Operand(1)); // 1 argument (not counting receiver). switch (op_) { case Token::SAR: __ InvokeBuiltin(Builtins::SAR, JUMP_JS); break; case Token::SHR: __ InvokeBuiltin(Builtins::SHR, JUMP_JS); break; case Token::SHL: __ InvokeBuiltin(Builtins::SHL, JUMP_JS); break; default: UNREACHABLE(); } __ bind(&exit); break; } default: UNREACHABLE(); } __ Ret();}void StackCheckStub::Generate(MacroAssembler* masm) { Label within_limit; __ mov(ip, Operand(ExternalReference::address_of_stack_guard_limit())); __ ldr(ip, MemOperand(ip)); __ cmp(sp, Operand(ip)); __ b(hs, &within_limit); // Do tail-call to runtime routine. __ push(r0); __ TailCallRuntime(ExternalReference(Runtime::kStackGuard), 1); __ bind(&within_limit); masm->StubReturn(1);}void UnarySubStub::Generate(MacroAssembler* masm) { Label undo; Label slow; Label done; // Enter runtime system if the value is not a smi. __ tst(r0, Operand(kSmiTagMask)); __ b(ne, &slow); // Enter runtime system if the value of the expression is zero // to make sure that we switch between 0 and -0. __ cmp(r0, Operand(0)); __ b(eq, &slow); // The value of the expression is a smi that is not zero. Try // optimistic subtraction '0 - value'. __ rsb(r1, r0, Operand(0), SetCC); __ b(vs, &slow); // If result is a smi we are done. __ tst(r1, Operand(kSmiTagMask)); __ mov(r0, Operand(r1), LeaveCC, eq); // conditionally set r0 to result __ b(eq, &done); // Enter runtime system. __ bind(&slow); __ push(r0); __ mov(r0, Operand(0)); // set number of arguments __ InvokeBuiltin(Builtins::UNARY_MINUS, JUMP_JS); __ bind(&done); masm->StubReturn(1);}class InvokeBuiltinStub : public CodeStub { public: enum Kind { Inc, Dec, ToNumber }; InvokeBuiltinStub(Kind kind, int argc) : kind_(kind), argc_(argc) { } private: Kind kind_; int argc_; Major MajorKey() { return InvokeBuiltin; } int MinorKey() { return (argc_ << 3) | static_cast<int>(kind_); } void Generate(MacroAssembler* masm); const char* GetName() { return "InvokeBuiltinStub"; }#ifdef DEBUG void Print() { PrintF("InvokeBuiltinStub (kind %d, argc, %d)\n", static_cast<int>(kind_), argc_); }#endif};void InvokeBuiltinStub::Generate(MacroAssembler* masm) { __ push(r0); __ mov(r0, Operand(0)); // set number of arguments switch (kind_) { case ToNumber: __ InvokeBuiltin(Builtins::TO_NUMBER, JUMP_JS); break; case Inc: __ InvokeBuiltin(Builtins::INC, JUMP_JS); break; case Dec: __ InvokeBuiltin(Builtins::DEC, JUMP_JS); break; default: UNREACHABLE(); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -