Skip to content

Commit

Permalink
Enable BigInt literals and Support
Browse files Browse the repository at this point in the history
Summary:
Enables Hermes BigInt Support by
1. enabling BigInt literals; and
2. exposing the %BigInt% prototype

Reviewed By: kodafb

Differential Revision: D34439989

fbshipit-source-id: 48d5a3719b5a78ab9776aecaf2e3aa38307703fe
  • Loading branch information
jpporto authored and facebook-github-bot committed Jul 9, 2022
1 parent 75d4f22 commit 4b20d6e
Show file tree
Hide file tree
Showing 35 changed files with 3,273 additions and 270 deletions.
7 changes: 0 additions & 7 deletions lib/AST/SemanticValidator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -315,13 +315,6 @@ void SemanticValidator::visit(LabeledStatementNode *labelStmt) {
visitESTreeChildren(*this, labelStmt);
}

void SemanticValidator::visit(BigIntLiteralNode *bigint) {
if (compile_) {
sm_.error(bigint->getSourceRange(), "BigInt literal is not supported");
}
visitESTreeChildren(*this, bigint);
}

/// Check RegExp syntax.
void SemanticValidator::visit(RegExpLiteralNode *regexp) {
llvh::StringRef regexpError;
Expand Down
1 change: 0 additions & 1 deletion lib/AST/SemanticValidator.h
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,6 @@ class SemanticValidator {

void visit(LabeledStatementNode *labelStmt);

void visit(BigIntLiteralNode *bigint);
void visit(RegExpLiteralNode *regexp);

void visit(TryStatementNode *tryStatement);
Expand Down
19 changes: 8 additions & 11 deletions lib/BCGen/HBC/BytecodeDisassembler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -312,14 +312,15 @@ void BytecodeDisassembler::disassembleBigIntStorage(raw_ostream &OS) {

for (uint32_t i = 0; i < bigintCount; ++i) {
const auto &entry = bigintTable[i];
uint32_t start = entry.offset;
uint32_t end = start + entry.length;
const uint32_t start = entry.offset;
const uint32_t count = entry.length;
OS << " " << i << "[";
if (start == end) {
OS << "empty]";
if (count == 0) {
OS << " " << i << "[empty]";
} else {
auto bytes = bigintStorage.slice(start, end);
OS << (end - 1) << ".." << start
auto bytes = bigintStorage.slice(start, count);
const uint32_t end = start + count - 1;
OS << " " << i << "[" << end << ".." << start
<< "]: " << bigintMagnitudeToLengthLimitedString(bytes);
}
OS << "\n";
Expand Down Expand Up @@ -626,12 +627,8 @@ void PrettyDisassembleVisitor::dumpOperandBigInt(

const uint32_t count = entry.length;
const uint32_t start = entry.offset;
const uint32_t end = start + count;

if (!bigintStorage.empty()) {
}

OS << bigintMagnitudeToLengthLimitedString(bigintStorage.slice(start, end))
OS << bigintMagnitudeToLengthLimitedString(bigintStorage.slice(start, count))
<< "n";
}

Expand Down
13 changes: 13 additions & 0 deletions lib/BCGen/HBC/ISel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include "hermes/BCGen/HBC/HBC.h"
#include "hermes/IR/Analysis.h"
#include "hermes/SourceMap/SourceMapGenerator.h"
#include "hermes/Support/BigIntSupport.h"
#include "hermes/Support/Statistic.h"

#include "llvh/ADT/Optional.h"
Expand Down Expand Up @@ -1413,6 +1414,18 @@ void HBCISel::generateHBCLoadConstInst(
}
break;
}
case ValueKind::LiteralBigIntKind: {
auto parsedBigInt = bigint::ParsedBigInt::parsedBigIntFromNumericValue(
cast<LiteralBigInt>(literal)->getValue());
assert(parsedBigInt && "should be valid");
auto idx = BCFGen_->addBigInt(std::move(*parsedBigInt));
if (idx <= UINT16_MAX) {
BCFGen_->emitLoadConstBigInt(output, idx);
} else {
BCFGen_->emitLoadConstBigIntLongIndex(output, idx);
}
break;
}
case ValueKind::LiteralStringKind: {
auto idx = BCFGen_->getStringID(cast<LiteralString>(literal));
if (idx <= UINT16_MAX) {
Expand Down
8 changes: 8 additions & 0 deletions lib/IRGen/ESTreeIRGen-expr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,14 @@ Value *ESTreeIRGen::genExpression(ESTree::Node *expr, Identifier nameHint) {
return Builder.getLiteralNumber(Lit->_value);
}

// Handle BigInt Literals.
// https://262.ecma-international.org/#sec-ecmascript-language-types-bigint-type
if (auto *Lit = llvh::dyn_cast<ESTree::BigIntLiteralNode>(expr)) {
LLVM_DEBUG(
dbgs() << "Loading BitInt Literal \"" << Lit->_bigint->str() << "\"\n");
return Builder.getLiteralBigInt(Lit->_bigint->str());
}

// Handle the assignment expression.
if (auto Assign = llvh::dyn_cast<ESTree::AssignmentExpressionNode>(expr)) {
return genAssignmentExpr(Assign);
Expand Down
20 changes: 15 additions & 5 deletions lib/Parser/JSLexer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1461,11 +1461,21 @@ void JSLexer::scanNumber(GrammarContext grammarContext) {

llvh::StringRef raw{rawStart, (size_t)(curCharPtr_ - rawStart)};
if (ok && !real && (!legacyOctal || raw == "0n") && tmpStorage_ == "n") {
// This is a BigInt.
rawStorage_.clear();
rawStorage_.append(raw);
token_.setBigIntLiteral(getStringLiteral(rawStorage_));
return;
assert(curCharPtr_ > start + 1 && "there should be numbers here");
// use parseIntWithRadix to validate the bigint literal's digits. The
// converted value does not matter, only whether or not the string was
// parsed correctly.
if (parseIntWithRadix</* AllowNumericSeparator */ true>(
llvh::ArrayRef<char>{start, (size_t)(curCharPtr_ - start - 1)},
radix)) {
// This is a BigInt.
rawStorage_.clear();
rawStorage_.append(raw);
token_.setBigIntLiteral(getStringLiteral(rawStorage_));
return;
}

// This is a BigInt with invalid digits; fail.
}

ok = false;
Expand Down
3 changes: 2 additions & 1 deletion lib/Support/BigIntSupport.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1986,7 +1986,8 @@ static std::tuple<uint32_t, bool> getShiftAmountAndSign(
? 0ll
: static_cast<SignedBigIntDigitType>(shiftAmnt.digits[0]);
assert(
shiftAmnt.digits[0] != std::numeric_limits<BigIntDigitType>::min() &&
(shiftAmnt.numDigits == 0 ||
shiftAmnt.digits[0] != std::numeric_limits<BigIntDigitType>::min()) &&
"shiftAmnt is MIN_INT, hence -signedShiftAmnt is MIN_INT");
// Always return a positive result -- thus negate sa if shiftAmnt is negative.
return std::make_tuple(shiftAmntIsNeg ? -sa : sa, shiftAmntIsNeg);
Expand Down
3 changes: 3 additions & 0 deletions lib/VM/JSLib/GlobalObject.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -576,6 +576,9 @@ void initGlobalObject(Runtime &runtime, const JSLibFlags &jsLibFlags) {
// String constructor.
createStringConstructor(runtime);

// BigInt constructor.
createBigIntConstructor(runtime);

// Function constructor.
runtime.functionConstructor =
createFunctionConstructor(runtime).getHermesValue();
Expand Down
8 changes: 7 additions & 1 deletion test/Parser/literal.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,10 @@
"use strict";
0x

//CHECK: No digits after 0x
// CHECK: No digits after 0x

0b2
// CHECK: invalid integer literal

0b2n
// CHECK: invalid numeric literal
Loading

0 comments on commit 4b20d6e

Please sign in to comment.