| OLD | NEW |
| 1 // Copyright 2011 the V8 project authors. All rights reserved. | 1 // Copyright 2011 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 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 75 | 75 |
| 76 | 76 |
| 77 #define __ masm()-> | 77 #define __ masm()-> |
| 78 | 78 |
| 79 bool LCodeGen::GenerateCode() { | 79 bool LCodeGen::GenerateCode() { |
| 80 HPhase phase("Code generation", chunk()); | 80 HPhase phase("Code generation", chunk()); |
| 81 ASSERT(is_unused()); | 81 ASSERT(is_unused()); |
| 82 status_ = GENERATING; | 82 status_ = GENERATING; |
| 83 CpuFeatures::Scope scope1(VFP3); | 83 CpuFeatures::Scope scope1(VFP3); |
| 84 CpuFeatures::Scope scope2(ARMv7); | 84 CpuFeatures::Scope scope2(ARMv7); |
| 85 |
| 86 CodeStub::GenerateFPStubs(); |
| 87 |
| 88 // Open a frame scope to indicate that there is a frame on the stack. The |
| 89 // NONE indicates that the scope shouldn't actually generate code to set up |
| 90 // the frame (that is done in GeneratePrologue). |
| 91 FrameScope frame_scope(masm_, StackFrame::NONE); |
| 92 |
| 85 return GeneratePrologue() && | 93 return GeneratePrologue() && |
| 86 GenerateBody() && | 94 GenerateBody() && |
| 87 GenerateDeferredCode() && | 95 GenerateDeferredCode() && |
| 88 GenerateDeoptJumpTable() && | 96 GenerateDeoptJumpTable() && |
| 89 GenerateSafepointTable(); | 97 GenerateSafepointTable(); |
| 90 } | 98 } |
| 91 | 99 |
| 92 | 100 |
| 93 void LCodeGen::FinishCode(Handle<Code> code) { | 101 void LCodeGen::FinishCode(Handle<Code> code) { |
| 94 ASSERT(is_done()); | 102 ASSERT(is_done()); |
| (...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 199 // Copy any necessary parameters into the context. | 207 // Copy any necessary parameters into the context. |
| 200 int num_parameters = scope()->num_parameters(); | 208 int num_parameters = scope()->num_parameters(); |
| 201 for (int i = 0; i < num_parameters; i++) { | 209 for (int i = 0; i < num_parameters; i++) { |
| 202 Variable* var = scope()->parameter(i); | 210 Variable* var = scope()->parameter(i); |
| 203 if (var->IsContextSlot()) { | 211 if (var->IsContextSlot()) { |
| 204 int parameter_offset = StandardFrameConstants::kCallerSPOffset + | 212 int parameter_offset = StandardFrameConstants::kCallerSPOffset + |
| 205 (num_parameters - 1 - i) * kPointerSize; | 213 (num_parameters - 1 - i) * kPointerSize; |
| 206 // Load parameter from stack. | 214 // Load parameter from stack. |
| 207 __ ldr(r0, MemOperand(fp, parameter_offset)); | 215 __ ldr(r0, MemOperand(fp, parameter_offset)); |
| 208 // Store it in the context. | 216 // Store it in the context. |
| 209 __ mov(r1, Operand(Context::SlotOffset(var->index()))); | 217 MemOperand target = ContextOperand(cp, var->index()); |
| 210 __ str(r0, MemOperand(cp, r1)); | 218 __ str(r0, target); |
| 211 // Update the write barrier. This clobbers all involved | 219 // Update the write barrier. This clobbers r3 and r0. |
| 212 // registers, so we have to use two more registers to avoid | 220 __ RecordWriteContextSlot( |
| 213 // clobbering cp. | 221 cp, target.offset(), r0, r3, kLRHasBeenSaved, kSaveFPRegs); |
| 214 __ mov(r2, Operand(cp)); | |
| 215 __ RecordWrite(r2, Operand(r1), r3, r0); | |
| 216 } | 222 } |
| 217 } | 223 } |
| 218 Comment(";;; End allocate local context"); | 224 Comment(";;; End allocate local context"); |
| 219 } | 225 } |
| 220 | 226 |
| 221 // Trace the call. | 227 // Trace the call. |
| 222 if (FLAG_trace) { | 228 if (FLAG_trace) { |
| 223 __ CallRuntime(Runtime::kTraceEnter, 0); | 229 __ CallRuntime(Runtime::kTraceEnter, 0); |
| 224 } | 230 } |
| 225 return !is_aborted(); | 231 return !is_aborted(); |
| (...skipping 29 matching lines...) Expand all Loading... |
| 255 } | 261 } |
| 256 } | 262 } |
| 257 | 263 |
| 258 | 264 |
| 259 bool LCodeGen::GenerateDeferredCode() { | 265 bool LCodeGen::GenerateDeferredCode() { |
| 260 ASSERT(is_generating()); | 266 ASSERT(is_generating()); |
| 261 if (deferred_.length() > 0) { | 267 if (deferred_.length() > 0) { |
| 262 for (int i = 0; !is_aborted() && i < deferred_.length(); i++) { | 268 for (int i = 0; !is_aborted() && i < deferred_.length(); i++) { |
| 263 LDeferredCode* code = deferred_[i]; | 269 LDeferredCode* code = deferred_[i]; |
| 264 __ bind(code->entry()); | 270 __ bind(code->entry()); |
| 271 Comment(";;; Deferred code @%d: %s.", |
| 272 code->instruction_index(), |
| 273 code->instr()->Mnemonic()); |
| 265 code->Generate(); | 274 code->Generate(); |
| 266 __ jmp(code->exit()); | 275 __ jmp(code->exit()); |
| 267 } | 276 } |
| 268 | 277 |
| 269 // Pad code to ensure that the last piece of deferred code have | 278 // Pad code to ensure that the last piece of deferred code have |
| 270 // room for lazy bailout. | 279 // room for lazy bailout. |
| 271 while ((masm()->pc_offset() - LastSafepointEnd()) | 280 while ((masm()->pc_offset() - LastSafepointEnd()) |
| 272 < Deoptimizer::patch_size()) { | 281 < Deoptimizer::patch_size()) { |
| 273 __ nop(); | 282 __ nop(); |
| 274 } | 283 } |
| (...skipping 457 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 732 } | 741 } |
| 733 | 742 |
| 734 | 743 |
| 735 void LCodeGen::RecordSafepoint( | 744 void LCodeGen::RecordSafepoint( |
| 736 LPointerMap* pointers, | 745 LPointerMap* pointers, |
| 737 Safepoint::Kind kind, | 746 Safepoint::Kind kind, |
| 738 int arguments, | 747 int arguments, |
| 739 int deoptimization_index) { | 748 int deoptimization_index) { |
| 740 ASSERT(expected_safepoint_kind_ == kind); | 749 ASSERT(expected_safepoint_kind_ == kind); |
| 741 | 750 |
| 742 const ZoneList<LOperand*>* operands = pointers->operands(); | 751 const ZoneList<LOperand*>* operands = pointers->GetNormalizedOperands(); |
| 743 Safepoint safepoint = safepoints_.DefineSafepoint(masm(), | 752 Safepoint safepoint = safepoints_.DefineSafepoint(masm(), |
| 744 kind, arguments, deoptimization_index); | 753 kind, arguments, deoptimization_index); |
| 745 for (int i = 0; i < operands->length(); i++) { | 754 for (int i = 0; i < operands->length(); i++) { |
| 746 LOperand* pointer = operands->at(i); | 755 LOperand* pointer = operands->at(i); |
| 747 if (pointer->IsStackSlot()) { | 756 if (pointer->IsStackSlot()) { |
| 748 safepoint.DefinePointerSlot(pointer->index()); | 757 safepoint.DefinePointerSlot(pointer->index()); |
| 749 } else if (pointer->IsRegister() && (kind & Safepoint::kWithRegisters)) { | 758 } else if (pointer->IsRegister() && (kind & Safepoint::kWithRegisters)) { |
| 750 safepoint.DefinePointerRegister(ToRegister(pointer)); | 759 safepoint.DefinePointerRegister(ToRegister(pointer)); |
| 751 } | 760 } |
| 752 } | 761 } |
| (...skipping 272 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1025 | 1034 |
| 1026 | 1035 |
| 1027 void LCodeGen::DoDivI(LDivI* instr) { | 1036 void LCodeGen::DoDivI(LDivI* instr) { |
| 1028 class DeferredDivI: public LDeferredCode { | 1037 class DeferredDivI: public LDeferredCode { |
| 1029 public: | 1038 public: |
| 1030 DeferredDivI(LCodeGen* codegen, LDivI* instr) | 1039 DeferredDivI(LCodeGen* codegen, LDivI* instr) |
| 1031 : LDeferredCode(codegen), instr_(instr) { } | 1040 : LDeferredCode(codegen), instr_(instr) { } |
| 1032 virtual void Generate() { | 1041 virtual void Generate() { |
| 1033 codegen()->DoDeferredBinaryOpStub(instr_, Token::DIV); | 1042 codegen()->DoDeferredBinaryOpStub(instr_, Token::DIV); |
| 1034 } | 1043 } |
| 1044 virtual LInstruction* instr() { return instr_; } |
| 1035 private: | 1045 private: |
| 1036 LDivI* instr_; | 1046 LDivI* instr_; |
| 1037 }; | 1047 }; |
| 1038 | 1048 |
| 1039 const Register left = ToRegister(instr->InputAt(0)); | 1049 const Register left = ToRegister(instr->InputAt(0)); |
| 1040 const Register right = ToRegister(instr->InputAt(1)); | 1050 const Register right = ToRegister(instr->InputAt(1)); |
| 1041 const Register scratch = scratch0(); | 1051 const Register scratch = scratch0(); |
| 1042 const Register result = ToRegister(instr->result()); | 1052 const Register result = ToRegister(instr->result()); |
| 1043 | 1053 |
| 1044 // Check for x / 0. | 1054 // Check for x / 0. |
| (...skipping 691 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1736 void LCodeGen::DoCmpConstantEqAndBranch(LCmpConstantEqAndBranch* instr) { | 1746 void LCodeGen::DoCmpConstantEqAndBranch(LCmpConstantEqAndBranch* instr) { |
| 1737 Register left = ToRegister(instr->InputAt(0)); | 1747 Register left = ToRegister(instr->InputAt(0)); |
| 1738 int true_block = chunk_->LookupDestination(instr->true_block_id()); | 1748 int true_block = chunk_->LookupDestination(instr->true_block_id()); |
| 1739 int false_block = chunk_->LookupDestination(instr->false_block_id()); | 1749 int false_block = chunk_->LookupDestination(instr->false_block_id()); |
| 1740 | 1750 |
| 1741 __ cmp(left, Operand(instr->hydrogen()->right())); | 1751 __ cmp(left, Operand(instr->hydrogen()->right())); |
| 1742 EmitBranch(true_block, false_block, eq); | 1752 EmitBranch(true_block, false_block, eq); |
| 1743 } | 1753 } |
| 1744 | 1754 |
| 1745 | 1755 |
| 1746 void LCodeGen::DoIsNullAndBranch(LIsNullAndBranch* instr) { | 1756 void LCodeGen::DoIsNilAndBranch(LIsNilAndBranch* instr) { |
| 1747 Register scratch = scratch0(); | 1757 Register scratch = scratch0(); |
| 1748 Register reg = ToRegister(instr->InputAt(0)); | 1758 Register reg = ToRegister(instr->InputAt(0)); |
| 1759 int false_block = chunk_->LookupDestination(instr->false_block_id()); |
| 1749 | 1760 |
| 1750 // TODO(fsc): If the expression is known to be a smi, then it's | 1761 // If the expression is known to be untagged or a smi, then it's definitely |
| 1751 // definitely not null. Jump to the false block. | 1762 // not null, and it can't be a an undetectable object. |
| 1763 if (instr->hydrogen()->representation().IsSpecialization() || |
| 1764 instr->hydrogen()->type().IsSmi()) { |
| 1765 EmitGoto(false_block); |
| 1766 return; |
| 1767 } |
| 1752 | 1768 |
| 1753 int true_block = chunk_->LookupDestination(instr->true_block_id()); | 1769 int true_block = chunk_->LookupDestination(instr->true_block_id()); |
| 1754 int false_block = chunk_->LookupDestination(instr->false_block_id()); | 1770 Heap::RootListIndex nil_value = instr->nil() == kNullValue ? |
| 1755 | 1771 Heap::kNullValueRootIndex : |
| 1756 __ LoadRoot(ip, Heap::kNullValueRootIndex); | 1772 Heap::kUndefinedValueRootIndex; |
| 1773 __ LoadRoot(ip, nil_value); |
| 1757 __ cmp(reg, ip); | 1774 __ cmp(reg, ip); |
| 1758 if (instr->is_strict()) { | 1775 if (instr->kind() == kStrictEquality) { |
| 1759 EmitBranch(true_block, false_block, eq); | 1776 EmitBranch(true_block, false_block, eq); |
| 1760 } else { | 1777 } else { |
| 1778 Heap::RootListIndex other_nil_value = instr->nil() == kNullValue ? |
| 1779 Heap::kUndefinedValueRootIndex : |
| 1780 Heap::kNullValueRootIndex; |
| 1761 Label* true_label = chunk_->GetAssemblyLabel(true_block); | 1781 Label* true_label = chunk_->GetAssemblyLabel(true_block); |
| 1762 Label* false_label = chunk_->GetAssemblyLabel(false_block); | 1782 Label* false_label = chunk_->GetAssemblyLabel(false_block); |
| 1763 __ b(eq, true_label); | 1783 __ b(eq, true_label); |
| 1764 __ LoadRoot(ip, Heap::kUndefinedValueRootIndex); | 1784 __ LoadRoot(ip, other_nil_value); |
| 1765 __ cmp(reg, ip); | 1785 __ cmp(reg, ip); |
| 1766 __ b(eq, true_label); | 1786 __ b(eq, true_label); |
| 1767 __ JumpIfSmi(reg, false_label); | 1787 __ JumpIfSmi(reg, false_label); |
| 1768 // Check for undetectable objects by looking in the bit field in | 1788 // Check for undetectable objects by looking in the bit field in |
| 1769 // the map. The object has already been smi checked. | 1789 // the map. The object has already been smi checked. |
| 1770 __ ldr(scratch, FieldMemOperand(reg, HeapObject::kMapOffset)); | 1790 __ ldr(scratch, FieldMemOperand(reg, HeapObject::kMapOffset)); |
| 1771 __ ldrb(scratch, FieldMemOperand(scratch, Map::kBitFieldOffset)); | 1791 __ ldrb(scratch, FieldMemOperand(scratch, Map::kBitFieldOffset)); |
| 1772 __ tst(scratch, Operand(1 << Map::kIsUndetectable)); | 1792 __ tst(scratch, Operand(1 << Map::kIsUndetectable)); |
| 1773 EmitBranch(true_block, false_block, ne); | 1793 EmitBranch(true_block, false_block, ne); |
| 1774 } | 1794 } |
| (...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1911 // the temp registers, but not the input. Only input and temp2 may alias. | 1931 // the temp registers, but not the input. Only input and temp2 may alias. |
| 1912 void LCodeGen::EmitClassOfTest(Label* is_true, | 1932 void LCodeGen::EmitClassOfTest(Label* is_true, |
| 1913 Label* is_false, | 1933 Label* is_false, |
| 1914 Handle<String>class_name, | 1934 Handle<String>class_name, |
| 1915 Register input, | 1935 Register input, |
| 1916 Register temp, | 1936 Register temp, |
| 1917 Register temp2) { | 1937 Register temp2) { |
| 1918 ASSERT(!input.is(temp)); | 1938 ASSERT(!input.is(temp)); |
| 1919 ASSERT(!temp.is(temp2)); // But input and temp2 may be the same register. | 1939 ASSERT(!temp.is(temp2)); // But input and temp2 may be the same register. |
| 1920 __ JumpIfSmi(input, is_false); | 1940 __ JumpIfSmi(input, is_false); |
| 1921 __ CompareObjectType(input, temp, temp2, FIRST_SPEC_OBJECT_TYPE); | |
| 1922 __ b(lt, is_false); | |
| 1923 | 1941 |
| 1924 // Map is now in temp. | |
| 1925 // Functions have class 'Function'. | |
| 1926 __ CompareInstanceType(temp, temp2, FIRST_CALLABLE_SPEC_OBJECT_TYPE); | |
| 1927 if (class_name->IsEqualTo(CStrVector("Function"))) { | 1942 if (class_name->IsEqualTo(CStrVector("Function"))) { |
| 1928 __ b(ge, is_true); | 1943 // Assuming the following assertions, we can use the same compares to test |
| 1944 // for both being a function type and being in the object type range. |
| 1945 STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2); |
| 1946 STATIC_ASSERT(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE == |
| 1947 FIRST_SPEC_OBJECT_TYPE + 1); |
| 1948 STATIC_ASSERT(LAST_NONCALLABLE_SPEC_OBJECT_TYPE == |
| 1949 LAST_SPEC_OBJECT_TYPE - 1); |
| 1950 STATIC_ASSERT(LAST_SPEC_OBJECT_TYPE == LAST_TYPE); |
| 1951 __ CompareObjectType(input, temp, temp2, FIRST_SPEC_OBJECT_TYPE); |
| 1952 __ b(lt, is_false); |
| 1953 __ b(eq, is_true); |
| 1954 __ cmp(temp2, Operand(LAST_SPEC_OBJECT_TYPE)); |
| 1955 __ b(eq, is_true); |
| 1929 } else { | 1956 } else { |
| 1930 __ b(ge, is_false); | 1957 // Faster code path to avoid two compares: subtract lower bound from the |
| 1958 // actual type and do a signed compare with the width of the type range. |
| 1959 __ ldr(temp, FieldMemOperand(input, HeapObject::kMapOffset)); |
| 1960 __ ldrb(temp2, FieldMemOperand(temp, Map::kInstanceTypeOffset)); |
| 1961 __ sub(temp2, temp2, Operand(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE)); |
| 1962 __ cmp(temp2, Operand(LAST_NONCALLABLE_SPEC_OBJECT_TYPE - |
| 1963 FIRST_NONCALLABLE_SPEC_OBJECT_TYPE)); |
| 1964 __ b(gt, is_false); |
| 1931 } | 1965 } |
| 1932 | 1966 |
| 1967 // Now we are in the FIRST-LAST_NONCALLABLE_SPEC_OBJECT_TYPE range. |
| 1933 // Check if the constructor in the map is a function. | 1968 // Check if the constructor in the map is a function. |
| 1934 __ ldr(temp, FieldMemOperand(temp, Map::kConstructorOffset)); | 1969 __ ldr(temp, FieldMemOperand(temp, Map::kConstructorOffset)); |
| 1935 | 1970 |
| 1936 // As long as LAST_CALLABLE_SPEC_OBJECT_TYPE is the last instance type and | |
| 1937 // FIRST_CALLABLE_SPEC_OBJECT_TYPE comes right after | |
| 1938 // LAST_NONCALLABLE_SPEC_OBJECT_TYPE, we can avoid checking for the latter. | |
| 1939 STATIC_ASSERT(LAST_TYPE == LAST_CALLABLE_SPEC_OBJECT_TYPE); | |
| 1940 STATIC_ASSERT(FIRST_CALLABLE_SPEC_OBJECT_TYPE == | |
| 1941 LAST_NONCALLABLE_SPEC_OBJECT_TYPE + 1); | |
| 1942 | |
| 1943 // Objects with a non-function constructor have class 'Object'. | 1971 // Objects with a non-function constructor have class 'Object'. |
| 1944 __ CompareObjectType(temp, temp2, temp2, JS_FUNCTION_TYPE); | 1972 __ CompareObjectType(temp, temp2, temp2, JS_FUNCTION_TYPE); |
| 1945 if (class_name->IsEqualTo(CStrVector("Object"))) { | 1973 if (class_name->IsEqualTo(CStrVector("Object"))) { |
| 1946 __ b(ne, is_true); | 1974 __ b(ne, is_true); |
| 1947 } else { | 1975 } else { |
| 1948 __ b(ne, is_false); | 1976 __ b(ne, is_false); |
| 1949 } | 1977 } |
| 1950 | 1978 |
| 1951 // temp now contains the constructor function. Grab the | 1979 // temp now contains the constructor function. Grab the |
| 1952 // instance class name from there. | 1980 // instance class name from there. |
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2009 | 2037 |
| 2010 void LCodeGen::DoInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr) { | 2038 void LCodeGen::DoInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr) { |
| 2011 class DeferredInstanceOfKnownGlobal: public LDeferredCode { | 2039 class DeferredInstanceOfKnownGlobal: public LDeferredCode { |
| 2012 public: | 2040 public: |
| 2013 DeferredInstanceOfKnownGlobal(LCodeGen* codegen, | 2041 DeferredInstanceOfKnownGlobal(LCodeGen* codegen, |
| 2014 LInstanceOfKnownGlobal* instr) | 2042 LInstanceOfKnownGlobal* instr) |
| 2015 : LDeferredCode(codegen), instr_(instr) { } | 2043 : LDeferredCode(codegen), instr_(instr) { } |
| 2016 virtual void Generate() { | 2044 virtual void Generate() { |
| 2017 codegen()->DoDeferredLInstanceOfKnownGlobal(instr_, &map_check_); | 2045 codegen()->DoDeferredLInstanceOfKnownGlobal(instr_, &map_check_); |
| 2018 } | 2046 } |
| 2019 | 2047 virtual LInstruction* instr() { return instr_; } |
| 2020 Label* map_check() { return &map_check_; } | 2048 Label* map_check() { return &map_check_; } |
| 2021 | |
| 2022 private: | 2049 private: |
| 2023 LInstanceOfKnownGlobal* instr_; | 2050 LInstanceOfKnownGlobal* instr_; |
| 2024 Label map_check_; | 2051 Label map_check_; |
| 2025 }; | 2052 }; |
| 2026 | 2053 |
| 2027 DeferredInstanceOfKnownGlobal* deferred; | 2054 DeferredInstanceOfKnownGlobal* deferred; |
| 2028 deferred = new DeferredInstanceOfKnownGlobal(this, instr); | 2055 deferred = new DeferredInstanceOfKnownGlobal(this, instr); |
| 2029 | 2056 |
| 2030 Label done, false_result; | 2057 Label done, false_result; |
| 2031 Register object = ToRegister(instr->InputAt(0)); | 2058 Register object = ToRegister(instr->InputAt(0)); |
| (...skipping 141 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2173 __ ldm(ia_w, sp, fp.bit() | lr.bit()); | 2200 __ ldm(ia_w, sp, fp.bit() | lr.bit()); |
| 2174 __ add(sp, sp, Operand(sp_delta)); | 2201 __ add(sp, sp, Operand(sp_delta)); |
| 2175 __ Jump(lr); | 2202 __ Jump(lr); |
| 2176 } | 2203 } |
| 2177 | 2204 |
| 2178 | 2205 |
| 2179 void LCodeGen::DoLoadGlobalCell(LLoadGlobalCell* instr) { | 2206 void LCodeGen::DoLoadGlobalCell(LLoadGlobalCell* instr) { |
| 2180 Register result = ToRegister(instr->result()); | 2207 Register result = ToRegister(instr->result()); |
| 2181 __ mov(ip, Operand(Handle<Object>(instr->hydrogen()->cell()))); | 2208 __ mov(ip, Operand(Handle<Object>(instr->hydrogen()->cell()))); |
| 2182 __ ldr(result, FieldMemOperand(ip, JSGlobalPropertyCell::kValueOffset)); | 2209 __ ldr(result, FieldMemOperand(ip, JSGlobalPropertyCell::kValueOffset)); |
| 2183 if (instr->hydrogen()->check_hole_value()) { | 2210 if (instr->hydrogen()->RequiresHoleCheck()) { |
| 2184 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex); | 2211 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex); |
| 2185 __ cmp(result, ip); | 2212 __ cmp(result, ip); |
| 2186 DeoptimizeIf(eq, instr->environment()); | 2213 DeoptimizeIf(eq, instr->environment()); |
| 2187 } | 2214 } |
| 2188 } | 2215 } |
| 2189 | 2216 |
| 2190 | 2217 |
| 2191 void LCodeGen::DoLoadGlobalGeneric(LLoadGlobalGeneric* instr) { | 2218 void LCodeGen::DoLoadGlobalGeneric(LLoadGlobalGeneric* instr) { |
| 2192 ASSERT(ToRegister(instr->global_object()).is(r0)); | 2219 ASSERT(ToRegister(instr->global_object()).is(r0)); |
| 2193 ASSERT(ToRegister(instr->result()).is(r0)); | 2220 ASSERT(ToRegister(instr->result()).is(r0)); |
| 2194 | 2221 |
| 2195 __ mov(r2, Operand(instr->name())); | 2222 __ mov(r2, Operand(instr->name())); |
| 2196 RelocInfo::Mode mode = instr->for_typeof() ? RelocInfo::CODE_TARGET | 2223 RelocInfo::Mode mode = instr->for_typeof() ? RelocInfo::CODE_TARGET |
| 2197 : RelocInfo::CODE_TARGET_CONTEXT; | 2224 : RelocInfo::CODE_TARGET_CONTEXT; |
| 2198 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize(); | 2225 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize(); |
| 2199 CallCode(ic, mode, instr); | 2226 CallCode(ic, mode, instr); |
| 2200 } | 2227 } |
| 2201 | 2228 |
| 2202 | 2229 |
| 2203 void LCodeGen::DoStoreGlobalCell(LStoreGlobalCell* instr) { | 2230 void LCodeGen::DoStoreGlobalCell(LStoreGlobalCell* instr) { |
| 2204 Register value = ToRegister(instr->InputAt(0)); | 2231 Register value = ToRegister(instr->InputAt(0)); |
| 2205 Register scratch = scratch0(); | 2232 Register scratch = scratch0(); |
| 2233 Register scratch2 = ToRegister(instr->TempAt(0)); |
| 2206 | 2234 |
| 2207 // Load the cell. | 2235 // Load the cell. |
| 2208 __ mov(scratch, Operand(Handle<Object>(instr->hydrogen()->cell()))); | 2236 __ mov(scratch, Operand(Handle<Object>(instr->hydrogen()->cell()))); |
| 2209 | 2237 |
| 2210 // If the cell we are storing to contains the hole it could have | 2238 // If the cell we are storing to contains the hole it could have |
| 2211 // been deleted from the property dictionary. In that case, we need | 2239 // been deleted from the property dictionary. In that case, we need |
| 2212 // to update the property details in the property dictionary to mark | 2240 // to update the property details in the property dictionary to mark |
| 2213 // it as no longer deleted. | 2241 // it as no longer deleted. |
| 2214 if (instr->hydrogen()->check_hole_value()) { | 2242 if (instr->hydrogen()->RequiresHoleCheck()) { |
| 2215 Register scratch2 = ToRegister(instr->TempAt(0)); | |
| 2216 __ ldr(scratch2, | 2243 __ ldr(scratch2, |
| 2217 FieldMemOperand(scratch, JSGlobalPropertyCell::kValueOffset)); | 2244 FieldMemOperand(scratch, JSGlobalPropertyCell::kValueOffset)); |
| 2218 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex); | 2245 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex); |
| 2219 __ cmp(scratch2, ip); | 2246 __ cmp(scratch2, ip); |
| 2220 DeoptimizeIf(eq, instr->environment()); | 2247 DeoptimizeIf(eq, instr->environment()); |
| 2221 } | 2248 } |
| 2222 | 2249 |
| 2223 // Store the value. | 2250 // Store the value. |
| 2224 __ str(value, FieldMemOperand(scratch, JSGlobalPropertyCell::kValueOffset)); | 2251 __ str(value, FieldMemOperand(scratch, JSGlobalPropertyCell::kValueOffset)); |
| 2252 |
| 2253 // Cells are always in the remembered set. |
| 2254 __ RecordWriteField(scratch, |
| 2255 JSGlobalPropertyCell::kValueOffset, |
| 2256 value, |
| 2257 scratch2, |
| 2258 kLRHasBeenSaved, |
| 2259 kSaveFPRegs, |
| 2260 OMIT_REMEMBERED_SET); |
| 2225 } | 2261 } |
| 2226 | 2262 |
| 2227 | 2263 |
| 2228 void LCodeGen::DoStoreGlobalGeneric(LStoreGlobalGeneric* instr) { | 2264 void LCodeGen::DoStoreGlobalGeneric(LStoreGlobalGeneric* instr) { |
| 2229 ASSERT(ToRegister(instr->global_object()).is(r1)); | 2265 ASSERT(ToRegister(instr->global_object()).is(r1)); |
| 2230 ASSERT(ToRegister(instr->value()).is(r0)); | 2266 ASSERT(ToRegister(instr->value()).is(r0)); |
| 2231 | 2267 |
| 2232 __ mov(r2, Operand(instr->name())); | 2268 __ mov(r2, Operand(instr->name())); |
| 2233 Handle<Code> ic = instr->strict_mode() | 2269 Handle<Code> ic = instr->strict_mode() |
| 2234 ? isolate()->builtins()->StoreIC_Initialize_Strict() | 2270 ? isolate()->builtins()->StoreIC_Initialize_Strict() |
| 2235 : isolate()->builtins()->StoreIC_Initialize(); | 2271 : isolate()->builtins()->StoreIC_Initialize(); |
| 2236 CallCode(ic, RelocInfo::CODE_TARGET_CONTEXT, instr); | 2272 CallCode(ic, RelocInfo::CODE_TARGET_CONTEXT, instr); |
| 2237 } | 2273 } |
| 2238 | 2274 |
| 2239 | 2275 |
| 2240 void LCodeGen::DoLoadContextSlot(LLoadContextSlot* instr) { | 2276 void LCodeGen::DoLoadContextSlot(LLoadContextSlot* instr) { |
| 2241 Register context = ToRegister(instr->context()); | 2277 Register context = ToRegister(instr->context()); |
| 2242 Register result = ToRegister(instr->result()); | 2278 Register result = ToRegister(instr->result()); |
| 2243 __ ldr(result, ContextOperand(context, instr->slot_index())); | 2279 __ ldr(result, ContextOperand(context, instr->slot_index())); |
| 2244 } | 2280 } |
| 2245 | 2281 |
| 2246 | 2282 |
| 2247 void LCodeGen::DoStoreContextSlot(LStoreContextSlot* instr) { | 2283 void LCodeGen::DoStoreContextSlot(LStoreContextSlot* instr) { |
| 2248 Register context = ToRegister(instr->context()); | 2284 Register context = ToRegister(instr->context()); |
| 2249 Register value = ToRegister(instr->value()); | 2285 Register value = ToRegister(instr->value()); |
| 2250 __ str(value, ContextOperand(context, instr->slot_index())); | 2286 MemOperand target = ContextOperand(context, instr->slot_index()); |
| 2287 __ str(value, target); |
| 2251 if (instr->needs_write_barrier()) { | 2288 if (instr->needs_write_barrier()) { |
| 2252 int offset = Context::SlotOffset(instr->slot_index()); | 2289 __ RecordWriteContextSlot(context, |
| 2253 __ RecordWrite(context, Operand(offset), value, scratch0()); | 2290 target.offset(), |
| 2291 value, |
| 2292 scratch0(), |
| 2293 kLRHasBeenSaved, |
| 2294 kSaveFPRegs); |
| 2254 } | 2295 } |
| 2255 } | 2296 } |
| 2256 | 2297 |
| 2257 | 2298 |
| 2258 void LCodeGen::DoLoadNamedField(LLoadNamedField* instr) { | 2299 void LCodeGen::DoLoadNamedField(LLoadNamedField* instr) { |
| 2259 Register object = ToRegister(instr->InputAt(0)); | 2300 Register object = ToRegister(instr->InputAt(0)); |
| 2260 Register result = ToRegister(instr->result()); | 2301 Register result = ToRegister(instr->result()); |
| 2261 if (instr->hydrogen()->is_in_object()) { | 2302 if (instr->hydrogen()->is_in_object()) { |
| 2262 __ ldr(result, FieldMemOperand(object, instr->hydrogen()->offset())); | 2303 __ ldr(result, FieldMemOperand(object, instr->hydrogen()->offset())); |
| 2263 } else { | 2304 } else { |
| (...skipping 229 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2493 Operand operand = key_is_constant | 2534 Operand operand = key_is_constant |
| 2494 ? Operand(constant_key * (1 << shift_size) + | 2535 ? Operand(constant_key * (1 << shift_size) + |
| 2495 FixedDoubleArray::kHeaderSize - kHeapObjectTag) | 2536 FixedDoubleArray::kHeaderSize - kHeapObjectTag) |
| 2496 : Operand(key, LSL, shift_size); | 2537 : Operand(key, LSL, shift_size); |
| 2497 __ add(elements, elements, operand); | 2538 __ add(elements, elements, operand); |
| 2498 if (!key_is_constant) { | 2539 if (!key_is_constant) { |
| 2499 __ add(elements, elements, | 2540 __ add(elements, elements, |
| 2500 Operand(FixedDoubleArray::kHeaderSize - kHeapObjectTag)); | 2541 Operand(FixedDoubleArray::kHeaderSize - kHeapObjectTag)); |
| 2501 } | 2542 } |
| 2502 | 2543 |
| 2503 if (instr->hydrogen()->RequiresHoleCheck()) { | 2544 __ ldr(scratch, MemOperand(elements, sizeof(kHoleNanLower32))); |
| 2504 // TODO(danno): If no hole check is required, there is no need to allocate | 2545 __ cmp(scratch, Operand(kHoleNanUpper32)); |
| 2505 // elements into a temporary register, instead scratch can be used. | 2546 DeoptimizeIf(eq, instr->environment()); |
| 2506 __ ldr(scratch, MemOperand(elements, sizeof(kHoleNanLower32))); | |
| 2507 __ cmp(scratch, Operand(kHoleNanUpper32)); | |
| 2508 DeoptimizeIf(eq, instr->environment()); | |
| 2509 } | |
| 2510 | 2547 |
| 2511 __ vldr(result, elements, 0); | 2548 __ vldr(result, elements, 0); |
| 2512 } | 2549 } |
| 2513 | 2550 |
| 2514 | 2551 |
| 2515 void LCodeGen::DoLoadKeyedSpecializedArrayElement( | 2552 void LCodeGen::DoLoadKeyedSpecializedArrayElement( |
| 2516 LLoadKeyedSpecializedArrayElement* instr) { | 2553 LLoadKeyedSpecializedArrayElement* instr) { |
| 2517 Register external_pointer = ToRegister(instr->external_pointer()); | 2554 Register external_pointer = ToRegister(instr->external_pointer()); |
| 2518 Register key = no_reg; | 2555 Register key = no_reg; |
| 2519 ElementsKind elements_kind = instr->elements_kind(); | 2556 ElementsKind elements_kind = instr->elements_kind(); |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2570 __ cmp(result, Operand(0x80000000)); | 2607 __ cmp(result, Operand(0x80000000)); |
| 2571 // TODO(danno): we could be more clever here, perhaps having a special | 2608 // TODO(danno): we could be more clever here, perhaps having a special |
| 2572 // version of the stub that detects if the overflow case actually | 2609 // version of the stub that detects if the overflow case actually |
| 2573 // happens, and generate code that returns a double rather than int. | 2610 // happens, and generate code that returns a double rather than int. |
| 2574 DeoptimizeIf(cs, instr->environment()); | 2611 DeoptimizeIf(cs, instr->environment()); |
| 2575 break; | 2612 break; |
| 2576 case EXTERNAL_FLOAT_ELEMENTS: | 2613 case EXTERNAL_FLOAT_ELEMENTS: |
| 2577 case EXTERNAL_DOUBLE_ELEMENTS: | 2614 case EXTERNAL_DOUBLE_ELEMENTS: |
| 2578 case FAST_DOUBLE_ELEMENTS: | 2615 case FAST_DOUBLE_ELEMENTS: |
| 2579 case FAST_ELEMENTS: | 2616 case FAST_ELEMENTS: |
| 2617 case FAST_SMI_ONLY_ELEMENTS: |
| 2580 case DICTIONARY_ELEMENTS: | 2618 case DICTIONARY_ELEMENTS: |
| 2581 case NON_STRICT_ARGUMENTS_ELEMENTS: | 2619 case NON_STRICT_ARGUMENTS_ELEMENTS: |
| 2582 UNREACHABLE(); | 2620 UNREACHABLE(); |
| 2583 break; | 2621 break; |
| 2584 } | 2622 } |
| 2585 } | 2623 } |
| 2586 } | 2624 } |
| 2587 | 2625 |
| 2588 | 2626 |
| 2589 void LCodeGen::DoLoadKeyedGeneric(LLoadKeyedGeneric* instr) { | 2627 void LCodeGen::DoLoadKeyedGeneric(LLoadKeyedGeneric* instr) { |
| (...skipping 309 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2899 void LCodeGen::DoMathAbs(LUnaryMathOperation* instr) { | 2937 void LCodeGen::DoMathAbs(LUnaryMathOperation* instr) { |
| 2900 // Class for deferred case. | 2938 // Class for deferred case. |
| 2901 class DeferredMathAbsTaggedHeapNumber: public LDeferredCode { | 2939 class DeferredMathAbsTaggedHeapNumber: public LDeferredCode { |
| 2902 public: | 2940 public: |
| 2903 DeferredMathAbsTaggedHeapNumber(LCodeGen* codegen, | 2941 DeferredMathAbsTaggedHeapNumber(LCodeGen* codegen, |
| 2904 LUnaryMathOperation* instr) | 2942 LUnaryMathOperation* instr) |
| 2905 : LDeferredCode(codegen), instr_(instr) { } | 2943 : LDeferredCode(codegen), instr_(instr) { } |
| 2906 virtual void Generate() { | 2944 virtual void Generate() { |
| 2907 codegen()->DoDeferredMathAbsTaggedHeapNumber(instr_); | 2945 codegen()->DoDeferredMathAbsTaggedHeapNumber(instr_); |
| 2908 } | 2946 } |
| 2947 virtual LInstruction* instr() { return instr_; } |
| 2909 private: | 2948 private: |
| 2910 LUnaryMathOperation* instr_; | 2949 LUnaryMathOperation* instr_; |
| 2911 }; | 2950 }; |
| 2912 | 2951 |
| 2913 Representation r = instr->hydrogen()->value()->representation(); | 2952 Representation r = instr->hydrogen()->value()->representation(); |
| 2914 if (r.IsDouble()) { | 2953 if (r.IsDouble()) { |
| 2915 DwVfpRegister input = ToDoubleRegister(instr->InputAt(0)); | 2954 DwVfpRegister input = ToDoubleRegister(instr->InputAt(0)); |
| 2916 DwVfpRegister result = ToDoubleRegister(instr->result()); | 2955 DwVfpRegister result = ToDoubleRegister(instr->result()); |
| 2917 __ vabs(result, input); | 2956 __ vabs(result, input); |
| 2918 } else if (r.IsInteger32()) { | 2957 } else if (r.IsInteger32()) { |
| (...skipping 276 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3195 CallCode(ic, mode, instr); | 3234 CallCode(ic, mode, instr); |
| 3196 // Restore context register. | 3235 // Restore context register. |
| 3197 __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); | 3236 __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); |
| 3198 } | 3237 } |
| 3199 | 3238 |
| 3200 | 3239 |
| 3201 void LCodeGen::DoCallFunction(LCallFunction* instr) { | 3240 void LCodeGen::DoCallFunction(LCallFunction* instr) { |
| 3202 ASSERT(ToRegister(instr->result()).is(r0)); | 3241 ASSERT(ToRegister(instr->result()).is(r0)); |
| 3203 | 3242 |
| 3204 int arity = instr->arity(); | 3243 int arity = instr->arity(); |
| 3205 CallFunctionStub stub(arity, RECEIVER_MIGHT_BE_IMPLICIT); | 3244 CallFunctionStub stub(arity, NO_CALL_FUNCTION_FLAGS); |
| 3206 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); | 3245 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); |
| 3207 __ Drop(1); | 3246 __ Drop(1); |
| 3208 __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); | 3247 __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); |
| 3209 } | 3248 } |
| 3210 | 3249 |
| 3211 | 3250 |
| 3212 void LCodeGen::DoCallGlobal(LCallGlobal* instr) { | 3251 void LCodeGen::DoCallGlobal(LCallGlobal* instr) { |
| 3213 ASSERT(ToRegister(instr->result()).is(r0)); | 3252 ASSERT(ToRegister(instr->result()).is(r0)); |
| 3214 | 3253 |
| 3215 int arity = instr->arity(); | 3254 int arity = instr->arity(); |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3255 if (!instr->transition().is_null()) { | 3294 if (!instr->transition().is_null()) { |
| 3256 __ mov(scratch, Operand(instr->transition())); | 3295 __ mov(scratch, Operand(instr->transition())); |
| 3257 __ str(scratch, FieldMemOperand(object, HeapObject::kMapOffset)); | 3296 __ str(scratch, FieldMemOperand(object, HeapObject::kMapOffset)); |
| 3258 } | 3297 } |
| 3259 | 3298 |
| 3260 // Do the store. | 3299 // Do the store. |
| 3261 if (instr->is_in_object()) { | 3300 if (instr->is_in_object()) { |
| 3262 __ str(value, FieldMemOperand(object, offset)); | 3301 __ str(value, FieldMemOperand(object, offset)); |
| 3263 if (instr->needs_write_barrier()) { | 3302 if (instr->needs_write_barrier()) { |
| 3264 // Update the write barrier for the object for in-object properties. | 3303 // Update the write barrier for the object for in-object properties. |
| 3265 __ RecordWrite(object, Operand(offset), value, scratch); | 3304 __ RecordWriteField( |
| 3305 object, offset, value, scratch, kLRHasBeenSaved, kSaveFPRegs); |
| 3266 } | 3306 } |
| 3267 } else { | 3307 } else { |
| 3268 __ ldr(scratch, FieldMemOperand(object, JSObject::kPropertiesOffset)); | 3308 __ ldr(scratch, FieldMemOperand(object, JSObject::kPropertiesOffset)); |
| 3269 __ str(value, FieldMemOperand(scratch, offset)); | 3309 __ str(value, FieldMemOperand(scratch, offset)); |
| 3270 if (instr->needs_write_barrier()) { | 3310 if (instr->needs_write_barrier()) { |
| 3271 // Update the write barrier for the properties array. | 3311 // Update the write barrier for the properties array. |
| 3272 // object is used as a scratch register. | 3312 // object is used as a scratch register. |
| 3273 __ RecordWrite(scratch, Operand(offset), value, object); | 3313 __ RecordWriteField( |
| 3314 scratch, offset, value, object, kLRHasBeenSaved, kSaveFPRegs); |
| 3274 } | 3315 } |
| 3275 } | 3316 } |
| 3276 } | 3317 } |
| 3277 | 3318 |
| 3278 | 3319 |
| 3279 void LCodeGen::DoStoreNamedGeneric(LStoreNamedGeneric* instr) { | 3320 void LCodeGen::DoStoreNamedGeneric(LStoreNamedGeneric* instr) { |
| 3280 ASSERT(ToRegister(instr->object()).is(r1)); | 3321 ASSERT(ToRegister(instr->object()).is(r1)); |
| 3281 ASSERT(ToRegister(instr->value()).is(r0)); | 3322 ASSERT(ToRegister(instr->value()).is(r0)); |
| 3282 | 3323 |
| 3283 // Name is always in r2. | 3324 // Name is always in r2. |
| (...skipping 10 matching lines...) Expand all Loading... |
| 3294 DeoptimizeIf(hs, instr->environment()); | 3335 DeoptimizeIf(hs, instr->environment()); |
| 3295 } | 3336 } |
| 3296 | 3337 |
| 3297 | 3338 |
| 3298 void LCodeGen::DoStoreKeyedFastElement(LStoreKeyedFastElement* instr) { | 3339 void LCodeGen::DoStoreKeyedFastElement(LStoreKeyedFastElement* instr) { |
| 3299 Register value = ToRegister(instr->value()); | 3340 Register value = ToRegister(instr->value()); |
| 3300 Register elements = ToRegister(instr->object()); | 3341 Register elements = ToRegister(instr->object()); |
| 3301 Register key = instr->key()->IsRegister() ? ToRegister(instr->key()) : no_reg; | 3342 Register key = instr->key()->IsRegister() ? ToRegister(instr->key()) : no_reg; |
| 3302 Register scratch = scratch0(); | 3343 Register scratch = scratch0(); |
| 3303 | 3344 |
| 3345 // This instruction cannot handle the FAST_SMI_ONLY_ELEMENTS -> FAST_ELEMENTS |
| 3346 // conversion, so it deopts in that case. |
| 3347 if (instr->hydrogen()->ValueNeedsSmiCheck()) { |
| 3348 __ tst(value, Operand(kSmiTagMask)); |
| 3349 DeoptimizeIf(ne, instr->environment()); |
| 3350 } |
| 3351 |
| 3304 // Do the store. | 3352 // Do the store. |
| 3305 if (instr->key()->IsConstantOperand()) { | 3353 if (instr->key()->IsConstantOperand()) { |
| 3306 ASSERT(!instr->hydrogen()->NeedsWriteBarrier()); | 3354 ASSERT(!instr->hydrogen()->NeedsWriteBarrier()); |
| 3307 LConstantOperand* const_operand = LConstantOperand::cast(instr->key()); | 3355 LConstantOperand* const_operand = LConstantOperand::cast(instr->key()); |
| 3308 int offset = | 3356 int offset = |
| 3309 ToInteger32(const_operand) * kPointerSize + FixedArray::kHeaderSize; | 3357 ToInteger32(const_operand) * kPointerSize + FixedArray::kHeaderSize; |
| 3310 __ str(value, FieldMemOperand(elements, offset)); | 3358 __ str(value, FieldMemOperand(elements, offset)); |
| 3311 } else { | 3359 } else { |
| 3312 __ add(scratch, elements, Operand(key, LSL, kPointerSizeLog2)); | 3360 __ add(scratch, elements, Operand(key, LSL, kPointerSizeLog2)); |
| 3313 __ str(value, FieldMemOperand(scratch, FixedArray::kHeaderSize)); | 3361 __ str(value, FieldMemOperand(scratch, FixedArray::kHeaderSize)); |
| 3314 } | 3362 } |
| 3315 | 3363 |
| 3316 if (instr->hydrogen()->NeedsWriteBarrier()) { | 3364 if (instr->hydrogen()->NeedsWriteBarrier()) { |
| 3317 // Compute address of modified element and store it into key register. | 3365 // Compute address of modified element and store it into key register. |
| 3318 __ add(key, scratch, Operand(FixedArray::kHeaderSize)); | 3366 __ add(key, scratch, Operand(FixedArray::kHeaderSize - kHeapObjectTag)); |
| 3319 __ RecordWrite(elements, key, value); | 3367 __ RecordWrite(elements, key, value, kLRHasBeenSaved, kSaveFPRegs); |
| 3320 } | 3368 } |
| 3321 } | 3369 } |
| 3322 | 3370 |
| 3323 | 3371 |
| 3324 void LCodeGen::DoStoreKeyedFastDoubleElement( | 3372 void LCodeGen::DoStoreKeyedFastDoubleElement( |
| 3325 LStoreKeyedFastDoubleElement* instr) { | 3373 LStoreKeyedFastDoubleElement* instr) { |
| 3326 DwVfpRegister value = ToDoubleRegister(instr->value()); | 3374 DwVfpRegister value = ToDoubleRegister(instr->value()); |
| 3327 Register elements = ToRegister(instr->elements()); | 3375 Register elements = ToRegister(instr->elements()); |
| 3328 Register key = no_reg; | 3376 Register key = no_reg; |
| 3329 Register scratch = scratch0(); | 3377 Register scratch = scratch0(); |
| (...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3410 __ strh(value, mem_operand); | 3458 __ strh(value, mem_operand); |
| 3411 break; | 3459 break; |
| 3412 case EXTERNAL_INT_ELEMENTS: | 3460 case EXTERNAL_INT_ELEMENTS: |
| 3413 case EXTERNAL_UNSIGNED_INT_ELEMENTS: | 3461 case EXTERNAL_UNSIGNED_INT_ELEMENTS: |
| 3414 __ str(value, mem_operand); | 3462 __ str(value, mem_operand); |
| 3415 break; | 3463 break; |
| 3416 case EXTERNAL_FLOAT_ELEMENTS: | 3464 case EXTERNAL_FLOAT_ELEMENTS: |
| 3417 case EXTERNAL_DOUBLE_ELEMENTS: | 3465 case EXTERNAL_DOUBLE_ELEMENTS: |
| 3418 case FAST_DOUBLE_ELEMENTS: | 3466 case FAST_DOUBLE_ELEMENTS: |
| 3419 case FAST_ELEMENTS: | 3467 case FAST_ELEMENTS: |
| 3468 case FAST_SMI_ONLY_ELEMENTS: |
| 3420 case DICTIONARY_ELEMENTS: | 3469 case DICTIONARY_ELEMENTS: |
| 3421 case NON_STRICT_ARGUMENTS_ELEMENTS: | 3470 case NON_STRICT_ARGUMENTS_ELEMENTS: |
| 3422 UNREACHABLE(); | 3471 UNREACHABLE(); |
| 3423 break; | 3472 break; |
| 3424 } | 3473 } |
| 3425 } | 3474 } |
| 3426 } | 3475 } |
| 3427 | 3476 |
| 3428 | 3477 |
| 3429 void LCodeGen::DoStoreKeyedGeneric(LStoreKeyedGeneric* instr) { | 3478 void LCodeGen::DoStoreKeyedGeneric(LStoreKeyedGeneric* instr) { |
| (...skipping 15 matching lines...) Expand all Loading... |
| 3445 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); | 3494 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); |
| 3446 } | 3495 } |
| 3447 | 3496 |
| 3448 | 3497 |
| 3449 void LCodeGen::DoStringCharCodeAt(LStringCharCodeAt* instr) { | 3498 void LCodeGen::DoStringCharCodeAt(LStringCharCodeAt* instr) { |
| 3450 class DeferredStringCharCodeAt: public LDeferredCode { | 3499 class DeferredStringCharCodeAt: public LDeferredCode { |
| 3451 public: | 3500 public: |
| 3452 DeferredStringCharCodeAt(LCodeGen* codegen, LStringCharCodeAt* instr) | 3501 DeferredStringCharCodeAt(LCodeGen* codegen, LStringCharCodeAt* instr) |
| 3453 : LDeferredCode(codegen), instr_(instr) { } | 3502 : LDeferredCode(codegen), instr_(instr) { } |
| 3454 virtual void Generate() { codegen()->DoDeferredStringCharCodeAt(instr_); } | 3503 virtual void Generate() { codegen()->DoDeferredStringCharCodeAt(instr_); } |
| 3504 virtual LInstruction* instr() { return instr_; } |
| 3455 private: | 3505 private: |
| 3456 LStringCharCodeAt* instr_; | 3506 LStringCharCodeAt* instr_; |
| 3457 }; | 3507 }; |
| 3458 | 3508 |
| 3459 Register string = ToRegister(instr->string()); | 3509 Register string = ToRegister(instr->string()); |
| 3460 Register index = ToRegister(instr->index()); | 3510 Register index = ToRegister(instr->index()); |
| 3461 Register result = ToRegister(instr->result()); | 3511 Register result = ToRegister(instr->result()); |
| 3462 | 3512 |
| 3463 DeferredStringCharCodeAt* deferred = | 3513 DeferredStringCharCodeAt* deferred = |
| 3464 new DeferredStringCharCodeAt(this, instr); | 3514 new DeferredStringCharCodeAt(this, instr); |
| (...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3568 __ StoreToSafepointRegisterSlot(r0, result); | 3618 __ StoreToSafepointRegisterSlot(r0, result); |
| 3569 } | 3619 } |
| 3570 | 3620 |
| 3571 | 3621 |
| 3572 void LCodeGen::DoStringCharFromCode(LStringCharFromCode* instr) { | 3622 void LCodeGen::DoStringCharFromCode(LStringCharFromCode* instr) { |
| 3573 class DeferredStringCharFromCode: public LDeferredCode { | 3623 class DeferredStringCharFromCode: public LDeferredCode { |
| 3574 public: | 3624 public: |
| 3575 DeferredStringCharFromCode(LCodeGen* codegen, LStringCharFromCode* instr) | 3625 DeferredStringCharFromCode(LCodeGen* codegen, LStringCharFromCode* instr) |
| 3576 : LDeferredCode(codegen), instr_(instr) { } | 3626 : LDeferredCode(codegen), instr_(instr) { } |
| 3577 virtual void Generate() { codegen()->DoDeferredStringCharFromCode(instr_); } | 3627 virtual void Generate() { codegen()->DoDeferredStringCharFromCode(instr_); } |
| 3628 virtual LInstruction* instr() { return instr_; } |
| 3578 private: | 3629 private: |
| 3579 LStringCharFromCode* instr_; | 3630 LStringCharFromCode* instr_; |
| 3580 }; | 3631 }; |
| 3581 | 3632 |
| 3582 DeferredStringCharFromCode* deferred = | 3633 DeferredStringCharFromCode* deferred = |
| 3583 new DeferredStringCharFromCode(this, instr); | 3634 new DeferredStringCharFromCode(this, instr); |
| 3584 | 3635 |
| 3585 ASSERT(instr->hydrogen()->value()->representation().IsInteger32()); | 3636 ASSERT(instr->hydrogen()->value()->representation().IsInteger32()); |
| 3586 Register char_code = ToRegister(instr->char_code()); | 3637 Register char_code = ToRegister(instr->char_code()); |
| 3587 Register result = ToRegister(instr->result()); | 3638 Register result = ToRegister(instr->result()); |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3639 __ vcvt_f64_s32(ToDoubleRegister(output), single_scratch); | 3690 __ vcvt_f64_s32(ToDoubleRegister(output), single_scratch); |
| 3640 } | 3691 } |
| 3641 | 3692 |
| 3642 | 3693 |
| 3643 void LCodeGen::DoNumberTagI(LNumberTagI* instr) { | 3694 void LCodeGen::DoNumberTagI(LNumberTagI* instr) { |
| 3644 class DeferredNumberTagI: public LDeferredCode { | 3695 class DeferredNumberTagI: public LDeferredCode { |
| 3645 public: | 3696 public: |
| 3646 DeferredNumberTagI(LCodeGen* codegen, LNumberTagI* instr) | 3697 DeferredNumberTagI(LCodeGen* codegen, LNumberTagI* instr) |
| 3647 : LDeferredCode(codegen), instr_(instr) { } | 3698 : LDeferredCode(codegen), instr_(instr) { } |
| 3648 virtual void Generate() { codegen()->DoDeferredNumberTagI(instr_); } | 3699 virtual void Generate() { codegen()->DoDeferredNumberTagI(instr_); } |
| 3700 virtual LInstruction* instr() { return instr_; } |
| 3649 private: | 3701 private: |
| 3650 LNumberTagI* instr_; | 3702 LNumberTagI* instr_; |
| 3651 }; | 3703 }; |
| 3652 | 3704 |
| 3653 LOperand* input = instr->InputAt(0); | 3705 LOperand* input = instr->InputAt(0); |
| 3654 ASSERT(input->IsRegister() && input->Equals(instr->result())); | 3706 ASSERT(input->IsRegister() && input->Equals(instr->result())); |
| 3655 Register reg = ToRegister(input); | 3707 Register reg = ToRegister(input); |
| 3656 | 3708 |
| 3657 DeferredNumberTagI* deferred = new DeferredNumberTagI(this, instr); | 3709 DeferredNumberTagI* deferred = new DeferredNumberTagI(this, instr); |
| 3658 __ SmiTag(reg, SetCC); | 3710 __ SmiTag(reg, SetCC); |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3704 __ StoreToSafepointRegisterSlot(reg, reg); | 3756 __ StoreToSafepointRegisterSlot(reg, reg); |
| 3705 } | 3757 } |
| 3706 | 3758 |
| 3707 | 3759 |
| 3708 void LCodeGen::DoNumberTagD(LNumberTagD* instr) { | 3760 void LCodeGen::DoNumberTagD(LNumberTagD* instr) { |
| 3709 class DeferredNumberTagD: public LDeferredCode { | 3761 class DeferredNumberTagD: public LDeferredCode { |
| 3710 public: | 3762 public: |
| 3711 DeferredNumberTagD(LCodeGen* codegen, LNumberTagD* instr) | 3763 DeferredNumberTagD(LCodeGen* codegen, LNumberTagD* instr) |
| 3712 : LDeferredCode(codegen), instr_(instr) { } | 3764 : LDeferredCode(codegen), instr_(instr) { } |
| 3713 virtual void Generate() { codegen()->DoDeferredNumberTagD(instr_); } | 3765 virtual void Generate() { codegen()->DoDeferredNumberTagD(instr_); } |
| 3766 virtual LInstruction* instr() { return instr_; } |
| 3714 private: | 3767 private: |
| 3715 LNumberTagD* instr_; | 3768 LNumberTagD* instr_; |
| 3716 }; | 3769 }; |
| 3717 | 3770 |
| 3718 DoubleRegister input_reg = ToDoubleRegister(instr->InputAt(0)); | 3771 DoubleRegister input_reg = ToDoubleRegister(instr->InputAt(0)); |
| 3719 Register scratch = scratch0(); | 3772 Register scratch = scratch0(); |
| 3720 Register reg = ToRegister(instr->result()); | 3773 Register reg = ToRegister(instr->result()); |
| 3721 Register temp1 = ToRegister(instr->TempAt(0)); | 3774 Register temp1 = ToRegister(instr->TempAt(0)); |
| 3722 Register temp2 = ToRegister(instr->TempAt(1)); | 3775 Register temp2 = ToRegister(instr->TempAt(1)); |
| 3723 | 3776 |
| (...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3812 // Smi to double register conversion | 3865 // Smi to double register conversion |
| 3813 __ bind(&load_smi); | 3866 __ bind(&load_smi); |
| 3814 __ SmiUntag(input_reg); // Untag smi before converting to float. | 3867 __ SmiUntag(input_reg); // Untag smi before converting to float. |
| 3815 __ vmov(flt_scratch, input_reg); | 3868 __ vmov(flt_scratch, input_reg); |
| 3816 __ vcvt_f64_s32(result_reg, flt_scratch); | 3869 __ vcvt_f64_s32(result_reg, flt_scratch); |
| 3817 __ SmiTag(input_reg); // Retag smi. | 3870 __ SmiTag(input_reg); // Retag smi. |
| 3818 __ bind(&done); | 3871 __ bind(&done); |
| 3819 } | 3872 } |
| 3820 | 3873 |
| 3821 | 3874 |
| 3822 class DeferredTaggedToI: public LDeferredCode { | |
| 3823 public: | |
| 3824 DeferredTaggedToI(LCodeGen* codegen, LTaggedToI* instr) | |
| 3825 : LDeferredCode(codegen), instr_(instr) { } | |
| 3826 virtual void Generate() { codegen()->DoDeferredTaggedToI(instr_); } | |
| 3827 private: | |
| 3828 LTaggedToI* instr_; | |
| 3829 }; | |
| 3830 | |
| 3831 | |
| 3832 void LCodeGen::DoDeferredTaggedToI(LTaggedToI* instr) { | 3875 void LCodeGen::DoDeferredTaggedToI(LTaggedToI* instr) { |
| 3833 Register input_reg = ToRegister(instr->InputAt(0)); | 3876 Register input_reg = ToRegister(instr->InputAt(0)); |
| 3834 Register scratch1 = scratch0(); | 3877 Register scratch1 = scratch0(); |
| 3835 Register scratch2 = ToRegister(instr->TempAt(0)); | 3878 Register scratch2 = ToRegister(instr->TempAt(0)); |
| 3836 DwVfpRegister double_scratch = double_scratch0(); | 3879 DwVfpRegister double_scratch = double_scratch0(); |
| 3837 SwVfpRegister single_scratch = double_scratch.low(); | 3880 SwVfpRegister single_scratch = double_scratch.low(); |
| 3838 | 3881 |
| 3839 ASSERT(!scratch1.is(input_reg) && !scratch1.is(scratch2)); | 3882 ASSERT(!scratch1.is(input_reg) && !scratch1.is(scratch2)); |
| 3840 ASSERT(!scratch2.is(input_reg) && !scratch2.is(scratch1)); | 3883 ASSERT(!scratch2.is(input_reg) && !scratch2.is(scratch1)); |
| 3841 | 3884 |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3904 __ vmov(scratch1, double_scratch.high()); | 3947 __ vmov(scratch1, double_scratch.high()); |
| 3905 __ tst(scratch1, Operand(HeapNumber::kSignMask)); | 3948 __ tst(scratch1, Operand(HeapNumber::kSignMask)); |
| 3906 DeoptimizeIf(ne, instr->environment()); | 3949 DeoptimizeIf(ne, instr->environment()); |
| 3907 } | 3950 } |
| 3908 } | 3951 } |
| 3909 __ bind(&done); | 3952 __ bind(&done); |
| 3910 } | 3953 } |
| 3911 | 3954 |
| 3912 | 3955 |
| 3913 void LCodeGen::DoTaggedToI(LTaggedToI* instr) { | 3956 void LCodeGen::DoTaggedToI(LTaggedToI* instr) { |
| 3957 class DeferredTaggedToI: public LDeferredCode { |
| 3958 public: |
| 3959 DeferredTaggedToI(LCodeGen* codegen, LTaggedToI* instr) |
| 3960 : LDeferredCode(codegen), instr_(instr) { } |
| 3961 virtual void Generate() { codegen()->DoDeferredTaggedToI(instr_); } |
| 3962 virtual LInstruction* instr() { return instr_; } |
| 3963 private: |
| 3964 LTaggedToI* instr_; |
| 3965 }; |
| 3966 |
| 3914 LOperand* input = instr->InputAt(0); | 3967 LOperand* input = instr->InputAt(0); |
| 3915 ASSERT(input->IsRegister()); | 3968 ASSERT(input->IsRegister()); |
| 3916 ASSERT(input->Equals(instr->result())); | 3969 ASSERT(input->Equals(instr->result())); |
| 3917 | 3970 |
| 3918 Register input_reg = ToRegister(input); | 3971 Register input_reg = ToRegister(input); |
| 3919 | 3972 |
| 3920 DeferredTaggedToI* deferred = new DeferredTaggedToI(this, instr); | 3973 DeferredTaggedToI* deferred = new DeferredTaggedToI(this, instr); |
| 3921 | 3974 |
| 3922 // Optimistically untag the input. | 3975 // Optimistically untag the input. |
| 3923 // If the input is a HeapObject, SmiUntag will set the carry flag. | 3976 // If the input is a HeapObject, SmiUntag will set the carry flag. |
| (...skipping 412 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4336 __ CompareRoot(input, Heap::kUndefinedValueRootIndex); | 4389 __ CompareRoot(input, Heap::kUndefinedValueRootIndex); |
| 4337 __ b(eq, true_label); | 4390 __ b(eq, true_label); |
| 4338 __ JumpIfSmi(input, false_label); | 4391 __ JumpIfSmi(input, false_label); |
| 4339 // Check for undetectable objects => true. | 4392 // Check for undetectable objects => true. |
| 4340 __ ldr(input, FieldMemOperand(input, HeapObject::kMapOffset)); | 4393 __ ldr(input, FieldMemOperand(input, HeapObject::kMapOffset)); |
| 4341 __ ldrb(ip, FieldMemOperand(input, Map::kBitFieldOffset)); | 4394 __ ldrb(ip, FieldMemOperand(input, Map::kBitFieldOffset)); |
| 4342 __ tst(ip, Operand(1 << Map::kIsUndetectable)); | 4395 __ tst(ip, Operand(1 << Map::kIsUndetectable)); |
| 4343 final_branch_condition = ne; | 4396 final_branch_condition = ne; |
| 4344 | 4397 |
| 4345 } else if (type_name->Equals(heap()->function_symbol())) { | 4398 } else if (type_name->Equals(heap()->function_symbol())) { |
| 4399 STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2); |
| 4346 __ JumpIfSmi(input, false_label); | 4400 __ JumpIfSmi(input, false_label); |
| 4347 __ CompareObjectType(input, input, scratch, | 4401 __ CompareObjectType(input, scratch, input, JS_FUNCTION_TYPE); |
| 4348 FIRST_CALLABLE_SPEC_OBJECT_TYPE); | 4402 __ b(eq, true_label); |
| 4349 final_branch_condition = ge; | 4403 __ cmp(input, Operand(JS_FUNCTION_PROXY_TYPE)); |
| 4404 final_branch_condition = eq; |
| 4350 | 4405 |
| 4351 } else if (type_name->Equals(heap()->object_symbol())) { | 4406 } else if (type_name->Equals(heap()->object_symbol())) { |
| 4352 __ JumpIfSmi(input, false_label); | 4407 __ JumpIfSmi(input, false_label); |
| 4353 if (!FLAG_harmony_typeof) { | 4408 if (!FLAG_harmony_typeof) { |
| 4354 __ CompareRoot(input, Heap::kNullValueRootIndex); | 4409 __ CompareRoot(input, Heap::kNullValueRootIndex); |
| 4355 __ b(eq, true_label); | 4410 __ b(eq, true_label); |
| 4356 } | 4411 } |
| 4357 __ CompareObjectType(input, input, scratch, | 4412 __ CompareObjectType(input, input, scratch, |
| 4358 FIRST_NONCALLABLE_SPEC_OBJECT_TYPE); | 4413 FIRST_NONCALLABLE_SPEC_OBJECT_TYPE); |
| 4359 __ b(lt, false_label); | 4414 __ b(lt, false_label); |
| (...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4461 safepoints_.SetPcAfterGap(pc); | 4516 safepoints_.SetPcAfterGap(pc); |
| 4462 } | 4517 } |
| 4463 | 4518 |
| 4464 | 4519 |
| 4465 void LCodeGen::DoStackCheck(LStackCheck* instr) { | 4520 void LCodeGen::DoStackCheck(LStackCheck* instr) { |
| 4466 class DeferredStackCheck: public LDeferredCode { | 4521 class DeferredStackCheck: public LDeferredCode { |
| 4467 public: | 4522 public: |
| 4468 DeferredStackCheck(LCodeGen* codegen, LStackCheck* instr) | 4523 DeferredStackCheck(LCodeGen* codegen, LStackCheck* instr) |
| 4469 : LDeferredCode(codegen), instr_(instr) { } | 4524 : LDeferredCode(codegen), instr_(instr) { } |
| 4470 virtual void Generate() { codegen()->DoDeferredStackCheck(instr_); } | 4525 virtual void Generate() { codegen()->DoDeferredStackCheck(instr_); } |
| 4526 virtual LInstruction* instr() { return instr_; } |
| 4471 private: | 4527 private: |
| 4472 LStackCheck* instr_; | 4528 LStackCheck* instr_; |
| 4473 }; | 4529 }; |
| 4474 | 4530 |
| 4475 if (instr->hydrogen()->is_function_entry()) { | 4531 if (instr->hydrogen()->is_function_entry()) { |
| 4476 // Perform stack overflow check. | 4532 // Perform stack overflow check. |
| 4477 Label done; | 4533 Label done; |
| 4478 __ LoadRoot(ip, Heap::kStackLimitRootIndex); | 4534 __ LoadRoot(ip, Heap::kStackLimitRootIndex); |
| 4479 __ cmp(sp, Operand(ip)); | 4535 __ cmp(sp, Operand(ip)); |
| 4480 __ b(hs, &done); | 4536 __ b(hs, &done); |
| (...skipping 29 matching lines...) Expand all Loading... |
| 4510 ASSERT(osr_pc_offset_ == -1); | 4566 ASSERT(osr_pc_offset_ == -1); |
| 4511 osr_pc_offset_ = masm()->pc_offset(); | 4567 osr_pc_offset_ = masm()->pc_offset(); |
| 4512 } | 4568 } |
| 4513 | 4569 |
| 4514 | 4570 |
| 4515 | 4571 |
| 4516 | 4572 |
| 4517 #undef __ | 4573 #undef __ |
| 4518 | 4574 |
| 4519 } } // namespace v8::internal | 4575 } } // namespace v8::internal |
| OLD | NEW |