<commit_before>#include <cmath>

#include <set>
#include <string>
#include <vector>
#include <sstream>

#include <fmt/format.h>

#include <wasm-binary.h>
#include <wasm-s-parser.h>
#include <wasm-validator.h>

#include "evm2wasm.h"
#include "wast-async.h"
#include "wast.h"

using namespace std;

using namespace fmt::literals;

namespace {

bool nibble2value(char input, unsigned& output) {
  if (input >= '0' && input <= '9') {
    output = input - '0';
    return true;
  } else if (input >= 'a' && input <= 'f') {
    output = input - 'a' + 10;
    return true;
  } else if (input >= 'A' && input <= 'F') {
    output = input - 'A' + 10;
    return true;
  }
  return false;
}

// Hand rolled hex parser, because cross platform error handling is
// more reliable than with strtol() and any of the built std function.
//
// Returns an empty vector if input is invalid (odd number of characters or invalid nibbles).
// Assumes input is whitespace free, therefore if input is non-zero long an empty output
// signals an error.
vector<uint8_t> hexstring2vector(const string& input) {
  size_t len = input.length();
  if (len % 2 != 0)
    return vector<uint8_t>{};
  vector<uint8_t> ret;
  for (size_t i = 0; i <= len - 2; i += 2) {
    unsigned lo, hi;
    if (!nibble2value(input[i], hi) || !nibble2value(input[i + 1], lo))
      return vector<uint8_t>{};
    ret.push_back(static_cast<uint8_t>((hi << 4) | lo));
  }
  return ret;
}

}

