1 // Copyright 2021 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/deoptimizer/translation-array.h"
6
7 #include "src/base/vlq.h"
8 #include "src/deoptimizer/translated-state.h"
9 #include "src/objects/fixed-array-inl.h"
10 #include "third_party/zlib/google/compression_utils_portable.h"
11
12 namespace v8 {
13 namespace internal {
14
15 namespace {
16
17 // Constants describing compressed TranslationArray layout. Only relevant if
18 // --turbo-compress-translation-arrays is enabled.
19 constexpr int kUncompressedSizeOffset = 0;
20 constexpr int kUncompressedSizeSize = kInt32Size;
21 constexpr int kCompressedDataOffset =
22 kUncompressedSizeOffset + kUncompressedSizeSize;
23 constexpr int kTranslationArrayElementSize = kInt32Size;
24
25 } // namespace
26
TranslationArrayIterator(TranslationArray buffer,int index)27 TranslationArrayIterator::TranslationArrayIterator(TranslationArray buffer,
28 int index)
29 : buffer_(buffer), index_(index) {
30 if (V8_UNLIKELY(FLAG_turbo_compress_translation_arrays)) {
31 const int size = buffer_.get_int(kUncompressedSizeOffset);
32 uncompressed_contents_.insert(uncompressed_contents_.begin(), size, 0);
33
34 uLongf uncompressed_size = size * kTranslationArrayElementSize;
35
36 CHECK_EQ(
37 zlib_internal::UncompressHelper(
38 zlib_internal::ZRAW,
39 bit_cast<Bytef*>(uncompressed_contents_.data()), &uncompressed_size,
40 buffer_.GetDataStartAddress() + kCompressedDataOffset,
41 buffer_.DataSize()),
42 Z_OK);
43 DCHECK(index >= 0 && index < size);
44 } else {
45 DCHECK(index >= 0 && index < buffer.length());
46 }
47 }
48
Next()49 int32_t TranslationArrayIterator::Next() {
50 if (V8_UNLIKELY(FLAG_turbo_compress_translation_arrays)) {
51 return uncompressed_contents_[index_++];
52 } else {
53 int32_t value = base::VLQDecode(buffer_.GetDataStartAddress(), &index_);
54 DCHECK_LE(index_, buffer_.length());
55 return value;
56 }
57 }
58
HasNext() const59 bool TranslationArrayIterator::HasNext() const {
60 if (V8_UNLIKELY(FLAG_turbo_compress_translation_arrays)) {
61 return index_ < static_cast<int>(uncompressed_contents_.size());
62 } else {
63 return index_ < buffer_.length();
64 }
65 }
66
Add(int32_t value)67 void TranslationArrayBuilder::Add(int32_t value) {
68 if (V8_UNLIKELY(FLAG_turbo_compress_translation_arrays)) {
69 contents_for_compression_.push_back(value);
70 } else {
71 base::VLQEncode(&contents_, value);
72 }
73 }
74
ToTranslationArray(Factory * factory)75 Handle<TranslationArray> TranslationArrayBuilder::ToTranslationArray(
76 Factory* factory) {
77 if (V8_UNLIKELY(FLAG_turbo_compress_translation_arrays)) {
78 const int input_size = SizeInBytes();
79 uLongf compressed_data_size = compressBound(input_size);
80
81 ZoneVector<byte> compressed_data(compressed_data_size, zone());
82
83 CHECK_EQ(
84 zlib_internal::CompressHelper(
85 zlib_internal::ZRAW, compressed_data.data(), &compressed_data_size,
86 bit_cast<const Bytef*>(contents_for_compression_.data()),
87 input_size, Z_DEFAULT_COMPRESSION, nullptr, nullptr),
88 Z_OK);
89
90 const int translation_array_size =
91 static_cast<int>(compressed_data_size) + kUncompressedSizeSize;
92 Handle<TranslationArray> result =
93 factory->NewByteArray(translation_array_size, AllocationType::kOld);
94
95 result->set_int(kUncompressedSizeOffset, Size());
96 std::memcpy(result->GetDataStartAddress() + kCompressedDataOffset,
97 compressed_data.data(), compressed_data_size);
98
99 return result;
100 } else {
101 Handle<TranslationArray> result =
102 factory->NewByteArray(SizeInBytes(), AllocationType::kOld);
103 memcpy(result->GetDataStartAddress(), contents_.data(),
104 contents_.size() * sizeof(uint8_t));
105 return result;
106 }
107 }
108
BeginBuiltinContinuationFrame(BytecodeOffset bytecode_offset,int literal_id,unsigned height)109 void TranslationArrayBuilder::BeginBuiltinContinuationFrame(
110 BytecodeOffset bytecode_offset, int literal_id, unsigned height) {
111 auto opcode = TranslationOpcode::BUILTIN_CONTINUATION_FRAME;
112 Add(opcode);
113 Add(bytecode_offset.ToInt());
114 Add(literal_id);
115 Add(height);
116 DCHECK_EQ(TranslationOpcodeOperandCount(opcode), 3);
117 }
118
119 #if V8_ENABLE_WEBASSEMBLY
BeginJSToWasmBuiltinContinuationFrame(BytecodeOffset bytecode_offset,int literal_id,unsigned height,base::Optional<wasm::ValueKind> return_kind)120 void TranslationArrayBuilder::BeginJSToWasmBuiltinContinuationFrame(
121 BytecodeOffset bytecode_offset, int literal_id, unsigned height,
122 base::Optional<wasm::ValueKind> return_kind) {
123 auto opcode = TranslationOpcode::JS_TO_WASM_BUILTIN_CONTINUATION_FRAME;
124 Add(opcode);
125 Add(bytecode_offset.ToInt());
126 Add(literal_id);
127 Add(height);
128 Add(return_kind ? static_cast<int>(return_kind.value()) : kNoWasmReturnKind);
129 DCHECK_EQ(TranslationOpcodeOperandCount(opcode), 4);
130 }
131 #endif // V8_ENABLE_WEBASSEMBLY
132
BeginJavaScriptBuiltinContinuationFrame(BytecodeOffset bytecode_offset,int literal_id,unsigned height)133 void TranslationArrayBuilder::BeginJavaScriptBuiltinContinuationFrame(
134 BytecodeOffset bytecode_offset, int literal_id, unsigned height) {
135 auto opcode = TranslationOpcode::JAVA_SCRIPT_BUILTIN_CONTINUATION_FRAME;
136 Add(opcode);
137 Add(bytecode_offset.ToInt());
138 Add(literal_id);
139 Add(height);
140 DCHECK_EQ(TranslationOpcodeOperandCount(opcode), 3);
141 }
142
BeginJavaScriptBuiltinContinuationWithCatchFrame(BytecodeOffset bytecode_offset,int literal_id,unsigned height)143 void TranslationArrayBuilder::BeginJavaScriptBuiltinContinuationWithCatchFrame(
144 BytecodeOffset bytecode_offset, int literal_id, unsigned height) {
145 auto opcode =
146 TranslationOpcode::JAVA_SCRIPT_BUILTIN_CONTINUATION_WITH_CATCH_FRAME;
147 Add(opcode);
148 Add(bytecode_offset.ToInt());
149 Add(literal_id);
150 Add(height);
151 DCHECK_EQ(TranslationOpcodeOperandCount(opcode), 3);
152 }
153
BeginConstructStubFrame(BytecodeOffset bytecode_offset,int literal_id,unsigned height)154 void TranslationArrayBuilder::BeginConstructStubFrame(
155 BytecodeOffset bytecode_offset, int literal_id, unsigned height) {
156 auto opcode = TranslationOpcode::CONSTRUCT_STUB_FRAME;
157 Add(opcode);
158 Add(bytecode_offset.ToInt());
159 Add(literal_id);
160 Add(height);
161 DCHECK_EQ(TranslationOpcodeOperandCount(opcode), 3);
162 }
163
BeginArgumentsAdaptorFrame(int literal_id,unsigned height)164 void TranslationArrayBuilder::BeginArgumentsAdaptorFrame(int literal_id,
165 unsigned height) {
166 auto opcode = TranslationOpcode::ARGUMENTS_ADAPTOR_FRAME;
167 Add(opcode);
168 Add(literal_id);
169 Add(height);
170 DCHECK_EQ(TranslationOpcodeOperandCount(opcode), 2);
171 }
172
BeginInterpretedFrame(BytecodeOffset bytecode_offset,int literal_id,unsigned height,int return_value_offset,int return_value_count)173 void TranslationArrayBuilder::BeginInterpretedFrame(
174 BytecodeOffset bytecode_offset, int literal_id, unsigned height,
175 int return_value_offset, int return_value_count) {
176 auto opcode = TranslationOpcode::INTERPRETED_FRAME;
177 Add(opcode);
178 Add(bytecode_offset.ToInt());
179 Add(literal_id);
180 Add(height);
181 Add(return_value_offset);
182 Add(return_value_count);
183 DCHECK_EQ(TranslationOpcodeOperandCount(opcode), 5);
184 }
185
ArgumentsElements(CreateArgumentsType type)186 void TranslationArrayBuilder::ArgumentsElements(CreateArgumentsType type) {
187 auto opcode = TranslationOpcode::ARGUMENTS_ELEMENTS;
188 Add(opcode);
189 Add(static_cast<uint8_t>(type));
190 DCHECK_EQ(TranslationOpcodeOperandCount(opcode), 1);
191 }
192
ArgumentsLength()193 void TranslationArrayBuilder::ArgumentsLength() {
194 auto opcode = TranslationOpcode::ARGUMENTS_LENGTH;
195 Add(opcode);
196 DCHECK_EQ(TranslationOpcodeOperandCount(opcode), 0);
197 }
198
BeginCapturedObject(int length)199 void TranslationArrayBuilder::BeginCapturedObject(int length) {
200 auto opcode = TranslationOpcode::CAPTURED_OBJECT;
201 Add(opcode);
202 Add(length);
203 DCHECK_EQ(TranslationOpcodeOperandCount(opcode), 1);
204 }
205
DuplicateObject(int object_index)206 void TranslationArrayBuilder::DuplicateObject(int object_index) {
207 auto opcode = TranslationOpcode::DUPLICATED_OBJECT;
208 Add(opcode);
209 Add(object_index);
210 DCHECK_EQ(TranslationOpcodeOperandCount(opcode), 1);
211 }
212
StoreRegister(Register reg)213 void TranslationArrayBuilder::StoreRegister(Register reg) {
214 auto opcode = TranslationOpcode::REGISTER;
215 Add(opcode);
216 Add(reg.code());
217 }
218
StoreInt32Register(Register reg)219 void TranslationArrayBuilder::StoreInt32Register(Register reg) {
220 auto opcode = TranslationOpcode::INT32_REGISTER;
221 Add(opcode);
222 Add(reg.code());
223 DCHECK_EQ(TranslationOpcodeOperandCount(opcode), 1);
224 }
225
StoreInt64Register(Register reg)226 void TranslationArrayBuilder::StoreInt64Register(Register reg) {
227 auto opcode = TranslationOpcode::INT64_REGISTER;
228 Add(opcode);
229 Add(reg.code());
230 DCHECK_EQ(TranslationOpcodeOperandCount(opcode), 1);
231 }
232
StoreUint32Register(Register reg)233 void TranslationArrayBuilder::StoreUint32Register(Register reg) {
234 auto opcode = TranslationOpcode::UINT32_REGISTER;
235 Add(opcode);
236 Add(reg.code());
237 }
238
StoreBoolRegister(Register reg)239 void TranslationArrayBuilder::StoreBoolRegister(Register reg) {
240 auto opcode = TranslationOpcode::BOOL_REGISTER;
241 Add(opcode);
242 Add(reg.code());
243 DCHECK_EQ(TranslationOpcodeOperandCount(opcode), 1);
244 }
245
StoreFloatRegister(FloatRegister reg)246 void TranslationArrayBuilder::StoreFloatRegister(FloatRegister reg) {
247 auto opcode = TranslationOpcode::FLOAT_REGISTER;
248 Add(opcode);
249 Add(reg.code());
250 }
251
StoreDoubleRegister(DoubleRegister reg)252 void TranslationArrayBuilder::StoreDoubleRegister(DoubleRegister reg) {
253 auto opcode = TranslationOpcode::DOUBLE_REGISTER;
254 Add(opcode);
255 Add(reg.code());
256 DCHECK_EQ(TranslationOpcodeOperandCount(opcode), 1);
257 }
258
StoreStackSlot(int index)259 void TranslationArrayBuilder::StoreStackSlot(int index) {
260 auto opcode = TranslationOpcode::STACK_SLOT;
261 Add(opcode);
262 Add(index);
263 DCHECK_EQ(TranslationOpcodeOperandCount(opcode), 1);
264 }
265
StoreInt32StackSlot(int index)266 void TranslationArrayBuilder::StoreInt32StackSlot(int index) {
267 auto opcode = TranslationOpcode::INT32_STACK_SLOT;
268 Add(opcode);
269 Add(index);
270 DCHECK_EQ(TranslationOpcodeOperandCount(opcode), 1);
271 }
272
StoreInt64StackSlot(int index)273 void TranslationArrayBuilder::StoreInt64StackSlot(int index) {
274 auto opcode = TranslationOpcode::INT64_STACK_SLOT;
275 Add(opcode);
276 Add(index);
277 DCHECK_EQ(TranslationOpcodeOperandCount(opcode), 1);
278 }
279
StoreUint32StackSlot(int index)280 void TranslationArrayBuilder::StoreUint32StackSlot(int index) {
281 auto opcode = TranslationOpcode::UINT32_STACK_SLOT;
282 Add(opcode);
283 Add(index);
284 DCHECK_EQ(TranslationOpcodeOperandCount(opcode), 1);
285 }
286
StoreBoolStackSlot(int index)287 void TranslationArrayBuilder::StoreBoolStackSlot(int index) {
288 auto opcode = TranslationOpcode::BOOL_STACK_SLOT;
289 Add(opcode);
290 Add(index);
291 DCHECK_EQ(TranslationOpcodeOperandCount(opcode), 1);
292 }
293
StoreFloatStackSlot(int index)294 void TranslationArrayBuilder::StoreFloatStackSlot(int index) {
295 auto opcode = TranslationOpcode::FLOAT_STACK_SLOT;
296 Add(opcode);
297 Add(index);
298 DCHECK_EQ(TranslationOpcodeOperandCount(opcode), 1);
299 }
300
StoreDoubleStackSlot(int index)301 void TranslationArrayBuilder::StoreDoubleStackSlot(int index) {
302 auto opcode = TranslationOpcode::DOUBLE_STACK_SLOT;
303 Add(opcode);
304 Add(index);
305 DCHECK_EQ(TranslationOpcodeOperandCount(opcode), 1);
306 }
307
StoreLiteral(int literal_id)308 void TranslationArrayBuilder::StoreLiteral(int literal_id) {
309 auto opcode = TranslationOpcode::LITERAL;
310 Add(opcode);
311 Add(literal_id);
312 DCHECK_EQ(TranslationOpcodeOperandCount(opcode), 1);
313 }
314
AddUpdateFeedback(int vector_literal,int slot)315 void TranslationArrayBuilder::AddUpdateFeedback(int vector_literal, int slot) {
316 auto opcode = TranslationOpcode::UPDATE_FEEDBACK;
317 Add(opcode);
318 Add(vector_literal);
319 Add(slot);
320 DCHECK_EQ(TranslationOpcodeOperandCount(opcode), 2);
321 }
322
StoreJSFrameFunction()323 void TranslationArrayBuilder::StoreJSFrameFunction() {
324 StoreStackSlot((StandardFrameConstants::kCallerPCOffset -
325 StandardFrameConstants::kFunctionOffset) /
326 kSystemPointerSize);
327 }
328
329 } // namespace internal
330 } // namespace v8
331