Line data Source code
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/interpreter/bytecode-array-writer.h"
6 :
7 : #include "src/api-inl.h"
8 : #include "src/interpreter/bytecode-jump-table.h"
9 : #include "src/interpreter/bytecode-label.h"
10 : #include "src/interpreter/bytecode-node.h"
11 : #include "src/interpreter/bytecode-register.h"
12 : #include "src/interpreter/bytecode-source-info.h"
13 : #include "src/interpreter/constant-array-builder.h"
14 : #include "src/interpreter/handler-table-builder.h"
15 : #include "src/log.h"
16 : #include "src/objects-inl.h"
17 :
18 : namespace v8 {
19 : namespace internal {
20 : namespace interpreter {
21 :
22 : STATIC_CONST_MEMBER_DEFINITION const size_t
23 : BytecodeArrayWriter::kMaxSizeOfPackedBytecode;
24 :
25 2137592 : BytecodeArrayWriter::BytecodeArrayWriter(
26 : Zone* zone, ConstantArrayBuilder* constant_array_builder,
27 : SourcePositionTableBuilder::RecordingMode source_position_mode)
28 : : bytecodes_(zone),
29 : unbound_jumps_(0),
30 : source_position_table_builder_(source_position_mode),
31 : constant_array_builder_(constant_array_builder),
32 : last_bytecode_(Bytecode::kIllegal),
33 : last_bytecode_offset_(0),
34 : last_bytecode_had_source_info_(false),
35 : elide_noneffectful_bytecodes_(FLAG_ignition_elide_noneffectful_bytecodes),
36 4275184 : exit_seen_in_block_(false) {
37 2137591 : bytecodes_.reserve(512); // Derived via experimentation.
38 2137594 : }
39 :
40 2112571 : Handle<BytecodeArray> BytecodeArrayWriter::ToBytecodeArray(
41 : Isolate* isolate, int register_count, int parameter_count,
42 : Handle<ByteArray> handler_table) {
43 : DCHECK_EQ(0, unbound_jumps_);
44 :
45 2112571 : int bytecode_size = static_cast<int>(bytecodes()->size());
46 2112571 : int frame_size = register_count * kSystemPointerSize;
47 : Handle<FixedArray> constant_pool =
48 2112571 : constant_array_builder()->ToFixedArray(isolate);
49 : Handle<BytecodeArray> bytecode_array = isolate->factory()->NewBytecodeArray(
50 : bytecode_size, &bytecodes()->front(), frame_size, parameter_count,
51 2112591 : constant_pool);
52 2112582 : bytecode_array->set_handler_table(*handler_table);
53 2112588 : if (!source_position_table_builder_.Lazy()) {
54 : Handle<ByteArray> source_position_table =
55 : source_position_table_builder_.Omit()
56 : ? ReadOnlyRoots(isolate).empty_byte_array_handle()
57 4225082 : : source_position_table_builder()->ToSourcePositionTable(isolate);
58 4225066 : bytecode_array->set_source_position_table(*source_position_table);
59 2112841 : LOG_CODE_EVENT(isolate, CodeLinePosInfoRecordEvent(
60 : bytecode_array->GetFirstBytecodeAddress(),
61 : *source_position_table));
62 : }
63 2112587 : return bytecode_array;
64 : }
65 :
66 78156867 : void BytecodeArrayWriter::Write(BytecodeNode* node) {
67 : DCHECK(!Bytecodes::IsJump(node->bytecode()));
68 :
69 78156867 : if (exit_seen_in_block_) return; // Don't emit dead code.
70 : UpdateExitSeenInBlock(node->bytecode());
71 77933438 : MaybeElideLastBytecode(node->bytecode(), node->source_info().is_valid());
72 :
73 77936402 : UpdateSourcePositionTable(node);
74 77936620 : EmitBytecode(node);
75 : }
76 :
77 1840322 : void BytecodeArrayWriter::WriteJump(BytecodeNode* node, BytecodeLabel* label) {
78 : DCHECK(Bytecodes::IsForwardJump(node->bytecode()));
79 :
80 1840322 : if (exit_seen_in_block_) return; // Don't emit dead code.
81 : UpdateExitSeenInBlock(node->bytecode());
82 1823278 : MaybeElideLastBytecode(node->bytecode(), node->source_info().is_valid());
83 :
84 1823278 : UpdateSourcePositionTable(node);
85 1823288 : EmitJump(node, label);
86 : }
87 :
88 262506 : void BytecodeArrayWriter::WriteJumpLoop(BytecodeNode* node,
89 : BytecodeLoopHeader* loop_header) {
90 : DCHECK_EQ(node->bytecode(), Bytecode::kJumpLoop);
91 :
92 262506 : if (exit_seen_in_block_) return; // Don't emit dead code.
93 : UpdateExitSeenInBlock(node->bytecode());
94 254086 : MaybeElideLastBytecode(node->bytecode(), node->source_info().is_valid());
95 :
96 254088 : UpdateSourcePositionTable(node);
97 254090 : EmitJumpLoop(node, loop_header);
98 : }
99 :
100 20205 : void BytecodeArrayWriter::WriteSwitch(BytecodeNode* node,
101 : BytecodeJumpTable* jump_table) {
102 : DCHECK(Bytecodes::IsSwitch(node->bytecode()));
103 :
104 20205 : if (exit_seen_in_block_) return; // Don't emit dead code.
105 : UpdateExitSeenInBlock(node->bytecode());
106 19821 : MaybeElideLastBytecode(node->bytecode(), node->source_info().is_valid());
107 :
108 19821 : UpdateSourcePositionTable(node);
109 : EmitSwitch(node, jump_table);
110 : }
111 :
112 1823268 : void BytecodeArrayWriter::BindLabel(BytecodeLabel* label) {
113 : DCHECK(label->has_referrer_jump());
114 : size_t current_offset = bytecodes()->size();
115 : // Update the jump instruction's location.
116 1823268 : PatchJump(current_offset, label->jump_offset());
117 : label->bind();
118 : StartBasicBlock();
119 1823269 : }
120 :
121 262467 : void BytecodeArrayWriter::BindLoopHeader(BytecodeLoopHeader* loop_header) {
122 : size_t current_offset = bytecodes()->size();
123 : loop_header->bind_to(current_offset);
124 : StartBasicBlock();
125 262467 : }
126 :
127 46770 : void BytecodeArrayWriter::BindJumpTableEntry(BytecodeJumpTable* jump_table,
128 : int case_value) {
129 : DCHECK(!jump_table->is_bound(case_value));
130 :
131 : size_t current_offset = bytecodes()->size();
132 46770 : size_t relative_jump = current_offset - jump_table->switch_bytecode_offset();
133 :
134 46770 : constant_array_builder()->SetJumpTableSmi(
135 : jump_table->ConstantPoolEntryFor(case_value),
136 46770 : Smi::FromInt(static_cast<int>(relative_jump)));
137 : jump_table->mark_bound(case_value);
138 :
139 : StartBasicBlock();
140 46770 : }
141 :
142 154772 : void BytecodeArrayWriter::BindHandlerTarget(
143 : HandlerTableBuilder* handler_table_builder, int handler_id) {
144 : size_t current_offset = bytecodes()->size();
145 : StartBasicBlock();
146 154772 : handler_table_builder->SetHandlerTarget(handler_id, current_offset);
147 154772 : }
148 :
149 154778 : void BytecodeArrayWriter::BindTryRegionStart(
150 : HandlerTableBuilder* handler_table_builder, int handler_id) {
151 : size_t current_offset = bytecodes()->size();
152 : // Try blocks don't have to be in a separate basic block, but we do have to
153 : // invalidate the bytecode to avoid eliding it and changing the offset.
154 : InvalidateLastBytecode();
155 154778 : handler_table_builder->SetTryRegionStart(handler_id, current_offset);
156 154777 : }
157 :
158 154770 : void BytecodeArrayWriter::BindTryRegionEnd(
159 : HandlerTableBuilder* handler_table_builder, int handler_id) {
160 : // Try blocks don't have to be in a separate basic block, but we do have to
161 : // invalidate the bytecode to avoid eliding it and changing the offset.
162 : InvalidateLastBytecode();
163 : size_t current_offset = bytecodes()->size();
164 154770 : handler_table_builder->SetTryRegionEnd(handler_id, current_offset);
165 154771 : }
166 :
167 0 : void BytecodeArrayWriter::StartBasicBlock() {
168 : InvalidateLastBytecode();
169 2287278 : exit_seen_in_block_ = false;
170 0 : }
171 :
172 80033005 : void BytecodeArrayWriter::UpdateSourcePositionTable(
173 : const BytecodeNode* const node) {
174 80033005 : int bytecode_offset = static_cast<int>(bytecodes()->size());
175 : const BytecodeSourceInfo& source_info = node->source_info();
176 80033005 : if (source_info.is_valid()) {
177 96372537 : source_position_table_builder()->AddPosition(
178 : bytecode_offset, SourcePosition(source_info.source_position()),
179 32124269 : source_info.is_statement());
180 : }
181 80032735 : }
182 :
183 0 : void BytecodeArrayWriter::UpdateExitSeenInBlock(Bytecode bytecode) {
184 : switch (bytecode) {
185 : case Bytecode::kReturn:
186 : case Bytecode::kThrow:
187 : case Bytecode::kReThrow:
188 : case Bytecode::kAbort:
189 : case Bytecode::kJump:
190 : case Bytecode::kJumpConstant:
191 : case Bytecode::kSuspendGenerator:
192 2954720 : exit_seen_in_block_ = true;
193 0 : break;
194 : default:
195 : break;
196 : }
197 0 : }
198 :
199 80029766 : void BytecodeArrayWriter::MaybeElideLastBytecode(Bytecode next_bytecode,
200 : bool has_source_info) {
201 80029766 : if (!elide_noneffectful_bytecodes_) return;
202 :
203 : // If the last bytecode loaded the accumulator without any external effect,
204 : // and the next bytecode clobbers this load without reading the accumulator,
205 : // then the previous bytecode can be elided as it has no effect.
206 179046132 : if (Bytecodes::IsAccumulatorLoadWithoutEffects(last_bytecode_) &&
207 80364186 : Bytecodes::GetAccumulatorUse(next_bytecode) == AccumulatorUse::kWrite &&
208 332539 : (!last_bytecode_had_source_info_ || !has_source_info)) {
209 : DCHECK_GT(bytecodes()->size(), last_bytecode_offset_);
210 329606 : bytecodes()->resize(last_bytecode_offset_);
211 : // If the last bytecode had source info we will transfer the source info
212 : // to this bytecode.
213 329606 : has_source_info |= last_bytecode_had_source_info_;
214 : }
215 80033227 : last_bytecode_ = next_bytecode;
216 80033227 : last_bytecode_had_source_info_ = has_source_info;
217 80033227 : last_bytecode_offset_ = bytecodes()->size();
218 : }
219 :
220 0 : void BytecodeArrayWriter::InvalidateLastBytecode() {
221 2596826 : last_bytecode_ = Bytecode::kIllegal;
222 0 : }
223 :
224 80033184 : void BytecodeArrayWriter::EmitBytecode(const BytecodeNode* const node) {
225 : DCHECK_NE(node->bytecode(), Bytecode::kIllegal);
226 :
227 : Bytecode bytecode = node->bytecode();
228 : OperandScale operand_scale = node->operand_scale();
229 :
230 80033184 : if (operand_scale != OperandScale::kSingle) {
231 : Bytecode prefix = Bytecodes::OperandScaleToPrefixBytecode(operand_scale);
232 24378220 : bytecodes()->push_back(Bytecodes::ToByte(prefix));
233 : }
234 160063127 : bytecodes()->push_back(Bytecodes::ToByte(bytecode));
235 :
236 : const uint32_t* const operands = node->operands();
237 : const int operand_count = node->operand_count();
238 : const OperandSize* operand_sizes =
239 : Bytecodes::GetOperandSizes(bytecode, operand_scale);
240 295907329 : for (int i = 0; i < operand_count; ++i) {
241 107942393 : switch (operand_sizes[i]) {
242 : case OperandSize::kNone:
243 0 : UNREACHABLE();
244 : break;
245 : case OperandSize::kByte:
246 173113113 : bytecodes()->push_back(static_cast<uint8_t>(operands[i]));
247 86554700 : break;
248 : case OperandSize::kShort: {
249 11305260 : uint16_t operand = static_cast<uint16_t>(operands[i]);
250 : const uint8_t* raw_operand = reinterpret_cast<const uint8_t*>(&operand);
251 11305260 : bytecodes()->push_back(raw_operand[0]);
252 11305285 : bytecodes()->push_back(raw_operand[1]);
253 : break;
254 : }
255 : case OperandSize::kQuad: {
256 : const uint8_t* raw_operand =
257 10081041 : reinterpret_cast<const uint8_t*>(&operands[i]);
258 10081041 : bytecodes()->push_back(raw_operand[0]);
259 10081042 : bytecodes()->push_back(raw_operand[1]);
260 10081043 : bytecodes()->push_back(raw_operand[2]);
261 10081045 : bytecodes()->push_back(raw_operand[3]);
262 10081044 : break;
263 : }
264 : }
265 : }
266 80026248 : }
267 :
268 : // static
269 24575 : Bytecode GetJumpWithConstantOperand(Bytecode jump_bytecode) {
270 24575 : switch (jump_bytecode) {
271 : case Bytecode::kJump:
272 : return Bytecode::kJumpConstant;
273 : case Bytecode::kJumpIfTrue:
274 8673 : return Bytecode::kJumpIfTrueConstant;
275 : case Bytecode::kJumpIfFalse:
276 5127 : return Bytecode::kJumpIfFalseConstant;
277 : case Bytecode::kJumpIfToBooleanTrue:
278 5242 : return Bytecode::kJumpIfToBooleanTrueConstant;
279 : case Bytecode::kJumpIfToBooleanFalse:
280 210 : return Bytecode::kJumpIfToBooleanFalseConstant;
281 : case Bytecode::kJumpIfNull:
282 210 : return Bytecode::kJumpIfNullConstant;
283 : case Bytecode::kJumpIfNotNull:
284 1 : return Bytecode::kJumpIfNotNullConstant;
285 : case Bytecode::kJumpIfUndefined:
286 355 : return Bytecode::kJumpIfUndefinedConstant;
287 : case Bytecode::kJumpIfNotUndefined:
288 1 : return Bytecode::kJumpIfNotUndefinedConstant;
289 : case Bytecode::kJumpIfJSReceiver:
290 1 : return Bytecode::kJumpIfJSReceiverConstant;
291 : default:
292 0 : UNREACHABLE();
293 : }
294 : }
295 :
296 1807315 : void BytecodeArrayWriter::PatchJumpWith8BitOperand(size_t jump_location,
297 : int delta) {
298 1807315 : Bytecode jump_bytecode = Bytecodes::FromByte(bytecodes()->at(jump_location));
299 : DCHECK(Bytecodes::IsForwardJump(jump_bytecode));
300 : DCHECK(Bytecodes::IsJumpImmediate(jump_bytecode));
301 : DCHECK_EQ(Bytecodes::GetOperandType(jump_bytecode, 0), OperandType::kUImm);
302 : DCHECK_GT(delta, 0);
303 1807315 : size_t operand_location = jump_location + 1;
304 : DCHECK_EQ(bytecodes()->at(operand_location), k8BitJumpPlaceholder);
305 3614630 : if (Bytecodes::ScaleForUnsignedOperand(delta) == OperandScale::kSingle) {
306 : // The jump fits within the range of an UImm8 operand, so cancel
307 : // the reservation and jump directly.
308 1782744 : constant_array_builder()->DiscardReservedEntry(OperandSize::kByte);
309 1782751 : bytecodes()->at(operand_location) = static_cast<uint8_t>(delta);
310 : } else {
311 : // The jump does not fit within the range of an UImm8 operand, so
312 : // commit reservation putting the offset into the constant pool,
313 : // and update the jump instruction and operand.
314 : size_t entry = constant_array_builder()->CommitReservedEntry(
315 24571 : OperandSize::kByte, Smi::FromInt(delta));
316 : DCHECK_EQ(Bytecodes::SizeForUnsignedOperand(static_cast<uint32_t>(entry)),
317 : OperandSize::kByte);
318 24570 : jump_bytecode = GetJumpWithConstantOperand(jump_bytecode);
319 24571 : bytecodes()->at(jump_location) = Bytecodes::ToByte(jump_bytecode);
320 24571 : bytecodes()->at(operand_location) = static_cast<uint8_t>(entry);
321 : }
322 1807322 : }
323 :
324 15949 : void BytecodeArrayWriter::PatchJumpWith16BitOperand(size_t jump_location,
325 : int delta) {
326 15949 : Bytecode jump_bytecode = Bytecodes::FromByte(bytecodes()->at(jump_location));
327 : DCHECK(Bytecodes::IsForwardJump(jump_bytecode));
328 : DCHECK(Bytecodes::IsJumpImmediate(jump_bytecode));
329 : DCHECK_EQ(Bytecodes::GetOperandType(jump_bytecode, 0), OperandType::kUImm);
330 : DCHECK_GT(delta, 0);
331 15949 : size_t operand_location = jump_location + 1;
332 : uint8_t operand_bytes[2];
333 31898 : if (Bytecodes::ScaleForUnsignedOperand(delta) <= OperandScale::kDouble) {
334 : // The jump fits within the range of an Imm16 operand, so cancel
335 : // the reservation and jump directly.
336 15944 : constant_array_builder()->DiscardReservedEntry(OperandSize::kShort);
337 : WriteUnalignedUInt16(reinterpret_cast<Address>(operand_bytes),
338 : static_cast<uint16_t>(delta));
339 : } else {
340 : // The jump does not fit within the range of an Imm16 operand, so
341 : // commit reservation putting the offset into the constant pool,
342 : // and update the jump instruction and operand.
343 : size_t entry = constant_array_builder()->CommitReservedEntry(
344 5 : OperandSize::kShort, Smi::FromInt(delta));
345 5 : jump_bytecode = GetJumpWithConstantOperand(jump_bytecode);
346 5 : bytecodes()->at(jump_location) = Bytecodes::ToByte(jump_bytecode);
347 5 : WriteUnalignedUInt16(reinterpret_cast<Address>(operand_bytes),
348 : static_cast<uint16_t>(entry));
349 : }
350 : DCHECK(bytecodes()->at(operand_location) == k8BitJumpPlaceholder &&
351 : bytecodes()->at(operand_location + 1) == k8BitJumpPlaceholder);
352 31898 : bytecodes()->at(operand_location++) = operand_bytes[0];
353 15949 : bytecodes()->at(operand_location) = operand_bytes[1];
354 15949 : }
355 :
356 5 : void BytecodeArrayWriter::PatchJumpWith32BitOperand(size_t jump_location,
357 : int delta) {
358 : DCHECK(Bytecodes::IsJumpImmediate(
359 : Bytecodes::FromByte(bytecodes()->at(jump_location))));
360 5 : constant_array_builder()->DiscardReservedEntry(OperandSize::kQuad);
361 : uint8_t operand_bytes[4];
362 5 : WriteUnalignedUInt32(reinterpret_cast<Address>(operand_bytes),
363 : static_cast<uint32_t>(delta));
364 5 : size_t operand_location = jump_location + 1;
365 : DCHECK(bytecodes()->at(operand_location) == k8BitJumpPlaceholder &&
366 : bytecodes()->at(operand_location + 1) == k8BitJumpPlaceholder &&
367 : bytecodes()->at(operand_location + 2) == k8BitJumpPlaceholder &&
368 : bytecodes()->at(operand_location + 3) == k8BitJumpPlaceholder);
369 10 : bytecodes()->at(operand_location++) = operand_bytes[0];
370 10 : bytecodes()->at(operand_location++) = operand_bytes[1];
371 10 : bytecodes()->at(operand_location++) = operand_bytes[2];
372 5 : bytecodes()->at(operand_location) = operand_bytes[3];
373 5 : }
374 :
375 1823273 : void BytecodeArrayWriter::PatchJump(size_t jump_target, size_t jump_location) {
376 1823273 : Bytecode jump_bytecode = Bytecodes::FromByte(bytecodes()->at(jump_location));
377 1823273 : int delta = static_cast<int>(jump_target - jump_location);
378 : int prefix_offset = 0;
379 : OperandScale operand_scale = OperandScale::kSingle;
380 1823273 : if (Bytecodes::IsPrefixScalingBytecode(jump_bytecode)) {
381 : // If a prefix scaling bytecode is emitted the target offset is one
382 : // less than the case of no prefix scaling bytecode.
383 15954 : delta -= 1;
384 : prefix_offset = 1;
385 15954 : operand_scale = Bytecodes::PrefixBytecodeToOperandScale(jump_bytecode);
386 : jump_bytecode =
387 15954 : Bytecodes::FromByte(bytecodes()->at(jump_location + prefix_offset));
388 : }
389 :
390 : DCHECK(Bytecodes::IsJump(jump_bytecode));
391 1823273 : switch (operand_scale) {
392 : case OperandScale::kSingle:
393 1807319 : PatchJumpWith8BitOperand(jump_location, delta);
394 1807323 : break;
395 : case OperandScale::kDouble:
396 15949 : PatchJumpWith16BitOperand(jump_location + prefix_offset, delta);
397 15949 : break;
398 : case OperandScale::kQuadruple:
399 5 : PatchJumpWith32BitOperand(jump_location + prefix_offset, delta);
400 5 : break;
401 : default:
402 0 : UNREACHABLE();
403 : }
404 1823277 : unbound_jumps_--;
405 1823277 : }
406 :
407 254087 : void BytecodeArrayWriter::EmitJumpLoop(BytecodeNode* node,
408 : BytecodeLoopHeader* loop_header) {
409 : DCHECK_EQ(node->bytecode(), Bytecode::kJumpLoop);
410 : DCHECK_EQ(0u, node->operand(0));
411 :
412 : size_t current_offset = bytecodes()->size();
413 :
414 254087 : CHECK_GE(current_offset, loop_header->offset());
415 254087 : CHECK_LE(current_offset, static_cast<size_t>(kMaxUInt32));
416 : // Label has been bound already so this is a backwards jump.
417 : uint32_t delta =
418 254087 : static_cast<uint32_t>(current_offset - loop_header->offset());
419 : OperandScale operand_scale = Bytecodes::ScaleForUnsignedOperand(delta);
420 254087 : if (operand_scale > OperandScale::kSingle) {
421 : // Adjust for scaling byte prefix for wide jump offset.
422 8406 : delta += 1;
423 : }
424 254087 : node->update_operand0(delta);
425 254089 : EmitBytecode(node);
426 254090 : }
427 :
428 1823283 : void BytecodeArrayWriter::EmitJump(BytecodeNode* node, BytecodeLabel* label) {
429 : DCHECK(Bytecodes::IsForwardJump(node->bytecode()));
430 : DCHECK_EQ(0u, node->operand(0));
431 :
432 : size_t current_offset = bytecodes()->size();
433 :
434 : // The label has not yet been bound so this is a forward reference
435 : // that will be patched when the label is bound. We create a
436 : // reservation in the constant pool so the jump can be patched
437 : // when the label is bound. The reservation means the maximum size
438 : // of the operand for the constant is known and the jump can
439 : // be emitted into the bytecode stream with space for the operand.
440 1823283 : unbound_jumps_++;
441 : label->set_referrer(current_offset);
442 : OperandSize reserved_operand_size =
443 1823283 : constant_array_builder()->CreateReservedEntry();
444 : DCHECK_NE(Bytecode::kJumpLoop, node->bytecode());
445 1823286 : switch (reserved_operand_size) {
446 : case OperandSize::kNone:
447 0 : UNREACHABLE();
448 : break;
449 : case OperandSize::kByte:
450 1807335 : node->update_operand0(k8BitJumpPlaceholder);
451 1807329 : break;
452 : case OperandSize::kShort:
453 15949 : node->update_operand0(k16BitJumpPlaceholder);
454 15949 : break;
455 : case OperandSize::kQuad:
456 5 : node->update_operand0(k32BitJumpPlaceholder);
457 5 : break;
458 : }
459 1823280 : EmitBytecode(node);
460 1823276 : }
461 :
462 0 : void BytecodeArrayWriter::EmitSwitch(BytecodeNode* node,
463 : BytecodeJumpTable* jump_table) {
464 : DCHECK(Bytecodes::IsSwitch(node->bytecode()));
465 :
466 : size_t current_offset = bytecodes()->size();
467 19821 : if (node->operand_scale() > OperandScale::kSingle) {
468 : // Adjust for scaling byte prefix.
469 122 : current_offset += 1;
470 : }
471 : jump_table->set_switch_bytecode_offset(current_offset);
472 :
473 19821 : EmitBytecode(node);
474 0 : }
475 :
476 : } // namespace interpreter
477 : } // namespace internal
478 122036 : } // namespace v8
|