diff options
Diffstat (limited to 'deps/v8/src/ia32/lithium-codegen-ia32.cc')
-rw-r--r-- | deps/v8/src/ia32/lithium-codegen-ia32.cc | 276 |
1 files changed, 131 insertions, 145 deletions
diff --git a/deps/v8/src/ia32/lithium-codegen-ia32.cc b/deps/v8/src/ia32/lithium-codegen-ia32.cc index d5ef4d95a..23db87406 100644 --- a/deps/v8/src/ia32/lithium-codegen-ia32.cc +++ b/deps/v8/src/ia32/lithium-codegen-ia32.cc @@ -341,6 +341,13 @@ int LCodeGen::ToInteger32(LConstantOperand* op) const { } +Handle<Object> LCodeGen::ToHandle(LConstantOperand* op) const { + Handle<Object> literal = chunk_->LookupLiteral(op); + ASSERT(chunk_->LookupLiteralRepresentation(op).IsTagged()); + return literal; +} + + double LCodeGen::ToDouble(LConstantOperand* op) const { Handle<Object> value = chunk_->LookupLiteral(op); return value->Number(); @@ -518,7 +525,7 @@ void LCodeGen::CallRuntimeFromDeferred(Runtime::FunctionId id, } else if (context->IsConstantOperand()) { Handle<Object> literal = chunk_->LookupLiteral(LConstantOperand::cast(context)); - LoadHeapObject(esi, Handle<Context>::cast(literal)); + __ LoadHeapObject(esi, Handle<Context>::cast(literal)); } else { UNREACHABLE(); } @@ -1219,7 +1226,7 @@ void LCodeGen::DoConstantT(LConstantT* instr) { Register reg = ToRegister(instr->result()); Handle<Object> handle = instr->value(); if (handle->IsHeapObject()) { - LoadHeapObject(reg, Handle<HeapObject>::cast(handle)); + __ LoadHeapObject(reg, Handle<HeapObject>::cast(handle)); } else { __ Set(reg, Immediate(handle)); } @@ -2030,7 +2037,7 @@ void LCodeGen::DoDeferredInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr, // the stub. Register temp = ToRegister(instr->TempAt(0)); ASSERT(MacroAssembler::SafepointRegisterStackIndex(temp) == 0); - __ mov(InstanceofStub::right(), Immediate(instr->function())); + __ LoadHeapObject(InstanceofStub::right(), instr->function()); static const int kAdditionalDelta = 13; int delta = masm_->SizeOfCodeGeneratedSince(map_check) + kAdditionalDelta; __ mov(temp, Immediate(delta)); @@ -2137,20 +2144,7 @@ void LCodeGen::DoStoreGlobalCell(LStoreGlobalCell* instr) { // Store the value. __ mov(FieldOperand(object, offset), value); - - // Cells are always in the remembered set. - if (instr->hydrogen()->NeedsWriteBarrier()) { - HType type = instr->hydrogen()->value()->type(); - SmiCheck check_needed = - type.IsHeapObject() ? OMIT_SMI_CHECK : INLINE_SMI_CHECK; - __ RecordWriteField(object, - offset, - value, - address, - kSaveFPRegs, - OMIT_REMEMBERED_SET, - check_needed); - } + // Cells are always rescanned, so no write barrier here. } @@ -2171,13 +2165,22 @@ void LCodeGen::DoLoadContextSlot(LLoadContextSlot* instr) { Register context = ToRegister(instr->context()); Register result = ToRegister(instr->result()); __ mov(result, ContextOperand(context, instr->slot_index())); + if (instr->hydrogen()->RequiresHoleCheck()) { + __ cmp(result, factory()->the_hole_value()); + DeoptimizeIf(equal, instr->environment()); + } } void LCodeGen::DoStoreContextSlot(LStoreContextSlot* instr) { Register context = ToRegister(instr->context()); Register value = ToRegister(instr->value()); - __ mov(ContextOperand(context, instr->slot_index()), value); + Operand target = ContextOperand(context, instr->slot_index()); + if (instr->hydrogen()->RequiresHoleCheck()) { + __ cmp(target, factory()->the_hole_value()); + DeoptimizeIf(equal, instr->environment()); + } + __ mov(target, value); if (instr->hydrogen()->NeedsWriteBarrier()) { HType type = instr->hydrogen()->value()->type(); SmiCheck check_needed = @@ -2229,7 +2232,24 @@ void LCodeGen::EmitLoadFieldOrConstantFunction(Register result, } } else { Handle<JSFunction> function(lookup.GetConstantFunctionFromMap(*type)); - LoadHeapObject(result, Handle<HeapObject>::cast(function)); + __ LoadHeapObject(result, function); + } +} + + +void LCodeGen::EmitPushTaggedOperand(LOperand* operand) { + ASSERT(!operand->IsDoubleRegister()); + if (operand->IsConstantOperand()) { + Handle<Object> object = ToHandle(LConstantOperand::cast(operand)); + if (object->IsSmi()) { + __ Push(Handle<Smi>::cast(object)); + } else { + __ PushHeapObject(Handle<HeapObject>::cast(object)); + } + } else if (operand->IsRegister()) { + __ push(ToRegister(operand)); + } else { + __ push(ToOperand(operand)); } } @@ -2639,17 +2659,13 @@ void LCodeGen::DoApplyArguments(LApplyArguments* instr) { void LCodeGen::DoPushArgument(LPushArgument* instr) { LOperand* argument = instr->InputAt(0); - if (argument->IsConstantOperand()) { - __ push(ToImmediate(argument)); - } else { - __ push(ToOperand(argument)); - } + EmitPushTaggedOperand(argument); } void LCodeGen::DoThisFunction(LThisFunction* instr) { Register result = ToRegister(instr->result()); - LoadHeapObject(result, instr->hydrogen()->closure()); + __ LoadHeapObject(result, instr->hydrogen()->closure()); } @@ -2719,7 +2735,7 @@ void LCodeGen::CallKnownFunction(Handle<JSFunction> function, void LCodeGen::DoCallConstantFunction(LCallConstantFunction* instr) { ASSERT(ToRegister(instr->result()).is(eax)); - __ mov(edi, instr->function()); + __ LoadHeapObject(edi, instr->function()); CallKnownFunction(instr->function(), instr->arity(), instr, @@ -2893,12 +2909,12 @@ void LCodeGen::DoMathRound(LUnaryMathOperation* instr) { __ movdbl(xmm_scratch, Operand::StaticVariable(one_half)); __ ucomisd(xmm_scratch, input_reg); __ j(above, &below_half); - // input = input + 0.5 - __ addsd(input_reg, xmm_scratch); + // xmm_scratch = input + 0.5 + __ addsd(xmm_scratch, input_reg); // Compute Math.floor(value + 0.5). // Use truncating instruction (OK because input is positive). - __ cvttsd2si(output_reg, Operand(input_reg)); + __ cvttsd2si(output_reg, Operand(xmm_scratch)); // Overflow is signalled with minint. __ cmp(output_reg, 0x80000000u); @@ -2934,72 +2950,67 @@ void LCodeGen::DoMathSqrt(LUnaryMathOperation* instr) { } -void LCodeGen::DoMathPowHalf(LUnaryMathOperation* instr) { +void LCodeGen::DoMathPowHalf(LMathPowHalf* instr) { XMMRegister xmm_scratch = xmm0; XMMRegister input_reg = ToDoubleRegister(instr->value()); + Register scratch = ToRegister(instr->temp()); ASSERT(ToDoubleRegister(instr->result()).is(input_reg)); + + // Note that according to ECMA-262 15.8.2.13: + // Math.pow(-Infinity, 0.5) == Infinity + // Math.sqrt(-Infinity) == NaN + Label done, sqrt; + // Check base for -Infinity. According to IEEE-754, single-precision + // -Infinity has the highest 9 bits set and the lowest 23 bits cleared. + __ mov(scratch, 0xFF800000); + __ movd(xmm_scratch, scratch); + __ cvtss2sd(xmm_scratch, xmm_scratch); + __ ucomisd(input_reg, xmm_scratch); + // Comparing -Infinity with NaN results in "unordered", which sets the + // zero flag as if both were equal. However, it also sets the carry flag. + __ j(not_equal, &sqrt, Label::kNear); + __ j(carry, &sqrt, Label::kNear); + // If input is -Infinity, return Infinity. + __ xorps(input_reg, input_reg); + __ subsd(input_reg, xmm_scratch); + __ jmp(&done, Label::kNear); + + // Square root. + __ bind(&sqrt); __ xorps(xmm_scratch, xmm_scratch); __ addsd(input_reg, xmm_scratch); // Convert -0 to +0. __ sqrtsd(input_reg, input_reg); + __ bind(&done); } void LCodeGen::DoPower(LPower* instr) { - LOperand* left = instr->InputAt(0); - LOperand* right = instr->InputAt(1); - DoubleRegister result_reg = ToDoubleRegister(instr->result()); Representation exponent_type = instr->hydrogen()->right()->representation(); - - if (exponent_type.IsDouble()) { - // It is safe to use ebx directly since the instruction is marked - // as a call. - __ PrepareCallCFunction(4, ebx); - __ movdbl(Operand(esp, 0 * kDoubleSize), ToDoubleRegister(left)); - __ movdbl(Operand(esp, 1 * kDoubleSize), ToDoubleRegister(right)); - __ CallCFunction(ExternalReference::power_double_double_function(isolate()), - 4); + // Having marked this as a call, we can use any registers. + // Just make sure that the input/output registers are the expected ones. + ASSERT(!instr->InputAt(1)->IsDoubleRegister() || + ToDoubleRegister(instr->InputAt(1)).is(xmm1)); + ASSERT(!instr->InputAt(1)->IsRegister() || + ToRegister(instr->InputAt(1)).is(eax)); + ASSERT(ToDoubleRegister(instr->InputAt(0)).is(xmm2)); + ASSERT(ToDoubleRegister(instr->result()).is(xmm3)); + + if (exponent_type.IsTagged()) { + Label no_deopt; + __ JumpIfSmi(eax, &no_deopt); + __ CmpObjectType(eax, HEAP_NUMBER_TYPE, ecx); + DeoptimizeIf(not_equal, instr->environment()); + __ bind(&no_deopt); + MathPowStub stub(MathPowStub::TAGGED); + __ CallStub(&stub); } else if (exponent_type.IsInteger32()) { - // It is safe to use ebx directly since the instruction is marked - // as a call. - ASSERT(!ToRegister(right).is(ebx)); - __ PrepareCallCFunction(4, ebx); - __ movdbl(Operand(esp, 0 * kDoubleSize), ToDoubleRegister(left)); - __ mov(Operand(esp, 1 * kDoubleSize), ToRegister(right)); - __ CallCFunction(ExternalReference::power_double_int_function(isolate()), - 4); + MathPowStub stub(MathPowStub::INTEGER); + __ CallStub(&stub); } else { - ASSERT(exponent_type.IsTagged()); - CpuFeatures::Scope scope(SSE2); - Register right_reg = ToRegister(right); - - Label non_smi, call; - __ JumpIfNotSmi(right_reg, &non_smi); - __ SmiUntag(right_reg); - __ cvtsi2sd(result_reg, Operand(right_reg)); - __ jmp(&call); - - __ bind(&non_smi); - // It is safe to use ebx directly since the instruction is marked - // as a call. - ASSERT(!right_reg.is(ebx)); - __ CmpObjectType(right_reg, HEAP_NUMBER_TYPE , ebx); - DeoptimizeIf(not_equal, instr->environment()); - __ movdbl(result_reg, FieldOperand(right_reg, HeapNumber::kValueOffset)); - - __ bind(&call); - __ PrepareCallCFunction(4, ebx); - __ movdbl(Operand(esp, 0 * kDoubleSize), ToDoubleRegister(left)); - __ movdbl(Operand(esp, 1 * kDoubleSize), result_reg); - __ CallCFunction(ExternalReference::power_double_double_function(isolate()), - 4); + ASSERT(exponent_type.IsDouble()); + MathPowStub stub(MathPowStub::DOUBLE); + __ CallStub(&stub); } - - // Return value is in st(0) on ia32. - // Store it into the (fixed) result register. - __ sub(Operand(esp), Immediate(kDoubleSize)); - __ fstp_d(Operand(esp, 0)); - __ movdbl(result_reg, Operand(esp, 0)); - __ add(Operand(esp), Immediate(kDoubleSize)); } @@ -3072,9 +3083,6 @@ void LCodeGen::DoUnaryMathOperation(LUnaryMathOperation* instr) { case kMathSqrt: DoMathSqrt(instr); break; - case kMathPowHalf: - DoMathPowHalf(instr); - break; case kMathCos: DoMathCos(instr); break; @@ -3159,7 +3167,7 @@ void LCodeGen::DoCallGlobal(LCallGlobal* instr) { void LCodeGen::DoCallKnownGlobal(LCallKnownGlobal* instr) { ASSERT(ToRegister(instr->result()).is(eax)); - __ mov(edi, instr->target()); + __ LoadHeapObject(edi, instr->target()); CallKnownFunction(instr->target(), instr->arity(), instr, CALL_AS_FUNCTION); } @@ -3524,16 +3532,8 @@ void LCodeGen::DoStringLength(LStringLength* instr) { void LCodeGen::DoStringAdd(LStringAdd* instr) { - if (instr->left()->IsConstantOperand()) { - __ push(ToImmediate(instr->left())); - } else { - __ push(ToOperand(instr->left())); - } - if (instr->right()->IsConstantOperand()) { - __ push(ToImmediate(instr->right())); - } else { - __ push(ToOperand(instr->right())); - } + EmitPushTaggedOperand(instr->left()); + EmitPushTaggedOperand(instr->right()); StringAddStub stub(NO_STRING_CHECK_IN_STUB); CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); } @@ -4032,7 +4032,7 @@ void LCodeGen::DoCheckFunction(LCheckFunction* instr) { __ cmp(reg, Operand::Cell(cell)); } else { Operand operand = ToOperand(instr->value()); - __ cmp(operand, instr->hydrogen()->target()); + __ cmp(operand, target); } DeoptimizeIf(not_equal, instr->environment()); } @@ -4096,17 +4096,6 @@ void LCodeGen::DoClampTToUint8(LClampTToUint8* instr) { } -void LCodeGen::LoadHeapObject(Register result, Handle<HeapObject> object) { - if (isolate()->heap()->InNewSpace(*object)) { - Handle<JSGlobalPropertyCell> cell = - isolate()->factory()->NewJSGlobalPropertyCell(object); - __ mov(result, Operand::Cell(cell)); - } else { - __ mov(result, object); - } -} - - void LCodeGen::DoCheckPrototypeMaps(LCheckPrototypeMaps* instr) { Register reg = ToRegister(instr->TempAt(0)); @@ -4114,7 +4103,7 @@ void LCodeGen::DoCheckPrototypeMaps(LCheckPrototypeMaps* instr) { Handle<JSObject> current_prototype = instr->prototype(); // Load prototype object. - LoadHeapObject(reg, current_prototype); + __ LoadHeapObject(reg, current_prototype); // Check prototype maps up to the holder. while (!current_prototype.is_identical_to(holder)) { @@ -4124,7 +4113,7 @@ void LCodeGen::DoCheckPrototypeMaps(LCheckPrototypeMaps* instr) { current_prototype = Handle<JSObject>(JSObject::cast(current_prototype->GetPrototype())); // Load next prototype object. - LoadHeapObject(reg, current_prototype); + __ LoadHeapObject(reg, current_prototype); } // Check the holder map. @@ -4136,17 +4125,32 @@ void LCodeGen::DoCheckPrototypeMaps(LCheckPrototypeMaps* instr) { void LCodeGen::DoArrayLiteral(LArrayLiteral* instr) { ASSERT(ToRegister(instr->context()).is(esi)); - - Handle<FixedArray> constant_elements = instr->hydrogen()->constant_elements(); - ASSERT_EQ(2, constant_elements->length()); - ElementsKind constant_elements_kind = - static_cast<ElementsKind>(Smi::cast(constant_elements->get(0))->value()); + Heap* heap = isolate()->heap(); + ElementsKind boilerplate_elements_kind = + instr->hydrogen()->boilerplate_elements_kind(); + + // Deopt if the array literal boilerplate ElementsKind is of a type different + // than the expected one. The check isn't necessary if the boilerplate has + // already been converted to FAST_ELEMENTS. + if (boilerplate_elements_kind != FAST_ELEMENTS) { + __ LoadHeapObject(eax, instr->hydrogen()->boilerplate_object()); + __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset)); + // Load the map's "bit field 2". We only need the first byte, + // but the following masking takes care of that anyway. + __ mov(ebx, FieldOperand(ebx, Map::kBitField2Offset)); + // Retrieve elements_kind from bit field 2. + __ and_(ebx, Map::kElementsKindMask); + __ cmp(ebx, boilerplate_elements_kind << Map::kElementsKindShift); + DeoptimizeIf(not_equal, instr->environment()); + } // Setup the parameters to the stub/runtime call. __ mov(eax, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset)); __ push(FieldOperand(eax, JSFunction::kLiteralsOffset)); __ push(Immediate(Smi::FromInt(instr->hydrogen()->literal_index()))); - __ push(Immediate(constant_elements)); + // Boilerplate already exists, constant elements are never accessed. + // Pass an empty fixed array. + __ push(Immediate(Handle<FixedArray>(heap->empty_fixed_array()))); // Pick the right runtime function or stub to call. int length = instr->hydrogen()->length(); @@ -4162,9 +4166,9 @@ void LCodeGen::DoArrayLiteral(LArrayLiteral* instr) { CallRuntime(Runtime::kCreateArrayLiteralShallow, 3, instr); } else { FastCloneShallowArrayStub::Mode mode = - constant_elements_kind == FAST_DOUBLE_ELEMENTS - ? FastCloneShallowArrayStub::CLONE_DOUBLE_ELEMENTS - : FastCloneShallowArrayStub::CLONE_ELEMENTS; + boilerplate_elements_kind == FAST_DOUBLE_ELEMENTS + ? FastCloneShallowArrayStub::CLONE_DOUBLE_ELEMENTS + : FastCloneShallowArrayStub::CLONE_ELEMENTS; FastCloneShallowArrayStub stub(mode, length); CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); } @@ -4179,7 +4183,7 @@ void LCodeGen::EmitDeepCopy(Handle<JSObject> object, ASSERT(!result.is(ecx)); if (FLAG_debug_code) { - LoadHeapObject(ecx, object); + __ LoadHeapObject(ecx, object); __ cmp(source, ecx); __ Assert(equal, "Unexpected object literal boilerplate"); } @@ -4209,10 +4213,10 @@ void LCodeGen::EmitDeepCopy(Handle<JSObject> object, Handle<JSObject> value_object = Handle<JSObject>::cast(value); __ lea(ecx, Operand(result, *offset)); __ mov(FieldOperand(result, total_offset), ecx); - LoadHeapObject(source, value_object); + __ LoadHeapObject(source, value_object); EmitDeepCopy(value_object, result, source, offset); } else if (value->IsHeapObject()) { - LoadHeapObject(ecx, Handle<HeapObject>::cast(value)); + __ LoadHeapObject(ecx, Handle<HeapObject>::cast(value)); __ mov(FieldOperand(result, total_offset), ecx); } else { __ mov(FieldOperand(result, total_offset), Immediate(value)); @@ -4237,7 +4241,7 @@ void LCodeGen::DoObjectLiteralFast(LObjectLiteralFast* instr) { __ bind(&allocated); int offset = 0; - LoadHeapObject(ebx, instr->hydrogen()->boilerplate()); + __ LoadHeapObject(ebx, instr->hydrogen()->boilerplate()); EmitDeepCopy(instr->hydrogen()->boilerplate(), eax, ebx, &offset); ASSERT_EQ(size, offset); } @@ -4359,11 +4363,7 @@ void LCodeGen::DoFunctionLiteral(LFunctionLiteral* instr) { void LCodeGen::DoTypeof(LTypeof* instr) { LOperand* input = instr->InputAt(1); - if (input->IsConstantOperand()) { - __ push(ToImmediate(input)); - } else { - __ push(ToOperand(input)); - } + EmitPushTaggedOperand(input); CallRuntime(Runtime::kTypeof, 1, instr); } @@ -4487,9 +4487,7 @@ void LCodeGen::EnsureSpaceForLazyDeopt() { int patch_size = Deoptimizer::patch_size(); if (current_pc < last_lazy_deopt_pc_ + patch_size) { int padding_size = last_lazy_deopt_pc_ + patch_size - current_pc; - while (padding_size-- > 0) { - __ nop(); - } + __ Nop(padding_size); } last_lazy_deopt_pc_ = masm()->pc_offset(); } @@ -4513,11 +4511,7 @@ void LCodeGen::DoDeleteProperty(LDeleteProperty* instr) { LOperand* obj = instr->object(); LOperand* key = instr->key(); __ push(ToOperand(obj)); - if (key->IsConstantOperand()) { - __ push(ToImmediate(key)); - } else { - __ push(ToOperand(key)); - } + EmitPushTaggedOperand(key); ASSERT(instr->HasPointerMap() && instr->HasDeoptimizationEnvironment()); LPointerMap* pointers = instr->pointer_map(); RecordPosition(pointers->position()); @@ -4614,16 +4608,8 @@ void LCodeGen::DoOsrEntry(LOsrEntry* instr) { void LCodeGen::DoIn(LIn* instr) { LOperand* obj = instr->object(); LOperand* key = instr->key(); - if (key->IsConstantOperand()) { - __ push(ToImmediate(key)); - } else { - __ push(ToOperand(key)); - } - if (obj->IsConstantOperand()) { - __ push(ToImmediate(obj)); - } else { - __ push(ToOperand(obj)); - } + EmitPushTaggedOperand(key); + EmitPushTaggedOperand(obj); ASSERT(instr->HasPointerMap() && instr->HasDeoptimizationEnvironment()); LPointerMap* pointers = instr->pointer_map(); RecordPosition(pointers->position()); |