1// Copyright 2015 the V8 project authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "src/s390/codegen-s390.h" 6 7#if V8_TARGET_ARCH_S390 8 9#include <memory> 10 11#include "src/codegen.h" 12#include "src/macro-assembler.h" 13#include "src/s390/simulator-s390.h" 14 15namespace v8 { 16namespace internal { 17 18#define __ masm. 19 20UnaryMathFunctionWithIsolate CreateSqrtFunction(Isolate* isolate) { 21#if defined(USE_SIMULATOR) 22 return nullptr; 23#else 24 size_t actual_size; 25 byte* buffer = 26 static_cast<byte*>(base::OS::Allocate(1 * KB, &actual_size, true)); 27 if (buffer == nullptr) return nullptr; 28 29 MacroAssembler masm(isolate, buffer, static_cast<int>(actual_size), 30 CodeObjectRequired::kNo); 31 32 __ MovFromFloatParameter(d0); 33 __ sqdbr(d0, d0); 34 __ MovToFloatResult(d0); 35 __ Ret(); 36 37 CodeDesc desc; 38 masm.GetCode(&desc); 39 DCHECK(ABI_USES_FUNCTION_DESCRIPTORS || !RelocInfo::RequiresRelocation(desc)); 40 41 Assembler::FlushICache(isolate, buffer, actual_size); 42 base::OS::ProtectCode(buffer, actual_size); 43 return FUNCTION_CAST<UnaryMathFunctionWithIsolate>(buffer); 44#endif 45} 46 47#undef __ 48 49// ------------------------------------------------------------------------- 50// Platform-specific RuntimeCallHelper functions. 51 52void StubRuntimeCallHelper::BeforeCall(MacroAssembler* masm) const { 53 masm->EnterFrame(StackFrame::INTERNAL); 54 DCHECK(!masm->has_frame()); 55 masm->set_has_frame(true); 56} 57 58void StubRuntimeCallHelper::AfterCall(MacroAssembler* masm) const { 59 masm->LeaveFrame(StackFrame::INTERNAL); 60 DCHECK(masm->has_frame()); 61 masm->set_has_frame(false); 62} 63 64// ------------------------------------------------------------------------- 65// Code generators 66 67#define __ ACCESS_MASM(masm) 68 69// assume ip can be used as a scratch register below 70void StringCharLoadGenerator::Generate(MacroAssembler* masm, Register string, 71 Register index, Register result, 72 Label* call_runtime) { 73 Label indirect_string_loaded; 74 __ bind(&indirect_string_loaded); 75 76 // Fetch the instance type of the receiver into result register. 77 __ LoadP(result, FieldMemOperand(string, HeapObject::kMapOffset)); 78 __ LoadlB(result, FieldMemOperand(result, Map::kInstanceTypeOffset)); 79 80 // We need special handling for indirect strings. 81 Label check_sequential; 82 __ mov(r0, Operand(kIsIndirectStringMask)); 83 __ AndP(r0, result); 84 __ beq(&check_sequential, Label::kNear /*, cr0*/); 85 86 // Dispatch on the indirect string shape: slice or cons. 87 Label cons_string, thin_string; 88 __ LoadRR(ip, result); 89 __ nilf(ip, Operand(kStringRepresentationMask)); 90 __ CmpP(ip, Operand(kConsStringTag)); 91 __ beq(&cons_string); 92 __ CmpP(ip, Operand(kThinStringTag)); 93 __ beq(&thin_string); 94 95 // Handle slices. 96 __ LoadP(result, FieldMemOperand(string, SlicedString::kOffsetOffset)); 97 __ LoadP(string, FieldMemOperand(string, SlicedString::kParentOffset)); 98 __ SmiUntag(ip, result); 99 __ AddP(index, ip); 100 __ b(&indirect_string_loaded); 101 102 // Handle thin strings. 103 __ bind(&thin_string); 104 __ LoadP(string, FieldMemOperand(string, ThinString::kActualOffset)); 105 __ b(&indirect_string_loaded); 106 107 // Handle cons strings. 108 // Check whether the right hand side is the empty string (i.e. if 109 // this is really a flat string in a cons string). If that is not 110 // the case we would rather go to the runtime system now to flatten 111 // the string. 112 __ bind(&cons_string); 113 __ LoadP(result, FieldMemOperand(string, ConsString::kSecondOffset)); 114 __ CompareRoot(result, Heap::kempty_stringRootIndex); 115 __ bne(call_runtime); 116 // Get the first of the two strings and load its instance type. 117 __ LoadP(string, FieldMemOperand(string, ConsString::kFirstOffset)); 118 __ b(&indirect_string_loaded); 119 120 // Distinguish sequential and external strings. Only these two string 121 // representations can reach here (slices and flat cons strings have been 122 // reduced to the underlying sequential or external string). 123 Label external_string, check_encoding; 124 __ bind(&check_sequential); 125 STATIC_ASSERT(kSeqStringTag == 0); 126 __ mov(r0, Operand(kStringRepresentationMask)); 127 __ AndP(r0, result); 128 __ bne(&external_string, Label::kNear); 129 130 // Prepare sequential strings 131 STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqOneByteString::kHeaderSize); 132 __ AddP(string, Operand(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); 133 __ b(&check_encoding, Label::kNear); 134 135 // Handle external strings. 136 __ bind(&external_string); 137 if (FLAG_debug_code) { 138 // Assert that we do not have a cons or slice (indirect strings) here. 139 // Sequential strings have already been ruled out. 140 __ mov(r0, Operand(kIsIndirectStringMask)); 141 __ AndP(r0, result); 142 __ Assert(eq, kExternalStringExpectedButNotFound, cr0); 143 } 144 // Rule out short external strings. 145 STATIC_ASSERT(kShortExternalStringTag != 0); 146 __ mov(r0, Operand(kShortExternalStringMask)); 147 __ AndP(r0, result); 148 __ bne(call_runtime /*, cr0*/); 149 __ LoadP(string, 150 FieldMemOperand(string, ExternalString::kResourceDataOffset)); 151 152 Label one_byte, done; 153 __ bind(&check_encoding); 154 STATIC_ASSERT(kTwoByteStringTag == 0); 155 __ mov(r0, Operand(kStringEncodingMask)); 156 __ AndP(r0, result); 157 __ bne(&one_byte, Label::kNear); 158 // Two-byte string. 159 __ ShiftLeftP(result, index, Operand(1)); 160 __ LoadLogicalHalfWordP(result, MemOperand(string, result)); 161 __ b(&done, Label::kNear); 162 __ bind(&one_byte); 163 // One-byte string. 164 __ LoadlB(result, MemOperand(string, index)); 165 __ bind(&done); 166} 167 168#undef __ 169 170CodeAgingHelper::CodeAgingHelper(Isolate* isolate) { 171 USE(isolate); 172 DCHECK(young_sequence_.length() == kNoCodeAgeSequenceLength); 173 // Since patcher is a large object, allocate it dynamically when needed, 174 // to avoid overloading the stack in stress conditions. 175 // DONT_FLUSH is used because the CodeAgingHelper is initialized early in 176 // the process, before ARM simulator ICache is setup. 177 std::unique_ptr<CodePatcher> patcher( 178 new CodePatcher(isolate, young_sequence_.start(), 179 young_sequence_.length(), CodePatcher::DONT_FLUSH)); 180 PredictableCodeSizeScope scope(patcher->masm(), young_sequence_.length()); 181 patcher->masm()->PushStandardFrame(r3); 182} 183 184#ifdef DEBUG 185bool CodeAgingHelper::IsOld(byte* candidate) const { 186 return Assembler::IsNop(Assembler::instr_at(candidate)); 187} 188#endif 189 190bool Code::IsYoungSequence(Isolate* isolate, byte* sequence) { 191 bool result = isolate->code_aging_helper()->IsYoung(sequence); 192 DCHECK(result || isolate->code_aging_helper()->IsOld(sequence)); 193 return result; 194} 195 196Code::Age Code::GetCodeAge(Isolate* isolate, byte* sequence) { 197 if (IsYoungSequence(isolate, sequence)) return kNoAgeCodeAge; 198 199 Code* code = NULL; 200 Address target_address = 201 Assembler::target_address_at(sequence + kCodeAgingTargetDelta, code); 202 Code* stub = GetCodeFromTargetAddress(target_address); 203 return GetAgeOfCodeAgeStub(stub); 204} 205 206void Code::PatchPlatformCodeAge(Isolate* isolate, byte* sequence, 207 Code::Age age) { 208 uint32_t young_length = isolate->code_aging_helper()->young_sequence_length(); 209 if (age == kNoAgeCodeAge) { 210 isolate->code_aging_helper()->CopyYoungSequenceTo(sequence); 211 Assembler::FlushICache(isolate, sequence, young_length); 212 } else { 213 // FIXED_SEQUENCE 214 Code* stub = GetCodeAgeStub(isolate, age); 215 CodePatcher patcher(isolate, sequence, young_length); 216 intptr_t target = reinterpret_cast<intptr_t>(stub->instruction_start()); 217 // We need to push lr on stack so that GenerateMakeCodeYoungAgainCommon 218 // knows where to pick up the return address 219 // 220 // Since we can no longer guarentee ip will hold the branch address 221 // because of BRASL, use Call so that GenerateMakeCodeYoungAgainCommon 222 // can calculate the branch address offset 223 patcher.masm()->nop(); // marker to detect sequence (see IsOld) 224 patcher.masm()->CleanseP(r14); 225 patcher.masm()->Push(r14); 226 patcher.masm()->mov(r2, Operand(target)); 227 patcher.masm()->Call(r2); 228 for (int i = 0; i < kNoCodeAgeSequenceLength - kCodeAgingSequenceLength; 229 i += 2) { 230 // TODO(joransiu): Create nop function to pad 231 // (kNoCodeAgeSequenceLength - kCodeAgingSequenceLength) bytes. 232 patcher.masm()->nop(); // 2-byte nops(). 233 } 234 } 235} 236 237} // namespace internal 238} // namespace v8 239 240#endif // V8_TARGET_ARCH_S390 241