| OLD | NEW |
| 1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 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 577 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 588 } | 588 } |
| 589 | 589 |
| 590 | 590 |
| 591 void LCodeGen::CallCode(Handle<Code> code, | 591 void LCodeGen::CallCode(Handle<Code> code, |
| 592 RelocInfo::Mode mode, | 592 RelocInfo::Mode mode, |
| 593 LInstruction* instr) { | 593 LInstruction* instr) { |
| 594 CallCodeGeneric(code, mode, instr, RECORD_SIMPLE_SAFEPOINT); | 594 CallCodeGeneric(code, mode, instr, RECORD_SIMPLE_SAFEPOINT); |
| 595 } | 595 } |
| 596 | 596 |
| 597 | 597 |
| 598 void LCodeGen::CallCodeFromDeferred(Handle<Code> code, |
| 599 RelocInfo::Mode mode, |
| 600 LInstruction* instr) { |
| 601 //CallCodeGeneric(code, mode, instr, RECORD_SIMPLE_SAFEPOINT); |
| 602 |
| 603 ASSERT(instr != NULL); |
| 604 LPointerMap* pointers = instr->pointer_map(); |
| 605 RecordPosition(pointers->position()); |
| 606 __ call(code, mode); |
| 607 RecordSafepointWithRegisters( |
| 608 instr->pointer_map(), 0, Safepoint::kNoLazyDeopt); |
| 609 |
| 610 // Signal that we don't inline smi code before these stubs in the |
| 611 // optimizing code generator. |
| 612 if (code->kind() == Code::BINARY_OP_IC || |
| 613 code->kind() == Code::COMPARE_IC) { |
| 614 __ nop(); |
| 615 } |
| 616 } |
| 617 |
| 618 |
| 598 void LCodeGen::CallRuntime(const Runtime::Function* fun, | 619 void LCodeGen::CallRuntime(const Runtime::Function* fun, |
| 599 int argc, | 620 int argc, |
| 600 LInstruction* instr) { | 621 LInstruction* instr) { |
| 601 ASSERT(instr != NULL); | 622 ASSERT(instr != NULL); |
| 602 ASSERT(instr->HasPointerMap()); | 623 ASSERT(instr->HasPointerMap()); |
| 603 LPointerMap* pointers = instr->pointer_map(); | 624 LPointerMap* pointers = instr->pointer_map(); |
| 604 RecordPosition(pointers->position()); | 625 RecordPosition(pointers->position()); |
| 605 | 626 |
| 606 __ CallRuntime(fun, argc); | 627 __ CallRuntime(fun, argc); |
| 607 | 628 |
| (...skipping 18 matching lines...) Expand all Loading... |
| 626 } else { | 647 } else { |
| 627 UNREACHABLE(); | 648 UNREACHABLE(); |
| 628 } | 649 } |
| 629 | 650 |
| 630 __ CallRuntimeSaveDoubles(id); | 651 __ CallRuntimeSaveDoubles(id); |
| 631 RecordSafepointWithRegisters( | 652 RecordSafepointWithRegisters( |
| 632 instr->pointer_map(), argc, Safepoint::kNoLazyDeopt); | 653 instr->pointer_map(), argc, Safepoint::kNoLazyDeopt); |
| 633 } | 654 } |
| 634 | 655 |
| 635 | 656 |
| 657 void LCodeGen::CallRuntimeFromDeferred(Runtime::FunctionId id, |
| 658 int argc, |
| 659 LInstruction* instr) { |
| 660 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); |
| 661 __ CallRuntimeSaveDoubles(id); |
| 662 RecordSafepointWithRegisters( |
| 663 instr->pointer_map(), argc, Safepoint::kNoLazyDeopt); |
| 664 } |
| 665 |
| 666 |
| 636 void LCodeGen::RegisterEnvironmentForDeoptimization( | 667 void LCodeGen::RegisterEnvironmentForDeoptimization( |
| 637 LEnvironment* environment, Safepoint::DeoptMode mode) { | 668 LEnvironment* environment, Safepoint::DeoptMode mode) { |
| 638 if (!environment->HasBeenRegistered()) { | 669 if (!environment->HasBeenRegistered()) { |
| 639 // Physical stack frame layout: | 670 // Physical stack frame layout: |
| 640 // -x ............. -4 0 ..................................... y | 671 // -x ............. -4 0 ..................................... y |
| 641 // [incoming arguments] [spill slots] [pushed outgoing arguments] | 672 // [incoming arguments] [spill slots] [pushed outgoing arguments] |
| 642 | 673 |
| 643 // Layout of the environment: | 674 // Layout of the environment: |
| 644 // 0 ..................................................... size-1 | 675 // 0 ..................................................... size-1 |
| 645 // [parameters] [locals] [expression stack including arguments] | 676 // [parameters] [locals] [expression stack including arguments] |
| (...skipping 3404 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4050 ASSERT(ToRegister(instr->key()).is(ecx)); | 4081 ASSERT(ToRegister(instr->key()).is(ecx)); |
| 4051 ASSERT(ToRegister(instr->value()).is(eax)); | 4082 ASSERT(ToRegister(instr->value()).is(eax)); |
| 4052 | 4083 |
| 4053 Handle<Code> ic = (instr->strict_mode_flag() == kStrictMode) | 4084 Handle<Code> ic = (instr->strict_mode_flag() == kStrictMode) |
| 4054 ? isolate()->builtins()->KeyedStoreIC_Initialize_Strict() | 4085 ? isolate()->builtins()->KeyedStoreIC_Initialize_Strict() |
| 4055 : isolate()->builtins()->KeyedStoreIC_Initialize(); | 4086 : isolate()->builtins()->KeyedStoreIC_Initialize(); |
| 4056 CallCode(ic, RelocInfo::CODE_TARGET, instr); | 4087 CallCode(ic, RelocInfo::CODE_TARGET, instr); |
| 4057 } | 4088 } |
| 4058 | 4089 |
| 4059 | 4090 |
| 4091 class DeferredTransitionElementsKind: public LDeferredCode { |
| 4092 public: |
| 4093 DeferredTransitionElementsKind(LCodeGen* codegen, LTransitionElementsKind* ins
tr) |
| 4094 : LDeferredCode(codegen), instr_(instr) { } |
| 4095 virtual void Generate() { codegen()->DoDeferredTransitionElementsKind(instr_);
} |
| 4096 virtual LInstruction* instr() { return instr_; } |
| 4097 private: |
| 4098 LTransitionElementsKind* instr_; |
| 4099 }; |
| 4100 |
| 4101 |
| 4102 void LCodeGen::DoDeferredTransitionElementsKind(LTransitionElementsKind* instr)
{ |
| 4103 Register object_reg = ToRegister(instr->object()); |
| 4104 Handle<Map> to_map = instr->transitioned_map(); |
| 4105 ElementsKind to_kind = to_map->elements_kind(); |
| 4106 |
| 4107 PushSafepointRegistersScope scope(this); |
| 4108 |
| 4109 /* |
| 4110 Handle<Code> code = IsFastDoubleElementsKind(to_kind) |
| 4111 ? isolate()->builtins()->TransitionElementsSmiToDouble() |
| 4112 : isolate()->builtins()->TransitionElementsDoubleToObject(); |
| 4113 |
| 4114 __ mov(ebx, to_map); |
| 4115 if (!edx.is(object_reg)) { |
| 4116 __ mov(edx, object_reg); |
| 4117 } |
| 4118 |
| 4119 |
| 4120 CallCodeFromDeferred(code, |
| 4121 RelocInfo::CODE_TARGET, |
| 4122 instr); |
| 4123 // RECORD_SAFEPOINT_WITH_REGISTERS_AND_NO_ARGUMENTS); |
| 4124 */ |
| 4125 |
| 4126 Runtime::FunctionId function_id = IsFastDoubleElementsKind(to_kind) |
| 4127 ? Runtime::kTransitionElementsSmiToDouble |
| 4128 : Runtime::kTransitionElementsDoubleToObject; |
| 4129 |
| 4130 __ push(object_reg); |
| 4131 CallRuntimeFromDeferred(function_id, 1, instr); |
| 4132 |
| 4133 // __ AssertSmi(eax); |
| 4134 // __ SmiUntag(eax); |
| 4135 __ StoreToSafepointRegisterSlot(object_reg, eax); |
| 4136 } |
| 4137 |
| 4138 |
| 4060 void LCodeGen::DoTransitionElementsKind(LTransitionElementsKind* instr) { | 4139 void LCodeGen::DoTransitionElementsKind(LTransitionElementsKind* instr) { |
| 4061 Register object_reg = ToRegister(instr->object()); | 4140 Register object_reg = ToRegister(instr->object()); |
| 4062 Register new_map_reg = ToRegister(instr->new_map_temp()); | 4141 Register new_map_reg = ToRegister(instr->new_map_temp()); |
| 4063 | 4142 |
| 4064 Handle<Map> from_map = instr->original_map(); | 4143 Handle<Map> from_map = instr->original_map(); |
| 4065 Handle<Map> to_map = instr->transitioned_map(); | 4144 Handle<Map> to_map = instr->transitioned_map(); |
| 4066 ElementsKind from_kind = from_map->elements_kind(); | 4145 ElementsKind from_kind = from_map->elements_kind(); |
| 4067 ElementsKind to_kind = to_map->elements_kind(); | 4146 ElementsKind to_kind = to_map->elements_kind(); |
| 4068 | 4147 |
| 4069 Label not_applicable; | 4148 Label not_applicable; |
| 4070 bool is_simple_map_transition = | 4149 bool is_simple_map_transition = |
| 4071 IsSimpleMapChangeTransition(from_kind, to_kind); | 4150 IsSimpleMapChangeTransition(from_kind, to_kind); |
| 4072 Label::Distance branch_distance = | 4151 Label::Distance branch_distance = |
| 4073 is_simple_map_transition ? Label::kNear : Label::kFar; | 4152 is_simple_map_transition ? Label::kNear : Label::kFar; |
| 4074 __ cmp(FieldOperand(object_reg, HeapObject::kMapOffset), from_map); | 4153 __ cmp(FieldOperand(object_reg, HeapObject::kMapOffset), from_map); |
| 4075 __ j(not_equal, ¬_applicable, branch_distance); | 4154 __ j(not_equal, ¬_applicable, branch_distance); |
| 4155 |
| 4076 if (is_simple_map_transition) { | 4156 if (is_simple_map_transition) { |
| 4077 Register object_reg = ToRegister(instr->object()); | 4157 Register object_reg = ToRegister(instr->object()); |
| 4078 Handle<Map> map = instr->hydrogen()->transitioned_map(); | 4158 Handle<Map> map = instr->hydrogen()->transitioned_map(); |
| 4079 __ mov(FieldOperand(object_reg, HeapObject::kMapOffset), | 4159 __ mov(FieldOperand(object_reg, HeapObject::kMapOffset), |
| 4080 Immediate(map)); | 4160 Immediate(map)); |
| 4081 // Write barrier. | 4161 // Write barrier. |
| 4082 ASSERT_NE(instr->temp(), NULL); | 4162 ASSERT_NE(instr->temp(), NULL); |
| 4083 __ RecordWriteForMap(object_reg, to_map, new_map_reg, | 4163 __ RecordWriteForMap(object_reg, to_map, new_map_reg, |
| 4084 ToRegister(instr->temp()), | 4164 ToRegister(instr->temp()), |
| 4085 kDontSaveFPRegs); | 4165 kDontSaveFPRegs); |
| 4086 } else if (IsFastSmiElementsKind(from_kind) && | 4166 } else if ((IsFastSmiElementsKind(from_kind) && |
| 4087 IsFastDoubleElementsKind(to_kind)) { | 4167 IsFastDoubleElementsKind(to_kind)) || |
| 4088 __ mov(new_map_reg, to_map); | 4168 (IsFastDoubleElementsKind(from_kind) && |
| 4089 Register fixed_object_reg = ToRegister(instr->temp()); | 4169 IsFastObjectElementsKind(to_kind))) { |
| 4090 ASSERT(fixed_object_reg.is(edx)); | 4170 DeferredTransitionElementsKind* deferred = |
| 4091 ASSERT(new_map_reg.is(ebx)); | 4171 new(zone()) DeferredTransitionElementsKind(this, instr); |
| 4092 __ mov(fixed_object_reg, object_reg); | 4172 __ jmp(deferred->entry()); |
| 4093 CallCode(isolate()->builtins()->TransitionElementsSmiToDouble(), | 4173 __ bind(deferred->exit()); |
| 4094 RelocInfo::CODE_TARGET, instr); | |
| 4095 } else if (IsFastDoubleElementsKind(from_kind) && | |
| 4096 IsFastObjectElementsKind(to_kind)) { | |
| 4097 __ mov(new_map_reg, to_map); | |
| 4098 Register fixed_object_reg = ToRegister(instr->temp()); | |
| 4099 ASSERT(fixed_object_reg.is(edx)); | |
| 4100 ASSERT(new_map_reg.is(ebx)); | |
| 4101 __ mov(fixed_object_reg, object_reg); | |
| 4102 CallCode(isolate()->builtins()->TransitionElementsDoubleToObject(), | |
| 4103 RelocInfo::CODE_TARGET, instr); | |
| 4104 } else { | 4174 } else { |
| 4105 UNREACHABLE(); | 4175 UNREACHABLE(); |
| 4106 } | 4176 } |
| 4107 __ bind(¬_applicable); | 4177 __ bind(¬_applicable); |
| 4108 } | 4178 } |
| 4109 | 4179 |
| 4110 | 4180 |
| 4111 void LCodeGen::DoStringCharCodeAt(LStringCharCodeAt* instr) { | 4181 void LCodeGen::DoStringCharCodeAt(LStringCharCodeAt* instr) { |
| 4112 class DeferredStringCharCodeAt: public LDeferredCode { | 4182 class DeferredStringCharCodeAt: public LDeferredCode { |
| 4113 public: | 4183 public: |
| (...skipping 1044 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5158 } | 5228 } |
| 5159 } else { | 5229 } else { |
| 5160 UNREACHABLE(); | 5230 UNREACHABLE(); |
| 5161 } | 5231 } |
| 5162 } | 5232 } |
| 5163 } | 5233 } |
| 5164 | 5234 |
| 5165 | 5235 |
| 5166 void LCodeGen::DoFastLiteral(LFastLiteral* instr) { | 5236 void LCodeGen::DoFastLiteral(LFastLiteral* instr) { |
| 5167 ASSERT(ToRegister(instr->context()).is(esi)); | 5237 ASSERT(ToRegister(instr->context()).is(esi)); |
| 5168 int size = instr->hydrogen()->total_size(); | 5238 Handle<JSObject> result = instr->hydrogen()->boilerplate(); |
| 5169 ElementsKind boilerplate_elements_kind = | |
| 5170 instr->hydrogen()->boilerplate()->GetElementsKind(); | |
| 5171 | 5239 |
| 5172 // Deopt if the literal boilerplate ElementsKind is of a type different than | 5240 if (instr->hydrogen()->TransitionRequested()) { |
| 5173 // the expected one. The check isn't necessary if the boilerplate has already | 5241 ElementsKind to_kind = instr->hydrogen()->TransitionTo(); |
| 5174 // already been converted to TERMINAL_FAST_ELEMENTS_KIND. | 5242 result = Runtime::DeepCopyBoilerplate(isolate(), |
| 5175 if (CanTransitionToMoreGeneralFastElementsKind( | 5243 instr->hydrogen()->boilerplate()); |
| 5176 boilerplate_elements_kind, true)) { | 5244 CHECK(!result.is_null()); |
| 5177 __ LoadHeapObject(ebx, instr->hydrogen()->boilerplate()); | 5245 // Now transition the copy |
| 5178 __ mov(ecx, FieldOperand(ebx, HeapObject::kMapOffset)); | 5246 CHECK(!JSObject::TransitionElementsKind(result, to_kind).is_null()); |
| 5179 // Load the map's "bit field 2". We only need the first byte, | 5247 } else { |
| 5180 // but the following masking takes care of that anyway. | 5248 // Deopt if the literal boilerplate ElementsKind is of a type different than |
| 5181 __ mov(ecx, FieldOperand(ecx, Map::kBitField2Offset)); | 5249 // the expected one. The check isn't necessary if the boilerplate has |
| 5182 // Retrieve elements_kind from bit field 2. | 5250 // already already been converted to TERMINAL_FAST_ELEMENTS_KIND. |
| 5183 __ and_(ecx, Map::kElementsKindMask); | 5251 ElementsKind boilerplate_elements_kind = result->GetElementsKind(); |
| 5184 __ cmp(ecx, boilerplate_elements_kind << Map::kElementsKindShift); | 5252 if (CanTransitionToMoreGeneralFastElementsKind( |
| 5185 DeoptimizeIf(not_equal, instr->environment()); | 5253 boilerplate_elements_kind, true)) { |
| 5254 __ LoadHeapObject(ebx, result); |
| 5255 __ mov(ecx, FieldOperand(ebx, HeapObject::kMapOffset)); |
| 5256 // Load the map's "bit field 2". We only need the first byte, |
| 5257 // but the following masking takes care of that anyway. |
| 5258 __ mov(ecx, FieldOperand(ecx, Map::kBitField2Offset)); |
| 5259 // Retrieve elements_kind from bit field 2. |
| 5260 __ and_(ecx, Map::kElementsKindMask); |
| 5261 __ cmp(ecx, boilerplate_elements_kind << Map::kElementsKindShift); |
| 5262 DeoptimizeIf(not_equal, instr->environment()); |
| 5263 } |
| 5186 } | 5264 } |
| 5187 | 5265 |
| 5188 // Allocate all objects that are part of the literal in one big | 5266 // We need to compute the size now. |
| 5267 int size = 0; |
| 5268 int max_properties = HFastLiteral::kMaxLiteralProperties; |
| 5269 HFastLiteral::IsFastLiteral(result, |
| 5270 HFastLiteral::kMaxLiteralDepth, |
| 5271 &max_properties, |
| 5272 &size); |
| 5273 |
| 5189 // allocation. This avoids multiple limit checks. | 5274 // allocation. This avoids multiple limit checks. |
| 5190 Label allocated, runtime_allocate; | 5275 Label allocated, runtime_allocate; |
| 5191 __ AllocateInNewSpace(size, eax, ecx, edx, &runtime_allocate, TAG_OBJECT); | 5276 __ AllocateInNewSpace(size, eax, ecx, edx, &runtime_allocate, TAG_OBJECT); |
| 5192 __ jmp(&allocated); | 5277 __ jmp(&allocated); |
| 5193 | 5278 |
| 5194 __ bind(&runtime_allocate); | 5279 __ bind(&runtime_allocate); |
| 5195 __ push(Immediate(Smi::FromInt(size))); | 5280 __ push(Immediate(Smi::FromInt(size))); |
| 5196 CallRuntime(Runtime::kAllocateInNewSpace, 1, instr); | 5281 CallRuntime(Runtime::kAllocateInNewSpace, 1, instr); |
| 5197 | 5282 |
| 5198 __ bind(&allocated); | 5283 __ bind(&allocated); |
| 5199 int offset = 0; | 5284 int offset = 0; |
| 5200 __ LoadHeapObject(ebx, instr->hydrogen()->boilerplate()); | 5285 __ LoadHeapObject(ebx, result); |
| 5201 EmitDeepCopy(instr->hydrogen()->boilerplate(), eax, ebx, &offset); | 5286 EmitDeepCopy(result, eax, ebx, &offset); |
| 5202 ASSERT_EQ(size, offset); | 5287 ASSERT_EQ(size, offset); |
| 5203 } | 5288 } |
| 5204 | 5289 |
| 5205 | 5290 |
| 5206 void LCodeGen::DoObjectLiteral(LObjectLiteral* instr) { | 5291 void LCodeGen::DoObjectLiteral(LObjectLiteral* instr) { |
| 5207 ASSERT(ToRegister(instr->context()).is(esi)); | 5292 ASSERT(ToRegister(instr->context()).is(esi)); |
| 5208 Handle<FixedArray> literals(instr->environment()->closure()->literals()); | 5293 Handle<FixedArray> literals(instr->environment()->closure()->literals()); |
| 5209 Handle<FixedArray> constant_properties = | 5294 Handle<FixedArray> constant_properties = |
| 5210 instr->hydrogen()->constant_properties(); | 5295 instr->hydrogen()->constant_properties(); |
| 5211 | 5296 |
| (...skipping 446 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5658 FixedArray::kHeaderSize - kPointerSize)); | 5743 FixedArray::kHeaderSize - kPointerSize)); |
| 5659 __ bind(&done); | 5744 __ bind(&done); |
| 5660 } | 5745 } |
| 5661 | 5746 |
| 5662 | 5747 |
| 5663 #undef __ | 5748 #undef __ |
| 5664 | 5749 |
| 5665 } } // namespace v8::internal | 5750 } } // namespace v8::internal |
| 5666 | 5751 |
| 5667 #endif // V8_TARGET_ARCH_IA32 | 5752 #endif // V8_TARGET_ARCH_IA32 |
| OLD | NEW |