* Copyright (c) 2026 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "ecmascript/arksteed/arksteed_comment.h"
#include "ecmascript/log_wrapper.h"
#include "securec.h"
#include <cstring>
namespace panda::ecmascript::arksteed {
static constexpr uint32_t OFFSET_TO_FIRST_COMMENT_ENTRY = sizeof(uint32_t);
static constexpr uint32_t OFFSET_TO_PC = 0;
static constexpr uint32_t OFFSET_TO_COMMENT_SIZE = OFFSET_TO_PC + sizeof(uint32_t);
static constexpr uint32_t OFFSET_TO_COMMENT_STRING = OFFSET_TO_COMMENT_SIZE + sizeof(uint32_t);
uint32_t CommentEntry::CommentLength() const
{
return static_cast<uint32_t>(comment.size() + 1);
}
uint32_t CommentEntry::Size() const
{
return OFFSET_TO_COMMENT_STRING + CommentLength();
}
void CommentList::Add(uint32_t pcOffset, std::string_view comment)
{
CommentEntry entry(pcOffset, comment);
byteCount_ += entry.Size();
comments_.push_back(std::move(entry));
}
const std::vector<CommentEntry> &CommentList::GetComments() const
{
return comments_;
}
size_t CommentList::Size() const
{
return comments_.size();
}
void CommentList::Clear()
{
comments_.clear();
byteCount_ = 0;
}
uint32_t CommentList::SectionSize() const
{
return OFFSET_TO_FIRST_COMMENT_ENTRY + byteCount_;
}
void CommentList::Emit(uint8_t *buffer) const
{
uint32_t totalSize = SectionSize();
*reinterpret_cast<uint32_t *>(buffer) = totalSize;
uint8_t *current = buffer + OFFSET_TO_FIRST_COMMENT_ENTRY;
for (const auto &entry : comments_) {
*reinterpret_cast<uint32_t *>(current + OFFSET_TO_PC) = entry.pcOffset;
*reinterpret_cast<uint32_t *>(current + OFFSET_TO_COMMENT_SIZE) = entry.CommentLength();
if (memcpy_s(current + OFFSET_TO_COMMENT_STRING, entry.CommentLength(),
entry.comment.c_str(), entry.CommentLength()) != EOK) {
LOG_JIT(FATAL) << "memcpy failed in Emit";
}
current += entry.Size();
}
}
CommentList::Iterator::Iterator(const uint8_t *data, uint32_t size)
: data_(data), size_(size), currentEntry_(data != nullptr ? data + OFFSET_TO_FIRST_COMMENT_ENTRY : nullptr)
{}
bool CommentList::Iterator::HasCurrent() const
{
return data_ != nullptr && currentEntry_ < data_ + size_;
}
uint32_t CommentList::Iterator::GetPCOffset() const
{
return HasCurrent() ? *reinterpret_cast<const uint32_t *>(currentEntry_ + OFFSET_TO_PC) : 0;
}
uint32_t CommentList::Iterator::GetCommentSize() const
{
return HasCurrent() ? *reinterpret_cast<const uint32_t *>(currentEntry_ + OFFSET_TO_COMMENT_SIZE) : 0;
}
const char *CommentList::Iterator::GetComment() const
{
return HasCurrent() ? reinterpret_cast<const char *>(currentEntry_ + OFFSET_TO_COMMENT_STRING) : nullptr;
}
void CommentList::Iterator::Next()
{
if (HasCurrent()) {
currentEntry_ += OFFSET_TO_COMMENT_STRING + GetCommentSize();
}
}
CommentList::Iterator CommentList::GetIterator(const uint8_t *data, uint32_t size) const
{
return Iterator(data, size);
}
uint32_t CommentList::GetCommentsDataSize() const
{
return SectionSize();
}
uint8_t *CommentList::EmitToBuffer() const
{
if (comments_.empty()) {
return nullptr;
}
uint8_t *buffer = new uint8_t[SectionSize()];
Emit(buffer);
return buffer;
}
const CommentEntry *CommentList::FindComment(uint32_t pcOffset) const
{
for (auto it = comments_.rbegin(); it != comments_.rend(); ++it) {
if (it->pcOffset <= pcOffset) {
return &(*it);
}
}
return nullptr;
}
}