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