<commit_before>#ifndef IV_LV5_JSENV_H_
#define IV_LV5_JSENV_H_
#include <algorithm>
#include <gc/gc_cpp.h>
#include <iv/notfound.h>
#include <iv/debug.h>
#include <iv/string_builder.h>
#include <iv/lv5/gc_template.h>
#include <iv/lv5/jsobject.h>
#include <iv/lv5/symbol.h>
#include <iv/lv5/property_fwd.h>
#include <iv/lv5/context_utils.h>
#include <iv/lv5/error.h>
#include <iv/lv5/jsval_fwd.h>
#include <iv/lv5/radio/cell.h>
#include <iv/lv5/radio/core_fwd.h>

namespace iv {
namespace lv5 {

class JSDeclEnv;
class JSObjectEnv;
class JSStaticEnv;

class JSEnv : public radio::HeapObject<radio::ENVIRONMENT> {
 public:
  virtual bool HasBinding(Context* ctx, Symbol name) const = 0;
  virtual bool DeleteBinding(Context* ctx, Symbol name) = 0;
  virtual void CreateMutableBinding(Context* ctx, Symbol name,
                                    bool del, Error* err) = 0;
  virtual void SetMutableBinding(Context* ctx,
                                 Symbol name,
                                 const JSVal& val,
                                 bool strict, Error* res) = 0;
  virtual JSVal GetBindingValue(Context* ctx, Symbol name,
                                bool strict, Error* res) const = 0;
  virtual JSVal ImplicitThisValue() const = 0;
  virtual JSDeclEnv* AsJSDeclEnv() = 0;
  virtual JSObjectEnv* AsJSObjectEnv() = 0;
  virtual JSStaticEnv* AsJSStaticEnv() = 0;
  inline JSEnv* outer() const {
    return outer_;
  }

  void MarkChildren(radio::Core* core) {
    core->MarkCell(outer_);
  }

 protected:
  explicit JSEnv(JSEnv* outer)
    : outer_(outer) {
  }

 private:
  JSEnv* outer_;
};

class JSDeclEnv : public JSEnv {
 private:
  class UpValue {
   public:
    enum RecordType {
      NONE = 0,
      IM_INITIALIZED = 1,
      IM_UNINITIALIZED = 2,
      MUTABLE = 4,
      DELETABLE = 8
    };

    UpValue()
      : attribute_(NONE),
        escaped_(JSEmpty),
        redirect_(&escaped_) {
      assert(&escaped_ == redirect_);
    }

    UpValue(const UpValue& rhs)
      : attribute_(rhs.attribute_),
        escaped_(rhs.escaped_),
        redirect_(&escaped_) {
      assert(&escaped_ == redirect_);
    }

    explicit UpValue(int attr)
      : attribute_(attr),
        escaped_(JSUndefined),
        redirect_(&escaped_) {
      assert(&escaped_ == redirect_);
    }

    UpValue(int attr, JSVal* reg)
      : attribute_(attr),
        escaped_(JSEmpty),
        redirect_(reg) {
    }

    UpValue(int attr, JSVal val)
      : attribute_(attr),
        escaped_(val),
        redirect_(&escaped_) {
      assert(&escaped_ == redirect_);
    }

    // close this upvalue to self referenced
    void Close() {
      escaped_ = *redirect_;
      redirect_ = &escaped_;
    }

    bool IsRedirected() const { return redirect_ != &escaped_; }

    JSVal value() const { return *redirect_; }

    void set_value(JSVal value) { *redirect_ = value; }

    int attribute() const { return attribute_; }

    void set_attribute(int attr) { attribute_ = attr; }

    UpValue& operator=(const UpValue& rhs) {
      using std::swap;
      attribute_ = rhs.attribute_;
      escaped_ = rhs.escaped_;
      return *this;
    }

    void swap(UpValue& rhs) {
      using std::swap;
      swap(attribute_, rhs.attribute_);
      swap(escaped_, rhs.escaped_);
    }

    friend void swap(UpValue& lhs, UpValue& rhs) {
      lhs.swap(rhs);
    }

   private:
    int attribute_;
    JSVal escaped_;
    JSVal* redirect_;
  };

 public:
  typedef GCVector<UpValue>::type Record;
  typedef GCHashMap<Symbol, uint32_t>::type Offsets;

  bool HasBinding(Context* ctx, Symbol name) const {
    return offsets_.find(name) != offsets_.end();
  }

