11cb0ef41Sopenharmony_ci// Copyright 2015 the V8 project authors. All rights reserved. 21cb0ef41Sopenharmony_ci// Use of this source code is governed by a BSD-style license that can be 31cb0ef41Sopenharmony_ci// found in the LICENSE file. 41cb0ef41Sopenharmony_ci 51cb0ef41Sopenharmony_ci#include "src/interpreter/bytecode-array-writer.h" 61cb0ef41Sopenharmony_ci 71cb0ef41Sopenharmony_ci#include "src/api/api-inl.h" 81cb0ef41Sopenharmony_ci#include "src/heap/local-factory-inl.h" 91cb0ef41Sopenharmony_ci#include "src/interpreter/bytecode-jump-table.h" 101cb0ef41Sopenharmony_ci#include "src/interpreter/bytecode-label.h" 111cb0ef41Sopenharmony_ci#include "src/interpreter/bytecode-node.h" 121cb0ef41Sopenharmony_ci#include "src/interpreter/bytecode-register.h" 131cb0ef41Sopenharmony_ci#include "src/interpreter/bytecode-source-info.h" 141cb0ef41Sopenharmony_ci#include "src/interpreter/constant-array-builder.h" 151cb0ef41Sopenharmony_ci#include "src/interpreter/handler-table-builder.h" 161cb0ef41Sopenharmony_ci#include "src/objects/objects-inl.h" 171cb0ef41Sopenharmony_ci 181cb0ef41Sopenharmony_cinamespace v8 { 191cb0ef41Sopenharmony_cinamespace internal { 201cb0ef41Sopenharmony_cinamespace interpreter { 211cb0ef41Sopenharmony_ci 221cb0ef41Sopenharmony_ciSTATIC_CONST_MEMBER_DEFINITION const size_t 231cb0ef41Sopenharmony_ci BytecodeArrayWriter::kMaxSizeOfPackedBytecode; 241cb0ef41Sopenharmony_ci 251cb0ef41Sopenharmony_ciBytecodeArrayWriter::BytecodeArrayWriter( 261cb0ef41Sopenharmony_ci Zone* zone, ConstantArrayBuilder* constant_array_builder, 271cb0ef41Sopenharmony_ci SourcePositionTableBuilder::RecordingMode source_position_mode) 281cb0ef41Sopenharmony_ci : bytecodes_(zone), 291cb0ef41Sopenharmony_ci unbound_jumps_(0), 301cb0ef41Sopenharmony_ci source_position_table_builder_(zone, source_position_mode), 311cb0ef41Sopenharmony_ci constant_array_builder_(constant_array_builder), 321cb0ef41Sopenharmony_ci last_bytecode_(Bytecode::kIllegal), 331cb0ef41Sopenharmony_ci last_bytecode_offset_(0), 341cb0ef41Sopenharmony_ci last_bytecode_had_source_info_(false), 351cb0ef41Sopenharmony_ci elide_noneffectful_bytecodes_(FLAG_ignition_elide_noneffectful_bytecodes), 361cb0ef41Sopenharmony_ci exit_seen_in_block_(false) { 371cb0ef41Sopenharmony_ci bytecodes_.reserve(512); // Derived via experimentation. 381cb0ef41Sopenharmony_ci} 391cb0ef41Sopenharmony_ci 401cb0ef41Sopenharmony_citemplate <typename IsolateT> 411cb0ef41Sopenharmony_ciHandle<BytecodeArray> BytecodeArrayWriter::ToBytecodeArray( 421cb0ef41Sopenharmony_ci IsolateT* isolate, int register_count, int parameter_count, 431cb0ef41Sopenharmony_ci Handle<ByteArray> handler_table) { 441cb0ef41Sopenharmony_ci DCHECK_EQ(0, unbound_jumps_); 451cb0ef41Sopenharmony_ci 461cb0ef41Sopenharmony_ci int bytecode_size = static_cast<int>(bytecodes()->size()); 471cb0ef41Sopenharmony_ci int frame_size = register_count * kSystemPointerSize; 481cb0ef41Sopenharmony_ci Handle<FixedArray> constant_pool = 491cb0ef41Sopenharmony_ci constant_array_builder()->ToFixedArray(isolate); 501cb0ef41Sopenharmony_ci Handle<BytecodeArray> bytecode_array = isolate->factory()->NewBytecodeArray( 511cb0ef41Sopenharmony_ci bytecode_size, &bytecodes()->front(), frame_size, parameter_count, 521cb0ef41Sopenharmony_ci constant_pool); 531cb0ef41Sopenharmony_ci bytecode_array->set_handler_table(*handler_table); 541cb0ef41Sopenharmony_ci return bytecode_array; 551cb0ef41Sopenharmony_ci} 561cb0ef41Sopenharmony_ci 571cb0ef41Sopenharmony_citemplate EXPORT_TEMPLATE_DEFINE(V8_EXPORT_PRIVATE) 581cb0ef41Sopenharmony_ci Handle<BytecodeArray> BytecodeArrayWriter::ToBytecodeArray( 591cb0ef41Sopenharmony_ci Isolate* isolate, int register_count, int parameter_count, 601cb0ef41Sopenharmony_ci Handle<ByteArray> handler_table); 611cb0ef41Sopenharmony_citemplate EXPORT_TEMPLATE_DEFINE(V8_EXPORT_PRIVATE) 621cb0ef41Sopenharmony_ci Handle<BytecodeArray> BytecodeArrayWriter::ToBytecodeArray( 631cb0ef41Sopenharmony_ci LocalIsolate* isolate, int register_count, int parameter_count, 641cb0ef41Sopenharmony_ci Handle<ByteArray> handler_table); 651cb0ef41Sopenharmony_ci 661cb0ef41Sopenharmony_citemplate <typename IsolateT> 671cb0ef41Sopenharmony_ciHandle<ByteArray> BytecodeArrayWriter::ToSourcePositionTable( 681cb0ef41Sopenharmony_ci IsolateT* isolate) { 691cb0ef41Sopenharmony_ci DCHECK(!source_position_table_builder_.Lazy()); 701cb0ef41Sopenharmony_ci Handle<ByteArray> source_position_table = 711cb0ef41Sopenharmony_ci source_position_table_builder_.Omit() 721cb0ef41Sopenharmony_ci ? isolate->factory()->empty_byte_array() 731cb0ef41Sopenharmony_ci : source_position_table_builder_.ToSourcePositionTable(isolate); 741cb0ef41Sopenharmony_ci return source_position_table; 751cb0ef41Sopenharmony_ci} 761cb0ef41Sopenharmony_ci 771cb0ef41Sopenharmony_citemplate EXPORT_TEMPLATE_DEFINE(V8_EXPORT_PRIVATE) 781cb0ef41Sopenharmony_ci Handle<ByteArray> BytecodeArrayWriter::ToSourcePositionTable( 791cb0ef41Sopenharmony_ci Isolate* isolate); 801cb0ef41Sopenharmony_citemplate EXPORT_TEMPLATE_DEFINE(V8_EXPORT_PRIVATE) 811cb0ef41Sopenharmony_ci Handle<ByteArray> BytecodeArrayWriter::ToSourcePositionTable( 821cb0ef41Sopenharmony_ci LocalIsolate* isolate); 831cb0ef41Sopenharmony_ci 841cb0ef41Sopenharmony_ci#ifdef DEBUG 851cb0ef41Sopenharmony_ciint BytecodeArrayWriter::CheckBytecodeMatches(BytecodeArray bytecode) { 861cb0ef41Sopenharmony_ci int mismatches = false; 871cb0ef41Sopenharmony_ci int bytecode_size = static_cast<int>(bytecodes()->size()); 881cb0ef41Sopenharmony_ci const byte* bytecode_ptr = &bytecodes()->front(); 891cb0ef41Sopenharmony_ci if (bytecode_size != bytecode.length()) mismatches = true; 901cb0ef41Sopenharmony_ci 911cb0ef41Sopenharmony_ci // If there's a mismatch only in the length of the bytecode (very unlikely) 921cb0ef41Sopenharmony_ci // then the first mismatch will be the first extra bytecode. 931cb0ef41Sopenharmony_ci int first_mismatch = std::min(bytecode_size, bytecode.length()); 941cb0ef41Sopenharmony_ci for (int i = 0; i < first_mismatch; ++i) { 951cb0ef41Sopenharmony_ci if (bytecode_ptr[i] != bytecode.get(i)) { 961cb0ef41Sopenharmony_ci mismatches = true; 971cb0ef41Sopenharmony_ci first_mismatch = i; 981cb0ef41Sopenharmony_ci break; 991cb0ef41Sopenharmony_ci } 1001cb0ef41Sopenharmony_ci } 1011cb0ef41Sopenharmony_ci 1021cb0ef41Sopenharmony_ci if (mismatches) { 1031cb0ef41Sopenharmony_ci return first_mismatch; 1041cb0ef41Sopenharmony_ci } 1051cb0ef41Sopenharmony_ci return -1; 1061cb0ef41Sopenharmony_ci} 1071cb0ef41Sopenharmony_ci#endif 1081cb0ef41Sopenharmony_ci 1091cb0ef41Sopenharmony_civoid BytecodeArrayWriter::Write(BytecodeNode* node) { 1101cb0ef41Sopenharmony_ci DCHECK(!Bytecodes::IsJump(node->bytecode())); 1111cb0ef41Sopenharmony_ci 1121cb0ef41Sopenharmony_ci if (exit_seen_in_block_) return; // Don't emit dead code. 1131cb0ef41Sopenharmony_ci UpdateExitSeenInBlock(node->bytecode()); 1141cb0ef41Sopenharmony_ci MaybeElideLastBytecode(node->bytecode(), node->source_info().is_valid()); 1151cb0ef41Sopenharmony_ci 1161cb0ef41Sopenharmony_ci UpdateSourcePositionTable(node); 1171cb0ef41Sopenharmony_ci EmitBytecode(node); 1181cb0ef41Sopenharmony_ci} 1191cb0ef41Sopenharmony_ci 1201cb0ef41Sopenharmony_civoid BytecodeArrayWriter::WriteJump(BytecodeNode* node, BytecodeLabel* label) { 1211cb0ef41Sopenharmony_ci DCHECK(Bytecodes::IsForwardJump(node->bytecode())); 1221cb0ef41Sopenharmony_ci 1231cb0ef41Sopenharmony_ci if (exit_seen_in_block_) return; // Don't emit dead code. 1241cb0ef41Sopenharmony_ci UpdateExitSeenInBlock(node->bytecode()); 1251cb0ef41Sopenharmony_ci MaybeElideLastBytecode(node->bytecode(), node->source_info().is_valid()); 1261cb0ef41Sopenharmony_ci 1271cb0ef41Sopenharmony_ci UpdateSourcePositionTable(node); 1281cb0ef41Sopenharmony_ci EmitJump(node, label); 1291cb0ef41Sopenharmony_ci} 1301cb0ef41Sopenharmony_ci 1311cb0ef41Sopenharmony_civoid BytecodeArrayWriter::WriteJumpLoop(BytecodeNode* node, 1321cb0ef41Sopenharmony_ci BytecodeLoopHeader* loop_header) { 1331cb0ef41Sopenharmony_ci DCHECK_EQ(node->bytecode(), Bytecode::kJumpLoop); 1341cb0ef41Sopenharmony_ci 1351cb0ef41Sopenharmony_ci if (exit_seen_in_block_) return; // Don't emit dead code. 1361cb0ef41Sopenharmony_ci UpdateExitSeenInBlock(node->bytecode()); 1371cb0ef41Sopenharmony_ci MaybeElideLastBytecode(node->bytecode(), node->source_info().is_valid()); 1381cb0ef41Sopenharmony_ci 1391cb0ef41Sopenharmony_ci UpdateSourcePositionTable(node); 1401cb0ef41Sopenharmony_ci EmitJumpLoop(node, loop_header); 1411cb0ef41Sopenharmony_ci} 1421cb0ef41Sopenharmony_ci 1431cb0ef41Sopenharmony_civoid BytecodeArrayWriter::WriteSwitch(BytecodeNode* node, 1441cb0ef41Sopenharmony_ci BytecodeJumpTable* jump_table) { 1451cb0ef41Sopenharmony_ci DCHECK(Bytecodes::IsSwitch(node->bytecode())); 1461cb0ef41Sopenharmony_ci 1471cb0ef41Sopenharmony_ci if (exit_seen_in_block_) return; // Don't emit dead code. 1481cb0ef41Sopenharmony_ci UpdateExitSeenInBlock(node->bytecode()); 1491cb0ef41Sopenharmony_ci MaybeElideLastBytecode(node->bytecode(), node->source_info().is_valid()); 1501cb0ef41Sopenharmony_ci 1511cb0ef41Sopenharmony_ci UpdateSourcePositionTable(node); 1521cb0ef41Sopenharmony_ci EmitSwitch(node, jump_table); 1531cb0ef41Sopenharmony_ci} 1541cb0ef41Sopenharmony_ci 1551cb0ef41Sopenharmony_civoid BytecodeArrayWriter::BindLabel(BytecodeLabel* label) { 1561cb0ef41Sopenharmony_ci DCHECK(label->has_referrer_jump()); 1571cb0ef41Sopenharmony_ci size_t current_offset = bytecodes()->size(); 1581cb0ef41Sopenharmony_ci // Update the jump instruction's location. 1591cb0ef41Sopenharmony_ci PatchJump(current_offset, label->jump_offset()); 1601cb0ef41Sopenharmony_ci label->bind(); 1611cb0ef41Sopenharmony_ci StartBasicBlock(); 1621cb0ef41Sopenharmony_ci} 1631cb0ef41Sopenharmony_ci 1641cb0ef41Sopenharmony_civoid BytecodeArrayWriter::BindLoopHeader(BytecodeLoopHeader* loop_header) { 1651cb0ef41Sopenharmony_ci size_t current_offset = bytecodes()->size(); 1661cb0ef41Sopenharmony_ci loop_header->bind_to(current_offset); 1671cb0ef41Sopenharmony_ci // Don't start a basic block when the entire loop is dead. 1681cb0ef41Sopenharmony_ci if (exit_seen_in_block_) return; 1691cb0ef41Sopenharmony_ci StartBasicBlock(); 1701cb0ef41Sopenharmony_ci} 1711cb0ef41Sopenharmony_ci 1721cb0ef41Sopenharmony_civoid BytecodeArrayWriter::BindJumpTableEntry(BytecodeJumpTable* jump_table, 1731cb0ef41Sopenharmony_ci int case_value) { 1741cb0ef41Sopenharmony_ci DCHECK(!jump_table->is_bound(case_value)); 1751cb0ef41Sopenharmony_ci 1761cb0ef41Sopenharmony_ci size_t current_offset = bytecodes()->size(); 1771cb0ef41Sopenharmony_ci size_t relative_jump = current_offset - jump_table->switch_bytecode_offset(); 1781cb0ef41Sopenharmony_ci 1791cb0ef41Sopenharmony_ci constant_array_builder()->SetJumpTableSmi( 1801cb0ef41Sopenharmony_ci jump_table->ConstantPoolEntryFor(case_value), 1811cb0ef41Sopenharmony_ci Smi::FromInt(static_cast<int>(relative_jump))); 1821cb0ef41Sopenharmony_ci jump_table->mark_bound(case_value); 1831cb0ef41Sopenharmony_ci 1841cb0ef41Sopenharmony_ci StartBasicBlock(); 1851cb0ef41Sopenharmony_ci} 1861cb0ef41Sopenharmony_ci 1871cb0ef41Sopenharmony_civoid BytecodeArrayWriter::BindHandlerTarget( 1881cb0ef41Sopenharmony_ci HandlerTableBuilder* handler_table_builder, int handler_id) { 1891cb0ef41Sopenharmony_ci size_t current_offset = bytecodes()->size(); 1901cb0ef41Sopenharmony_ci StartBasicBlock(); 1911cb0ef41Sopenharmony_ci handler_table_builder->SetHandlerTarget(handler_id, current_offset); 1921cb0ef41Sopenharmony_ci} 1931cb0ef41Sopenharmony_ci 1941cb0ef41Sopenharmony_civoid BytecodeArrayWriter::BindTryRegionStart( 1951cb0ef41Sopenharmony_ci HandlerTableBuilder* handler_table_builder, int handler_id) { 1961cb0ef41Sopenharmony_ci size_t current_offset = bytecodes()->size(); 1971cb0ef41Sopenharmony_ci // Try blocks don't have to be in a separate basic block, but we do have to 1981cb0ef41Sopenharmony_ci // invalidate the bytecode to avoid eliding it and changing the offset. 1991cb0ef41Sopenharmony_ci InvalidateLastBytecode(); 2001cb0ef41Sopenharmony_ci handler_table_builder->SetTryRegionStart(handler_id, current_offset); 2011cb0ef41Sopenharmony_ci} 2021cb0ef41Sopenharmony_ci 2031cb0ef41Sopenharmony_civoid BytecodeArrayWriter::BindTryRegionEnd( 2041cb0ef41Sopenharmony_ci HandlerTableBuilder* handler_table_builder, int handler_id) { 2051cb0ef41Sopenharmony_ci // Try blocks don't have to be in a separate basic block, but we do have to 2061cb0ef41Sopenharmony_ci // invalidate the bytecode to avoid eliding it and changing the offset. 2071cb0ef41Sopenharmony_ci InvalidateLastBytecode(); 2081cb0ef41Sopenharmony_ci size_t current_offset = bytecodes()->size(); 2091cb0ef41Sopenharmony_ci handler_table_builder->SetTryRegionEnd(handler_id, current_offset); 2101cb0ef41Sopenharmony_ci} 2111cb0ef41Sopenharmony_ci 2121cb0ef41Sopenharmony_civoid BytecodeArrayWriter::SetFunctionEntrySourcePosition(int position) { 2131cb0ef41Sopenharmony_ci bool is_statement = false; 2141cb0ef41Sopenharmony_ci source_position_table_builder_.AddPosition( 2151cb0ef41Sopenharmony_ci kFunctionEntryBytecodeOffset, SourcePosition(position), is_statement); 2161cb0ef41Sopenharmony_ci} 2171cb0ef41Sopenharmony_ci 2181cb0ef41Sopenharmony_civoid BytecodeArrayWriter::StartBasicBlock() { 2191cb0ef41Sopenharmony_ci InvalidateLastBytecode(); 2201cb0ef41Sopenharmony_ci exit_seen_in_block_ = false; 2211cb0ef41Sopenharmony_ci} 2221cb0ef41Sopenharmony_ci 2231cb0ef41Sopenharmony_civoid BytecodeArrayWriter::UpdateSourcePositionTable( 2241cb0ef41Sopenharmony_ci const BytecodeNode* const node) { 2251cb0ef41Sopenharmony_ci int bytecode_offset = static_cast<int>(bytecodes()->size()); 2261cb0ef41Sopenharmony_ci const BytecodeSourceInfo& source_info = node->source_info(); 2271cb0ef41Sopenharmony_ci if (source_info.is_valid()) { 2281cb0ef41Sopenharmony_ci source_position_table_builder()->AddPosition( 2291cb0ef41Sopenharmony_ci bytecode_offset, SourcePosition(source_info.source_position()), 2301cb0ef41Sopenharmony_ci source_info.is_statement()); 2311cb0ef41Sopenharmony_ci } 2321cb0ef41Sopenharmony_ci} 2331cb0ef41Sopenharmony_ci 2341cb0ef41Sopenharmony_civoid BytecodeArrayWriter::UpdateExitSeenInBlock(Bytecode bytecode) { 2351cb0ef41Sopenharmony_ci switch (bytecode) { 2361cb0ef41Sopenharmony_ci case Bytecode::kReturn: 2371cb0ef41Sopenharmony_ci case Bytecode::kThrow: 2381cb0ef41Sopenharmony_ci case Bytecode::kReThrow: 2391cb0ef41Sopenharmony_ci case Bytecode::kAbort: 2401cb0ef41Sopenharmony_ci case Bytecode::kJump: 2411cb0ef41Sopenharmony_ci case Bytecode::kJumpLoop: 2421cb0ef41Sopenharmony_ci case Bytecode::kJumpConstant: 2431cb0ef41Sopenharmony_ci case Bytecode::kSuspendGenerator: 2441cb0ef41Sopenharmony_ci exit_seen_in_block_ = true; 2451cb0ef41Sopenharmony_ci break; 2461cb0ef41Sopenharmony_ci default: 2471cb0ef41Sopenharmony_ci break; 2481cb0ef41Sopenharmony_ci } 2491cb0ef41Sopenharmony_ci} 2501cb0ef41Sopenharmony_ci 2511cb0ef41Sopenharmony_civoid BytecodeArrayWriter::MaybeElideLastBytecode(Bytecode next_bytecode, 2521cb0ef41Sopenharmony_ci bool has_source_info) { 2531cb0ef41Sopenharmony_ci if (!elide_noneffectful_bytecodes_) return; 2541cb0ef41Sopenharmony_ci 2551cb0ef41Sopenharmony_ci // If the last bytecode loaded the accumulator without any external effect, 2561cb0ef41Sopenharmony_ci // and the next bytecode clobbers this load without reading the accumulator, 2571cb0ef41Sopenharmony_ci // then the previous bytecode can be elided as it has no effect. 2581cb0ef41Sopenharmony_ci if (Bytecodes::IsAccumulatorLoadWithoutEffects(last_bytecode_) && 2591cb0ef41Sopenharmony_ci Bytecodes::GetImplicitRegisterUse(next_bytecode) == 2601cb0ef41Sopenharmony_ci ImplicitRegisterUse::kWriteAccumulator && 2611cb0ef41Sopenharmony_ci (!last_bytecode_had_source_info_ || !has_source_info)) { 2621cb0ef41Sopenharmony_ci DCHECK_GT(bytecodes()->size(), last_bytecode_offset_); 2631cb0ef41Sopenharmony_ci bytecodes()->resize(last_bytecode_offset_); 2641cb0ef41Sopenharmony_ci // If the last bytecode had source info we will transfer the source info 2651cb0ef41Sopenharmony_ci // to this bytecode. 2661cb0ef41Sopenharmony_ci has_source_info |= last_bytecode_had_source_info_; 2671cb0ef41Sopenharmony_ci } 2681cb0ef41Sopenharmony_ci last_bytecode_ = next_bytecode; 2691cb0ef41Sopenharmony_ci last_bytecode_had_source_info_ = has_source_info; 2701cb0ef41Sopenharmony_ci last_bytecode_offset_ = bytecodes()->size(); 2711cb0ef41Sopenharmony_ci} 2721cb0ef41Sopenharmony_ci 2731cb0ef41Sopenharmony_civoid BytecodeArrayWriter::InvalidateLastBytecode() { 2741cb0ef41Sopenharmony_ci last_bytecode_ = Bytecode::kIllegal; 2751cb0ef41Sopenharmony_ci} 2761cb0ef41Sopenharmony_ci 2771cb0ef41Sopenharmony_civoid BytecodeArrayWriter::EmitBytecode(const BytecodeNode* const node) { 2781cb0ef41Sopenharmony_ci DCHECK_NE(node->bytecode(), Bytecode::kIllegal); 2791cb0ef41Sopenharmony_ci 2801cb0ef41Sopenharmony_ci Bytecode bytecode = node->bytecode(); 2811cb0ef41Sopenharmony_ci OperandScale operand_scale = node->operand_scale(); 2821cb0ef41Sopenharmony_ci 2831cb0ef41Sopenharmony_ci if (operand_scale != OperandScale::kSingle) { 2841cb0ef41Sopenharmony_ci Bytecode prefix = Bytecodes::OperandScaleToPrefixBytecode(operand_scale); 2851cb0ef41Sopenharmony_ci bytecodes()->push_back(Bytecodes::ToByte(prefix)); 2861cb0ef41Sopenharmony_ci } 2871cb0ef41Sopenharmony_ci bytecodes()->push_back(Bytecodes::ToByte(bytecode)); 2881cb0ef41Sopenharmony_ci 2891cb0ef41Sopenharmony_ci const uint32_t* const operands = node->operands(); 2901cb0ef41Sopenharmony_ci const int operand_count = node->operand_count(); 2911cb0ef41Sopenharmony_ci const OperandSize* operand_sizes = 2921cb0ef41Sopenharmony_ci Bytecodes::GetOperandSizes(bytecode, operand_scale); 2931cb0ef41Sopenharmony_ci for (int i = 0; i < operand_count; ++i) { 2941cb0ef41Sopenharmony_ci switch (operand_sizes[i]) { 2951cb0ef41Sopenharmony_ci case OperandSize::kNone: 2961cb0ef41Sopenharmony_ci UNREACHABLE(); 2971cb0ef41Sopenharmony_ci case OperandSize::kByte: 2981cb0ef41Sopenharmony_ci bytecodes()->push_back(static_cast<uint8_t>(operands[i])); 2991cb0ef41Sopenharmony_ci break; 3001cb0ef41Sopenharmony_ci case OperandSize::kShort: { 3011cb0ef41Sopenharmony_ci uint16_t operand = static_cast<uint16_t>(operands[i]); 3021cb0ef41Sopenharmony_ci const uint8_t* raw_operand = reinterpret_cast<const uint8_t*>(&operand); 3031cb0ef41Sopenharmony_ci bytecodes()->push_back(raw_operand[0]); 3041cb0ef41Sopenharmony_ci bytecodes()->push_back(raw_operand[1]); 3051cb0ef41Sopenharmony_ci break; 3061cb0ef41Sopenharmony_ci } 3071cb0ef41Sopenharmony_ci case OperandSize::kQuad: { 3081cb0ef41Sopenharmony_ci const uint8_t* raw_operand = 3091cb0ef41Sopenharmony_ci reinterpret_cast<const uint8_t*>(&operands[i]); 3101cb0ef41Sopenharmony_ci bytecodes()->push_back(raw_operand[0]); 3111cb0ef41Sopenharmony_ci bytecodes()->push_back(raw_operand[1]); 3121cb0ef41Sopenharmony_ci bytecodes()->push_back(raw_operand[2]); 3131cb0ef41Sopenharmony_ci bytecodes()->push_back(raw_operand[3]); 3141cb0ef41Sopenharmony_ci break; 3151cb0ef41Sopenharmony_ci } 3161cb0ef41Sopenharmony_ci } 3171cb0ef41Sopenharmony_ci } 3181cb0ef41Sopenharmony_ci} 3191cb0ef41Sopenharmony_ci 3201cb0ef41Sopenharmony_ci// static 3211cb0ef41Sopenharmony_ciBytecode GetJumpWithConstantOperand(Bytecode jump_bytecode) { 3221cb0ef41Sopenharmony_ci switch (jump_bytecode) { 3231cb0ef41Sopenharmony_ci case Bytecode::kJump: 3241cb0ef41Sopenharmony_ci return Bytecode::kJumpConstant; 3251cb0ef41Sopenharmony_ci case Bytecode::kJumpIfTrue: 3261cb0ef41Sopenharmony_ci return Bytecode::kJumpIfTrueConstant; 3271cb0ef41Sopenharmony_ci case Bytecode::kJumpIfFalse: 3281cb0ef41Sopenharmony_ci return Bytecode::kJumpIfFalseConstant; 3291cb0ef41Sopenharmony_ci case Bytecode::kJumpIfToBooleanTrue: 3301cb0ef41Sopenharmony_ci return Bytecode::kJumpIfToBooleanTrueConstant; 3311cb0ef41Sopenharmony_ci case Bytecode::kJumpIfToBooleanFalse: 3321cb0ef41Sopenharmony_ci return Bytecode::kJumpIfToBooleanFalseConstant; 3331cb0ef41Sopenharmony_ci case Bytecode::kJumpIfNull: 3341cb0ef41Sopenharmony_ci return Bytecode::kJumpIfNullConstant; 3351cb0ef41Sopenharmony_ci case Bytecode::kJumpIfNotNull: 3361cb0ef41Sopenharmony_ci return Bytecode::kJumpIfNotNullConstant; 3371cb0ef41Sopenharmony_ci case Bytecode::kJumpIfUndefined: 3381cb0ef41Sopenharmony_ci return Bytecode::kJumpIfUndefinedConstant; 3391cb0ef41Sopenharmony_ci case Bytecode::kJumpIfNotUndefined: 3401cb0ef41Sopenharmony_ci return Bytecode::kJumpIfNotUndefinedConstant; 3411cb0ef41Sopenharmony_ci case Bytecode::kJumpIfUndefinedOrNull: 3421cb0ef41Sopenharmony_ci return Bytecode::kJumpIfUndefinedOrNullConstant; 3431cb0ef41Sopenharmony_ci case Bytecode::kJumpIfJSReceiver: 3441cb0ef41Sopenharmony_ci return Bytecode::kJumpIfJSReceiverConstant; 3451cb0ef41Sopenharmony_ci default: 3461cb0ef41Sopenharmony_ci UNREACHABLE(); 3471cb0ef41Sopenharmony_ci } 3481cb0ef41Sopenharmony_ci} 3491cb0ef41Sopenharmony_ci 3501cb0ef41Sopenharmony_civoid BytecodeArrayWriter::PatchJumpWith8BitOperand(size_t jump_location, 3511cb0ef41Sopenharmony_ci int delta) { 3521cb0ef41Sopenharmony_ci Bytecode jump_bytecode = Bytecodes::FromByte(bytecodes()->at(jump_location)); 3531cb0ef41Sopenharmony_ci DCHECK(Bytecodes::IsForwardJump(jump_bytecode)); 3541cb0ef41Sopenharmony_ci DCHECK(Bytecodes::IsJumpImmediate(jump_bytecode)); 3551cb0ef41Sopenharmony_ci DCHECK_EQ(Bytecodes::GetOperandType(jump_bytecode, 0), OperandType::kUImm); 3561cb0ef41Sopenharmony_ci DCHECK_GT(delta, 0); 3571cb0ef41Sopenharmony_ci size_t operand_location = jump_location + 1; 3581cb0ef41Sopenharmony_ci DCHECK_EQ(bytecodes()->at(operand_location), k8BitJumpPlaceholder); 3591cb0ef41Sopenharmony_ci if (Bytecodes::ScaleForUnsignedOperand(delta) == OperandScale::kSingle) { 3601cb0ef41Sopenharmony_ci // The jump fits within the range of an UImm8 operand, so cancel 3611cb0ef41Sopenharmony_ci // the reservation and jump directly. 3621cb0ef41Sopenharmony_ci constant_array_builder()->DiscardReservedEntry(OperandSize::kByte); 3631cb0ef41Sopenharmony_ci bytecodes()->at(operand_location) = static_cast<uint8_t>(delta); 3641cb0ef41Sopenharmony_ci } else { 3651cb0ef41Sopenharmony_ci // The jump does not fit within the range of an UImm8 operand, so 3661cb0ef41Sopenharmony_ci // commit reservation putting the offset into the constant pool, 3671cb0ef41Sopenharmony_ci // and update the jump instruction and operand. 3681cb0ef41Sopenharmony_ci size_t entry = constant_array_builder()->CommitReservedEntry( 3691cb0ef41Sopenharmony_ci OperandSize::kByte, Smi::FromInt(delta)); 3701cb0ef41Sopenharmony_ci DCHECK_EQ(Bytecodes::SizeForUnsignedOperand(static_cast<uint32_t>(entry)), 3711cb0ef41Sopenharmony_ci OperandSize::kByte); 3721cb0ef41Sopenharmony_ci jump_bytecode = GetJumpWithConstantOperand(jump_bytecode); 3731cb0ef41Sopenharmony_ci bytecodes()->at(jump_location) = Bytecodes::ToByte(jump_bytecode); 3741cb0ef41Sopenharmony_ci bytecodes()->at(operand_location) = static_cast<uint8_t>(entry); 3751cb0ef41Sopenharmony_ci } 3761cb0ef41Sopenharmony_ci} 3771cb0ef41Sopenharmony_ci 3781cb0ef41Sopenharmony_civoid BytecodeArrayWriter::PatchJumpWith16BitOperand(size_t jump_location, 3791cb0ef41Sopenharmony_ci int delta) { 3801cb0ef41Sopenharmony_ci Bytecode jump_bytecode = Bytecodes::FromByte(bytecodes()->at(jump_location)); 3811cb0ef41Sopenharmony_ci DCHECK(Bytecodes::IsForwardJump(jump_bytecode)); 3821cb0ef41Sopenharmony_ci DCHECK(Bytecodes::IsJumpImmediate(jump_bytecode)); 3831cb0ef41Sopenharmony_ci DCHECK_EQ(Bytecodes::GetOperandType(jump_bytecode, 0), OperandType::kUImm); 3841cb0ef41Sopenharmony_ci DCHECK_GT(delta, 0); 3851cb0ef41Sopenharmony_ci size_t operand_location = jump_location + 1; 3861cb0ef41Sopenharmony_ci uint8_t operand_bytes[2]; 3871cb0ef41Sopenharmony_ci if (Bytecodes::ScaleForUnsignedOperand(delta) <= OperandScale::kDouble) { 3881cb0ef41Sopenharmony_ci // The jump fits within the range of an Imm16 operand, so cancel 3891cb0ef41Sopenharmony_ci // the reservation and jump directly. 3901cb0ef41Sopenharmony_ci constant_array_builder()->DiscardReservedEntry(OperandSize::kShort); 3911cb0ef41Sopenharmony_ci base::WriteUnalignedValue<uint16_t>( 3921cb0ef41Sopenharmony_ci reinterpret_cast<Address>(operand_bytes), static_cast<uint16_t>(delta)); 3931cb0ef41Sopenharmony_ci } else { 3941cb0ef41Sopenharmony_ci // The jump does not fit within the range of an Imm16 operand, so 3951cb0ef41Sopenharmony_ci // commit reservation putting the offset into the constant pool, 3961cb0ef41Sopenharmony_ci // and update the jump instruction and operand. 3971cb0ef41Sopenharmony_ci size_t entry = constant_array_builder()->CommitReservedEntry( 3981cb0ef41Sopenharmony_ci OperandSize::kShort, Smi::FromInt(delta)); 3991cb0ef41Sopenharmony_ci jump_bytecode = GetJumpWithConstantOperand(jump_bytecode); 4001cb0ef41Sopenharmony_ci bytecodes()->at(jump_location) = Bytecodes::ToByte(jump_bytecode); 4011cb0ef41Sopenharmony_ci base::WriteUnalignedValue<uint16_t>( 4021cb0ef41Sopenharmony_ci reinterpret_cast<Address>(operand_bytes), static_cast<uint16_t>(entry)); 4031cb0ef41Sopenharmony_ci } 4041cb0ef41Sopenharmony_ci DCHECK(bytecodes()->at(operand_location) == k8BitJumpPlaceholder && 4051cb0ef41Sopenharmony_ci bytecodes()->at(operand_location + 1) == k8BitJumpPlaceholder); 4061cb0ef41Sopenharmony_ci bytecodes()->at(operand_location++) = operand_bytes[0]; 4071cb0ef41Sopenharmony_ci bytecodes()->at(operand_location) = operand_bytes[1]; 4081cb0ef41Sopenharmony_ci} 4091cb0ef41Sopenharmony_ci 4101cb0ef41Sopenharmony_civoid BytecodeArrayWriter::PatchJumpWith32BitOperand(size_t jump_location, 4111cb0ef41Sopenharmony_ci int delta) { 4121cb0ef41Sopenharmony_ci DCHECK(Bytecodes::IsJumpImmediate( 4131cb0ef41Sopenharmony_ci Bytecodes::FromByte(bytecodes()->at(jump_location)))); 4141cb0ef41Sopenharmony_ci constant_array_builder()->DiscardReservedEntry(OperandSize::kQuad); 4151cb0ef41Sopenharmony_ci uint8_t operand_bytes[4]; 4161cb0ef41Sopenharmony_ci base::WriteUnalignedValue<uint32_t>(reinterpret_cast<Address>(operand_bytes), 4171cb0ef41Sopenharmony_ci static_cast<uint32_t>(delta)); 4181cb0ef41Sopenharmony_ci size_t operand_location = jump_location + 1; 4191cb0ef41Sopenharmony_ci DCHECK(bytecodes()->at(operand_location) == k8BitJumpPlaceholder && 4201cb0ef41Sopenharmony_ci bytecodes()->at(operand_location + 1) == k8BitJumpPlaceholder && 4211cb0ef41Sopenharmony_ci bytecodes()->at(operand_location + 2) == k8BitJumpPlaceholder && 4221cb0ef41Sopenharmony_ci bytecodes()->at(operand_location + 3) == k8BitJumpPlaceholder); 4231cb0ef41Sopenharmony_ci bytecodes()->at(operand_location++) = operand_bytes[0]; 4241cb0ef41Sopenharmony_ci bytecodes()->at(operand_location++) = operand_bytes[1]; 4251cb0ef41Sopenharmony_ci bytecodes()->at(operand_location++) = operand_bytes[2]; 4261cb0ef41Sopenharmony_ci bytecodes()->at(operand_location) = operand_bytes[3]; 4271cb0ef41Sopenharmony_ci} 4281cb0ef41Sopenharmony_ci 4291cb0ef41Sopenharmony_civoid BytecodeArrayWriter::PatchJump(size_t jump_target, size_t jump_location) { 4301cb0ef41Sopenharmony_ci Bytecode jump_bytecode = Bytecodes::FromByte(bytecodes()->at(jump_location)); 4311cb0ef41Sopenharmony_ci int delta = static_cast<int>(jump_target - jump_location); 4321cb0ef41Sopenharmony_ci int prefix_offset = 0; 4331cb0ef41Sopenharmony_ci OperandScale operand_scale = OperandScale::kSingle; 4341cb0ef41Sopenharmony_ci if (Bytecodes::IsPrefixScalingBytecode(jump_bytecode)) { 4351cb0ef41Sopenharmony_ci // If a prefix scaling bytecode is emitted the target offset is one 4361cb0ef41Sopenharmony_ci // less than the case of no prefix scaling bytecode. 4371cb0ef41Sopenharmony_ci delta -= 1; 4381cb0ef41Sopenharmony_ci prefix_offset = 1; 4391cb0ef41Sopenharmony_ci operand_scale = Bytecodes::PrefixBytecodeToOperandScale(jump_bytecode); 4401cb0ef41Sopenharmony_ci jump_bytecode = 4411cb0ef41Sopenharmony_ci Bytecodes::FromByte(bytecodes()->at(jump_location + prefix_offset)); 4421cb0ef41Sopenharmony_ci } 4431cb0ef41Sopenharmony_ci 4441cb0ef41Sopenharmony_ci DCHECK(Bytecodes::IsJump(jump_bytecode)); 4451cb0ef41Sopenharmony_ci switch (operand_scale) { 4461cb0ef41Sopenharmony_ci case OperandScale::kSingle: 4471cb0ef41Sopenharmony_ci PatchJumpWith8BitOperand(jump_location, delta); 4481cb0ef41Sopenharmony_ci break; 4491cb0ef41Sopenharmony_ci case OperandScale::kDouble: 4501cb0ef41Sopenharmony_ci PatchJumpWith16BitOperand(jump_location + prefix_offset, delta); 4511cb0ef41Sopenharmony_ci break; 4521cb0ef41Sopenharmony_ci case OperandScale::kQuadruple: 4531cb0ef41Sopenharmony_ci PatchJumpWith32BitOperand(jump_location + prefix_offset, delta); 4541cb0ef41Sopenharmony_ci break; 4551cb0ef41Sopenharmony_ci default: 4561cb0ef41Sopenharmony_ci UNREACHABLE(); 4571cb0ef41Sopenharmony_ci } 4581cb0ef41Sopenharmony_ci unbound_jumps_--; 4591cb0ef41Sopenharmony_ci} 4601cb0ef41Sopenharmony_ci 4611cb0ef41Sopenharmony_civoid BytecodeArrayWriter::EmitJumpLoop(BytecodeNode* node, 4621cb0ef41Sopenharmony_ci BytecodeLoopHeader* loop_header) { 4631cb0ef41Sopenharmony_ci DCHECK_EQ(node->bytecode(), Bytecode::kJumpLoop); 4641cb0ef41Sopenharmony_ci DCHECK_EQ(0u, node->operand(0)); 4651cb0ef41Sopenharmony_ci 4661cb0ef41Sopenharmony_ci size_t current_offset = bytecodes()->size(); 4671cb0ef41Sopenharmony_ci 4681cb0ef41Sopenharmony_ci CHECK_GE(current_offset, loop_header->offset()); 4691cb0ef41Sopenharmony_ci CHECK_LE(current_offset, static_cast<size_t>(kMaxUInt32)); 4701cb0ef41Sopenharmony_ci // Label has been bound already so this is a backwards jump. 4711cb0ef41Sopenharmony_ci uint32_t delta = 4721cb0ef41Sopenharmony_ci static_cast<uint32_t>(current_offset - loop_header->offset()); 4731cb0ef41Sopenharmony_ci OperandScale operand_scale = Bytecodes::ScaleForUnsignedOperand(delta); 4741cb0ef41Sopenharmony_ci if (operand_scale > OperandScale::kSingle) { 4751cb0ef41Sopenharmony_ci // Adjust for scaling byte prefix for wide jump offset. 4761cb0ef41Sopenharmony_ci delta += 1; 4771cb0ef41Sopenharmony_ci } 4781cb0ef41Sopenharmony_ci node->update_operand0(delta); 4791cb0ef41Sopenharmony_ci EmitBytecode(node); 4801cb0ef41Sopenharmony_ci} 4811cb0ef41Sopenharmony_ci 4821cb0ef41Sopenharmony_civoid BytecodeArrayWriter::EmitJump(BytecodeNode* node, BytecodeLabel* label) { 4831cb0ef41Sopenharmony_ci DCHECK(Bytecodes::IsForwardJump(node->bytecode())); 4841cb0ef41Sopenharmony_ci DCHECK_EQ(0u, node->operand(0)); 4851cb0ef41Sopenharmony_ci 4861cb0ef41Sopenharmony_ci size_t current_offset = bytecodes()->size(); 4871cb0ef41Sopenharmony_ci 4881cb0ef41Sopenharmony_ci // The label has not yet been bound so this is a forward reference 4891cb0ef41Sopenharmony_ci // that will be patched when the label is bound. We create a 4901cb0ef41Sopenharmony_ci // reservation in the constant pool so the jump can be patched 4911cb0ef41Sopenharmony_ci // when the label is bound. The reservation means the maximum size 4921cb0ef41Sopenharmony_ci // of the operand for the constant is known and the jump can 4931cb0ef41Sopenharmony_ci // be emitted into the bytecode stream with space for the operand. 4941cb0ef41Sopenharmony_ci unbound_jumps_++; 4951cb0ef41Sopenharmony_ci label->set_referrer(current_offset); 4961cb0ef41Sopenharmony_ci OperandSize reserved_operand_size = 4971cb0ef41Sopenharmony_ci constant_array_builder()->CreateReservedEntry(); 4981cb0ef41Sopenharmony_ci DCHECK_NE(Bytecode::kJumpLoop, node->bytecode()); 4991cb0ef41Sopenharmony_ci switch (reserved_operand_size) { 5001cb0ef41Sopenharmony_ci case OperandSize::kNone: 5011cb0ef41Sopenharmony_ci UNREACHABLE(); 5021cb0ef41Sopenharmony_ci case OperandSize::kByte: 5031cb0ef41Sopenharmony_ci node->update_operand0(k8BitJumpPlaceholder); 5041cb0ef41Sopenharmony_ci break; 5051cb0ef41Sopenharmony_ci case OperandSize::kShort: 5061cb0ef41Sopenharmony_ci node->update_operand0(k16BitJumpPlaceholder); 5071cb0ef41Sopenharmony_ci break; 5081cb0ef41Sopenharmony_ci case OperandSize::kQuad: 5091cb0ef41Sopenharmony_ci node->update_operand0(k32BitJumpPlaceholder); 5101cb0ef41Sopenharmony_ci break; 5111cb0ef41Sopenharmony_ci } 5121cb0ef41Sopenharmony_ci EmitBytecode(node); 5131cb0ef41Sopenharmony_ci} 5141cb0ef41Sopenharmony_ci 5151cb0ef41Sopenharmony_civoid BytecodeArrayWriter::EmitSwitch(BytecodeNode* node, 5161cb0ef41Sopenharmony_ci BytecodeJumpTable* jump_table) { 5171cb0ef41Sopenharmony_ci DCHECK(Bytecodes::IsSwitch(node->bytecode())); 5181cb0ef41Sopenharmony_ci 5191cb0ef41Sopenharmony_ci size_t current_offset = bytecodes()->size(); 5201cb0ef41Sopenharmony_ci if (node->operand_scale() > OperandScale::kSingle) { 5211cb0ef41Sopenharmony_ci // Adjust for scaling byte prefix. 5221cb0ef41Sopenharmony_ci current_offset += 1; 5231cb0ef41Sopenharmony_ci } 5241cb0ef41Sopenharmony_ci jump_table->set_switch_bytecode_offset(current_offset); 5251cb0ef41Sopenharmony_ci 5261cb0ef41Sopenharmony_ci EmitBytecode(node); 5271cb0ef41Sopenharmony_ci} 5281cb0ef41Sopenharmony_ci 5291cb0ef41Sopenharmony_ci} // namespace interpreter 5301cb0ef41Sopenharmony_ci} // namespace internal 5311cb0ef41Sopenharmony_ci} // namespace v8 532