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 337 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
348 | 348 |
349 int LCodeGen::ToInteger32(LConstantOperand* op) const { | 349 int LCodeGen::ToInteger32(LConstantOperand* op) const { |
350 Handle<Object> value = chunk_->LookupLiteral(op); | 350 Handle<Object> value = chunk_->LookupLiteral(op); |
351 ASSERT(chunk_->LookupLiteralRepresentation(op).IsInteger32()); | 351 ASSERT(chunk_->LookupLiteralRepresentation(op).IsInteger32()); |
352 ASSERT(static_cast<double>(static_cast<int32_t>(value->Number())) == | 352 ASSERT(static_cast<double>(static_cast<int32_t>(value->Number())) == |
353 value->Number()); | 353 value->Number()); |
354 return static_cast<int32_t>(value->Number()); | 354 return static_cast<int32_t>(value->Number()); |
355 } | 355 } |
356 | 356 |
357 | 357 |
| 358 double LCodeGen::ToDouble(LConstantOperand* op) const { |
| 359 Handle<Object> value = chunk_->LookupLiteral(op); |
| 360 return value->Number(); |
| 361 } |
| 362 |
| 363 |
358 Immediate LCodeGen::ToImmediate(LOperand* op) { | 364 Immediate LCodeGen::ToImmediate(LOperand* op) { |
359 LConstantOperand* const_op = LConstantOperand::cast(op); | 365 LConstantOperand* const_op = LConstantOperand::cast(op); |
360 Handle<Object> literal = chunk_->LookupLiteral(const_op); | 366 Handle<Object> literal = chunk_->LookupLiteral(const_op); |
361 Representation r = chunk_->LookupLiteralRepresentation(const_op); | 367 Representation r = chunk_->LookupLiteralRepresentation(const_op); |
362 if (r.IsInteger32()) { | 368 if (r.IsInteger32()) { |
363 ASSERT(literal->IsNumber()); | 369 ASSERT(literal->IsNumber()); |
364 return Immediate(static_cast<int32_t>(literal->Number())); | 370 return Immediate(static_cast<int32_t>(literal->Number())); |
365 } else if (r.IsDouble()) { | 371 } else if (r.IsDouble()) { |
366 Abort("unsupported double immediate"); | 372 Abort("unsupported double immediate"); |
367 } | 373 } |
(...skipping 1199 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1567 break; | 1573 break; |
1568 case Token::IN: | 1574 case Token::IN: |
1569 case Token::INSTANCEOF: | 1575 case Token::INSTANCEOF: |
1570 default: | 1576 default: |
1571 UNREACHABLE(); | 1577 UNREACHABLE(); |
1572 } | 1578 } |
1573 return cond; | 1579 return cond; |
1574 } | 1580 } |
1575 | 1581 |
1576 | 1582 |
1577 void LCodeGen::EmitCmpI(LOperand* left, LOperand* right) { | |
1578 if (right->IsConstantOperand()) { | |
1579 __ cmp(ToOperand(left), ToImmediate(right)); | |
1580 } else { | |
1581 __ cmp(ToRegister(left), ToOperand(right)); | |
1582 } | |
1583 } | |
1584 | |
1585 | |
1586 void LCodeGen::DoCmpIDAndBranch(LCmpIDAndBranch* instr) { | 1583 void LCodeGen::DoCmpIDAndBranch(LCmpIDAndBranch* instr) { |
1587 LOperand* left = instr->InputAt(0); | 1584 LOperand* left = instr->InputAt(0); |
1588 LOperand* right = instr->InputAt(1); | 1585 LOperand* right = instr->InputAt(1); |
1589 int false_block = chunk_->LookupDestination(instr->false_block_id()); | 1586 int false_block = chunk_->LookupDestination(instr->false_block_id()); |
1590 int true_block = chunk_->LookupDestination(instr->true_block_id()); | 1587 int true_block = chunk_->LookupDestination(instr->true_block_id()); |
| 1588 Condition cc = TokenToCondition(instr->op(), instr->is_double()); |
1591 | 1589 |
1592 if (instr->is_double()) { | 1590 if (left->IsConstantOperand() && right->IsConstantOperand()) { |
1593 // Don't base result on EFLAGS when a NaN is involved. Instead | 1591 // We can statically evaluate the comparison. |
1594 // jump to the false block. | 1592 double left_val = ToDouble(LConstantOperand::cast(left)); |
1595 __ ucomisd(ToDoubleRegister(left), ToDoubleRegister(right)); | 1593 double right_val = ToDouble(LConstantOperand::cast(right)); |
1596 __ j(parity_even, chunk_->GetAssemblyLabel(false_block)); | 1594 int next_block = |
| 1595 EvalComparison(instr->op(), left_val, right_val) ? true_block |
| 1596 : false_block; |
| 1597 EmitGoto(next_block); |
1597 } else { | 1598 } else { |
1598 EmitCmpI(left, right); | 1599 if (instr->is_double()) { |
| 1600 // Don't base result on EFLAGS when a NaN is involved. Instead |
| 1601 // jump to the false block. |
| 1602 __ ucomisd(ToDoubleRegister(left), ToDoubleRegister(right)); |
| 1603 __ j(parity_even, chunk_->GetAssemblyLabel(false_block)); |
| 1604 } else { |
| 1605 if (right->IsConstantOperand()) { |
| 1606 __ cmp(ToRegister(left), ToImmediate(right)); |
| 1607 } else if (left->IsConstantOperand()) { |
| 1608 __ cmp(ToOperand(right), ToImmediate(left)); |
| 1609 // We transposed the operands. Reverse the condition. |
| 1610 cc = ReverseCondition(cc); |
| 1611 } else { |
| 1612 __ cmp(ToRegister(left), ToOperand(right)); |
| 1613 } |
| 1614 } |
| 1615 EmitBranch(true_block, false_block, cc); |
1599 } | 1616 } |
1600 | |
1601 Condition cc = TokenToCondition(instr->op(), instr->is_double()); | |
1602 EmitBranch(true_block, false_block, cc); | |
1603 } | 1617 } |
1604 | 1618 |
1605 | 1619 |
1606 void LCodeGen::DoCmpObjectEqAndBranch(LCmpObjectEqAndBranch* instr) { | 1620 void LCodeGen::DoCmpObjectEqAndBranch(LCmpObjectEqAndBranch* instr) { |
1607 Register left = ToRegister(instr->InputAt(0)); | 1621 Register left = ToRegister(instr->InputAt(0)); |
1608 Operand right = ToOperand(instr->InputAt(1)); | 1622 Operand right = ToOperand(instr->InputAt(1)); |
1609 int false_block = chunk_->LookupDestination(instr->false_block_id()); | 1623 int false_block = chunk_->LookupDestination(instr->false_block_id()); |
1610 int true_block = chunk_->LookupDestination(instr->true_block_id()); | 1624 int true_block = chunk_->LookupDestination(instr->true_block_id()); |
1611 | 1625 |
1612 __ cmp(left, Operand(right)); | 1626 __ cmp(left, Operand(right)); |
(...skipping 409 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2022 } | 2036 } |
2023 | 2037 |
2024 | 2038 |
2025 void LCodeGen::DoCmpT(LCmpT* instr) { | 2039 void LCodeGen::DoCmpT(LCmpT* instr) { |
2026 Token::Value op = instr->op(); | 2040 Token::Value op = instr->op(); |
2027 | 2041 |
2028 Handle<Code> ic = CompareIC::GetUninitialized(op); | 2042 Handle<Code> ic = CompareIC::GetUninitialized(op); |
2029 CallCode(ic, RelocInfo::CODE_TARGET, instr); | 2043 CallCode(ic, RelocInfo::CODE_TARGET, instr); |
2030 | 2044 |
2031 Condition condition = ComputeCompareCondition(op); | 2045 Condition condition = ComputeCompareCondition(op); |
2032 if (op == Token::GT || op == Token::LTE) { | |
2033 condition = ReverseCondition(condition); | |
2034 } | |
2035 Label true_value, done; | 2046 Label true_value, done; |
2036 __ test(eax, Operand(eax)); | 2047 __ test(eax, Operand(eax)); |
2037 __ j(condition, &true_value, Label::kNear); | 2048 __ j(condition, &true_value, Label::kNear); |
2038 __ mov(ToRegister(instr->result()), factory()->false_value()); | 2049 __ mov(ToRegister(instr->result()), factory()->false_value()); |
2039 __ jmp(&done, Label::kNear); | 2050 __ jmp(&done, Label::kNear); |
2040 __ bind(&true_value); | 2051 __ bind(&true_value); |
2041 __ mov(ToRegister(instr->result()), factory()->true_value()); | 2052 __ mov(ToRegister(instr->result()), factory()->true_value()); |
2042 __ bind(&done); | 2053 __ bind(&done); |
2043 } | 2054 } |
2044 | 2055 |
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2109 // it as no longer deleted. We deoptimize in that case. | 2120 // it as no longer deleted. We deoptimize in that case. |
2110 if (instr->hydrogen()->RequiresHoleCheck()) { | 2121 if (instr->hydrogen()->RequiresHoleCheck()) { |
2111 __ cmp(FieldOperand(object, offset), factory()->the_hole_value()); | 2122 __ cmp(FieldOperand(object, offset), factory()->the_hole_value()); |
2112 DeoptimizeIf(equal, instr->environment()); | 2123 DeoptimizeIf(equal, instr->environment()); |
2113 } | 2124 } |
2114 | 2125 |
2115 // Store the value. | 2126 // Store the value. |
2116 __ mov(FieldOperand(object, offset), value); | 2127 __ mov(FieldOperand(object, offset), value); |
2117 | 2128 |
2118 // Cells are always in the remembered set. | 2129 // Cells are always in the remembered set. |
2119 __ RecordWriteField(object, | 2130 if (instr->hydrogen()->NeedsWriteBarrier()) { |
2120 offset, | 2131 HType type = instr->hydrogen()->value()->type(); |
2121 value, | 2132 SmiCheck check_needed = |
2122 address, | 2133 type.IsHeapObject() ? OMIT_SMI_CHECK : INLINE_SMI_CHECK; |
2123 kSaveFPRegs, | 2134 __ RecordWriteField(object, |
2124 OMIT_REMEMBERED_SET); | 2135 offset, |
| 2136 value, |
| 2137 address, |
| 2138 kSaveFPRegs, |
| 2139 OMIT_REMEMBERED_SET, |
| 2140 check_needed); |
| 2141 } |
2125 } | 2142 } |
2126 | 2143 |
2127 | 2144 |
2128 void LCodeGen::DoStoreGlobalGeneric(LStoreGlobalGeneric* instr) { | 2145 void LCodeGen::DoStoreGlobalGeneric(LStoreGlobalGeneric* instr) { |
2129 ASSERT(ToRegister(instr->context()).is(esi)); | 2146 ASSERT(ToRegister(instr->context()).is(esi)); |
2130 ASSERT(ToRegister(instr->global_object()).is(edx)); | 2147 ASSERT(ToRegister(instr->global_object()).is(edx)); |
2131 ASSERT(ToRegister(instr->value()).is(eax)); | 2148 ASSERT(ToRegister(instr->value()).is(eax)); |
2132 | 2149 |
2133 __ mov(ecx, instr->name()); | 2150 __ mov(ecx, instr->name()); |
2134 Handle<Code> ic = instr->strict_mode() | 2151 Handle<Code> ic = instr->strict_mode() |
2135 ? isolate()->builtins()->StoreIC_Initialize_Strict() | 2152 ? isolate()->builtins()->StoreIC_Initialize_Strict() |
2136 : isolate()->builtins()->StoreIC_Initialize(); | 2153 : isolate()->builtins()->StoreIC_Initialize(); |
2137 CallCode(ic, RelocInfo::CODE_TARGET_CONTEXT, instr); | 2154 CallCode(ic, RelocInfo::CODE_TARGET_CONTEXT, instr); |
2138 } | 2155 } |
2139 | 2156 |
2140 | 2157 |
2141 void LCodeGen::DoLoadContextSlot(LLoadContextSlot* instr) { | 2158 void LCodeGen::DoLoadContextSlot(LLoadContextSlot* instr) { |
2142 Register context = ToRegister(instr->context()); | 2159 Register context = ToRegister(instr->context()); |
2143 Register result = ToRegister(instr->result()); | 2160 Register result = ToRegister(instr->result()); |
2144 __ mov(result, ContextOperand(context, instr->slot_index())); | 2161 __ mov(result, ContextOperand(context, instr->slot_index())); |
2145 } | 2162 } |
2146 | 2163 |
2147 | 2164 |
2148 void LCodeGen::DoStoreContextSlot(LStoreContextSlot* instr) { | 2165 void LCodeGen::DoStoreContextSlot(LStoreContextSlot* instr) { |
2149 Register context = ToRegister(instr->context()); | 2166 Register context = ToRegister(instr->context()); |
2150 Register value = ToRegister(instr->value()); | 2167 Register value = ToRegister(instr->value()); |
2151 __ mov(ContextOperand(context, instr->slot_index()), value); | 2168 __ mov(ContextOperand(context, instr->slot_index()), value); |
2152 if (instr->needs_write_barrier()) { | 2169 if (instr->hydrogen()->NeedsWriteBarrier()) { |
| 2170 HType type = instr->hydrogen()->value()->type(); |
| 2171 SmiCheck check_needed = |
| 2172 type.IsHeapObject() ? OMIT_SMI_CHECK : INLINE_SMI_CHECK; |
2153 Register temp = ToRegister(instr->TempAt(0)); | 2173 Register temp = ToRegister(instr->TempAt(0)); |
2154 int offset = Context::SlotOffset(instr->slot_index()); | 2174 int offset = Context::SlotOffset(instr->slot_index()); |
2155 __ RecordWriteContextSlot(context, offset, value, temp, kSaveFPRegs); | 2175 __ RecordWriteContextSlot(context, |
| 2176 offset, |
| 2177 value, |
| 2178 temp, |
| 2179 kSaveFPRegs, |
| 2180 EMIT_REMEMBERED_SET, |
| 2181 check_needed); |
2156 } | 2182 } |
2157 } | 2183 } |
2158 | 2184 |
2159 | 2185 |
2160 void LCodeGen::DoLoadNamedField(LLoadNamedField* instr) { | 2186 void LCodeGen::DoLoadNamedField(LLoadNamedField* instr) { |
2161 Register object = ToRegister(instr->object()); | 2187 Register object = ToRegister(instr->object()); |
2162 Register result = ToRegister(instr->result()); | 2188 Register result = ToRegister(instr->result()); |
2163 if (instr->hydrogen()->is_in_object()) { | 2189 if (instr->hydrogen()->is_in_object()) { |
2164 __ mov(result, FieldOperand(object, instr->hydrogen()->offset())); | 2190 __ mov(result, FieldOperand(object, instr->hydrogen()->offset())); |
2165 } else { | 2191 } else { |
2166 __ mov(result, FieldOperand(object, JSObject::kPropertiesOffset)); | 2192 __ mov(result, FieldOperand(object, JSObject::kPropertiesOffset)); |
2167 __ mov(result, FieldOperand(result, instr->hydrogen()->offset())); | 2193 __ mov(result, FieldOperand(result, instr->hydrogen()->offset())); |
2168 } | 2194 } |
2169 } | 2195 } |
2170 | 2196 |
2171 | 2197 |
2172 void LCodeGen::EmitLoadFieldOrConstantFunction(Register result, | 2198 void LCodeGen::EmitLoadFieldOrConstantFunction(Register result, |
2173 Register object, | 2199 Register object, |
2174 Handle<Map> type, | 2200 Handle<Map> type, |
2175 Handle<String> name) { | 2201 Handle<String> name) { |
2176 LookupResult lookup; | 2202 LookupResult lookup(isolate()); |
2177 type->LookupInDescriptors(NULL, *name, &lookup); | 2203 type->LookupInDescriptors(NULL, *name, &lookup); |
2178 ASSERT(lookup.IsProperty() && | 2204 ASSERT(lookup.IsProperty() && |
2179 (lookup.type() == FIELD || lookup.type() == CONSTANT_FUNCTION)); | 2205 (lookup.type() == FIELD || lookup.type() == CONSTANT_FUNCTION)); |
2180 if (lookup.type() == FIELD) { | 2206 if (lookup.type() == FIELD) { |
2181 int index = lookup.GetLocalFieldIndexFromMap(*type); | 2207 int index = lookup.GetLocalFieldIndexFromMap(*type); |
2182 int offset = index * kPointerSize; | 2208 int offset = index * kPointerSize; |
2183 if (index < 0) { | 2209 if (index < 0) { |
2184 // Negative property indices are in-object properties, indexed | 2210 // Negative property indices are in-object properties, indexed |
2185 // from the end of the fixed part of the object. | 2211 // from the end of the fixed part of the object. |
2186 __ mov(result, FieldOperand(object, offset + type->instance_size())); | 2212 __ mov(result, FieldOperand(object, offset + type->instance_size())); |
(...skipping 420 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2607 if (argument->IsConstantOperand()) { | 2633 if (argument->IsConstantOperand()) { |
2608 __ push(ToImmediate(argument)); | 2634 __ push(ToImmediate(argument)); |
2609 } else { | 2635 } else { |
2610 __ push(ToOperand(argument)); | 2636 __ push(ToOperand(argument)); |
2611 } | 2637 } |
2612 } | 2638 } |
2613 | 2639 |
2614 | 2640 |
2615 void LCodeGen::DoThisFunction(LThisFunction* instr) { | 2641 void LCodeGen::DoThisFunction(LThisFunction* instr) { |
2616 Register result = ToRegister(instr->result()); | 2642 Register result = ToRegister(instr->result()); |
2617 __ mov(result, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset)); | 2643 LoadHeapObject(result, instr->hydrogen()->closure()); |
2618 } | 2644 } |
2619 | 2645 |
2620 | 2646 |
2621 void LCodeGen::DoContext(LContext* instr) { | 2647 void LCodeGen::DoContext(LContext* instr) { |
2622 Register result = ToRegister(instr->result()); | 2648 Register result = ToRegister(instr->result()); |
2623 __ mov(result, Operand(ebp, StandardFrameConstants::kContextOffset)); | 2649 __ mov(result, Operand(ebp, StandardFrameConstants::kContextOffset)); |
2624 } | 2650 } |
2625 | 2651 |
2626 | 2652 |
2627 void LCodeGen::DoOuterContext(LOuterContext* instr) { | 2653 void LCodeGen::DoOuterContext(LOuterContext* instr) { |
(...skipping 511 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3139 void LCodeGen::DoStoreNamedField(LStoreNamedField* instr) { | 3165 void LCodeGen::DoStoreNamedField(LStoreNamedField* instr) { |
3140 Register object = ToRegister(instr->object()); | 3166 Register object = ToRegister(instr->object()); |
3141 Register value = ToRegister(instr->value()); | 3167 Register value = ToRegister(instr->value()); |
3142 int offset = instr->offset(); | 3168 int offset = instr->offset(); |
3143 | 3169 |
3144 if (!instr->transition().is_null()) { | 3170 if (!instr->transition().is_null()) { |
3145 __ mov(FieldOperand(object, HeapObject::kMapOffset), instr->transition()); | 3171 __ mov(FieldOperand(object, HeapObject::kMapOffset), instr->transition()); |
3146 } | 3172 } |
3147 | 3173 |
3148 // Do the store. | 3174 // Do the store. |
| 3175 HType type = instr->hydrogen()->value()->type(); |
| 3176 SmiCheck check_needed = |
| 3177 type.IsHeapObject() ? OMIT_SMI_CHECK : INLINE_SMI_CHECK; |
3149 if (instr->is_in_object()) { | 3178 if (instr->is_in_object()) { |
3150 __ mov(FieldOperand(object, offset), value); | 3179 __ mov(FieldOperand(object, offset), value); |
3151 if (instr->needs_write_barrier()) { | 3180 if (instr->hydrogen()->NeedsWriteBarrier()) { |
3152 Register temp = ToRegister(instr->TempAt(0)); | 3181 Register temp = ToRegister(instr->TempAt(0)); |
3153 // Update the write barrier for the object for in-object properties. | 3182 // Update the write barrier for the object for in-object properties. |
3154 __ RecordWriteField(object, offset, value, temp, kSaveFPRegs); | 3183 __ RecordWriteField(object, |
| 3184 offset, |
| 3185 value, |
| 3186 temp, |
| 3187 kSaveFPRegs, |
| 3188 EMIT_REMEMBERED_SET, |
| 3189 check_needed); |
3155 } | 3190 } |
3156 } else { | 3191 } else { |
3157 Register temp = ToRegister(instr->TempAt(0)); | 3192 Register temp = ToRegister(instr->TempAt(0)); |
3158 __ mov(temp, FieldOperand(object, JSObject::kPropertiesOffset)); | 3193 __ mov(temp, FieldOperand(object, JSObject::kPropertiesOffset)); |
3159 __ mov(FieldOperand(temp, offset), value); | 3194 __ mov(FieldOperand(temp, offset), value); |
3160 if (instr->needs_write_barrier()) { | 3195 if (instr->hydrogen()->NeedsWriteBarrier()) { |
3161 // Update the write barrier for the properties array. | 3196 // Update the write barrier for the properties array. |
3162 // object is used as a scratch register. | 3197 // object is used as a scratch register. |
3163 __ RecordWriteField(temp, offset, value, object, kSaveFPRegs); | 3198 __ RecordWriteField(temp, |
| 3199 offset, |
| 3200 value, |
| 3201 object, |
| 3202 kSaveFPRegs, |
| 3203 EMIT_REMEMBERED_SET, |
| 3204 check_needed); |
3164 } | 3205 } |
3165 } | 3206 } |
3166 } | 3207 } |
3167 | 3208 |
3168 | 3209 |
3169 void LCodeGen::DoStoreNamedGeneric(LStoreNamedGeneric* instr) { | 3210 void LCodeGen::DoStoreNamedGeneric(LStoreNamedGeneric* instr) { |
3170 ASSERT(ToRegister(instr->context()).is(esi)); | 3211 ASSERT(ToRegister(instr->context()).is(esi)); |
3171 ASSERT(ToRegister(instr->object()).is(edx)); | 3212 ASSERT(ToRegister(instr->object()).is(edx)); |
3172 ASSERT(ToRegister(instr->value()).is(eax)); | 3213 ASSERT(ToRegister(instr->value()).is(eax)); |
3173 | 3214 |
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3252 __ mov(FieldOperand(elements, offset), value); | 3293 __ mov(FieldOperand(elements, offset), value); |
3253 } else { | 3294 } else { |
3254 __ mov(FieldOperand(elements, | 3295 __ mov(FieldOperand(elements, |
3255 key, | 3296 key, |
3256 times_pointer_size, | 3297 times_pointer_size, |
3257 FixedArray::kHeaderSize), | 3298 FixedArray::kHeaderSize), |
3258 value); | 3299 value); |
3259 } | 3300 } |
3260 | 3301 |
3261 if (instr->hydrogen()->NeedsWriteBarrier()) { | 3302 if (instr->hydrogen()->NeedsWriteBarrier()) { |
| 3303 HType type = instr->hydrogen()->value()->type(); |
| 3304 SmiCheck check_needed = |
| 3305 type.IsHeapObject() ? OMIT_SMI_CHECK : INLINE_SMI_CHECK; |
3262 // Compute address of modified element and store it into key register. | 3306 // Compute address of modified element and store it into key register. |
3263 __ lea(key, | 3307 __ lea(key, |
3264 FieldOperand(elements, | 3308 FieldOperand(elements, |
3265 key, | 3309 key, |
3266 times_pointer_size, | 3310 times_pointer_size, |
3267 FixedArray::kHeaderSize)); | 3311 FixedArray::kHeaderSize)); |
3268 __ RecordWrite(elements, key, value, kSaveFPRegs); | 3312 __ RecordWrite(elements, |
| 3313 key, |
| 3314 value, |
| 3315 kSaveFPRegs, |
| 3316 EMIT_REMEMBERED_SET, |
| 3317 check_needed); |
3269 } | 3318 } |
3270 } | 3319 } |
3271 | 3320 |
3272 | 3321 |
3273 void LCodeGen::DoStoreKeyedFastDoubleElement( | 3322 void LCodeGen::DoStoreKeyedFastDoubleElement( |
3274 LStoreKeyedFastDoubleElement* instr) { | 3323 LStoreKeyedFastDoubleElement* instr) { |
3275 XMMRegister value = ToDoubleRegister(instr->value()); | 3324 XMMRegister value = ToDoubleRegister(instr->value()); |
3276 Label have_value; | 3325 Label have_value; |
3277 | 3326 |
3278 __ ucomisd(value, value); | 3327 __ ucomisd(value, value); |
(...skipping 17 matching lines...) Expand all Loading... |
3296 ASSERT(ToRegister(instr->key()).is(ecx)); | 3345 ASSERT(ToRegister(instr->key()).is(ecx)); |
3297 ASSERT(ToRegister(instr->value()).is(eax)); | 3346 ASSERT(ToRegister(instr->value()).is(eax)); |
3298 | 3347 |
3299 Handle<Code> ic = instr->strict_mode() | 3348 Handle<Code> ic = instr->strict_mode() |
3300 ? isolate()->builtins()->KeyedStoreIC_Initialize_Strict() | 3349 ? isolate()->builtins()->KeyedStoreIC_Initialize_Strict() |
3301 : isolate()->builtins()->KeyedStoreIC_Initialize(); | 3350 : isolate()->builtins()->KeyedStoreIC_Initialize(); |
3302 CallCode(ic, RelocInfo::CODE_TARGET, instr); | 3351 CallCode(ic, RelocInfo::CODE_TARGET, instr); |
3303 } | 3352 } |
3304 | 3353 |
3305 | 3354 |
| 3355 void LCodeGen::DoTransitionElementsKind(LTransitionElementsKind* instr) { |
| 3356 Register object_reg = ToRegister(instr->object()); |
| 3357 Register new_map_reg = ToRegister(instr->new_map_reg()); |
| 3358 |
| 3359 Handle<Map> from_map = instr->original_map(); |
| 3360 Handle<Map> to_map = instr->transitioned_map(); |
| 3361 ElementsKind from_kind = from_map->elements_kind(); |
| 3362 ElementsKind to_kind = to_map->elements_kind(); |
| 3363 |
| 3364 Label not_applicable; |
| 3365 __ cmp(FieldOperand(object_reg, HeapObject::kMapOffset), from_map); |
| 3366 __ j(not_equal, ¬_applicable); |
| 3367 __ mov(new_map_reg, to_map); |
| 3368 if (from_kind == FAST_SMI_ONLY_ELEMENTS && to_kind == FAST_ELEMENTS) { |
| 3369 Register object_reg = ToRegister(instr->object()); |
| 3370 __ mov(FieldOperand(object_reg, HeapObject::kMapOffset), new_map_reg); |
| 3371 // Write barrier. |
| 3372 ASSERT_NE(instr->temp_reg(), NULL); |
| 3373 __ RecordWriteField(object_reg, HeapObject::kMapOffset, new_map_reg, |
| 3374 ToRegister(instr->temp_reg()), kDontSaveFPRegs); |
| 3375 } else if (from_kind == FAST_SMI_ONLY_ELEMENTS && |
| 3376 to_kind == FAST_DOUBLE_ELEMENTS) { |
| 3377 Register fixed_object_reg = ToRegister(instr->temp_reg()); |
| 3378 ASSERT(fixed_object_reg.is(edx)); |
| 3379 ASSERT(new_map_reg.is(ebx)); |
| 3380 __ mov(fixed_object_reg, object_reg); |
| 3381 CallCode(isolate()->builtins()->TransitionElementsSmiToDouble(), |
| 3382 RelocInfo::CODE_TARGET, instr); |
| 3383 } else if (from_kind == FAST_DOUBLE_ELEMENTS && to_kind == FAST_ELEMENTS) { |
| 3384 Register fixed_object_reg = ToRegister(instr->temp_reg()); |
| 3385 ASSERT(fixed_object_reg.is(edx)); |
| 3386 ASSERT(new_map_reg.is(ebx)); |
| 3387 __ mov(fixed_object_reg, object_reg); |
| 3388 CallCode(isolate()->builtins()->TransitionElementsDoubleToObject(), |
| 3389 RelocInfo::CODE_TARGET, instr); |
| 3390 } else { |
| 3391 UNREACHABLE(); |
| 3392 } |
| 3393 __ bind(¬_applicable); |
| 3394 } |
| 3395 |
| 3396 |
3306 void LCodeGen::DoStringCharCodeAt(LStringCharCodeAt* instr) { | 3397 void LCodeGen::DoStringCharCodeAt(LStringCharCodeAt* instr) { |
3307 class DeferredStringCharCodeAt: public LDeferredCode { | 3398 class DeferredStringCharCodeAt: public LDeferredCode { |
3308 public: | 3399 public: |
3309 DeferredStringCharCodeAt(LCodeGen* codegen, LStringCharCodeAt* instr) | 3400 DeferredStringCharCodeAt(LCodeGen* codegen, LStringCharCodeAt* instr) |
3310 : LDeferredCode(codegen), instr_(instr) { } | 3401 : LDeferredCode(codegen), instr_(instr) { } |
3311 virtual void Generate() { codegen()->DoDeferredStringCharCodeAt(instr_); } | 3402 virtual void Generate() { codegen()->DoDeferredStringCharCodeAt(instr_); } |
3312 virtual LInstruction* instr() { return instr_; } | 3403 virtual LInstruction* instr() { return instr_; } |
3313 private: | 3404 private: |
3314 LStringCharCodeAt* instr_; | 3405 LStringCharCodeAt* instr_; |
3315 }; | 3406 }; |
(...skipping 772 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4088 | 4179 |
4089 // Check the holder map. | 4180 // Check the holder map. |
4090 __ cmp(FieldOperand(reg, HeapObject::kMapOffset), | 4181 __ cmp(FieldOperand(reg, HeapObject::kMapOffset), |
4091 Handle<Map>(current_prototype->map())); | 4182 Handle<Map>(current_prototype->map())); |
4092 DeoptimizeIf(not_equal, instr->environment()); | 4183 DeoptimizeIf(not_equal, instr->environment()); |
4093 } | 4184 } |
4094 | 4185 |
4095 | 4186 |
4096 void LCodeGen::DoArrayLiteral(LArrayLiteral* instr) { | 4187 void LCodeGen::DoArrayLiteral(LArrayLiteral* instr) { |
4097 ASSERT(ToRegister(instr->context()).is(esi)); | 4188 ASSERT(ToRegister(instr->context()).is(esi)); |
| 4189 |
| 4190 Handle<FixedArray> constant_elements = instr->hydrogen()->constant_elements(); |
| 4191 ASSERT_EQ(2, constant_elements->length()); |
| 4192 ElementsKind constant_elements_kind = |
| 4193 static_cast<ElementsKind>(Smi::cast(constant_elements->get(0))->value()); |
| 4194 |
4098 // Setup the parameters to the stub/runtime call. | 4195 // Setup the parameters to the stub/runtime call. |
4099 __ mov(eax, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset)); | 4196 __ mov(eax, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset)); |
4100 __ push(FieldOperand(eax, JSFunction::kLiteralsOffset)); | 4197 __ push(FieldOperand(eax, JSFunction::kLiteralsOffset)); |
4101 __ push(Immediate(Smi::FromInt(instr->hydrogen()->literal_index()))); | 4198 __ push(Immediate(Smi::FromInt(instr->hydrogen()->literal_index()))); |
4102 __ push(Immediate(instr->hydrogen()->constant_elements())); | 4199 __ push(Immediate(constant_elements)); |
4103 | 4200 |
4104 // Pick the right runtime function or stub to call. | 4201 // Pick the right runtime function or stub to call. |
4105 int length = instr->hydrogen()->length(); | 4202 int length = instr->hydrogen()->length(); |
4106 if (instr->hydrogen()->IsCopyOnWrite()) { | 4203 if (instr->hydrogen()->IsCopyOnWrite()) { |
4107 ASSERT(instr->hydrogen()->depth() == 1); | 4204 ASSERT(instr->hydrogen()->depth() == 1); |
4108 FastCloneShallowArrayStub::Mode mode = | 4205 FastCloneShallowArrayStub::Mode mode = |
4109 FastCloneShallowArrayStub::COPY_ON_WRITE_ELEMENTS; | 4206 FastCloneShallowArrayStub::COPY_ON_WRITE_ELEMENTS; |
4110 FastCloneShallowArrayStub stub(mode, length); | 4207 FastCloneShallowArrayStub stub(mode, length); |
4111 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); | 4208 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); |
4112 } else if (instr->hydrogen()->depth() > 1) { | 4209 } else if (instr->hydrogen()->depth() > 1) { |
4113 CallRuntime(Runtime::kCreateArrayLiteral, 3, instr); | 4210 CallRuntime(Runtime::kCreateArrayLiteral, 3, instr); |
4114 } else if (length > FastCloneShallowArrayStub::kMaximumClonedLength) { | 4211 } else if (length > FastCloneShallowArrayStub::kMaximumClonedLength) { |
4115 CallRuntime(Runtime::kCreateArrayLiteralShallow, 3, instr); | 4212 CallRuntime(Runtime::kCreateArrayLiteralShallow, 3, instr); |
4116 } else { | 4213 } else { |
4117 FastCloneShallowArrayStub::Mode mode = | 4214 FastCloneShallowArrayStub::Mode mode = |
4118 FastCloneShallowArrayStub::CLONE_ELEMENTS; | 4215 constant_elements_kind == FAST_DOUBLE_ELEMENTS |
| 4216 ? FastCloneShallowArrayStub::CLONE_DOUBLE_ELEMENTS |
| 4217 : FastCloneShallowArrayStub::CLONE_ELEMENTS; |
4119 FastCloneShallowArrayStub stub(mode, length); | 4218 FastCloneShallowArrayStub stub(mode, length); |
4120 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); | 4219 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); |
4121 } | 4220 } |
4122 } | 4221 } |
4123 | 4222 |
4124 | 4223 |
4125 void LCodeGen::DoObjectLiteral(LObjectLiteral* instr) { | 4224 void LCodeGen::DoObjectLiteral(LObjectLiteral* instr) { |
4126 ASSERT(ToRegister(instr->context()).is(esi)); | 4225 ASSERT(ToRegister(instr->context()).is(esi)); |
4127 // Setup the parameters to the stub/runtime call. | 4226 // Setup the parameters to the stub/runtime call. |
4128 __ mov(eax, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset)); | 4227 __ mov(eax, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset)); |
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4207 } | 4306 } |
4208 | 4307 |
4209 | 4308 |
4210 void LCodeGen::DoFunctionLiteral(LFunctionLiteral* instr) { | 4309 void LCodeGen::DoFunctionLiteral(LFunctionLiteral* instr) { |
4211 ASSERT(ToRegister(instr->context()).is(esi)); | 4310 ASSERT(ToRegister(instr->context()).is(esi)); |
4212 // Use the fast case closure allocation code that allocates in new | 4311 // Use the fast case closure allocation code that allocates in new |
4213 // space for nested functions that don't need literals cloning. | 4312 // space for nested functions that don't need literals cloning. |
4214 Handle<SharedFunctionInfo> shared_info = instr->shared_info(); | 4313 Handle<SharedFunctionInfo> shared_info = instr->shared_info(); |
4215 bool pretenure = instr->hydrogen()->pretenure(); | 4314 bool pretenure = instr->hydrogen()->pretenure(); |
4216 if (!pretenure && shared_info->num_literals() == 0) { | 4315 if (!pretenure && shared_info->num_literals() == 0) { |
4217 FastNewClosureStub stub( | 4316 FastNewClosureStub stub(shared_info->strict_mode_flag()); |
4218 shared_info->strict_mode() ? kStrictMode : kNonStrictMode); | |
4219 __ push(Immediate(shared_info)); | 4317 __ push(Immediate(shared_info)); |
4220 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); | 4318 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); |
4221 } else { | 4319 } else { |
4222 __ push(Operand(ebp, StandardFrameConstants::kContextOffset)); | 4320 __ push(Operand(ebp, StandardFrameConstants::kContextOffset)); |
4223 __ push(Immediate(shared_info)); | 4321 __ push(Immediate(shared_info)); |
4224 __ push(Immediate(pretenure | 4322 __ push(Immediate(pretenure |
4225 ? factory()->true_value() | 4323 ? factory()->true_value() |
4226 : factory()->false_value())); | 4324 : factory()->false_value())); |
4227 CallRuntime(Runtime::kNewClosure, 3, instr); | 4325 CallRuntime(Runtime::kNewClosure, 3, instr); |
4228 } | 4326 } |
(...skipping 11 matching lines...) Expand all Loading... |
4240 } | 4338 } |
4241 | 4339 |
4242 | 4340 |
4243 void LCodeGen::DoTypeofIsAndBranch(LTypeofIsAndBranch* instr) { | 4341 void LCodeGen::DoTypeofIsAndBranch(LTypeofIsAndBranch* instr) { |
4244 Register input = ToRegister(instr->InputAt(0)); | 4342 Register input = ToRegister(instr->InputAt(0)); |
4245 int true_block = chunk_->LookupDestination(instr->true_block_id()); | 4343 int true_block = chunk_->LookupDestination(instr->true_block_id()); |
4246 int false_block = chunk_->LookupDestination(instr->false_block_id()); | 4344 int false_block = chunk_->LookupDestination(instr->false_block_id()); |
4247 Label* true_label = chunk_->GetAssemblyLabel(true_block); | 4345 Label* true_label = chunk_->GetAssemblyLabel(true_block); |
4248 Label* false_label = chunk_->GetAssemblyLabel(false_block); | 4346 Label* false_label = chunk_->GetAssemblyLabel(false_block); |
4249 | 4347 |
4250 Condition final_branch_condition = EmitTypeofIs(true_label, | 4348 Condition final_branch_condition = |
4251 false_label, | 4349 EmitTypeofIs(true_label, false_label, input, instr->type_literal()); |
4252 input, | 4350 if (final_branch_condition != no_condition) { |
4253 instr->type_literal()); | 4351 EmitBranch(true_block, false_block, final_branch_condition); |
4254 | 4352 } |
4255 EmitBranch(true_block, false_block, final_branch_condition); | |
4256 } | 4353 } |
4257 | 4354 |
4258 | 4355 |
4259 Condition LCodeGen::EmitTypeofIs(Label* true_label, | 4356 Condition LCodeGen::EmitTypeofIs(Label* true_label, |
4260 Label* false_label, | 4357 Label* false_label, |
4261 Register input, | 4358 Register input, |
4262 Handle<String> type_name) { | 4359 Handle<String> type_name) { |
4263 Condition final_branch_condition = no_condition; | 4360 Condition final_branch_condition = no_condition; |
4264 if (type_name->Equals(heap()->number_symbol())) { | 4361 if (type_name->Equals(heap()->number_symbol())) { |
4265 __ JumpIfSmi(input, true_label); | 4362 __ JumpIfSmi(input, true_label); |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4312 __ CmpObjectType(input, FIRST_NONCALLABLE_SPEC_OBJECT_TYPE, input); | 4409 __ CmpObjectType(input, FIRST_NONCALLABLE_SPEC_OBJECT_TYPE, input); |
4313 __ j(below, false_label); | 4410 __ j(below, false_label); |
4314 __ CmpInstanceType(input, LAST_NONCALLABLE_SPEC_OBJECT_TYPE); | 4411 __ CmpInstanceType(input, LAST_NONCALLABLE_SPEC_OBJECT_TYPE); |
4315 __ j(above, false_label); | 4412 __ j(above, false_label); |
4316 // Check for undetectable objects => false. | 4413 // Check for undetectable objects => false. |
4317 __ test_b(FieldOperand(input, Map::kBitFieldOffset), | 4414 __ test_b(FieldOperand(input, Map::kBitFieldOffset), |
4318 1 << Map::kIsUndetectable); | 4415 1 << Map::kIsUndetectable); |
4319 final_branch_condition = zero; | 4416 final_branch_condition = zero; |
4320 | 4417 |
4321 } else { | 4418 } else { |
4322 final_branch_condition = not_equal; | |
4323 __ jmp(false_label); | 4419 __ jmp(false_label); |
4324 // A dead branch instruction will be generated after this point. | |
4325 } | 4420 } |
4326 | |
4327 return final_branch_condition; | 4421 return final_branch_condition; |
4328 } | 4422 } |
4329 | 4423 |
4330 | 4424 |
4331 void LCodeGen::DoIsConstructCallAndBranch(LIsConstructCallAndBranch* instr) { | 4425 void LCodeGen::DoIsConstructCallAndBranch(LIsConstructCallAndBranch* instr) { |
4332 Register temp = ToRegister(instr->TempAt(0)); | 4426 Register temp = ToRegister(instr->TempAt(0)); |
4333 int true_block = chunk_->LookupDestination(instr->true_block_id()); | 4427 int true_block = chunk_->LookupDestination(instr->true_block_id()); |
4334 int false_block = chunk_->LookupDestination(instr->false_block_id()); | 4428 int false_block = chunk_->LookupDestination(instr->false_block_id()); |
4335 | 4429 |
4336 EmitIsConstructCall(temp); | 4430 EmitIsConstructCall(temp); |
(...skipping 152 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4489 env->deoptimization_index()); | 4583 env->deoptimization_index()); |
4490 __ InvokeBuiltin(Builtins::IN, CALL_FUNCTION, safepoint_generator); | 4584 __ InvokeBuiltin(Builtins::IN, CALL_FUNCTION, safepoint_generator); |
4491 } | 4585 } |
4492 | 4586 |
4493 | 4587 |
4494 #undef __ | 4588 #undef __ |
4495 | 4589 |
4496 } } // namespace v8::internal | 4590 } } // namespace v8::internal |
4497 | 4591 |
4498 #endif // V8_TARGET_ARCH_IA32 | 4592 #endif // V8_TARGET_ARCH_IA32 |
OLD | NEW |