| // Copyright 2015 the V8 project authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "src/s390/codegen-s390.h" |
| |
| #if V8_TARGET_ARCH_S390 |
| |
| #include <memory> |
| |
| #include "src/codegen.h" |
| #include "src/macro-assembler.h" |
| #include "src/s390/simulator-s390.h" |
| |
| namespace v8 { |
| namespace internal { |
| |
| #define __ masm. |
| |
| UnaryMathFunctionWithIsolate CreateSqrtFunction(Isolate* isolate) { |
| #if defined(USE_SIMULATOR) |
| return nullptr; |
| #else |
| size_t actual_size; |
| byte* buffer = |
| static_cast<byte*>(base::OS::Allocate(1 * KB, &actual_size, true)); |
| if (buffer == nullptr) return nullptr; |
| |
| MacroAssembler masm(isolate, buffer, static_cast<int>(actual_size), |
| CodeObjectRequired::kNo); |
| |
| __ MovFromFloatParameter(d0); |
| __ sqdbr(d0, d0); |
| __ MovToFloatResult(d0); |
| __ Ret(); |
| |
| CodeDesc desc; |
| masm.GetCode(&desc); |
| DCHECK(ABI_USES_FUNCTION_DESCRIPTORS || !RelocInfo::RequiresRelocation(desc)); |
| |
| Assembler::FlushICache(isolate, buffer, actual_size); |
| base::OS::ProtectCode(buffer, actual_size); |
| return FUNCTION_CAST<UnaryMathFunctionWithIsolate>(buffer); |
| #endif |
| } |
| |
| #undef __ |
| |
| // ------------------------------------------------------------------------- |
| // Platform-specific RuntimeCallHelper functions. |
| |
| void StubRuntimeCallHelper::BeforeCall(MacroAssembler* masm) const { |
| masm->EnterFrame(StackFrame::INTERNAL); |
| DCHECK(!masm->has_frame()); |
| masm->set_has_frame(true); |
| } |
| |
| void StubRuntimeCallHelper::AfterCall(MacroAssembler* masm) const { |
| masm->LeaveFrame(StackFrame::INTERNAL); |
| DCHECK(masm->has_frame()); |
| masm->set_has_frame(false); |
| } |
| |
| // ------------------------------------------------------------------------- |
| // Code generators |
| |
| #define __ ACCESS_MASM(masm) |
| |
| // assume ip can be used as a scratch register below |
| void StringCharLoadGenerator::Generate(MacroAssembler* masm, Register string, |
| Register index, Register result, |
| Label* call_runtime) { |
| Label indirect_string_loaded; |
| __ bind(&indirect_string_loaded); |
| |
| // Fetch the instance type of the receiver into result register. |
| __ LoadP(result, FieldMemOperand(string, HeapObject::kMapOffset)); |
| __ LoadlB(result, FieldMemOperand(result, Map::kInstanceTypeOffset)); |
| |
| // We need special handling for indirect strings. |
| Label check_sequential; |
| __ mov(r0, Operand(kIsIndirectStringMask)); |
| __ AndP(r0, result); |
| __ beq(&check_sequential, Label::kNear /*, cr0*/); |
| |
| // Dispatch on the indirect string shape: slice or cons. |
| Label cons_string, thin_string; |
| __ LoadRR(ip, result); |
| __ nilf(ip, Operand(kStringRepresentationMask)); |
| __ CmpP(ip, Operand(kConsStringTag)); |
| __ beq(&cons_string); |
| __ CmpP(ip, Operand(kThinStringTag)); |
| __ beq(&thin_string); |
| |
| // Handle slices. |
| __ LoadP(result, FieldMemOperand(string, SlicedString::kOffsetOffset)); |
| __ LoadP(string, FieldMemOperand(string, SlicedString::kParentOffset)); |
| __ SmiUntag(ip, result); |
| __ AddP(index, ip); |
| __ b(&indirect_string_loaded); |
| |
| // Handle thin strings. |
| __ bind(&thin_string); |
| __ LoadP(string, FieldMemOperand(string, ThinString::kActualOffset)); |
| __ b(&indirect_string_loaded); |
| |
| // Handle cons strings. |
| // Check whether the right hand side is the empty string (i.e. if |
| // this is really a flat string in a cons string). If that is not |
| // the case we would rather go to the runtime system now to flatten |
| // the string. |
| __ bind(&cons_string); |
| __ LoadP(result, FieldMemOperand(string, ConsString::kSecondOffset)); |
| __ CompareRoot(result, Heap::kempty_stringRootIndex); |
| __ bne(call_runtime); |
| // Get the first of the two strings and load its instance type. |
| __ LoadP(string, FieldMemOperand(string, ConsString::kFirstOffset)); |
| __ b(&indirect_string_loaded); |
| |
| // Distinguish sequential and external strings. Only these two string |
| // representations can reach here (slices and flat cons strings have been |
| // reduced to the underlying sequential or external string). |
| Label external_string, check_encoding; |
| __ bind(&check_sequential); |
| STATIC_ASSERT(kSeqStringTag == 0); |
| __ mov(r0, Operand(kStringRepresentationMask)); |
| __ AndP(r0, result); |
| __ bne(&external_string, Label::kNear); |
| |
| // Prepare sequential strings |
| STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqOneByteString::kHeaderSize); |
| __ AddP(string, Operand(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); |
| __ b(&check_encoding, Label::kNear); |
| |
| // Handle external strings. |
| __ bind(&external_string); |
| if (FLAG_debug_code) { |
| // Assert that we do not have a cons or slice (indirect strings) here. |
| // Sequential strings have already been ruled out. |
| __ mov(r0, Operand(kIsIndirectStringMask)); |
| __ AndP(r0, result); |
| __ Assert(eq, kExternalStringExpectedButNotFound, cr0); |
| } |
| // Rule out short external strings. |
| STATIC_ASSERT(kShortExternalStringTag != 0); |
| __ mov(r0, Operand(kShortExternalStringMask)); |
| __ AndP(r0, result); |
| __ bne(call_runtime /*, cr0*/); |
| __ LoadP(string, |
| FieldMemOperand(string, ExternalString::kResourceDataOffset)); |
| |
| Label one_byte, done; |
| __ bind(&check_encoding); |
| STATIC_ASSERT(kTwoByteStringTag == 0); |
| __ mov(r0, Operand(kStringEncodingMask)); |
| __ AndP(r0, result); |
| __ bne(&one_byte, Label::kNear); |
| // Two-byte string. |
| __ ShiftLeftP(result, index, Operand(1)); |
| __ LoadLogicalHalfWordP(result, MemOperand(string, result)); |
| __ b(&done, Label::kNear); |
| __ bind(&one_byte); |
| // One-byte string. |
| __ LoadlB(result, MemOperand(string, index)); |
| __ bind(&done); |
| } |
| |
| #undef __ |
| |
| CodeAgingHelper::CodeAgingHelper(Isolate* isolate) { |
| USE(isolate); |
| DCHECK(young_sequence_.length() == kNoCodeAgeSequenceLength); |
| // Since patcher is a large object, allocate it dynamically when needed, |
| // to avoid overloading the stack in stress conditions. |
| // DONT_FLUSH is used because the CodeAgingHelper is initialized early in |
| // the process, before ARM simulator ICache is setup. |
| std::unique_ptr<CodePatcher> patcher( |
| new CodePatcher(isolate, young_sequence_.start(), |
| young_sequence_.length(), CodePatcher::DONT_FLUSH)); |
| PredictableCodeSizeScope scope(patcher->masm(), young_sequence_.length()); |
| patcher->masm()->PushStandardFrame(r3); |
| } |
| |
| #ifdef DEBUG |
| bool CodeAgingHelper::IsOld(byte* candidate) const { |
| return Assembler::IsNop(Assembler::instr_at(candidate)); |
| } |
| #endif |
| |
| bool Code::IsYoungSequence(Isolate* isolate, byte* sequence) { |
| bool result = isolate->code_aging_helper()->IsYoung(sequence); |
| DCHECK(result || isolate->code_aging_helper()->IsOld(sequence)); |
| return result; |
| } |
| |
| Code::Age Code::GetCodeAge(Isolate* isolate, byte* sequence) { |
| if (IsYoungSequence(isolate, sequence)) return kNoAgeCodeAge; |
| |
| Code* code = NULL; |
| Address target_address = |
| Assembler::target_address_at(sequence + kCodeAgingTargetDelta, code); |
| Code* stub = GetCodeFromTargetAddress(target_address); |
| return GetAgeOfCodeAgeStub(stub); |
| } |
| |
| void Code::PatchPlatformCodeAge(Isolate* isolate, byte* sequence, |
| Code::Age age) { |
| uint32_t young_length = isolate->code_aging_helper()->young_sequence_length(); |
| if (age == kNoAgeCodeAge) { |
| isolate->code_aging_helper()->CopyYoungSequenceTo(sequence); |
| Assembler::FlushICache(isolate, sequence, young_length); |
| } else { |
| // FIXED_SEQUENCE |
| Code* stub = GetCodeAgeStub(isolate, age); |
| CodePatcher patcher(isolate, sequence, young_length); |
| intptr_t target = reinterpret_cast<intptr_t>(stub->instruction_start()); |
| // We need to push lr on stack so that GenerateMakeCodeYoungAgainCommon |
| // knows where to pick up the return address |
| // |
| // Since we can no longer guarentee ip will hold the branch address |
| // because of BRASL, use Call so that GenerateMakeCodeYoungAgainCommon |
| // can calculate the branch address offset |
| patcher.masm()->nop(); // marker to detect sequence (see IsOld) |
| patcher.masm()->CleanseP(r14); |
| patcher.masm()->Push(r14); |
| patcher.masm()->mov(r2, Operand(target)); |
| patcher.masm()->Call(r2); |
| for (int i = 0; i < kNoCodeAgeSequenceLength - kCodeAgingSequenceLength; |
| i += 2) { |
| // TODO(joransiu): Create nop function to pad |
| // (kNoCodeAgeSequenceLength - kCodeAgingSequenceLength) bytes. |
| patcher.masm()->nop(); // 2-byte nops(). |
| } |
| } |
| } |
| |
| } // namespace internal |
| } // namespace v8 |
| |
| #endif // V8_TARGET_ARCH_S390 |