| Index: src/ia32/lithium-codegen-ia32.cc
|
| ===================================================================
|
| --- src/ia32/lithium-codegen-ia32.cc (revision 7180)
|
| +++ src/ia32/lithium-codegen-ia32.cc (working copy)
|
| @@ -55,7 +55,7 @@
|
| // Ensure that we have enough space in the reloc info to patch
|
| // this with calls when doing deoptimization.
|
| if (ensure_reloc_space_) {
|
| - codegen_->masm()->RecordComment(RelocInfo::kFillerCommentString, true);
|
| + codegen_->EnsureRelocSpaceForDeoptimization();
|
| }
|
| codegen_->RecordSafepoint(pointers_, deoptimization_index_);
|
| }
|
| @@ -78,6 +78,7 @@
|
| return GeneratePrologue() &&
|
| GenerateBody() &&
|
| GenerateDeferredCode() &&
|
| + GenerateRelocPadding() &&
|
| GenerateSafepointTable();
|
| }
|
|
|
| @@ -92,8 +93,8 @@
|
|
|
| void LCodeGen::Abort(const char* format, ...) {
|
| if (FLAG_trace_bailout) {
|
| - SmartPointer<char> debug_name = graph()->debug_name()->ToCString();
|
| - PrintF("Aborting LCodeGen in @\"%s\": ", *debug_name);
|
| + SmartPointer<char> name(info()->shared_info()->DebugName()->ToCString());
|
| + PrintF("Aborting LCodeGen in @\"%s\": ", *name);
|
| va_list arguments;
|
| va_start(arguments, format);
|
| OS::VPrint(format, arguments);
|
| @@ -122,6 +123,16 @@
|
| }
|
|
|
|
|
| +bool LCodeGen::GenerateRelocPadding() {
|
| + int reloc_size = masm()->relocation_writer_size();
|
| + while (reloc_size < deoptimization_reloc_size.min_size) {
|
| + __ RecordComment(RelocInfo::kFillerCommentString, true);
|
| + reloc_size += RelocInfo::kMinRelocCommentSize;
|
| + }
|
| + return !is_aborted();
|
| +}
|
| +
|
| +
|
| bool LCodeGen::GeneratePrologue() {
|
| ASSERT(is_generating());
|
|
|
| @@ -163,6 +174,45 @@
|
| }
|
| }
|
|
|
| + // Possibly allocate a local context.
|
| + int heap_slots = scope()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS;
|
| + if (heap_slots > 0) {
|
| + Comment(";;; Allocate local context");
|
| + // Argument to NewContext is the function, which is still in edi.
|
| + __ push(edi);
|
| + if (heap_slots <= FastNewContextStub::kMaximumSlots) {
|
| + FastNewContextStub stub(heap_slots);
|
| + __ CallStub(&stub);
|
| + } else {
|
| + __ CallRuntime(Runtime::kNewContext, 1);
|
| + }
|
| + RecordSafepoint(Safepoint::kNoDeoptimizationIndex);
|
| + // Context is returned in both eax and esi. It replaces the context
|
| + // passed to us. It's saved in the stack and kept live in esi.
|
| + __ mov(Operand(ebp, StandardFrameConstants::kContextOffset), esi);
|
| +
|
| + // Copy parameters into context if necessary.
|
| + int num_parameters = scope()->num_parameters();
|
| + for (int i = 0; i < num_parameters; i++) {
|
| + Slot* slot = scope()->parameter(i)->AsSlot();
|
| + if (slot != NULL && slot->type() == Slot::CONTEXT) {
|
| + int parameter_offset = StandardFrameConstants::kCallerSPOffset +
|
| + (num_parameters - 1 - i) * kPointerSize;
|
| + // Load parameter from stack.
|
| + __ mov(eax, Operand(ebp, parameter_offset));
|
| + // Store it in the context.
|
| + int context_offset = Context::SlotOffset(slot->index());
|
| + __ mov(Operand(esi, context_offset), eax);
|
| + // Update the write barrier. This clobbers all involved
|
| + // registers, so we have to use a third register to avoid
|
| + // clobbering esi.
|
| + __ mov(ecx, esi);
|
| + __ RecordWrite(ecx, context_offset, eax, ebx);
|
| + }
|
| + }
|
| + Comment(";;; End allocate local context");
|
| + }
|
| +
|
| // Trace the call.
|
| if (FLAG_trace) {
|
| // We have not executed any compiled code yet, so esi still holds the
|
| @@ -335,6 +385,22 @@
|
| }
|
|
|
|
|
| +void LCodeGen::EnsureRelocSpaceForDeoptimization() {
|
| + // Since we patch the reloc info with RUNTIME_ENTRY calls every patch
|
| + // site will take up 2 bytes + any pc-jumps.
|
| + // We are conservative and always reserver 6 bytes in case where a
|
| + // simple pc-jump is not enough.
|
| + uint32_t pc_delta =
|
| + masm()->pc_offset() - deoptimization_reloc_size.last_pc_offset;
|
| + if (is_uintn(pc_delta, 6)) {
|
| + deoptimization_reloc_size.min_size += 2;
|
| + } else {
|
| + deoptimization_reloc_size.min_size += 6;
|
| + }
|
| + deoptimization_reloc_size.last_pc_offset = masm()->pc_offset();
|
| +}
|
| +
|
| +
|
| void LCodeGen::AddToTranslation(Translation* translation,
|
| LOperand* op,
|
| bool is_tagged) {
|
| @@ -382,10 +448,13 @@
|
| ASSERT(instr != NULL);
|
| LPointerMap* pointers = instr->pointer_map();
|
| RecordPosition(pointers->position());
|
| +
|
| if (!adjusted) {
|
| __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
|
| }
|
| __ call(code, mode);
|
| +
|
| + EnsureRelocSpaceForDeoptimization();
|
| RegisterLazyDeoptimization(instr);
|
|
|
| // Signal that we don't inline smi code before these stubs in the
|
| @@ -519,7 +588,8 @@
|
| Handle<DeoptimizationInputData> data =
|
| Factory::NewDeoptimizationInputData(length, TENURED);
|
|
|
| - data->SetTranslationByteArray(*translations_.CreateByteArray());
|
| + Handle<ByteArray> translations = translations_.CreateByteArray();
|
| + data->SetTranslationByteArray(*translations);
|
| data->SetInlinedFunctionCount(Smi::FromInt(inlined_function_count_));
|
|
|
| Handle<FixedArray> literals =
|
| @@ -595,6 +665,12 @@
|
| }
|
|
|
|
|
| +void LCodeGen::RecordSafepoint(int deoptimization_index) {
|
| + LPointerMap empty_pointers(RelocInfo::kNoPosition);
|
| + RecordSafepoint(&empty_pointers, deoptimization_index);
|
| +}
|
| +
|
| +
|
| void LCodeGen::RecordSafepointWithRegisters(LPointerMap* pointers,
|
| int arguments,
|
| int deoptimization_index) {
|
| @@ -667,16 +743,6 @@
|
| CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
|
| break;
|
| }
|
| - case CodeStub::StringCharAt: {
|
| - StringCharAtStub stub;
|
| - CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
|
| - break;
|
| - }
|
| - case CodeStub::MathPow: {
|
| - MathPowStub stub;
|
| - CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
|
| - break;
|
| - }
|
| case CodeStub::NumberToString: {
|
| NumberToStringStub stub;
|
| CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
|
| @@ -710,41 +776,64 @@
|
|
|
|
|
| void LCodeGen::DoModI(LModI* instr) {
|
| - LOperand* right = instr->InputAt(1);
|
| - ASSERT(ToRegister(instr->result()).is(edx));
|
| - ASSERT(ToRegister(instr->InputAt(0)).is(eax));
|
| - ASSERT(!ToRegister(instr->InputAt(1)).is(eax));
|
| - ASSERT(!ToRegister(instr->InputAt(1)).is(edx));
|
| + if (instr->hydrogen()->HasPowerOf2Divisor()) {
|
| + Register dividend = ToRegister(instr->InputAt(0));
|
|
|
| - Register right_reg = ToRegister(right);
|
| + int32_t divisor =
|
| + HConstant::cast(instr->hydrogen()->right())->Integer32Value();
|
|
|
| - // Check for x % 0.
|
| - if (instr->hydrogen()->CheckFlag(HValue::kCanBeDivByZero)) {
|
| - __ test(right_reg, ToOperand(right));
|
| - DeoptimizeIf(zero, instr->environment());
|
| - }
|
| + if (divisor < 0) divisor = -divisor;
|
|
|
| - // Sign extend to edx.
|
| - __ cdq();
|
| + NearLabel positive_dividend, done;
|
| + __ test(dividend, Operand(dividend));
|
| + __ j(not_sign, &positive_dividend);
|
| + __ neg(dividend);
|
| + __ and_(dividend, divisor - 1);
|
| + __ neg(dividend);
|
| + if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
|
| + __ j(not_zero, &done);
|
| + DeoptimizeIf(no_condition, instr->environment());
|
| + }
|
| + __ bind(&positive_dividend);
|
| + __ and_(dividend, divisor - 1);
|
| + __ bind(&done);
|
| + } else {
|
| + LOperand* right = instr->InputAt(1);
|
| + ASSERT(ToRegister(instr->InputAt(0)).is(eax));
|
| + ASSERT(ToRegister(instr->result()).is(edx));
|
|
|
| - // Check for (0 % -x) that will produce negative zero.
|
| - if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
|
| - NearLabel positive_left;
|
| - NearLabel done;
|
| - __ test(eax, Operand(eax));
|
| - __ j(not_sign, &positive_left);
|
| - __ idiv(right_reg);
|
| + Register right_reg = ToRegister(right);
|
| + ASSERT(!right_reg.is(eax));
|
| + ASSERT(!right_reg.is(edx));
|
|
|
| - // Test the remainder for 0, because then the result would be -0.
|
| - __ test(edx, Operand(edx));
|
| - __ j(not_zero, &done);
|
| + // Check for x % 0.
|
| + if (instr->hydrogen()->CheckFlag(HValue::kCanBeDivByZero)) {
|
| + __ test(right_reg, ToOperand(right));
|
| + DeoptimizeIf(zero, instr->environment());
|
| + }
|
|
|
| - DeoptimizeIf(no_condition, instr->environment());
|
| - __ bind(&positive_left);
|
| - __ idiv(right_reg);
|
| - __ bind(&done);
|
| - } else {
|
| - __ idiv(right_reg);
|
| + // Sign extend to edx.
|
| + __ cdq();
|
| +
|
| + // Check for (0 % -x) that will produce negative zero.
|
| + if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
|
| + NearLabel positive_left;
|
| + NearLabel done;
|
| + __ test(eax, Operand(eax));
|
| + __ j(not_sign, &positive_left);
|
| + __ idiv(right_reg);
|
| +
|
| + // Test the remainder for 0, because then the result would be -0.
|
| + __ test(edx, Operand(edx));
|
| + __ j(not_zero, &done);
|
| +
|
| + DeoptimizeIf(no_condition, instr->environment());
|
| + __ bind(&positive_left);
|
| + __ idiv(right_reg);
|
| + __ bind(&done);
|
| + } else {
|
| + __ idiv(right_reg);
|
| + }
|
| }
|
| }
|
|
|
| @@ -1010,10 +1099,10 @@
|
| }
|
|
|
|
|
| -void LCodeGen::DoPixelArrayLength(LPixelArrayLength* instr) {
|
| +void LCodeGen::DoExternalArrayLength(LExternalArrayLength* instr) {
|
| Register result = ToRegister(instr->result());
|
| Register array = ToRegister(instr->InputAt(0));
|
| - __ mov(result, FieldOperand(array, PixelArray::kLengthOffset));
|
| + __ mov(result, FieldOperand(array, ExternalArray::kLengthOffset));
|
| }
|
|
|
|
|
| @@ -1072,35 +1161,36 @@
|
|
|
|
|
| void LCodeGen::DoArithmeticD(LArithmeticD* instr) {
|
| - LOperand* left = instr->InputAt(0);
|
| - LOperand* right = instr->InputAt(1);
|
| + XMMRegister left = ToDoubleRegister(instr->InputAt(0));
|
| + XMMRegister right = ToDoubleRegister(instr->InputAt(1));
|
| + XMMRegister result = ToDoubleRegister(instr->result());
|
| // Modulo uses a fixed result register.
|
| - ASSERT(instr->op() == Token::MOD || left->Equals(instr->result()));
|
| + ASSERT(instr->op() == Token::MOD || left.is(result));
|
| switch (instr->op()) {
|
| case Token::ADD:
|
| - __ addsd(ToDoubleRegister(left), ToDoubleRegister(right));
|
| + __ addsd(left, right);
|
| break;
|
| case Token::SUB:
|
| - __ subsd(ToDoubleRegister(left), ToDoubleRegister(right));
|
| + __ subsd(left, right);
|
| break;
|
| case Token::MUL:
|
| - __ mulsd(ToDoubleRegister(left), ToDoubleRegister(right));
|
| + __ mulsd(left, right);
|
| break;
|
| case Token::DIV:
|
| - __ divsd(ToDoubleRegister(left), ToDoubleRegister(right));
|
| + __ divsd(left, right);
|
| break;
|
| case Token::MOD: {
|
| // Pass two doubles as arguments on the stack.
|
| __ PrepareCallCFunction(4, eax);
|
| - __ movdbl(Operand(esp, 0 * kDoubleSize), ToDoubleRegister(left));
|
| - __ movdbl(Operand(esp, 1 * kDoubleSize), ToDoubleRegister(right));
|
| + __ movdbl(Operand(esp, 0 * kDoubleSize), left);
|
| + __ movdbl(Operand(esp, 1 * kDoubleSize), right);
|
| __ CallCFunction(ExternalReference::double_fp_operation(Token::MOD), 4);
|
|
|
| // 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(ToDoubleRegister(instr->result()), Operand(esp, 0));
|
| + __ movdbl(result, Operand(esp, 0));
|
| __ add(Operand(esp), Immediate(kDoubleSize));
|
| break;
|
| }
|
| @@ -1577,6 +1667,19 @@
|
| }
|
|
|
|
|
| +void LCodeGen::DoGetCachedArrayIndex(LGetCachedArrayIndex* instr) {
|
| + Register input = ToRegister(instr->InputAt(0));
|
| + Register result = ToRegister(instr->result());
|
| +
|
| + if (FLAG_debug_code) {
|
| + __ AbortIfNotString(input);
|
| + }
|
| +
|
| + __ mov(result, FieldOperand(input, String::kHashFieldOffset));
|
| + __ IndexFromHash(result, result);
|
| +}
|
| +
|
| +
|
| void LCodeGen::DoHasCachedArrayIndex(LHasCachedArrayIndex* instr) {
|
| Register input = ToRegister(instr->InputAt(0));
|
| Register result = ToRegister(instr->result());
|
| @@ -1586,7 +1689,7 @@
|
| __ test(FieldOperand(input, String::kHashFieldOffset),
|
| Immediate(String::kContainsCachedArrayIndexMask));
|
| NearLabel done;
|
| - __ j(not_zero, &done);
|
| + __ j(zero, &done);
|
| __ mov(result, Factory::false_value());
|
| __ bind(&done);
|
| }
|
| @@ -1601,7 +1704,7 @@
|
|
|
| __ test(FieldOperand(input, String::kHashFieldOffset),
|
| Immediate(String::kContainsCachedArrayIndexMask));
|
| - EmitBranch(true_block, false_block, not_equal);
|
| + EmitBranch(true_block, false_block, equal);
|
| }
|
|
|
|
|
| @@ -1833,19 +1936,11 @@
|
| __ mov(InstanceofStub::right(), Immediate(instr->function()));
|
| static const int kAdditionalDelta = 16;
|
| int delta = masm_->SizeOfCodeGeneratedSince(map_check) + kAdditionalDelta;
|
| - Label before_push_delta;
|
| - __ bind(&before_push_delta);
|
| __ mov(temp, Immediate(delta));
|
| - __ mov(Operand(esp, EspIndexForPushAll(temp) * kPointerSize), temp);
|
| - __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
|
| - __ call(stub.GetCode(), RelocInfo::CODE_TARGET);
|
| - ASSERT_EQ(kAdditionalDelta,
|
| - masm_->SizeOfCodeGeneratedSince(&before_push_delta));
|
| - RecordSafepointWithRegisters(
|
| - instr->pointer_map(), 0, Safepoint::kNoDeoptimizationIndex);
|
| + __ StoreToSafepointRegisterSlot(temp, temp);
|
| + CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr, false);
|
| // Put the result value into the eax slot and restore all registers.
|
| - __ mov(Operand(esp, EspIndexForPushAll(eax) * kPointerSize), eax);
|
| -
|
| + __ StoreToSafepointRegisterSlot(eax, eax);
|
| __ PopSafepointRegisters();
|
| }
|
|
|
| @@ -2059,7 +2154,7 @@
|
| Immediate(Factory::fixed_array_map()));
|
| __ j(equal, &done);
|
| __ cmp(FieldOperand(result, HeapObject::kMapOffset),
|
| - Immediate(Factory::pixel_array_map()));
|
| + Immediate(Factory::external_pixel_array_map()));
|
| __ j(equal, &done);
|
| __ cmp(FieldOperand(result, HeapObject::kMapOffset),
|
| Immediate(Factory::fixed_cow_array_map()));
|
| @@ -2069,11 +2164,12 @@
|
| }
|
|
|
|
|
| -void LCodeGen::DoLoadPixelArrayExternalPointer(
|
| - LLoadPixelArrayExternalPointer* instr) {
|
| +void LCodeGen::DoLoadExternalArrayPointer(
|
| + LLoadExternalArrayPointer* instr) {
|
| Register result = ToRegister(instr->result());
|
| Register input = ToRegister(instr->InputAt(0));
|
| - __ mov(result, FieldOperand(input, PixelArray::kExternalPointerOffset));
|
| + __ mov(result, FieldOperand(input,
|
| + ExternalArray::kExternalPointerOffset));
|
| }
|
|
|
|
|
| @@ -2111,13 +2207,13 @@
|
|
|
|
|
| void LCodeGen::DoLoadPixelArrayElement(LLoadPixelArrayElement* instr) {
|
| - Register external_elements = ToRegister(instr->external_pointer());
|
| + Register external_pointer = ToRegister(instr->external_pointer());
|
| Register key = ToRegister(instr->key());
|
| Register result = ToRegister(instr->result());
|
| - ASSERT(result.is(external_elements));
|
| + ASSERT(result.is(external_pointer));
|
|
|
| // Load the result.
|
| - __ movzx_b(result, Operand(external_elements, key, times_1, 0));
|
| + __ movzx_b(result, Operand(external_pointer, key, times_1, 0));
|
| }
|
|
|
|
|
| @@ -2290,7 +2386,7 @@
|
| LInstruction* instr) {
|
| // Change context if needed.
|
| bool change_context =
|
| - (graph()->info()->closure()->context() != function->context()) ||
|
| + (info()->closure()->context() != function->context()) ||
|
| scope()->contains_with() ||
|
| (scope()->num_heap_slots() > 0);
|
| if (change_context) {
|
| @@ -2309,14 +2405,11 @@
|
| RecordPosition(pointers->position());
|
|
|
| // Invoke function.
|
| - if (*function == *graph()->info()->closure()) {
|
| + if (*function == *info()->closure()) {
|
| __ CallSelf();
|
| } else {
|
| - // This is an indirect call and will not be recorded in the reloc info.
|
| - // Add a comment to the reloc info in case we need to patch this during
|
| - // deoptimization.
|
| - __ RecordComment(RelocInfo::kFillerCommentString, true);
|
| __ call(FieldOperand(edi, JSFunction::kCodeEntryOffset));
|
| + EnsureRelocSpaceForDeoptimization();
|
| }
|
|
|
| // Setup deoptimization.
|
| @@ -2371,7 +2464,7 @@
|
| if (!tmp.is(eax)) __ mov(tmp, eax);
|
|
|
| // Restore input_reg after call to runtime.
|
| - __ mov(input_reg, Operand(esp, EspIndexForPushAll(input_reg) * kPointerSize));
|
| + __ LoadFromSafepointRegisterSlot(input_reg, input_reg);
|
|
|
| __ bind(&allocated);
|
| __ mov(tmp2, FieldOperand(input_reg, HeapNumber::kExponentOffset));
|
| @@ -2379,7 +2472,7 @@
|
| __ mov(FieldOperand(tmp, HeapNumber::kExponentOffset), tmp2);
|
| __ mov(tmp2, FieldOperand(input_reg, HeapNumber::kMantissaOffset));
|
| __ mov(FieldOperand(tmp, HeapNumber::kMantissaOffset), tmp2);
|
| - __ mov(Operand(esp, EspIndexForPushAll(input_reg) * kPointerSize), tmp);
|
| + __ StoreToSafepointRegisterSlot(input_reg, tmp);
|
|
|
| __ bind(&done);
|
| __ PopSafepointRegisters();
|
| @@ -2504,11 +2597,6 @@
|
| XMMRegister xmm_scratch = xmm0;
|
| XMMRegister input_reg = ToDoubleRegister(instr->InputAt(0));
|
| ASSERT(ToDoubleRegister(instr->result()).is(input_reg));
|
| - ExternalReference negative_infinity =
|
| - ExternalReference::address_of_negative_infinity();
|
| - __ movdbl(xmm_scratch, Operand::StaticVariable(negative_infinity));
|
| - __ ucomisd(xmm_scratch, input_reg);
|
| - DeoptimizeIf(equal, instr->environment());
|
| __ xorpd(xmm_scratch, xmm_scratch);
|
| __ addsd(input_reg, xmm_scratch); // Convert -0 to +0.
|
| __ sqrtsd(input_reg, input_reg);
|
| @@ -2731,7 +2819,9 @@
|
| ASSERT(ToRegister(instr->value()).is(eax));
|
|
|
| __ mov(ecx, instr->name());
|
| - Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
|
| + Handle<Code> ic(Builtins::builtin(
|
| + info_->is_strict() ? Builtins::StoreIC_Initialize_Strict
|
| + : Builtins::StoreIC_Initialize));
|
| CallCode(ic, RelocInfo::CODE_TARGET, instr);
|
| }
|
|
|
| @@ -2742,6 +2832,25 @@
|
| }
|
|
|
|
|
| +void LCodeGen::DoStorePixelArrayElement(LStorePixelArrayElement* instr) {
|
| + Register external_pointer = ToRegister(instr->external_pointer());
|
| + Register key = ToRegister(instr->key());
|
| + Register value = ToRegister(instr->value());
|
| + ASSERT(ToRegister(instr->TempAt(0)).is(eax));
|
| +
|
| + __ mov(eax, value);
|
| + { // Clamp the value to [0..255].
|
| + NearLabel done;
|
| + __ test(eax, Immediate(0xFFFFFF00));
|
| + __ j(zero, &done);
|
| + __ setcc(negative, eax); // 1 if negative, 0 if positive.
|
| + __ dec_b(eax); // 0 if negative, 255 if positive.
|
| + __ bind(&done);
|
| + }
|
| + __ mov_b(Operand(external_pointer, key, times_1, 0), eax);
|
| +}
|
| +
|
| +
|
| void LCodeGen::DoStoreKeyedFastElement(LStoreKeyedFastElement* instr) {
|
| Register value = ToRegister(instr->value());
|
| Register elements = ToRegister(instr->object());
|
| @@ -2780,7 +2889,9 @@
|
| ASSERT(ToRegister(instr->key()).is(ecx));
|
| ASSERT(ToRegister(instr->value()).is(eax));
|
|
|
| - Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize));
|
| + Handle<Code> ic(Builtins::builtin(
|
| + info_->is_strict() ? Builtins::KeyedStoreIC_Initialize_Strict
|
| + : Builtins::KeyedStoreIC_Initialize));
|
| CallCode(ic, RelocInfo::CODE_TARGET, instr);
|
| }
|
|
|
| @@ -2851,19 +2962,20 @@
|
| __ test(result, Immediate(kStringRepresentationMask));
|
| __ j(not_zero, deferred->entry());
|
|
|
| - // Check for 1-byte or 2-byte string.
|
| + // Check for ASCII or two-byte string.
|
| __ bind(&flat_string);
|
| STATIC_ASSERT(kAsciiStringTag != 0);
|
| __ test(result, Immediate(kStringEncodingMask));
|
| __ j(not_zero, &ascii_string);
|
|
|
| - // 2-byte string.
|
| - // Load the 2-byte character code into the result register.
|
| + // Two-byte string.
|
| + // Load the two-byte character code into the result register.
|
| STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize == 1);
|
| if (instr->index()->IsConstantOperand()) {
|
| __ movzx_w(result,
|
| FieldOperand(string,
|
| - SeqTwoByteString::kHeaderSize + 2 * const_index));
|
| + SeqTwoByteString::kHeaderSize +
|
| + (kUC16Size * const_index)));
|
| } else {
|
| __ movzx_w(result, FieldOperand(string,
|
| index,
|
| @@ -2919,11 +3031,61 @@
|
| __ AbortIfNotSmi(eax);
|
| }
|
| __ SmiUntag(eax);
|
| - __ mov(Operand(esp, EspIndexForPushAll(result) * kPointerSize), eax);
|
| + __ StoreToSafepointRegisterSlot(result, eax);
|
| __ PopSafepointRegisters();
|
| }
|
|
|
|
|
| +void LCodeGen::DoStringCharFromCode(LStringCharFromCode* instr) {
|
| + class DeferredStringCharFromCode: public LDeferredCode {
|
| + public:
|
| + DeferredStringCharFromCode(LCodeGen* codegen, LStringCharFromCode* instr)
|
| + : LDeferredCode(codegen), instr_(instr) { }
|
| + virtual void Generate() { codegen()->DoDeferredStringCharFromCode(instr_); }
|
| + private:
|
| + LStringCharFromCode* instr_;
|
| + };
|
| +
|
| + DeferredStringCharFromCode* deferred =
|
| + new DeferredStringCharFromCode(this, instr);
|
| +
|
| + ASSERT(instr->hydrogen()->value()->representation().IsInteger32());
|
| + Register char_code = ToRegister(instr->char_code());
|
| + Register result = ToRegister(instr->result());
|
| + ASSERT(!char_code.is(result));
|
| +
|
| + __ cmp(char_code, String::kMaxAsciiCharCode);
|
| + __ j(above, deferred->entry());
|
| + __ Set(result, Immediate(Factory::single_character_string_cache()));
|
| + __ mov(result, FieldOperand(result,
|
| + char_code, times_pointer_size,
|
| + FixedArray::kHeaderSize));
|
| + __ cmp(result, Factory::undefined_value());
|
| + __ j(equal, deferred->entry());
|
| + __ bind(deferred->exit());
|
| +}
|
| +
|
| +
|
| +void LCodeGen::DoDeferredStringCharFromCode(LStringCharFromCode* instr) {
|
| + Register char_code = ToRegister(instr->char_code());
|
| + Register result = ToRegister(instr->result());
|
| +
|
| + // TODO(3095996): Get rid of this. For now, we need to make the
|
| + // result register contain a valid pointer because it is already
|
| + // contained in the register pointer map.
|
| + __ Set(result, Immediate(0));
|
| +
|
| + __ PushSafepointRegisters();
|
| + __ SmiTag(char_code);
|
| + __ push(char_code);
|
| + __ CallRuntimeSaveDoubles(Runtime::kCharFromCode);
|
| + RecordSafepointWithRegisters(
|
| + instr->pointer_map(), 1, Safepoint::kNoDeoptimizationIndex);
|
| + __ StoreToSafepointRegisterSlot(result, eax);
|
| + __ PopSafepointRegisters();
|
| +}
|
| +
|
| +
|
| void LCodeGen::DoStringLength(LStringLength* instr) {
|
| Register string = ToRegister(instr->string());
|
| Register result = ToRegister(instr->result());
|
| @@ -2987,7 +3149,7 @@
|
| // TODO(3095996): Put a valid pointer value in the stack slot where the result
|
| // register is stored, as this register is in the pointer map, but contains an
|
| // integer value.
|
| - __ mov(Operand(esp, EspIndexForPushAll(reg) * kPointerSize), Immediate(0));
|
| + __ StoreToSafepointRegisterSlot(reg, Immediate(0));
|
|
|
| __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
|
| __ CallRuntimeSaveDoubles(Runtime::kAllocateHeapNumber);
|
| @@ -2999,7 +3161,7 @@
|
| // number.
|
| __ bind(&done);
|
| __ movdbl(FieldOperand(reg, HeapNumber::kValueOffset), xmm0);
|
| - __ mov(Operand(esp, EspIndexForPushAll(reg) * kPointerSize), reg);
|
| + __ StoreToSafepointRegisterSlot(reg, reg);
|
| __ PopSafepointRegisters();
|
| }
|
|
|
| @@ -3041,7 +3203,7 @@
|
| __ CallRuntimeSaveDoubles(Runtime::kAllocateHeapNumber);
|
| RecordSafepointWithRegisters(
|
| instr->pointer_map(), 0, Safepoint::kNoDeoptimizationIndex);
|
| - __ mov(Operand(esp, EspIndexForPushAll(reg) * kPointerSize), eax);
|
| + __ StoreToSafepointRegisterSlot(reg, eax);
|
| __ PopSafepointRegisters();
|
| }
|
|
|
| @@ -3613,21 +3775,18 @@
|
| Handle<String> type_name) {
|
| Condition final_branch_condition = no_condition;
|
| if (type_name->Equals(Heap::number_symbol())) {
|
| - __ test(input, Immediate(kSmiTagMask));
|
| - __ j(zero, true_label);
|
| + __ JumpIfSmi(input, true_label);
|
| __ cmp(FieldOperand(input, HeapObject::kMapOffset),
|
| Factory::heap_number_map());
|
| final_branch_condition = equal;
|
|
|
| } else if (type_name->Equals(Heap::string_symbol())) {
|
| - __ test(input, Immediate(kSmiTagMask));
|
| - __ j(zero, false_label);
|
| - __ mov(input, FieldOperand(input, HeapObject::kMapOffset));
|
| + __ JumpIfSmi(input, false_label);
|
| + __ CmpObjectType(input, FIRST_NONSTRING_TYPE, input);
|
| + __ j(above_equal, false_label);
|
| __ test_b(FieldOperand(input, Map::kBitFieldOffset),
|
| 1 << Map::kIsUndetectable);
|
| - __ j(not_zero, false_label);
|
| - __ CmpInstanceType(input, FIRST_NONSTRING_TYPE);
|
| - final_branch_condition = below;
|
| + final_branch_condition = zero;
|
|
|
| } else if (type_name->Equals(Heap::boolean_symbol())) {
|
| __ cmp(input, Factory::true_value());
|
| @@ -3638,8 +3797,7 @@
|
| } else if (type_name->Equals(Heap::undefined_symbol())) {
|
| __ cmp(input, Factory::undefined_value());
|
| __ j(equal, true_label);
|
| - __ test(input, Immediate(kSmiTagMask));
|
| - __ j(zero, false_label);
|
| + __ JumpIfSmi(input, false_label);
|
| // Check for undetectable objects => true.
|
| __ mov(input, FieldOperand(input, HeapObject::kMapOffset));
|
| __ test_b(FieldOperand(input, Map::kBitFieldOffset),
|
| @@ -3647,8 +3805,7 @@
|
| final_branch_condition = not_zero;
|
|
|
| } else if (type_name->Equals(Heap::function_symbol())) {
|
| - __ test(input, Immediate(kSmiTagMask));
|
| - __ j(zero, false_label);
|
| + __ JumpIfSmi(input, false_label);
|
| __ CmpObjectType(input, JS_FUNCTION_TYPE, input);
|
| __ j(equal, true_label);
|
| // Regular expressions => 'function' (they are callable).
|
| @@ -3656,22 +3813,18 @@
|
| final_branch_condition = equal;
|
|
|
| } else if (type_name->Equals(Heap::object_symbol())) {
|
| - __ test(input, Immediate(kSmiTagMask));
|
| - __ j(zero, false_label);
|
| + __ JumpIfSmi(input, false_label);
|
| __ cmp(input, Factory::null_value());
|
| __ j(equal, true_label);
|
| // Regular expressions => 'function', not 'object'.
|
| - __ CmpObjectType(input, JS_REGEXP_TYPE, input);
|
| - __ j(equal, false_label);
|
| + __ CmpObjectType(input, FIRST_JS_OBJECT_TYPE, input);
|
| + __ j(below, false_label);
|
| + __ CmpInstanceType(input, FIRST_FUNCTION_CLASS_TYPE);
|
| + __ j(above_equal, false_label);
|
| // Check for undetectable objects => false.
|
| __ test_b(FieldOperand(input, Map::kBitFieldOffset),
|
| 1 << Map::kIsUndetectable);
|
| - __ j(not_zero, false_label);
|
| - // Check for JS objects => true.
|
| - __ CmpInstanceType(input, FIRST_JS_OBJECT_TYPE);
|
| - __ j(below, false_label);
|
| - __ CmpInstanceType(input, LAST_JS_OBJECT_TYPE);
|
| - final_branch_condition = below_equal;
|
| + final_branch_condition = zero;
|
|
|
| } else {
|
| final_branch_condition = not_equal;
|
|
|