Commit e87e3b1f authored by Tobias Tebbi's avatar Tobias Tebbi Committed by Commit Bot

[torque] named arguments for constructors

This changes the syntax for constructing structs and classes to explicitly
mention the fieldnames, similar to JavaScript object literals.
The fields still have to be listed in the same order as in the struct/class
declaration.
As in Javascript, {foo: foo} can be abbreviated as {foo}.

Example:

macro NewJSArray(implicit context: Context)(
    map: Map, elements: FixedArrayBase): JSArray {
  return new JSArray{
    map,
    properties_or_hash: kEmptyFixedArray,
    elements,
    length: elements.length
  };
}

Drive-by cleanup: Make struct and class constructors follow the same pattern
                  in the parser and the AST.

Bug: v8:9018 v8:7793
Change-Id: I22ff7f68270e4f406aa80731a709d41ea52f52bb
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1551999Reviewed-by: 's avatarSigurd Schneider <sigurds@chromium.org>
Reviewed-by: 's avatarDaniel Clifford <danno@chromium.org>
Commit-Queue: Tobias Tebbi <tebbi@chromium.org>
Cr-Commit-Position: refs/heads/master@{#60622}
parent ecec2c61
......@@ -43,12 +43,16 @@ namespace arguments {
const adaptor: ArgumentsAdaptorFrame =
Cast<ArgumentsAdaptorFrame>(frame.caller)
otherwise return ArgumentsInfo{frame, argumentCount, formalParameterCount};
otherwise return ArgumentsInfo{
frame,
argument_count: argumentCount,
formal_parameter_count: formalParameterCount
};
return ArgumentsInfo{
adaptor,
Convert<bint>(adaptor.length),
formalParameterCount
frame: adaptor,
argument_count: Convert<bint>(adaptor.length),
formal_parameter_count: formalParameterCount
};
}
}
......@@ -219,10 +219,10 @@ namespace array_join {
Signed(len);
assert(cappedBufferSize > 0);
return Buffer{
AllocateZeroedFixedArray(cappedBufferSize),
0,
0,
IsOneByteStringInstanceType(sep.instanceType)
fixedArray: AllocateZeroedFixedArray(cappedBufferSize),
index: 0,
totalStringLength: 0,
isOneByte: IsOneByteStringInstanceType(sep.instanceType)
};
}
......
......@@ -173,7 +173,12 @@ namespace array_map {
AllocateFixedArrayWithHoles(
SmiUntag(length), kAllowLargeObjectAllocation) :
kEmptyFixedArray;
return Vector{fixedArray, true, true, false};
return Vector{
fixedArray,
onlySmis: true,
onlyNumbers: true,
skippedElements: false
};
}
transitioning macro FastArrayMap(implicit context: Context)(
......
......@@ -157,13 +157,17 @@ extern class JSObject extends JSReceiver { elements: FixedArrayBase; }
macro NewJSObject(
map: Map, properties: FixedArrayBase | Smi,
elements: FixedArrayBase): JSObject {
return new JSObject{map, properties, elements};
return new JSObject{map, properties_or_hash: properties, elements};
}
macro NewJSObject(implicit context: Context)(): JSObject {
const objectFunction: JSFunction = GetObjectFunction();
const map: Map = Cast<Map>(objectFunction.prototype_or_initial_map)
otherwise unreachable;
return new JSObject{map, kEmptyFixedArray, kEmptyFixedArray};
return new JSObject{
map,
properties_or_hash: kEmptyFixedArray,
elements: kEmptyFixedArray
};
}
extern class JSFunction extends JSObject {
......@@ -187,11 +191,11 @@ extern class JSProxyRevocableResult extends JSObject {
macro NewJSProxyRevocableResult(implicit context: Context)(
proxy: JSProxy, revoke: JSFunction): JSProxyRevocableResult {
return new JSProxyRevocableResult{
GetProxyRevocableResultMap(), // HeapObject.map
kEmptyFixedArray, // JSReceiver.properties_or_hash
kEmptyFixedArray, // JSObject.elements
proxy, // JSProxyRevocableResult.proxy
revoke // JSProxyRevocableResult.revoke
map: GetProxyRevocableResultMap(),
properties_or_hash: kEmptyFixedArray,
elements: kEmptyFixedArray,
proxy,
revoke
};
}
......@@ -222,15 +226,20 @@ extern class JSArray extends JSObject {
macro NewJSArray(implicit context: Context)(
map: Map, elements: FixedArrayBase): JSArray {
return new JSArray{map, kEmptyFixedArray, elements, elements.length};
return new JSArray{
map,
properties_or_hash: kEmptyFixedArray,
elements,
length: elements.length
};
}
macro NewJSArray(implicit context: Context)(): JSArray {
return new JSArray{
GetFastPackedSmiElementsJSArrayMap(),
kEmptyFixedArray,
kEmptyFixedArray,
0
map: GetFastPackedSmiElementsJSArrayMap(),
properties_or_hash: kEmptyFixedArray,
elements: kEmptyFixedArray,
length: 0
};
}
......@@ -424,8 +433,12 @@ extern class JSTypedArray extends JSArrayBufferView {
Convert<uintptr>(externalPointer) >= Convert<uintptr>(backingStore));
this.buffer = buffer;
this.elements = new
FixedTypedArrayBase{map, length, basePointer, externalPointer};
this.elements = new FixedTypedArrayBase{
map,
length,
base_pointer: basePointer,
external_pointer: externalPointer
};
}
length: Smi;
......@@ -2047,12 +2060,12 @@ struct FastJSArrayWitness {
macro NewFastJSArrayWitness(array: FastJSArray): FastJSArrayWitness {
let kind = array.map.elements_kind;
return FastJSArrayWitness{
array,
array,
array.map,
!IsElementsKindLessThanOrEqual(kind, HOLEY_ELEMENTS),
IsElementsKindLessThanOrEqual(kind, HOLEY_SMI_ELEMENTS),
false
stable: array,
unstable: array,
map: array.map,
hasDoubles: !IsElementsKindLessThanOrEqual(kind, HOLEY_ELEMENTS),
hasSmis: IsElementsKindLessThanOrEqual(kind, HOLEY_SMI_ELEMENTS),
arrayIsPushable: false
};
}
......
......@@ -14,18 +14,18 @@ namespace collections {
typeswitch (a.elements) {
case (elements: FixedArray): {
return KeyValuePair{
length > 0 ? array::LoadElementOrUndefined(elements, 0) :
Undefined,
length > 1 ? array::LoadElementOrUndefined(elements, 1) :
Undefined
key: length > 0 ? array::LoadElementOrUndefined(elements, 0) :
Undefined,
value: length > 1 ? array::LoadElementOrUndefined(elements, 1) :
Undefined
};
}
case (elements: FixedDoubleArray): {
return KeyValuePair{
length > 0 ? array::LoadElementOrUndefined(elements, 0) :
Undefined,
length > 1 ? array::LoadElementOrUndefined(elements, 1) :
Undefined
key: length > 0 ? array::LoadElementOrUndefined(elements, 0) :
Undefined,
value: length > 1 ? array::LoadElementOrUndefined(elements, 1) :
Undefined
};
}
case (Object): deferred {
......@@ -49,8 +49,8 @@ namespace collections {
}
label Generic {
return KeyValuePair{
GetProperty(o, Convert<Smi>(0)),
GetProperty(o, Convert<Smi>(1))
key: GetProperty(o, Convert<Smi>(0)),
value: GetProperty(o, Convert<Smi>(1))
};
}
}
......
......@@ -40,6 +40,6 @@ namespace growable_fixed_array {
}
macro NewGrowableFixedArray(): GrowableFixedArray {
return GrowableFixedArray{kEmptyFixedArray, 0, 0};
return GrowableFixedArray{array: kEmptyFixedArray, capacity: 0, length: 0};
}
}
......@@ -111,9 +111,9 @@ namespace typed_array {
AttachedJSTypedArrayWitness {
const kind = array.elements_kind;
return AttachedJSTypedArrayWitness{
array,
array,
GetLoadFnForElementsKind(kind)
stable: array,
unstable: array,
loadfn: GetLoadFnForElementsKind(kind)
};
}
......
......@@ -291,18 +291,20 @@ struct CallExpression : Expression {
std::vector<std::string> labels;
};
struct NameAndExpression {
Identifier* name;
Expression* expression;
};
struct StructExpression : Expression {
DEFINE_AST_NODE_LEAF_BOILERPLATE(StructExpression)
StructExpression(SourcePosition pos,
std::vector<std::string> namespace_qualification,
std::string name, std::vector<Expression*> expressions)
StructExpression(SourcePosition pos, TypeExpression* type,
std::vector<NameAndExpression> initializers)
: Expression(kKind, pos),
namespace_qualification(std::move(namespace_qualification)),
name(std::move(name)),
expressions(std::move(expressions)) {}
std::vector<std::string> namespace_qualification;
std::string name;
std::vector<Expression*> expressions;
type(type),
initializers(std::move(initializers)) {}
TypeExpression* type;
std::vector<NameAndExpression> initializers;
};
struct LogicalOrExpression : Expression {
......@@ -410,10 +412,12 @@ struct AssumeTypeImpossibleExpression : Expression {
struct NewExpression : Expression {
DEFINE_AST_NODE_LEAF_BOILERPLATE(NewExpression)
NewExpression(SourcePosition pos, TypeExpression* type,
std::vector<Expression*> parameters)
: Expression(kKind, pos), type(type), parameters(parameters) {}
std::vector<NameAndExpression> initializers)
: Expression(kKind, pos),
type(type),
initializers(std::move(initializers)) {}
TypeExpression* type;
std::vector<Expression*> parameters;
std::vector<NameAndExpression> initializers;
};
struct ParameterList {
......
......@@ -54,9 +54,11 @@ enum class ParseResultHolderBase::TypeId {
kLabelBlockPtr,
kOptionalLabelBlockPtr,
kNameAndTypeExpression,
kNameAndExpression,
kClassFieldExpression,
kStructFieldExpression,
kStdVectorOfNameAndTypeExpression,
kStdVectorOfNameAndExpression,
kStdVectorOfClassFieldExpression,
kStdVectorOfStructFieldExpression,
kIncrementDecrementOperator,
......
......@@ -1250,10 +1250,11 @@ VisitResult ImplementationVisitor::Visit(StatementExpression* expr) {
}
InitializerResults ImplementationVisitor::VisitInitializerResults(
const std::vector<Expression*>& expressions) {
const std::vector<NameAndExpression>& initializers) {
InitializerResults result;
for (auto e : expressions) {
result.results.push_back(Visit(e));
for (const NameAndExpression& initializer : initializers) {
result.names.push_back(initializer.name);
result.results.push_back(Visit(initializer.expression));
}
return result;
}
......@@ -1271,12 +1272,18 @@ size_t ImplementationVisitor::InitializeAggregateHelper(
}
}
for (auto f : aggregate_type->fields()) {
for (Field f : aggregate_type->fields()) {
if (current == initializer_results.results.size()) {
ReportError("insufficient number of initializers for ",
aggregate_type->name());
}
VisitResult current_value = initializer_results.results[current];
Identifier* fieldname = initializer_results.names[current];
if (fieldname->value != f.name_and_type.name) {
CurrentSourcePosition::Scope scope(fieldname->pos);
ReportError("Expected fieldname \"", f.name_and_type.name,
"\" instead of \"", fieldname->value, "\"");
}
if (aggregate_type->IsClassType()) {
allocate_result.SetType(aggregate_type);
GenerateCopy(allocate_result);
......@@ -1320,7 +1327,7 @@ VisitResult ImplementationVisitor::Visit(NewExpression* expr) {
}
InitializerResults initializer_results =
VisitInitializerResults(expr->parameters);
VisitInitializerResults(expr->initializers);
// Output the code to generate an uninitialized object of the class size in
// the GC heap.
......@@ -1692,18 +1699,15 @@ VisitResult ImplementationVisitor::GenerateCopy(const VisitResult& to_copy) {
return to_copy;
}
VisitResult ImplementationVisitor::Visit(StructExpression* decl) {
VisitResult ImplementationVisitor::Visit(StructExpression* expr) {
StackScope stack_scope(this);
const Type* raw_type = Declarations::LookupType(
QualifiedName(decl->namespace_qualification, decl->name));
const Type* raw_type = Declarations::GetType(expr->type);
if (!raw_type->IsStructType()) {
std::stringstream s;
s << decl->name << " is not a struct but used like one ";
ReportError(s.str());
ReportError(*raw_type, " is not a struct but used like one");
}
InitializerResults initialization_results =
ImplementationVisitor::VisitInitializerResults(decl->expressions);
ImplementationVisitor::VisitInitializerResults(expr->initializers);
const StructType* struct_type = StructType::cast(raw_type);
// Push uninitialized 'this'
......
......@@ -140,6 +140,7 @@ class LocationReference {
};
struct InitializerResults {
std::vector<Identifier*> names;
std::vector<VisitResult> results;
};
......@@ -261,7 +262,7 @@ class ImplementationVisitor : public FileVisitor {
const Type* Visit(Statement* stmt);
InitializerResults VisitInitializerResults(
const std::vector<Expression*>& expressions);
const std::vector<NameAndExpression>& expressions);
size_t InitializeAggregateHelper(
const AggregateType* aggregate_type, VisitResult allocate_result,
......
......@@ -79,6 +79,10 @@ V8_EXPORT_PRIVATE const ParseResultTypeId
ParseResultHolder<NameAndTypeExpression>::id =
ParseResultTypeId::kNameAndTypeExpression;
template <>
V8_EXPORT_PRIVATE const ParseResultTypeId
ParseResultHolder<NameAndExpression>::id =
ParseResultTypeId::kNameAndExpression;
template <>
V8_EXPORT_PRIVATE const ParseResultTypeId
ParseResultHolder<ClassFieldExpression>::id =
ParseResultTypeId::kClassFieldExpression;
......@@ -91,6 +95,10 @@ V8_EXPORT_PRIVATE const ParseResultTypeId
ParseResultHolder<std::vector<NameAndTypeExpression>>::id =
ParseResultTypeId::kStdVectorOfNameAndTypeExpression;
template <>
V8_EXPORT_PRIVATE const ParseResultTypeId
ParseResultHolder<std::vector<NameAndExpression>>::id =
ParseResultTypeId::kStdVectorOfNameAndExpression;
template <>
V8_EXPORT_PRIVATE const ParseResultTypeId
ParseResultHolder<std::vector<ClassFieldExpression>>::id =
ParseResultTypeId::kStdVectorOfClassFieldExpression;
......@@ -257,7 +265,7 @@ base::Optional<ParseResult> MakeCall(ParseResultIterator* child_results) {
auto args = child_results->NextAs<std::vector<Expression*>>();
auto otherwise = child_results->NextAs<std::vector<Statement*>>();
IdentifierExpression* target = IdentifierExpression::cast(callee);
return ParseResult{MakeCall(target, base::nullopt, args, otherwise)};
return ParseResult{MakeCall(target, base::nullopt, args, otherwise)};
}
base::Optional<ParseResult> MakeMethodCall(ParseResultIterator* child_results) {
......@@ -270,10 +278,11 @@ base::Optional<ParseResult> MakeMethodCall(ParseResultIterator* child_results) {
this_arg, args, otherwise)};
}
base::Optional<ParseResult> MakeNew(ParseResultIterator* child_results) {
TypeExpression* type = child_results->NextAs<TypeExpression*>();
auto args = child_results->NextAs<std::vector<Expression*>>();
Expression* result = MakeNode<NewExpression>(type, args);
base::Optional<ParseResult> MakeNewExpression(
ParseResultIterator* child_results) {
auto type = child_results->NextAs<TypeExpression*>();
auto initializers = child_results->NextAs<std::vector<NameAndExpression>>();
Expression* result = MakeNode<NewExpression>(type, std::move(initializers));
return ParseResult{result};
}
......@@ -1007,13 +1016,10 @@ base::Optional<ParseResult> MakeElementAccessExpression(
base::Optional<ParseResult> MakeStructExpression(
ParseResultIterator* child_results) {
auto namespace_qualification =
child_results->NextAs<std::vector<std::string>>();
auto name = child_results->NextAs<std::string>();
auto expressions = child_results->NextAs<std::vector<Expression*>>();
auto type = child_results->NextAs<TypeExpression*>();
auto initializers = child_results->NextAs<std::vector<NameAndExpression>>();
Expression* result =
MakeNode<StructExpression>(std::move(namespace_qualification),
std::move(name), std::move(expressions));
MakeNode<StructExpression>(type, std::move(initializers));
return ParseResult{result};
}
......@@ -1102,6 +1108,26 @@ base::Optional<ParseResult> MakeNameAndType(
return ParseResult{NameAndTypeExpression{name, type}};
}
base::Optional<ParseResult> MakeNameAndExpression(
ParseResultIterator* child_results) {
auto name = child_results->NextAs<Identifier*>();
auto expression = child_results->NextAs<Expression*>();
return ParseResult{NameAndExpression{name, expression}};
}
base::Optional<ParseResult> MakeNameAndExpressionFromExpression(
ParseResultIterator* child_results) {
auto expression = child_results->NextAs<Expression*>();
if (auto* id = IdentifierExpression::DynamicCast(expression)) {
if (!id->generic_arguments.empty() ||
!id->namespace_qualification.empty()) {
ReportError("expected a plain identifier without qualification");
}
return ParseResult{NameAndExpression{id->name, id}};
}
ReportError("Constructor parameters need to be named.");
}
base::Optional<ParseResult> MakeClassField(ParseResultIterator* child_results) {
auto weak = child_results->NextAs<bool>();
auto const_qualified = child_results->NextAs<bool>();
......@@ -1308,8 +1334,8 @@ struct TorqueGrammar : Grammar {
// Result: NameAndTypeExpression
Symbol nameAndType = {Rule({&name, Token(":"), &type}, MakeNameAndType)};
Symbol* optionalArraySpecifier = {
Optional<std::string>(Sequence({Token("["), &identifier, Token("]")}))};
Symbol* optionalArraySpecifier =
Optional<std::string>(Sequence({Token("["), &identifier, Token("]")}));
Symbol classField = {
Rule({CheckIf(Token("weak")), CheckIf(Token("const")), &name,
......@@ -1385,16 +1411,21 @@ struct TorqueGrammar : Grammar {
Symbol callExpression = {Rule(
{&identifierExpression, &argumentList, optionalOtherwise}, MakeCall)};
// Result: Expression*
Symbol callMethodExpression = {
Rule({&primaryExpression, Token("."), &identifier, &argumentList,
optionalOtherwise},
MakeMethodCall)};
Symbol initializerList = {Rule(
{Token("{"), List<Expression*>(expression, Token(",")), Token("}")})};
// Result: NameAndExpression
Symbol namedExpression = {
Rule({&name, Token(":"), expression}, MakeNameAndExpression),
Rule({expression}, MakeNameAndExpressionFromExpression)};
Symbol newExpression = {
Rule({Token("new"), &type, &initializerList}, MakeNew)};
// Result: std::vector<NameAndExpression>
Symbol initializerList = {
Rule({Token("{"), List<NameAndExpression>(&namedExpression, Token(",")),
Token("}")})};
// Result: Expression*
Symbol intrinsicCallExpression = {Rule(
......@@ -1404,7 +1435,6 @@ struct TorqueGrammar : Grammar {
// Result: Expression*
Symbol primaryExpression = {
Rule({&newExpression}),
Rule({&callExpression}),
Rule({&callMethodExpression}),
Rule({&intrinsicCallExpression}),
......@@ -1412,10 +1442,8 @@ struct TorqueGrammar : Grammar {
CastParseResult<LocationExpression*, Expression*>),
Rule({&decimalLiteral}, MakeNumberLiteralExpression),
Rule({&stringLiteral}, MakeStringLiteralExpression),
Rule(
{List<std::string>(Sequence({&identifier, Token("::")})), &identifier,
Token("{"), List<Expression*>(expression, Token(",")), Token("}")},
MakeStructExpression),
Rule({&simpleType, &initializerList}, MakeStructExpression),
Rule({Token("new"), &simpleType, &initializerList}, MakeNewExpression),
Rule({Token("("), expression, Token(")")})};
// Result: Expression*
......
......@@ -123,7 +123,7 @@ DEFINE_CONTEXTUAL_VARIABLE(LintErrorStatus)
[[noreturn]] void ReportErrorString(const std::string& error,
bool print_position) {
if (print_position) std::cerr << CurrentPositionAsString() << ": ";
std::cerr << ": Torque error: " << error << "\n";
std::cerr << "Torque error: " << error << "\n";
v8::base::OS::Abort();
}
......
......@@ -278,22 +278,29 @@ namespace test {
}
macro TestStruct2(implicit context: Context)(): TestStructA {
return TestStructA{UnsafeCast<FixedArray>(kEmptyFixedArray), 27, 31};
return TestStructA{
indexes: UnsafeCast<FixedArray>(kEmptyFixedArray),
i: 27,
k: 31
};
}
macro TestStruct3(implicit context: Context)(): TestStructA {
let a: TestStructA =
TestStructA{UnsafeCast<FixedArray>(kEmptyFixedArray), 13, 5};
TestStructA{indexes: UnsafeCast<FixedArray>(kEmptyFixedArray), i: 13, k: 5};
let b: TestStructA = a;
let c: TestStructA = TestStruct2();
a.i = TestStruct1(c);
a.k = a.i;
let d: TestStructB;
d.x = a;
d = TestStructB{a, 7};
d = TestStructB{x: a, y: 7};
let e: TestStructA = d.x;
let f: Smi =
TestStructA{UnsafeCast<FixedArray>(kEmptyFixedArray), 27, 31}.i;
let f: Smi = TestStructA{
indexes: UnsafeCast<FixedArray>(kEmptyFixedArray),
i: 27,
k: 31
}.i;
f = TestStruct2().i;
return a;
}
......@@ -304,7 +311,7 @@ namespace test {
}
macro TestStruct4(implicit context: Context)(): TestStructC {
return TestStructC{TestStruct2(), TestStruct2()};
return TestStructC{x: TestStruct2(), y: TestStruct2()};
}
macro TestStructInLabel(implicit context: Context)(): never
......@@ -751,7 +758,7 @@ namespace test {
macro TestStructConstructor(implicit context: Context)() {
// Test default constructor
let a: TestOuter = TestOuter{5, TestInner{6, 7}, 8};
let a: TestOuter = TestOuter{a: 5, b: TestInner{x: 6, y: 7}, c: 8};
assert(a.a == 5);
assert(a.b.x == 6);
assert(a.b.y == 7);
......@@ -811,7 +818,7 @@ namespace test {
}
macro NewInternalClass(x: Smi): InternalClass {
return new InternalClass{x, x + 1};
return new InternalClass{a: x, b: x + 1};
}
macro TestInternalClass(implicit context: Context)() {
......@@ -833,8 +840,8 @@ namespace test {
}
macro TestConstInStructs() {
const x = StructWithConst{Null, 1};
let y = StructWithConst{Null, 1};
const x = StructWithConst{a: Null, b: 1};
let y = StructWithConst{a: Null, b: 1};
y.a = Undefined;
const copy = x;
}
......
......@@ -135,19 +135,19 @@ namespace array {
return new SortState{
receiver,
map,
initialReceiverMap: map,
initialReceiverLength,
comparefn,
userCmpFn: comparefn,
sortComparePtr,
loadFn,
storeFn,
canUseSameAccessorFn,
kSuccess,
kMinGallopWins,
0,
AllocateZeroedFixedArray(Convert<intptr>(kMaxMergePending)),
AllocateZeroedFixedArray(Convert<intptr>(sortLength)),
kEmptyFixedArray
bailoutStatus: kSuccess,
minGallop: kMinGallopWins,
pendingRunsSize: 0,
pendingRuns: AllocateZeroedFixedArray(Convert<intptr>(kMaxMergePending)),
workArray: AllocateZeroedFixedArray(Convert<intptr>(sortLength)),
tempArray: kEmptyFixedArray
};
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment