/* * Copyright (C) 2016 Charybdis Development Team * Copyright (C) 2016 Jason Volk * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice is present in all copies. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include "/home/jason/charybdis/charybdis/gecko-dev/js/src/vm/Opcodes.h" namespace ircd { namespace js { decltype(xdr::bytecode::info) xdr::bytecode::info { 0 }; } // namespace js } // namespace ircd ircd::js::xdr::xdr(const uint8_t *const &buf, const size_t &len) :header { reinterpret_cast(buf) } ,name { reinterpret_cast(buf + sizeof(*header)) } ,binding{[this] { const auto *ret(reinterpret_cast(this->name)); for_each_name([&ret](const struct atom &atom) { ret += sizeof(struct atom) + atom.length; }); return reinterpret_cast(ret); }()} ,sourcecode{[this] { const auto bindings(header->num_bindings()); const auto *ptr(reinterpret_cast(this->binding + bindings)); return reinterpret_cast(ptr); }()} ,sourcemap{[this] { const auto *ptr(reinterpret_cast(this->sourcecode + 1) + this->sourcecode->compressed_length); return reinterpret_cast(ptr); }()} ,displayurl{[this] { if(!this->sourcemap->have) { const auto ptr(reinterpret_cast(this->sourcemap) + 1); return reinterpret_cast(ptr); } const auto ptr(reinterpret_cast(this->sourcemap + 1) + this->sourcemap->len); return reinterpret_cast(ptr); }()} ,filename{[this] { if(!this->displayurl->have) { const auto ptr(reinterpret_cast(this->displayurl) + 1); return reinterpret_cast(ptr); } const auto ptr(reinterpret_cast(this->displayurl + 1) + this->displayurl->len); return reinterpret_cast(ptr); }()} ,source{[this] { if(!this->filename->have) { const auto ptr(reinterpret_cast(this->filename) + 1); return reinterpret_cast(ptr); } const auto ptr(reinterpret_cast(this->filename + 1) + strlen(this->filename->name) + 1); return reinterpret_cast(ptr); }()} ,bytecode{[this] { const auto ptr(reinterpret_cast(this->source + 1)); return reinterpret_cast(ptr); }()} ,srcnote{[this] { const auto ptr(reinterpret_cast(this->bytecode + this->header->length)); return reinterpret_cast(ptr); }()} ,atom{[this] { const auto ptr(reinterpret_cast(this->srcnote + this->header->n_srcnotes)); return reinterpret_cast(ptr); }()} ,consts{[this] { const auto *ptr(reinterpret_cast(this->atom)); for_each_atom([&ptr](const struct atom &atom) { ptr += sizeof(struct atom) + atom.length; }); return reinterpret_cast(ptr); }()} ,object{[this] { const auto *ptr(reinterpret_cast(this->consts)); for_each_const([&ptr](const struct consts &c) { ptr += length(c); }); return reinterpret_cast(ptr); }()} { } void ircd::js::xdr::for_each_object(const std::function &cb) const { auto object(this->object); const auto *ptr(reinterpret_cast(object)); for(size_t i(0); i < header->n_objects; i++) { cb(*object); ptr += length(*object); object = reinterpret_cast(ptr); } } void ircd::js::xdr::for_each_const(const std::function &cb) const { auto consts(this->consts); const auto *ptr(reinterpret_cast(this->consts)); for(size_t i(0); i< header->n_consts; i++) { cb(*consts); ptr += length(*consts); consts = reinterpret_cast(ptr); } } void ircd::js::xdr::for_each_bytecode(const std::function &cb) const { const uint8_t *const start(reinterpret_cast(bytecode)); const uint8_t *ptr(reinterpret_cast(bytecode)); for(; ptr < start + header->length;) { const auto &bytecode(*reinterpret_cast(ptr)); ptr += info(bytecode).length; cb(bytecode); } } void ircd::js::xdr::for_each_binding(const std::function &cb) const { const auto *binding(this->binding); const size_t bindings(header->num_names()); for(; binding < this->binding + bindings; ++binding) cb(*binding); } void ircd::js::xdr::for_each_name(const std::function &cb) const { const uint8_t *ptr(reinterpret_cast(name)); const auto names(header->num_names()); for(size_t i(0); i < names; ++i) { const auto atom(reinterpret_cast(ptr)); cb(*atom); ptr += sizeof(struct atom) + atom->length; } } void ircd::js::xdr::for_each_atom(const std::function &cb) const { const uint8_t *ptr(reinterpret_cast(atom)); for(size_t i(0); i < header->n_atoms; ++i) { const auto atom(reinterpret_cast(ptr)); cb(*atom); ptr += sizeof(struct atom) + atom->length; } } size_t ircd::js::xdr::header::num_bindings() const { return num_names(); } size_t ircd::js::xdr::header::num_names() const { return n_args + n_vars + n_body_level_lexicals; } size_t ircd::js::length(const struct xdr::consts &consts) { switch(consts.tag) { case 0: return 4 + 4; // ::js::SCRIPT_INT case 1: return 4 + 8; // ::js::SCRIPT_DOUBLE case 2: // ::js::SCRIPT_ATOM return 4 + 4; //return 4 + 4 + consts.atom.length; case 3: return 4 + 0; // ::js::SCRIPT_TRUE case 4: return 4 + 0; // ::js::SCRIPT_FALSE case 5: return 4 + 0; // ::js::SCRIPT_NULL case 6: // ::js::SCRIPT_OBJECT throw error("unsupported consts (object)"); case 7: return 4 + 0; // ::js::SCRIPT_VOID case 8: return 4 + 0; // ::js::SCRIPT_HOLE default: throw error("unsupported consts tag [%u]", consts.tag); } } size_t ircd::js::length(const struct xdr::object &object) { switch(object.classk) { case 0: return 4 + length(object.block); case 1: return 4 + length(object.with); case 2: return 4 + length(object.function); case 3: return 4 + length(object.literal); default: throw error("unsupported object class kind [%u]", object.classk); } } size_t ircd::js::length(const struct xdr::object::literal &literal) { size_t ret(0); const auto *ptr(reinterpret_cast(&literal) + 8); for(size_t i(0); i < literal.n_properties; ++i) { const auto prop(reinterpret_cast(ptr + ret)); printf("i[%zu] atom [%u] length [%u]\n", i, prop->u32, prop->atom.length); const auto len(length(*prop)); ret += 8; } return 8 + ret; } size_t ircd::js::length(const struct xdr::object::function &function) { return 12; } size_t ircd::js::length(const struct xdr::object::with &with) { return 0; } size_t ircd::js::length(const struct xdr::object::block &block) { return 0; } __attribute__((constructor)) void init_opcodes() { using xdr = ircd::js::xdr; #define IRCD_JS_INIT_OP(code, value, name, image, len, nuses, ndefs, format) \ xdr::bytecode::info[value] = { name, uint8_t(len), uint8_t(ndefs), uint8_t(nuses) }; static const auto js_undefined_str(""); static const auto js_false_str("false"); static const auto js_true_str("false"); static const auto js_void_str("void"); static const auto js_null_str("null"); static const auto js_throw_str("throw"); static const auto js_in_str("in"); static const auto js_instanceof_str("instanceOf"); static const auto js_typeof_str("typeOf"); FOR_EACH_OPCODE(IRCD_JS_INIT_OP); }