--- a/js/src/frontend/BinSource.cpp
+++ b/js/src/frontend/BinSource.cpp
@@ -12,37 +12,38 @@
using namespace mozilla;
using NameBag = GCHashSet<JSString*>;
using Names = GCVector<JSString*, 8>;
// FIXME: Better error handling.
// FIXME: Check that subnodes have the right type.
// FIXME: Check scope information.
+// FIXME: Handle directives.
namespace js {
namespace frontend {
-
// Copied from Parser.cpp
template <typename Scope>
static typename Scope::Data*
NewEmptyBindingData(JSContext* cx, LifoAlloc& alloc, uint32_t numBindings)
{
size_t allocSize = Scope::sizeOfData(numBindings);
typename Scope::Data* bindings = static_cast<typename Scope::Data*>(alloc.alloc(allocSize));
if (!bindings) {
ReportOutOfMemory(cx);
return nullptr;
}
PodZero(bindings);
return bindings;
}
+
struct ScopeData MOZ_STACK_CLASS {
public:
ScopeData(JSContext* cx)
: letNames(cx)
, constNames(cx)
, varNames(cx)
, capturedNames(cx)
{ }
@@ -70,19 +71,27 @@ public:
const std::string BINJS_SCOPE = "BINJS:Scope";
const std::string BINJS_VAR_NAME = "BINJS:VarDeclaredNames";
const std::string BINJS_LET_NAME = "BINJS:LetDeclaredNames";
const std::string BINJS_CONST_NAME = "BINJS:ConstDeclaredNames";
const std::string BINJS_CAPTURED_NAME = "BINJS:CapturedNames";
const std::string BINJS_DIRECT_EVAL = "BINJS:HasDirectEval";
-class ASTReader
+class ASTReader: private JS::AutoGCRooter
{
public:
+ ASTReader(JSContext* cx_, LifoAlloc& alloc_)
+ : AutoGCRooter(cx_, BINPARSER)
+ , traceListHead(nullptr)
+ , allocator(cx_, alloc_)
+ , cx(cx_)
+ , alloc(alloc_)
+ { }
+
bool parse(char* start, char* stop, GlobalSharedContext* sc, UniquePtr<ParseNode>& out);
private:
bool raiseError();
// --- Parse full nodes.
bool parseBool(SimpleTokenReader*, Maybe<bool>*);
bool parseProgram(SimpleTokenReader* reader, UniquePtr<ParseNode>& out);
@@ -94,32 +103,45 @@ private:
bool parseStringSet(SimpleTokenReader* reader, MutableHandle<NameBag>);
bool parseScope(SimpleTokenReader* reader, ScopeData& out);
bool parseExpression(SimpleTokenReader* reader, UniquePtr<ParseNode>& out);
bool parsePropertyName(SimpleTokenReader* reader, UniquePtr<PropertyName>& out);
bool parseSwitchCaseList(SimpleTokenReader* reader, UniquePtr<ParseNode>& out);
bool parseBlockStatement(SimpleTokenReader* reader, UniquePtr<ParseNode>&);
bool parseCatchClause(SimpleTokenReader* reader, UniquePtr<ParseNode>&);
bool parseVariableDeclarator(SimpleTokenReader* reader, UniquePtr<ParseNode>&);
+ bool parsePatternList(SimpleTokenReader* reader, UniquePtr<ParseNode>&);
// --- Parse the contents of a node whose kind has already been determined.
bool parseFunctionAux(SimpleTokenReader* reader, const std::string& name, const SimpleTokenReader::Fields* fields, UniquePtr<ParseNode>& out);
bool parsePatternAux(SimpleTokenReader* reader, const std::string& name, const SimpleTokenReader::Fields* fields, UniquePtr<ParseNode>& out);
bool parseBlockStatementAux(SimpleTokenReader* reader, const std::string& name, const SimpleTokenReader::Fields* fields, UniquePtr<ParseNode>& out);
bool parseExpressionStatementAux(SimpleTokenReader* reader, const std::string& name, const SimpleTokenReader::Fields* fields, UniquePtr<ParseNode>& out);
bool parseExpressionAux(SimpleTokenReader* reader, const std::string& name, const SimpleTokenReader::Fields* fields, UniquePtr<ParseNode>& out);
bool parseVariableDeclarationAux(SimpleTokenReader* reader, const std::string& name, const SimpleTokenReader::Fields* fields, UniquePtr<ParseNode>& out);
// --- Utilities.
+
bool readString(SimpleTokenReader* reader, std::string&);
bool readString(SimpleTokenReader* reader, MutableHandleString);
+ bool readString(SimpleTokenReader* reader, MutableHandleAtom);
+ const Directives& currentDirectives() const;
const ReadOnlyCompileOptions& options() const;
+ // --- GC.
+
+ /* List of objects allocated during parsing, for GC tracing. */
+ ObjectBox* traceListHead;
+ void trace(JSTracer* trc)
+ {
+ ObjectBox::TraceList(trc, this->traceListHead);
+ }
+
ParseNodeAllocator allocator;
ParseNode* allocParseNode(size_t size) {
MOZ_ASSERT(size == sizeof(ParseNode));
return static_cast<ParseNode*>(allocator.allocNode());
}
ParseNode* cloneNode(const ParseNode& other) {
@@ -130,16 +152,19 @@ private:
return node;
}
JS_DECLARE_NEW_METHODS(new_, allocParseNode, inline)
private:
JSContext* cx;
LifoAlloc& alloc;
+
+ // Needs access to AutoGCRooter.
+ friend void TraceBinParser(JSTracer* trc, AutoGCRooter* parser);
};
class BinParseContext: public ParseContext {
public:
BinParseContext(ASTReader*, GlobalSharedContext*, Directives*);
};
bool
@@ -880,17 +905,94 @@ ASTReader::parseStatement(SimpleTokenRea
Unused << forHead.release();
Unused << body.release();
out = Move(result);
} else if (name == "FunctionDeclaration") {
- // FIXME: Implement
+ RootedAtom funName(this->cx);
+ UniquePtr<ParseNode> params;
+ UniquePtr<ParseNode> body;
+ ScopeData scope(this->cx);
+
+ for (auto field: fields) {
+ if (field == "id") {
+ if (!this->readString(&sub, &funName)) {
+ return false;
+ }
+ } else if (field == "params") {
+ if (!this->parsePatternList(&sub, params)) {
+ return false;
+ }
+ } else if (field == "body") {
+ if (!this->parseStatement(&sub, body)) {
+ return false;
+ }
+ } else if (field == BINJS_SCOPE) {
+ if (!this->parseScope(&sub, scope)) {
+ return false;
+ }
+ } else {
+ return this->raiseError();
+ }
+ }
+
+ if (!funName || !params || !body || !scope.isSome()) {
+ return this->raiseError();
+ }
+
+ RootedFunction fun(this->cx,
+ NewFunctionWithProto(this->cx,
+ /*native*/nullptr,
+ /*nargs ?*/0,
+ /*flags */ JSFunction::INTERPRETED_NORMAL,
+ /*enclosing env*/nullptr,
+ /*name*/ funName,
+ /*proto*/ nullptr,
+ /*alloc*/gc::AllocKind::FUNCTION,
+ TenuredObject
+ ));
+ if (!fun) {
+ return false;
+ }
+
+ FunctionBox* funbox = new_<FunctionBox>(this->cx,
+ this->alloc,
+ this->traceListHead,
+ fun,
+ /*toStringStart*/0,
+ /*Directives*/this->currentDirectives(),
+ /*extraWarning*/false,
+ GeneratorKind::NotGenerator,
+ FunctionAsyncKind::SyncFunction
+ );
+ if (!funbox) {
+ return false;
+ }
+ this->traceListHead = funbox;
+
+ MOZ_ASSERT(params->isArity(PN_LIST));
+ params->setKind(PNK_PARAMSBODY);
+ params->setOp(JSOP_NOP);
+
+ MOZ_ASSERT(body->getKind() == PNK_STATEMENTLIST); // FIXME: If that's not the case, promote to PNK_STATEMENTLIST
+ params->append(body.release());
+
+ UniquePtr<ParseNode> result(new_<CodeNode>(PNK_FUNCTION, JSOP_NOP, TokenPos()));
+ if (!result) {
+ return false;
+ }
+ result->pn_funbox = funbox;
+ result->pn_body = params.release();
+
+ out = Move(result);
+
+ // FIXME: Scope
} else if (name == "VariableDeclaration") {
if (!this->parseVariableDeclarationAux(&sub, name, &fields, out)) {
return false;
}
} else {
@@ -996,11 +1098,16 @@ ASTReader::parseBool(SimpleTokenReader*
}
bool
ASTReader::raiseError() {
// FIXME: Implement actual error conditions.
return false;
}
+void
+TraceBinParser(JSTracer* trc, AutoGCRooter* parser)
+{
+ static_cast<ASTReader*>(parser)->trace(trc);
+}
} // namespace frontend
} // namespace js
--- a/js/src/jspubtd.h
+++ b/js/src/jspubtd.h
@@ -239,16 +239,17 @@ class JS_PUBLIC_API(AutoGCRooter)
* below. Any other negative value indicates some deeper problem such as
* memory corruption.
*/
ptrdiff_t tag_;
enum {
VALARRAY = -2, /* js::AutoValueArray */
PARSER = -3, /* js::frontend::Parser */
+ BINPARSER = -4, /* js::frontend::BinSource */
VALVECTOR = -10, /* js::AutoValueVector */
IDVECTOR = -11, /* js::AutoIdVector */
OBJVECTOR = -14, /* js::AutoObjectVector */
IONMASM = -19, /* js::jit::MacroAssembler */
WRAPVECTOR = -20, /* js::AutoWrapperVector */
WRAPPER = -21, /* js::AutoWrapperRooter */
CUSTOM = -26 /* js::CustomAutoRooter */
};