  bool DeleteBinding(Context* ctx, Symbol name) {
    const Offsets::const_iterator it = offsets_.find(name);
    if (it == offsets_.end()) {
      return true;
    }<commit_msg>remove redirect in JSEnv<commit_after>#ifndef IV_LV5_JSENV_H_
#define IV_LV5_JSENV_H_
#include <algorithm>
#include <gc/gc_cpp.h>
#include <iv/notfound.h>
#include <iv/debug.h>
#include <iv/string_builder.h>
#include <iv/lv5/gc_template.h>
#include <iv/lv5/jsobject.h>
#include <iv/lv5/symbol.h>
#include <iv/lv5/property_fwd.h>
#include <iv/lv5/context_utils.h>
#include <iv/lv5/error.h>
#include <iv/lv5/jsval_fwd.h>
#include <iv/lv5/radio/cell.h>
#include <iv/lv5/radio/core_fwd.h>

namespace iv {
namespace lv5 {

class JSDeclEnv;
class JSObjectEnv;
class JSStaticEnv;

class JSEnv : public radio::HeapObject<radio::ENVIRONMENT> {
 public:
  virtual bool HasBinding(Context* ctx, Symbol name) const = 0;
  virtual bool DeleteBinding(Context* ctx, Symbol name) = 0;
  virtual void CreateMutableBinding(Context* ctx, Symbol name,
                                    bool del, Error* err) = 0;
  virtual void SetMutableBinding(Context* ctx,
                                 Symbol name,
                                 const JSVal& val,
                                 bool strict, Error* res) = 0;
  virtual JSVal GetBindingValue(Context* ctx, Symbol name,
                                bool strict, Error* res) const = 0;
  virtual JSVal ImplicitThisValue() const = 0;
  virtual JSDeclEnv* AsJSDeclEnv() = 0;
  virtual JSObjectEnv* AsJSObjectEnv() = 0;
  virtual JSStaticEnv* AsJSStaticEnv() = 0;
  inline JSEnv* outer() const {
    return outer_;
  }

  void MarkChildren(radio::Core* core) {
    core->MarkCell(outer_);
  }

 protected:
  explicit JSEnv(JSEnv* outer)
    : outer_(outer) {
  }

 private:
  JSEnv* outer_;
};

class JSDeclEnv : public JSEnv {
 private:
  class UpValue {
   public:
    enum RecordType {
      NONE = 0,
      IM_INITIALIZED = 1,
      IM_UNINITIALIZED = 2,
      MUTABLE = 4,
      DELETABLE = 8
    };

    UpValue()
      : attribute_(NONE),
        escaped_(JSEmpty) {
    }

    UpValue(const UpValue& rhs)
      : attribute_(rhs.attribute_),
        escaped_(rhs.escaped_) {
    }

    explicit UpValue(int attr)
      : attribute_(attr),
        escaped_(JSUndefined) {
    }

    UpValue(int attr, JSVal* reg)
      : attribute_(attr),
        escaped_(JSEmpty) {
    }

    UpValue(int attr, JSVal val)
      : attribute_(attr),
        escaped_(val) {
    }

    JSVal value() const { return escaped_; }

    void set_value(JSVal value) { escaped_ = value; }

    int attribute() const { return attribute_; }

    void set_attribute(int attr) { attribute_ = attr; }

    UpValue& operator=(const UpValue& rhs) {
      using std::swap;
      attribute_ = rhs.attribute_;
      escaped_ = rhs.escaped_;
      return *this;
    }

    void swap(UpValue& rhs) {
      using std::swap;
      swap(attribute_, rhs.attribute_);
      swap(escaped_, rhs.escaped_);
    }

    friend void swap(UpValue& lhs, UpValue& rhs) {
      lhs.swap(rhs);
    }

   private:
    int attribute_;
    JSVal escaped_;
  };

 public:
  typedef GCVector<UpValue>::type Record;
  typedef GCHashMap<Symbol, uint32_t>::type Offsets;

  bool HasBinding(Context* ctx, Symbol name) const {
    return offsets_.find(name) != offsets_.end();
  }

  bool DeleteBinding(Context* ctx, Symbol name) {
    const Offsets::const_iterator it = offsets_.find(name);
    if (it == offsets_.end()) {
      return true;
    }
{'fraction_non_alphanumeric': 0.11704799107142858, 'fraction_numerical': 0.0078125, 'mean_word_length': 2.644636502287748, 'pattern_counts': {'":': 0, '<': 37, '<?xml version=': 0, '>': 39, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 10, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '294600', 'n_tokens_mistral': 2443, 'n_tokens_neox': 2353, 'n_words': 562}