namespace evm2wasm {

string wast2wasm(const string& input, bool debug) {
  wasm::Module module;

  try {
    if (debug) std::cerr << "s-parsing..." << std::endl;
    // FIXME: binaryen 1.37.28 actually modifies the input...
    //        as a workaround make a copy here
    string tmp = input;
    wasm::SExpressionParser parser(const_cast<char*>(tmp.c_str()));
    wasm::Element& root = *parser.root;
    if (debug) std::cerr << "w-parsing..." << std::endl;
    wasm::SExpressionWasmBuilder builder(module, *root[0]);
  } catch (wasm::ParseException& p) {
    if (debug) {
      std::cerr << "error in parsing input" << std::endl;
      p.dump(std::cerr);
    }
    return string();
  }

  if (!wasm::WasmValidator().validate(module)) {
    if (debug) std::cerr << "module is invalid" << std::endl;
    return string();
  }

  if (debug) std::cerr << "binarification..." << std::endl;
  wasm::BufferWithRandomAccess buffer(debug);
  wasm::WasmBinaryWriter writer(&module, buffer, debug);
  writer.setNamesSection(false);
  writer.write();

  if (debug) std::cerr << "writing to output..." << std::endl;

  ostringstream output;
  buffer.writeTo(output);

  if (debug) std::cerr << "Done." << std::endl;
  
  return output.str();
}

string evm2wast(const vector<uint8_t>& evmCode, bool stackTrace, bool useAsyncAPI, bool inlineOps, bool chargePerOp)
{
    // this keep track of the opcode we have found so far. This will be used to
    // to figure out what .wast files to include
    std::set<opcodeEnum> opcodesUsed;
    std::set<opcodeEnum> ignoredOps = {opcodeEnum::JUMP, opcodeEnum::JUMPI, opcodeEnum::JUMPDEST,
        opcodeEnum::POP, opcodeEnum::STOP, opcodeEnum::INVALID};
    std::vector<std::string> callbackTable;

    // an array of found segments
    std::vector<JumpSegment> jumpSegments;

    // the transcompiled EVM code
    fmt::MemoryWriter wast;
    fmt::MemoryWriter segment;
    //
    // keeps track of the gas that each section uses
    int gasCount = 0;

    // used for pruning dead code
    bool jumpFound = false;

    // the accumulative stack difference for the current segment
    int segmentStackDelta = 0;
    int segmentStackHigh = 0;
    int segmentStackLow = 0;

    // adds stack height checks to the beginning of a segment
    auto addStackCheck = [&segment, &segmentStackHigh, &segmentStackLow, &segmentStackDelta]() {
        fmt::MemoryWriter check;
        if (segmentStackHigh != 0)
        {
            check << "(if (i32.gt_s (get_global $sp) (i32.const {check}))\n\
                        (then (unreachable)))"_format("check"_a = ((1023 - segmentStackHigh) * 32));
        }

        if (segmentStackLow != 0)
        {
            check << "(if (i32.gt_s (get_global $sp) (i32.const {check}))\n\
                        (then (unreachable)))"_format("check"_a = (-segmentStackLow * 32 - 32));
        }

        check << segment.str();
        segment = std::move(check);
        segmentStackHigh = 0;
        segmentStackLow = 0;
        segmentStackDelta = 0;
    };

    // add a metering statment at the beginning of a segment<commit_msg>Fix stack check typo in cpp implementation<commit_after>#include <cmath>

#include <set>
#include <string>
#include <vector>
#include <sstream>

#include <fmt/format.h>

#include <wasm-binary.h>
#include <wasm-s-parser.h>
#include <wasm-validator.h>

#include "evm2wasm.h"
#include "wast-async.h"
#include "wast.h"

using namespace std;

using namespace fmt::literals;

namespace {

bool nibble2value(char input, unsigned& output) {
  if (input >= '0' && input <= '9') {
    output = input - '0';
    return true;
  } else if (input >= 'a' && input <= 'f') {
    output = input - 'a' + 10;
    return true;
  } else if (input >= 'A' && input <= 'F') {
    output = input - 'A' + 10;
    return true;
  }
  return false;
}

// Hand rolled hex parser, because cross platform error handling is
// more reliable than with strtol() and any of the built std function.
//
// Returns an empty vector if input is invalid (odd number of characters or invalid nibbles).
// Assumes input is whitespace free, therefore if input is non-zero long an empty output
// signals an error.
vector<uint8_t> hexstring2vector(const string& input) {
  size_t len = input.length();
  if (len % 2 != 0)
    return vector<uint8_t>{};
  vector<uint8_t> ret;
  for (size_t i = 0; i <= len - 2; i += 2) {
    unsigned lo, hi;
    if (!nibble2value(input[i], hi) || !nibble2value(input[i + 1], lo))
      return vector<uint8_t>{};
    ret.push_back(static_cast<uint8_t>((hi << 4) | lo));
  }
  return ret;
}

}

namespace evm2wasm {

string wast2wasm(const string& input, bool debug) {
  wasm::Module module;

  try {
    if (debug) std::cerr << "s-parsing..." << std::endl;
    // FIXME: binaryen 1.37.28 actually modifies the input...
    //        as a workaround make a copy here
    string tmp = input;
    wasm::SExpressionParser parser(const_cast<char*>(tmp.c_str()));
    wasm::Element& root = *parser.root;
    if (debug) std::cerr << "w-parsing..." << std::endl;
    wasm::SExpressionWasmBuilder builder(module, *root[0]);
  } catch (wasm::ParseException& p) {
    if (debug) {
      std::cerr << "error in parsing input" << std::endl;
      p.dump(std::cerr);
    }
    return string();
  }

  if (!wasm::WasmValidator().validate(module)) {
    if (debug) std::cerr << "module is invalid" << std::endl;
    return string();
  }

  if (debug) std::cerr << "binarification..." << std::endl;
  wasm::BufferWithRandomAccess buffer(debug);
  wasm::WasmBinaryWriter writer(&module, buffer, debug);
  writer.setNamesSection(false);
  writer.write();

  if (debug) std::cerr << "writing to output..." << std::endl;

  ostringstream output;
  buffer.writeTo(output);

  if (debug) std::cerr << "Done." << std::endl;
  
  return output.str();
}

string evm2wast(const vector<uint8_t>& evmCode, bool stackTrace, bool useAsyncAPI, bool inlineOps, bool chargePerOp)
{
    // this keep track of the opcode we have found so far. This will be used to
    // to figure out what .wast files to include
    std::set<opcodeEnum> opcodesUsed;
    std::set<opcodeEnum> ignoredOps = {opcodeEnum::JUMP, opcodeEnum::JUMPI, opcodeEnum::JUMPDEST,
        opcodeEnum::POP, opcodeEnum::STOP, opcodeEnum::INVALID};
    std::vector<std::string> callbackTable;

    // an array of found segments
    std::vector<JumpSegment> jumpSegments;

    // the transcompiled EVM code
    fmt::MemoryWriter wast;
    fmt::MemoryWriter segment;
    //
    // keeps track of the gas that each section uses
    int gasCount = 0;

    // used for pruning dead code
    bool jumpFound = false;

    // the accumulative stack difference for the current segment
    int segmentStackDelta = 0;
    int segmentStackHigh = 0;
    int segmentStackLow = 0;

    // adds stack height checks to the beginning of a segment
    auto addStackCheck = [&segment, &segmentStackHigh, &segmentStackLow, &segmentStackDelta]() {
        fmt::MemoryWriter check;
        if (segmentStackHigh != 0)
        {
            check << "(if (i32.gt_s (get_global $sp) (i32.const {check}))\n\
                        (then (unreachable)))"_format("check"_a = ((1023 - segmentStackHigh) * 32));
        }

        if (segmentStackLow != 0)
        {
            check << "(if (i32.lt_s (get_global $sp) (i32.const {check}))\n\
                        (then (unreachable)))"_format("check"_a = (-segmentStackLow * 32 - 32));
        }

        check << segment.str();
        segment = std::move(check);
        segmentStackHigh = 0;
        segmentStackLow = 0;
        segmentStackDelta = 0;
    };

    // add a metering statment at the beginning of a segment
{'fraction_non_alphanumeric': 0.1435638122457953, 'fraction_numerical': 0.013411014620204463, 'mean_word_length': 3.0489541611036937, 'pattern_counts': {'":': 0, '<': 123, '<?xml version=': 0, '>': 49, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3713331', 'n_tokens_mistral': 3077, 'n_tokens_neox': 2964, 'n_words': 875}