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
12namespace v8 {
13namespace internal {
14
15namespace {
16
17// Constants describing compressed TranslationArray layout. Only relevant if
18// --turbo-compress-translation-arrays is enabled.
19constexpr int kUncompressedSizeOffset = 0;
20constexpr int kUncompressedSizeSize = kInt32Size;
21constexpr int kCompressedDataOffset =
22    kUncompressedSizeOffset + kUncompressedSizeSize;
23constexpr int kTranslationArrayElementSize = kInt32Size;
24
25}  // namespace
26
27TranslationArrayIterator::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
49int32_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
59bool 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
67void 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
75Handle<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
109void 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
120void 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
133void 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
143void 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
154void 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
164void 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
173void 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
186void 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
193void TranslationArrayBuilder::ArgumentsLength() {
194  auto opcode = TranslationOpcode::ARGUMENTS_LENGTH;
195  Add(opcode);
196  DCHECK_EQ(TranslationOpcodeOperandCount(opcode), 0);
197}
198
199void TranslationArrayBuilder::BeginCapturedObject(int length) {
200  auto opcode = TranslationOpcode::CAPTURED_OBJECT;
201  Add(opcode);
202  Add(length);
203  DCHECK_EQ(TranslationOpcodeOperandCount(opcode), 1);
204}
205
206void 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
213void TranslationArrayBuilder::StoreRegister(Register reg) {
214  auto opcode = TranslationOpcode::REGISTER;
215  Add(opcode);
216  Add(reg.code());
217}
218
219void 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
226void 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
233void TranslationArrayBuilder::StoreUint32Register(Register reg) {
234  auto opcode = TranslationOpcode::UINT32_REGISTER;
235  Add(opcode);
236  Add(reg.code());
237}
238
239void 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
246void TranslationArrayBuilder::StoreFloatRegister(FloatRegister reg) {
247  auto opcode = TranslationOpcode::FLOAT_REGISTER;
248  Add(opcode);
249  Add(reg.code());
250}
251
252void 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
259void TranslationArrayBuilder::StoreStackSlot(int index) {
260  auto opcode = TranslationOpcode::STACK_SLOT;
261  Add(opcode);
262  Add(index);
263  DCHECK_EQ(TranslationOpcodeOperandCount(opcode), 1);
264}
265
266void 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
273void 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
280void 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
287void 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
294void 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
301void 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
308void 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
315void 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
323void TranslationArrayBuilder::StoreJSFrameFunction() {
324  StoreStackSlot((StandardFrameConstants::kCallerPCOffset -
325                  StandardFrameConstants::kFunctionOffset) /
326                 kSystemPointerSize);
327}
328
329}  // namespace internal
330}  // namespace v8
331