summaryrefslogtreecommitdiffstats
path: root/js/src/frontend/ObjLiteral.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'js/src/frontend/ObjLiteral.cpp')
-rw-r--r--js/src/frontend/ObjLiteral.cpp246
1 files changed, 246 insertions, 0 deletions
diff --git a/js/src/frontend/ObjLiteral.cpp b/js/src/frontend/ObjLiteral.cpp
new file mode 100644
index 0000000000..0c9546680c
--- /dev/null
+++ b/js/src/frontend/ObjLiteral.cpp
@@ -0,0 +1,246 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * vim: set ts=8 sw=2 et tw=0 ft=c:
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "frontend/ObjLiteral.h"
+
+#include "mozilla/DebugOnly.h"
+
+#include "frontend/CompilationInfo.h" // frontend::CompilationAtomCache
+#include "frontend/ParserAtom.h" // frontend::ParserAtom, frontend::ParserAtomTable
+#include "js/RootingAPI.h"
+#include "vm/JSAtom.h"
+#include "vm/JSObject.h"
+#include "vm/JSONPrinter.h" // js::JSONPrinter
+#include "vm/ObjectGroup.h"
+#include "vm/Printer.h" // js::Fprinter
+
+#include "gc/ObjectKind-inl.h"
+#include "vm/JSAtom-inl.h"
+#include "vm/JSObject-inl.h"
+
+namespace js {
+
+static void InterpretObjLiteralValue(JSContext* cx,
+ frontend::CompilationAtomCache& atomCache,
+ const ObjLiteralInsn& insn,
+ JS::Value* valOut) {
+ switch (insn.getOp()) {
+ case ObjLiteralOpcode::ConstValue:
+ *valOut = insn.getConstValue();
+ return;
+ case ObjLiteralOpcode::ConstAtom: {
+ frontend::TaggedParserAtomIndex index = insn.getAtomIndex();
+ JSAtom* jsatom = atomCache.getExistingAtomAt(cx, index);
+ MOZ_ASSERT(jsatom);
+ *valOut = StringValue(jsatom);
+ return;
+ }
+ case ObjLiteralOpcode::Null:
+ *valOut = NullValue();
+ return;
+ case ObjLiteralOpcode::Undefined:
+ *valOut = UndefinedValue();
+ return;
+ case ObjLiteralOpcode::True:
+ *valOut = BooleanValue(true);
+ return;
+ case ObjLiteralOpcode::False:
+ *valOut = BooleanValue(false);
+ return;
+ default:
+ MOZ_CRASH("Unexpected object-literal instruction opcode");
+ }
+}
+
+static JSObject* InterpretObjLiteralObj(
+ JSContext* cx, frontend::CompilationAtomCache& atomCache,
+ const mozilla::Span<const uint8_t> literalInsns, ObjLiteralFlags flags) {
+ bool singleton = flags.contains(ObjLiteralFlag::Singleton);
+
+ ObjLiteralReader reader(literalInsns);
+ ObjLiteralInsn insn;
+
+ Rooted<IdValueVector> properties(cx, IdValueVector(cx));
+
+ // Compute property values and build the key/value-pair list.
+ while (reader.readInsn(&insn)) {
+ MOZ_ASSERT(insn.isValid());
+
+ jsid propId;
+ if (insn.getKey().isArrayIndex()) {
+ propId = INT_TO_JSID(insn.getKey().getArrayIndex());
+ } else {
+ JSAtom* jsatom =
+ atomCache.getExistingAtomAt(cx, insn.getKey().getAtomIndex());
+ MOZ_ASSERT(jsatom);
+ propId = AtomToId(jsatom);
+ }
+
+ JS::Value propVal;
+ if (singleton) {
+ InterpretObjLiteralValue(cx, atomCache, insn, &propVal);
+ }
+
+ if (!properties.emplaceBack(propId, propVal)) {
+ return nullptr;
+ }
+ }
+
+ return NewPlainObjectWithProperties(cx, properties.begin(),
+ properties.length(), TenuredObject);
+}
+
+static JSObject* InterpretObjLiteralArray(
+ JSContext* cx, frontend::CompilationAtomCache& atomCache,
+ const mozilla::Span<const uint8_t> literalInsns, ObjLiteralFlags flags) {
+ ObjLiteralReader reader(literalInsns);
+ ObjLiteralInsn insn;
+
+ Rooted<ValueVector> elements(cx, ValueVector(cx));
+
+ while (reader.readInsn(&insn)) {
+ MOZ_ASSERT(insn.isValid());
+
+ JS::Value propVal;
+ InterpretObjLiteralValue(cx, atomCache, insn, &propVal);
+ if (!elements.append(propVal)) {
+ return nullptr;
+ }
+ }
+
+ return NewDenseCopiedArray(cx, elements.length(), elements.begin(),
+ /* proto = */ nullptr,
+ NewObjectKind::TenuredObject);
+}
+
+JSObject* InterpretObjLiteral(JSContext* cx,
+ frontend::CompilationAtomCache& atomCache,
+ const mozilla::Span<const uint8_t> literalInsns,
+ ObjLiteralFlags flags) {
+ return flags.contains(ObjLiteralFlag::Array)
+ ? InterpretObjLiteralArray(cx, atomCache, literalInsns, flags)
+ : InterpretObjLiteralObj(cx, atomCache, literalInsns, flags);
+}
+
+#if defined(DEBUG) || defined(JS_JITSPEW)
+
+static void DumpObjLiteralFlagsItems(js::JSONPrinter& json,
+ ObjLiteralFlags flags) {
+ if (flags.contains(ObjLiteralFlag::Array)) {
+ json.value("Array");
+ flags -= ObjLiteralFlag::Array;
+ }
+ if (flags.contains(ObjLiteralFlag::Singleton)) {
+ json.value("Singleton");
+ flags -= ObjLiteralFlag::Singleton;
+ }
+
+ if (!flags.isEmpty()) {
+ json.value("Unknown(%x)", flags.serialize());
+ }
+}
+
+static void DumpObjLiteral(js::JSONPrinter& json,
+ frontend::BaseCompilationStencil* stencil,
+ mozilla::Span<const uint8_t> code,
+ const ObjLiteralFlags& flags) {
+ json.beginListProperty("flags");
+ DumpObjLiteralFlagsItems(json, flags);
+ json.endList();
+
+ json.beginListProperty("code");
+ ObjLiteralReader reader(code);
+ ObjLiteralInsn insn;
+ while (reader.readInsn(&insn)) {
+ json.beginObject();
+
+ if (insn.getKey().isNone()) {
+ json.nullProperty("key");
+ } else if (insn.getKey().isAtomIndex()) {
+ frontend::TaggedParserAtomIndex index = insn.getKey().getAtomIndex();
+ json.beginObjectProperty("key");
+ DumpTaggedParserAtomIndex(json, index, stencil);
+ json.endObject();
+ } else if (insn.getKey().isArrayIndex()) {
+ uint32_t index = insn.getKey().getArrayIndex();
+ json.formatProperty("key", "ArrayIndex(%u)", index);
+ }
+
+ switch (insn.getOp()) {
+ case ObjLiteralOpcode::ConstValue: {
+ const Value& v = insn.getConstValue();
+ json.formatProperty("op", "ConstValue(%f)", v.toNumber());
+ break;
+ }
+ case ObjLiteralOpcode::ConstAtom: {
+ frontend::TaggedParserAtomIndex index = insn.getAtomIndex();
+ json.beginObjectProperty("op");
+ DumpTaggedParserAtomIndex(json, index, stencil);
+ json.endObject();
+ break;
+ }
+ case ObjLiteralOpcode::Null:
+ json.property("op", "Null");
+ break;
+ case ObjLiteralOpcode::Undefined:
+ json.property("op", "Undefined");
+ break;
+ case ObjLiteralOpcode::True:
+ json.property("op", "True");
+ break;
+ case ObjLiteralOpcode::False:
+ json.property("op", "False");
+ break;
+ default:
+ json.formatProperty("op", "Invalid(%x)", uint8_t(insn.getOp()));
+ break;
+ }
+
+ json.endObject();
+ }
+ json.endList();
+}
+
+void ObjLiteralWriter::dump() {
+ js::Fprinter out(stderr);
+ js::JSONPrinter json(out);
+ dump(json, nullptr);
+}
+
+void ObjLiteralWriter::dump(js::JSONPrinter& json,
+ frontend::BaseCompilationStencil* stencil) {
+ json.beginObject();
+ dumpFields(json, stencil);
+ json.endObject();
+}
+
+void ObjLiteralWriter::dumpFields(js::JSONPrinter& json,
+ frontend::BaseCompilationStencil* stencil) {
+ DumpObjLiteral(json, stencil, getCode(), flags_);
+}
+
+void ObjLiteralStencil::dump() {
+ js::Fprinter out(stderr);
+ js::JSONPrinter json(out);
+ dump(json, nullptr);
+}
+
+void ObjLiteralStencil::dump(js::JSONPrinter& json,
+ frontend::BaseCompilationStencil* stencil) {
+ json.beginObject();
+ dumpFields(json, stencil);
+ json.endObject();
+}
+
+void ObjLiteralStencil::dumpFields(js::JSONPrinter& json,
+ frontend::BaseCompilationStencil* stencil) {
+ DumpObjLiteral(json, stencil, code_, flags_);
+}
+
+#endif // defined(DEBUG) || defined(JS_JITSPEW)
+
+} // namespace js