1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2  * vim: set ts=8 sts=2 et sw=2 tw=80:
3  * This Source Code Form is subject to the terms of the Mozilla Public
4  * License, v. 2.0. If a copy of the MPL was not distributed with this
5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 
7 #include "frontend/BinASTTokenReaderBase.h"
8 
9 #include "frontend/BinAST-macros.h"
10 #include "js/Result.h"
11 
12 namespace js::frontend {
13 
14 template <typename T>
15 using ErrorResult = mozilla::GenericErrorResult<T>;
16 
17 // We use signalling NaN (which doesn't exist in the JS syntax)
18 // to represent a `null` number.
19 const uint64_t NULL_FLOAT_REPRESENTATION = 0x7FF0000000000001;
20 
updateLatestKnownGood()21 void BinASTTokenReaderBase::updateLatestKnownGood() {
22   MOZ_ASSERT(current_ >= start_);
23   const size_t update = current_ - start_;
24   MOZ_ASSERT(update >= latestKnownGoodPos_);
25   latestKnownGoodPos_ = update;
26 }
27 
raiseError(const char * description)28 ErrorResult<JS::Error&> BinASTTokenReaderBase::raiseError(
29     const char* description) {
30   MOZ_ASSERT(!hasRaisedError());
31   errorReporter_->errorNoOffset(JSMSG_BINAST, description);
32   return cx_->alreadyReportedError();
33 }
34 
raiseOOM()35 ErrorResult<JS::Error&> BinASTTokenReaderBase::raiseOOM() {
36   ReportOutOfMemory(cx_);
37   return cx_->alreadyReportedError();
38 }
39 
raiseInvalidNumberOfFields(const BinASTKind kind,const uint32_t expected,const uint32_t got)40 ErrorResult<JS::Error&> BinASTTokenReaderBase::raiseInvalidNumberOfFields(
41     const BinASTKind kind, const uint32_t expected, const uint32_t got) {
42   Sprinter out(cx_);
43   BINJS_TRY(out.init());
44   BINJS_TRY(out.printf("In %s, invalid number of fields: expected %u, got %u",
45                        describeBinASTKind(kind), expected, got));
46   return raiseError(out.string());
47 }
48 
raiseInvalidField(const char * kind,const BinASTField field)49 ErrorResult<JS::Error&> BinASTTokenReaderBase::raiseInvalidField(
50     const char* kind, const BinASTField field) {
51   Sprinter out(cx_);
52   BINJS_TRY(out.init());
53   BINJS_TRY(out.printf("In %s, invalid field '%s'", kind,
54                        describeBinASTField(field)));
55   return raiseError(out.string());
56 }
57 
hasRaisedError() const58 bool BinASTTokenReaderBase::hasRaisedError() const {
59   if (cx_->isHelperThreadContext()) {
60     // When performing off-main-thread parsing, we don't set a pending
61     // exception but instead add a pending compile error.
62     return cx_->isCompileErrorPending();
63   }
64 
65   return cx_->isExceptionPending();
66 }
67 
pos()68 TokenPos BinASTTokenReaderBase::pos() { return pos(offset()); }
69 
pos(size_t start)70 TokenPos BinASTTokenReaderBase::pos(size_t start) {
71   TokenPos pos;
72   pos.begin = start;
73   pos.end = current_ - start_;
74   MOZ_ASSERT(pos.end >= pos.begin);
75   return pos;
76 }
77 
seek(size_t offset)78 void BinASTTokenReaderBase::seek(size_t offset) {
79   MOZ_ASSERT(start_ + offset >= start_ && start_ + offset < stop_);
80   current_ = start_ + offset;
81 }
82 
readBuf(uint8_t * bytes,uint32_t len)83 JS::Result<Ok> BinASTTokenReaderBase::readBuf(uint8_t* bytes, uint32_t len) {
84   MOZ_ASSERT(!hasRaisedError());
85 
86   if (MOZ_UNLIKELY(stop_ < current_ + len)) {
87     return raiseError("Buffer exceeds length");
88   }
89 
90   for (uint32_t i = 0; i < len; ++i) {
91     *bytes++ = *current_++;
92   }
93 
94   return Ok();
95 }
96 
readByte()97 JS::Result<uint8_t> BinASTTokenReaderBase::readByte() {
98   MOZ_ASSERT(!hasRaisedError());
99 
100   if (MOZ_UNLIKELY(stop_ == current_)) {
101     return raiseError("Buffer exceeds length");
102   }
103 
104   return *current_++;
105 }
106 
107 }  // namespace js::frontend
108