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