Commit fe6839ba authored by Joyee Cheung's avatar Joyee Cheung Committed by Commit Bot

[class] parse static private methods and accessors

This patch uses a bit in the Variable bit fields to distinguish
static private names from instance private names, so that we
can check the conflicts of private accessors that are complementary
but with different staticness in the parser, and use this
information later when generating code for checking static brands
for private method access.

Design doc: https://docs.google.com/document/d/1rgGRw5RdzaRrM-GrIMhsn-DLULtADV2dmIdh_iIZxlc/edit

Bug: v8:8330
Change-Id: I8d70600e594e3d07f77ea519751b7ca2e0de87b5
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1781010Reviewed-by: 's avatarToon Verwaest <verwaest@chromium.org>
Reviewed-by: 's avatarRoss McIlroy <rmcilroy@chromium.org>
Commit-Queue: Joyee Cheung <joyee@igalia.com>
Cr-Commit-Position: refs/heads/master@{#63677}
parent 75a0c1fc
......@@ -40,7 +40,7 @@ Variable* VariableMap::Declare(Zone* zone, Scope* scope,
VariableKind kind,
InitializationFlag initialization_flag,
MaybeAssignedFlag maybe_assigned_flag,
bool* was_added) {
IsStaticFlag is_static_flag, bool* was_added) {
// AstRawStrings are unambiguous, i.e., the same string is always represented
// by the same AstRawString*.
// FIXME(marja): fix the type of Lookup.
......@@ -51,8 +51,9 @@ Variable* VariableMap::Declare(Zone* zone, Scope* scope,
if (*was_added) {
// The variable has not been declared yet -> insert it.
DCHECK_EQ(name, p->key);
Variable* variable = new (zone) Variable(
scope, name, mode, kind, initialization_flag, maybe_assigned_flag);
Variable* variable =
new (zone) Variable(scope, name, mode, kind, initialization_flag,
maybe_assigned_flag, is_static_flag);
p->value = variable;
}
return reinterpret_cast<Variable*>(p->value);
......@@ -797,11 +798,13 @@ Variable* Scope::LookupInScopeInfo(const AstRawString* name, Scope* cache) {
VariableMode mode;
InitializationFlag init_flag;
MaybeAssignedFlag maybe_assigned_flag;
IsStaticFlag is_static_flag;
{
location = VariableLocation::CONTEXT;
index = ScopeInfo::ContextSlotIndex(*scope_info_, name_handle, &mode,
&init_flag, &maybe_assigned_flag);
&init_flag, &maybe_assigned_flag,
&is_static_flag);
found = index >= 0;
}
......@@ -826,9 +829,9 @@ Variable* Scope::LookupInScopeInfo(const AstRawString* name, Scope* cache) {
}
bool was_added;
Variable* var =
cache->variables_.Declare(zone(), this, name, mode, NORMAL_VARIABLE,
init_flag, maybe_assigned_flag, &was_added);
Variable* var = cache->variables_.Declare(
zone(), this, name, mode, NORMAL_VARIABLE, init_flag, maybe_assigned_flag,
IsStaticFlag::kNotStatic, &was_added);
DCHECK(was_added);
var->AllocateTo(location, index);
return var;
......@@ -1057,7 +1060,7 @@ Variable* DeclarationScope::DeclareDynamicGlobal(const AstRawString* name,
bool was_added;
return cache->variables_.Declare(
zone(), this, name, VariableMode::kDynamicGlobal, kind,
kCreatedInitialized, kNotAssigned, &was_added);
kCreatedInitialized, kNotAssigned, IsStaticFlag::kNotStatic, &was_added);
// TODO(neis): Mark variable as maybe-assigned?
}
......@@ -1784,9 +1787,9 @@ Variable* Scope::NonLocal(const AstRawString* name, VariableMode mode) {
// Declare a new non-local.
DCHECK(IsDynamicVariableMode(mode));
bool was_added;
Variable* var =
variables_.Declare(zone(), this, name, mode, NORMAL_VARIABLE,
kCreatedInitialized, kNotAssigned, &was_added);
Variable* var = variables_.Declare(zone(), this, name, mode, NORMAL_VARIABLE,
kCreatedInitialized, kNotAssigned,
IsStaticFlag::kNotStatic, &was_added);
// Allocate it by giving it a dynamic lookup.
var->AllocateTo(VariableLocation::LOOKUP, -1);
return var;
......@@ -2407,14 +2410,17 @@ bool IsComplementaryAccessorPair(VariableMode a, VariableMode b) {
}
Variable* ClassScope::DeclarePrivateName(const AstRawString* name,
VariableMode mode, bool* was_added) {
VariableMode mode,
IsStaticFlag is_static_flag,
bool* was_added) {
Variable* result = EnsureRareData()->private_name_map.Declare(
zone(), this, name, mode, NORMAL_VARIABLE,
InitializationFlag::kNeedsInitialization,
MaybeAssignedFlag::kMaybeAssigned, was_added);
MaybeAssignedFlag::kMaybeAssigned, is_static_flag, was_added);
if (*was_added) {
locals_.Add(result);
} else if (IsComplementaryAccessorPair(result->mode(), mode)) {
} else if (IsComplementaryAccessorPair(result->mode(), mode) &&
result->is_static_flag() == is_static_flag) {
*was_added = true;
result->set_mode(VariableMode::kPrivateGetterAndSetter);
}
......@@ -2493,8 +2499,10 @@ Variable* ClassScope::LookupPrivateNameInScopeInfo(const AstRawString* name) {
VariableMode mode;
InitializationFlag init_flag;
MaybeAssignedFlag maybe_assigned_flag;
int index = ScopeInfo::ContextSlotIndex(*scope_info_, name_handle, &mode,
&init_flag, &maybe_assigned_flag);
IsStaticFlag is_static_flag;
int index =
ScopeInfo::ContextSlotIndex(*scope_info_, name_handle, &mode, &init_flag,
&maybe_assigned_flag, &is_static_flag);
if (index < 0) {
return nullptr;
}
......@@ -2506,7 +2514,7 @@ Variable* ClassScope::LookupPrivateNameInScopeInfo(const AstRawString* name) {
// Add the found private name to the map to speed up subsequent
// lookups for the same name.
bool was_added;
Variable* var = DeclarePrivateName(name, mode, &was_added);
Variable* var = DeclarePrivateName(name, mode, is_static_flag, &was_added);
DCHECK(was_added);
var->AllocateTo(VariableLocation::CONTEXT, index);
return var;
......@@ -2615,6 +2623,7 @@ VariableProxy* ClassScope::ResolvePrivateNamesPartially() {
}
Variable* ClassScope::DeclareBrandVariable(AstValueFactory* ast_value_factory,
IsStaticFlag is_static_flag,
int class_token_pos) {
DCHECK_IMPLIES(GetRareData() != nullptr, GetRareData()->brand == nullptr);
bool was_added;
......@@ -2623,6 +2632,7 @@ Variable* ClassScope::DeclareBrandVariable(AstValueFactory* ast_value_factory,
InitializationFlag::kNeedsInitialization,
MaybeAssignedFlag::kMaybeAssigned, &was_added);
DCHECK(was_added);
brand->set_is_static_flag(is_static_flag);
brand->ForceContextAllocation();
brand->set_is_used();
EnsureRareData()->brand = brand;
......
......@@ -44,7 +44,7 @@ class VariableMap : public ZoneHashMap {
VariableMode mode, VariableKind kind,
InitializationFlag initialization_flag,
MaybeAssignedFlag maybe_assigned_flag,
bool* was_added);
IsStaticFlag is_static_flag, bool* was_added);
V8_EXPORT_PRIVATE Variable* Lookup(const AstRawString* name);
void Remove(Variable* var);
......@@ -556,9 +556,10 @@ class V8_EXPORT_PRIVATE Scope : public NON_EXPORTED_BASE(ZoneObject) {
Variable* Declare(Zone* zone, const AstRawString* name, VariableMode mode,
VariableKind kind, InitializationFlag initialization_flag,
MaybeAssignedFlag maybe_assigned_flag, bool* was_added) {
Variable* result =
variables_.Declare(zone, this, name, mode, kind, initialization_flag,
maybe_assigned_flag, was_added);
// Static variables can only be declared using ClassScope methods.
Variable* result = variables_.Declare(
zone, this, name, mode, kind, initialization_flag, maybe_assigned_flag,
IsStaticFlag::kNotStatic, was_added);
if (*was_added) locals_.Add(result);
return result;
}
......@@ -1256,7 +1257,7 @@ class V8_EXPORT_PRIVATE ClassScope : public Scope {
// Declare a private name in the private name map and add it to the
// local variables of this scope.
Variable* DeclarePrivateName(const AstRawString* name, VariableMode mode,
bool* was_added);
IsStaticFlag is_static_flag, bool* was_added);
// Try resolving all unresolved private names found in the current scope.
// Called from DeclarationScope::AllocateVariables() when reparsing a
......@@ -1287,6 +1288,7 @@ class V8_EXPORT_PRIVATE ClassScope : public Scope {
void MigrateUnresolvedPrivateNameTail(AstNodeFactory* ast_node_factory,
UnresolvedList::Iterator tail);
Variable* DeclareBrandVariable(AstValueFactory* ast_value_factory,
IsStaticFlag is_static_flag,
int class_token_pos);
Variable* brand() {
return GetRareData() == nullptr ? nullptr : GetRareData()->brand;
......
......@@ -21,7 +21,8 @@ class Variable final : public ZoneObject {
public:
Variable(Scope* scope, const AstRawString* name, VariableMode mode,
VariableKind kind, InitializationFlag initialization_flag,
MaybeAssignedFlag maybe_assigned_flag = kNotAssigned)
MaybeAssignedFlag maybe_assigned_flag = kNotAssigned,
IsStaticFlag is_static_flag = IsStaticFlag::kNotStatic)
: scope_(scope),
name_(name),
local_if_not_shadowed_(nullptr),
......@@ -35,10 +36,13 @@ class Variable final : public ZoneObject {
ForceContextAllocationField::encode(false) |
ForceHoleInitializationField::encode(false) |
LocationField::encode(VariableLocation::UNALLOCATED) |
VariableKindField::encode(kind)) {
VariableKindField::encode(kind) |
IsStaticFlagField::encode(is_static_flag)) {
// Var declared variables never need initialization.
DCHECK(!(mode == VariableMode::kVar &&
initialization_flag == kNeedsInitialization));
DCHECK_IMPLIES(is_static_flag == IsStaticFlag::kStatic,
IsConstVariableMode(mode));
}
explicit Variable(Variable* other);
......@@ -59,6 +63,14 @@ class Variable final : public ZoneObject {
void set_mode(VariableMode mode) {
bit_field_ = VariableModeField::update(bit_field_, mode);
}
void set_is_static_flag(IsStaticFlag is_static_flag) {
bit_field_ = IsStaticFlagField::update(bit_field_, is_static_flag);
}
IsStaticFlag is_static_flag() const {
return IsStaticFlagField::decode(bit_field_);
}
bool is_static() const { return is_static_flag() == IsStaticFlag::kStatic; }
bool has_forced_context_allocation() const {
return ForceContextAllocationField::decode(bit_field_);
}
......@@ -249,6 +261,7 @@ class Variable final : public ZoneObject {
using ForceHoleInitializationField = InitializationFlagField::Next<bool, 1>;
using MaybeAssignedFlagField =
ForceHoleInitializationField::Next<MaybeAssignedFlag, 1>;
using IsStaticFlagField = MaybeAssignedFlagField::Next<IsStaticFlag, 1>;
Variable** next() { return &next_; }
friend List;
......
......@@ -1216,6 +1216,10 @@ enum VariableLocation : uint8_t {
// immediately initialized upon creation (kCreatedInitialized).
enum InitializationFlag : uint8_t { kNeedsInitialization, kCreatedInitialized };
// Static variables can only be used with the class in the closest
// class scope as receivers.
enum class IsStaticFlag : uint8_t { kNotStatic, kStatic };
enum MaybeAssignedFlag : uint8_t { kNotAssigned, kMaybeAssigned };
enum class InterpreterPushArgsMode : unsigned {
......
......@@ -93,8 +93,10 @@ bool FrameInspector::ParameterIsShadowedByContextLocal(
VariableMode mode;
InitializationFlag init_flag;
MaybeAssignedFlag maybe_assigned_flag;
IsStaticFlag is_static_flag;
return ScopeInfo::ContextSlotIndex(*info, *parameter_name, &mode, &init_flag,
&maybe_assigned_flag) != -1;
&maybe_assigned_flag,
&is_static_flag) != -1;
}
RedirectActiveFunctions::RedirectActiveFunctions(SharedFunctionInfo shared,
......
......@@ -1006,9 +1006,10 @@ bool ScopeIterator::SetContextVariableValue(Handle<String> variable_name,
VariableMode mode;
InitializationFlag flag;
MaybeAssignedFlag maybe_assigned_flag;
IsStaticFlag is_static_flag;
int slot_index =
ScopeInfo::ContextSlotIndex(context_->scope_info(), *variable_name, &mode,
&flag, &maybe_assigned_flag);
&flag, &maybe_assigned_flag, &is_static_flag);
if (slot_index < 0) return false;
context_->set(slot_index, *new_value);
......
......@@ -97,9 +97,10 @@ v8::MaybeLocal<v8::Value> DebugStackTraceIterator::GetReceiver() const {
VariableMode mode;
InitializationFlag flag;
MaybeAssignedFlag maybe_assigned_flag;
IsStaticFlag is_static_flag;
int slot_index = ScopeInfo::ContextSlotIndex(
context->scope_info(), ReadOnlyRoots(isolate_->heap()).this_string(),
&mode, &flag, &maybe_assigned_flag);
&mode, &flag, &maybe_assigned_flag, &is_static_flag);
if (slot_index < 0) return v8::MaybeLocal<v8::Value>();
Handle<Object> value = handle(context->get(slot_index), isolate_);
if (value->IsTheHole(isolate_)) return v8::MaybeLocal<v8::Value>();
......
......@@ -39,12 +39,14 @@ Handle<ScriptContextTable> ScriptContextTable::Extend(
bool ScriptContextTable::Lookup(Isolate* isolate, ScriptContextTable table,
String name, LookupResult* result) {
DisallowHeapAllocation no_gc;
// Static variables cannot be in script contexts.
IsStaticFlag is_static_flag;
for (int i = 0; i < table.used(); i++) {
Context context = table.get_context(i);
DCHECK(context.IsScriptContext());
int slot_index = ScopeInfo::ContextSlotIndex(
context.scope_info(), name, &result->mode, &result->init_flag,
&result->maybe_assigned_flag);
&result->maybe_assigned_flag, &is_static_flag);
if (slot_index >= 0) {
result->context_index = i;
......@@ -286,8 +288,10 @@ Handle<Object> Context::Lookup(Handle<Context> context, Handle<String> name,
VariableMode mode;
InitializationFlag flag;
MaybeAssignedFlag maybe_assigned_flag;
int slot_index = ScopeInfo::ContextSlotIndex(scope_info, *name, &mode,
&flag, &maybe_assigned_flag);
IsStaticFlag is_static_flag;
int slot_index =
ScopeInfo::ContextSlotIndex(scope_info, *name, &mode, &flag,
&maybe_assigned_flag, &is_static_flag);
DCHECK(slot_index < 0 || slot_index >= MIN_CONTEXT_SLOTS);
if (slot_index >= 0) {
if (FLAG_trace_contexts) {
......
......@@ -223,7 +223,8 @@ Handle<ScopeInfo> ScopeInfo::Create(Isolate* isolate, Zone* zone, Scope* scope,
VariableModeField::encode(var->mode()) |
InitFlagField::encode(var->initialization_flag()) |
MaybeAssignedFlagField::encode(var->maybe_assigned()) |
ParameterNumberField::encode(ParameterNumberField::kMax);
ParameterNumberField::encode(ParameterNumberField::kMax) |
IsStaticFlagField::encode(var->is_static_flag());
scope_info.set(context_local_base + local_index, *var->name(), mode);
scope_info.set(context_local_info_base + local_index,
Smi::FromInt(info));
......@@ -238,7 +239,8 @@ Handle<ScopeInfo> ScopeInfo::Create(Isolate* isolate, Zone* zone, Scope* scope,
VariableModeField::encode(var->mode()) |
InitFlagField::encode(var->initialization_flag()) |
MaybeAssignedFlagField::encode(var->maybe_assigned()) |
ParameterNumberField::encode(ParameterNumberField::kMax);
ParameterNumberField::encode(ParameterNumberField::kMax) |
IsStaticFlagField::encode(var->is_static_flag());
scope_info.set(module_var_entry + kModuleVariablePropertiesOffset,
Smi::FromInt(properties));
module_var_entry += kModuleVariableEntryLength;
......@@ -276,7 +278,8 @@ Handle<ScopeInfo> ScopeInfo::Create(Isolate* isolate, Zone* zone, Scope* scope,
VariableModeField::encode(var->mode()) |
InitFlagField::encode(var->initialization_flag()) |
MaybeAssignedFlagField::encode(var->maybe_assigned()) |
ParameterNumberField::encode(ParameterNumberField::kMax);
ParameterNumberField::encode(ParameterNumberField::kMax) |
IsStaticFlagField::encode(var->is_static_flag());
scope_info.set(context_local_base + local_index, *var->name(), mode);
scope_info.set(context_local_info_base + local_index,
Smi::FromInt(info));
......@@ -456,7 +459,8 @@ Handle<ScopeInfo> ScopeInfo::CreateForBootstrapping(Isolate* isolate,
VariableModeField::encode(VariableMode::kConst) |
InitFlagField::encode(kCreatedInitialized) |
MaybeAssignedFlagField::encode(kNotAssigned) |
ParameterNumberField::encode(ParameterNumberField::kMax);
ParameterNumberField::encode(ParameterNumberField::kMax) |
IsStaticFlagField::encode(IsStaticFlag::kNotStatic);
scope_info->set(index++, Smi::FromInt(value));
}
......@@ -686,6 +690,14 @@ VariableMode ScopeInfo::ContextLocalMode(int var) const {
return VariableModeField::decode(value);
}
IsStaticFlag ScopeInfo::ContextLocalIsStaticFlag(int var) const {
DCHECK_LE(0, var);
DCHECK_LT(var, ContextLocalCount());
int info_index = ContextLocalInfosIndex() + var;
int value = Smi::ToInt(get(info_index));
return IsStaticFlagField::decode(value);
}
InitializationFlag ScopeInfo::ContextLocalInitFlag(int var) const {
DCHECK_LE(0, var);
DCHECK_LT(var, ContextLocalCount());
......@@ -756,7 +768,8 @@ int ScopeInfo::ModuleIndex(String name, VariableMode* mode,
int ScopeInfo::ContextSlotIndex(ScopeInfo scope_info, String name,
VariableMode* mode,
InitializationFlag* init_flag,
MaybeAssignedFlag* maybe_assigned_flag) {
MaybeAssignedFlag* maybe_assigned_flag,
IsStaticFlag* is_static_flag) {
DisallowHeapAllocation no_gc;
DCHECK(name.IsInternalizedString());
DCHECK_NOT_NULL(mode);
......@@ -771,6 +784,7 @@ int ScopeInfo::ContextSlotIndex(ScopeInfo scope_info, String name,
if (name != scope_info.get(i)) continue;
int var = i - start;
*mode = scope_info.ContextLocalMode(var);
*is_static_flag = scope_info.ContextLocalIsStaticFlag(var);
*init_flag = scope_info.ContextLocalInitFlag(var);
*maybe_assigned_flag = scope_info.ContextLocalMaybeAssignedFlag(var);
int result = Context::MIN_CONTEXT_SLOTS + var;
......
......@@ -121,6 +121,9 @@ class ScopeInfo : public FixedArray {
// Return the mode of the given context local.
VariableMode ContextLocalMode(int var) const;
// Return whether the given context local variable is static.
IsStaticFlag ContextLocalIsStaticFlag(int var) const;
// Return the initialization flag of the given context local.
InitializationFlag ContextLocalInitFlag(int var) const;
......@@ -141,7 +144,8 @@ class ScopeInfo : public FixedArray {
// mode for that variable.
static int ContextSlotIndex(ScopeInfo scope_info, String name,
VariableMode* mode, InitializationFlag* init_flag,
MaybeAssignedFlag* maybe_assigned_flag);
MaybeAssignedFlag* maybe_assigned_flag,
IsStaticFlag* is_static_flag);
// Lookup metadata of a MODULE-allocated variable. Return 0 if there is no
// module variable with the given name (the index value of a MODULE variable
......@@ -316,6 +320,7 @@ class ScopeInfo : public FixedArray {
using InitFlagField = VariableModeField::Next<InitializationFlag, 1>;
using MaybeAssignedFlagField = InitFlagField::Next<MaybeAssignedFlag, 1>;
using ParameterNumberField = MaybeAssignedFlagField::Next<uint32_t, 16>;
using IsStaticFlagField = ParameterNumberField::Next<IsStaticFlag, 1>;
friend class ScopeIterator;
friend std::ostream& operator<<(std::ostream& os,
......
......@@ -4440,7 +4440,9 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseClassLiteral(
}
if (class_info.requires_brand) {
class_scope->DeclareBrandVariable(ast_value_factory(), kNoSourcePosition);
// TODO(joyee): implement static brand checking
class_scope->DeclareBrandVariable(
ast_value_factory(), IsStaticFlag::kNotStatic, kNoSourcePosition);
}
return impl()->RewriteClassLiteral(class_scope, name, &class_info,
......
......@@ -2782,13 +2782,15 @@ Variable* Parser::CreateSyntheticContextVariable(const AstRawString* name) {
Variable* Parser::CreatePrivateNameVariable(ClassScope* scope,
VariableMode mode,
IsStaticFlag is_static_flag,
const AstRawString* name) {
DCHECK_NOT_NULL(name);
int begin = position();
int end = end_position();
bool was_added = false;
DCHECK(IsConstVariableMode(mode));
Variable* var = scope->DeclarePrivateName(name, mode, &was_added);
Variable* var =
scope->DeclarePrivateName(name, mode, is_static_flag, &was_added);
if (!was_added) {
Scanner::Location loc(begin, end);
ReportMessageAt(loc, MessageTemplate::kVarRedeclaration, var->raw_name());
......@@ -2834,8 +2836,10 @@ void Parser::DeclarePrivateClassMember(ClassScope* scope,
}
}
Variable* private_name_var =
CreatePrivateNameVariable(scope, GetVariableMode(kind), property_name);
Variable* private_name_var = CreatePrivateNameVariable(
scope, GetVariableMode(kind),
is_static ? IsStaticFlag::kStatic : IsStaticFlag::kNotStatic,
property_name);
int pos = property->value()->position();
if (pos == kNoSourcePosition) {
pos = property->key()->position();
......
......@@ -300,6 +300,7 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) {
ZonePtrList<const AstRawString>* names);
Variable* CreateSyntheticContextVariable(const AstRawString* synthetic_name);
Variable* CreatePrivateNameVariable(ClassScope* scope, VariableMode mode,
IsStaticFlag is_static_flag,
const AstRawString* name);
FunctionLiteral* CreateInitializerFunction(
const char* name, DeclarationScope* scope,
......
......@@ -1108,9 +1108,10 @@ class PreParser : public ParserBase<PreParser> {
Variable* DeclarePrivateVariableName(const AstRawString* name,
ClassScope* scope, VariableMode mode,
IsStaticFlag is_static_flag,
bool* was_added) {
DCHECK(IsConstVariableMode(mode));
return scope->DeclarePrivateName(name, mode, was_added);
return scope->DeclarePrivateName(name, mode, is_static_flag, was_added);
}
Variable* DeclareVariableName(const AstRawString* name, VariableMode mode,
......@@ -1258,8 +1259,10 @@ class PreParser : public ParserBase<PreParser> {
bool is_static, ClassInfo* class_info) {
bool was_added;
DeclarePrivateVariableName(property_name.string_, scope,
GetVariableMode(kind), &was_added);
DeclarePrivateVariableName(
property_name.string_, scope, GetVariableMode(kind),
is_static ? IsStaticFlag::kStatic : IsStaticFlag::kNotStatic,
&was_added);
if (!was_added) {
Scanner::Location loc(property.position(), property.position() + 1);
ReportMessageAt(loc, MessageTemplate::kVarRedeclaration,
......
#
# Autogenerated by generate-bytecode-expectations.
#
---
wrap: yes
private methods: yes
---
snippet: "
{
class A {
static #a() { return 1; }
}
}
"
frame size: 7
parameter count: 1
bytecode array length: 55
bytecodes: [
/* 30 E> */ B(StackCheck),
B(CreateBlockContext), U8(0),
B(PushContext), R(2),
B(LdaTheHole),
B(Star), R(6),
B(CreateClosure), U8(2), U8(0), U8(2),
B(Star), R(3),
B(LdaConstant), U8(1),
B(Star), R(4),
B(CreateClosure), U8(3), U8(1), U8(2),
B(StaCurrentContextSlot), U8(4),
B(Mov), R(3), R(5),
B(CallRuntime), U16(Runtime::kDefineClass), R(4), U8(3),
B(Star), R(4),
B(Mov), R(5), R(1),
B(LdaConstant), U8(4),
B(Star), R(5),
B(CallRuntime), U16(Runtime::kCreatePrivateNameSymbol), R(5), U8(1),
B(StaCurrentContextSlot), U8(5),
B(PopContext), R(2),
B(Mov), R(1), R(0),
B(LdaUndefined),
/* 84 S> */ B(Return),
]
constant pool: [
SCOPE_INFO_TYPE,
FIXED_ARRAY_TYPE,
SHARED_FUNCTION_INFO_TYPE,
SHARED_FUNCTION_INFO_TYPE,
ONE_BYTE_INTERNALIZED_STRING_TYPE ["A"],
]
handlers: [
]
---
snippet: "
{
class A {
static get #a() { return 1; }
}
}
"
frame size: 8
parameter count: 1
bytecode array length: 65
bytecodes: [
/* 30 E> */ B(StackCheck),
B(CreateBlockContext), U8(0),
B(PushContext), R(2),
B(LdaTheHole),
B(Star), R(6),
B(CreateClosure), U8(2), U8(0), U8(2),
B(Star), R(3),
B(LdaConstant), U8(1),
B(Star), R(4),
B(Mov), R(3), R(5),
B(CallRuntime), U16(Runtime::kDefineClass), R(4), U8(3),
B(Star), R(4),
B(Mov), R(5), R(1),
B(LdaConstant), U8(3),
B(Star), R(5),
B(CallRuntime), U16(Runtime::kCreatePrivateNameSymbol), R(5), U8(1),
B(StaCurrentContextSlot), U8(5),
B(CreateClosure), U8(4), U8(1), U8(2),
B(Star), R(6),
B(LdaNull),
B(Star), R(7),
B(CallRuntime), U16(Runtime::kCreatePrivateAccessors), R(6), U8(2),
B(StaCurrentContextSlot), U8(4),
B(PopContext), R(2),
B(Mov), R(1), R(0),
B(LdaUndefined),
/* 88 S> */ B(Return),
]
constant pool: [
SCOPE_INFO_TYPE,
FIXED_ARRAY_TYPE,
SHARED_FUNCTION_INFO_TYPE,
ONE_BYTE_INTERNALIZED_STRING_TYPE ["A"],
SHARED_FUNCTION_INFO_TYPE,
]
handlers: [
]
---
snippet: "
{
class A {
static set #a(val) { }
}
}
"
frame size: 8
parameter count: 1
bytecode array length: 65
bytecodes: [
/* 30 E> */ B(StackCheck),
B(CreateBlockContext), U8(0),
B(PushContext), R(2),
B(LdaTheHole),
B(Star), R(6),
B(CreateClosure), U8(2), U8(0), U8(2),
B(Star), R(3),
B(LdaConstant), U8(1),
B(Star), R(4),
B(Mov), R(3), R(5),
B(CallRuntime), U16(Runtime::kDefineClass), R(4), U8(3),
B(Star), R(4),
B(Mov), R(5), R(1),
B(LdaConstant), U8(3),
B(Star), R(5),
B(CallRuntime), U16(Runtime::kCreatePrivateNameSymbol), R(5), U8(1),
B(StaCurrentContextSlot), U8(5),
B(LdaNull),
B(Star), R(6),
B(CreateClosure), U8(4), U8(1), U8(2),
B(Star), R(7),
B(CallRuntime), U16(Runtime::kCreatePrivateAccessors), R(6), U8(2),
B(StaCurrentContextSlot), U8(4),
B(PopContext), R(2),
B(Mov), R(1), R(0),
B(LdaUndefined),
/* 81 S> */ B(Return),
]
constant pool: [
SCOPE_INFO_TYPE,
FIXED_ARRAY_TYPE,
SHARED_FUNCTION_INFO_TYPE,
ONE_BYTE_INTERNALIZED_STRING_TYPE ["A"],
SHARED_FUNCTION_INFO_TYPE,
]
handlers: [
]
---
snippet: "
{
class A {
static get #a() { return 1; }
static set #a(val) { }
}
}
"
frame size: 8
parameter count: 1
bytecode array length: 68
bytecodes: [
/* 30 E> */ B(StackCheck),
B(CreateBlockContext), U8(0),
B(PushContext), R(2),
B(LdaTheHole),
B(Star), R(6),
B(CreateClosure), U8(2), U8(0), U8(2),
B(Star), R(3),
B(LdaConstant), U8(1),
B(Star), R(4),
B(Mov), R(3), R(5),
B(CallRuntime), U16(Runtime::kDefineClass), R(4), U8(3),
B(Star), R(4),
B(Mov), R(5), R(1),
B(LdaConstant), U8(3),
B(Star), R(5),
B(CallRuntime), U16(Runtime::kCreatePrivateNameSymbol), R(5), U8(1),
B(StaCurrentContextSlot), U8(5),
B(CreateClosure), U8(4), U8(1), U8(2),
B(Star), R(6),
B(CreateClosure), U8(5), U8(2), U8(2),
B(Star), R(7),
B(CallRuntime), U16(Runtime::kCreatePrivateAccessors), R(6), U8(2),
B(StaCurrentContextSlot), U8(4),
B(PopContext), R(2),
B(Mov), R(1), R(0),
B(LdaUndefined),
/* 115 S> */ B(Return),
]
constant pool: [
SCOPE_INFO_TYPE,
FIXED_ARRAY_TYPE,
SHARED_FUNCTION_INFO_TYPE,
ONE_BYTE_INTERNALIZED_STRING_TYPE ["A"],
SHARED_FUNCTION_INFO_TYPE,
SHARED_FUNCTION_INFO_TYPE,
]
handlers: [
]
---
snippet: "
{
class A {
static #a() { }
#b() { }
}
}
"
frame size: 7
parameter count: 1
bytecode array length: 61
bytecodes: [
/* 30 E> */ B(StackCheck),
B(CreateBlockContext), U8(0),
B(PushContext), R(2),
B(LdaTheHole),
B(Star), R(6),
B(CreateClosure), U8(2), U8(0), U8(2),
B(Star), R(3),
B(LdaConstant), U8(1),
B(Star), R(4),
B(CreateClosure), U8(3), U8(1), U8(2),
B(StaCurrentContextSlot), U8(4),
B(CreateClosure), U8(4), U8(2), U8(2),
B(StaCurrentContextSlot), U8(5),
B(Mov), R(3), R(5),
B(CallRuntime), U16(Runtime::kDefineClass), R(4), U8(3),
B(Star), R(4),
B(Mov), R(5), R(1),
B(LdaConstant), U8(5),
B(Star), R(5),
B(CallRuntime), U16(Runtime::kCreatePrivateNameSymbol), R(5), U8(1),
B(StaCurrentContextSlot), U8(6),
B(PopContext), R(2),
B(Mov), R(1), R(0),
B(LdaUndefined),
/* 87 S> */ B(Return),
]
constant pool: [
SCOPE_INFO_TYPE,
FIXED_ARRAY_TYPE,
SHARED_FUNCTION_INFO_TYPE,
SHARED_FUNCTION_INFO_TYPE,
SHARED_FUNCTION_INFO_TYPE,
ONE_BYTE_INTERNALIZED_STRING_TYPE ["A"],
]
handlers: [
]
......@@ -2884,6 +2884,50 @@ TEST(PrivateAccessorAccess) {
i::FLAG_harmony_private_methods = old_methods_flag;
}
TEST(StaticPrivateMethodDeclaration) {
bool old_methods_flag = i::FLAG_harmony_private_methods;
i::FLAG_harmony_private_methods = true;
InitializedIgnitionHandleScope scope;
BytecodeExpectationsPrinter printer(CcTest::isolate());
const char* snippets[] = {
"{\n"
" class A {\n"
" static #a() { return 1; }\n"
" }\n"
"}\n",
"{\n"
" class A {\n"
" static get #a() { return 1; }\n"
" }\n"
"}\n",
"{\n"
" class A {\n"
" static set #a(val) { }\n"
" }\n"
"}\n",
"{\n"
" class A {\n"
" static get #a() { return 1; }\n"
" static set #a(val) { }\n"
" }\n"
"}\n",
"{\n"
" class A {\n"
" static #a() { }\n"
" #b() { }\n"
" }\n"
"}\n"};
CHECK(CompareTexts(BuildActual(printer, snippets),
LoadGolden("StaticPrivateMethodDeclaration.golden")));
i::FLAG_harmony_private_methods = old_methods_flag;
}
TEST(PrivateAccessorDeclaration) {
bool old_methods_flag = i::FLAG_harmony_private_methods;
i::FLAG_harmony_private_methods = true;
......
......@@ -5877,6 +5877,70 @@ TEST(PrivateMembersWrongAccessNoEarlyErrors) {
private_methods, arraysize(private_methods));
}
TEST(PrivateStaticClassMethodsAndAccessorsNoErrors) {
// clang-format off
// Tests proposed class fields syntax.
const char* context_data[][2] = {{"(class {", "});"},
{"(class extends Base {", "});"},
{"class C {", "}"},
{"class C extends Base {", "}"},
{nullptr, nullptr}};
const char* class_body_data[] = {
"static #a() { }",
"static get #a() { }",
"static set #a(val) { }",
"static get #a() { } static set #a(val) { }",
"static *#a() { }",
"static async #a() { }",
"static async *#a() { }",
nullptr
};
// clang-format on
RunParserSyncTest(context_data, class_body_data, kError);
static const ParserFlag private_methods[] = {kAllowHarmonyPrivateMethods};
RunParserSyncTest(context_data, class_body_data, kSuccess, nullptr, 0,
private_methods, arraysize(private_methods));
}
TEST(PrivateStaticClassMethodsAndAccessorsDuplicateErrors) {
// clang-format off
// Tests proposed class fields syntax.
const char* context_data[][2] = {{"(class {", "});"},
{"(class extends Base {", "});"},
{"class C {", "}"},
{"class C extends Base {", "}"},
{nullptr, nullptr}};
const char* class_body_data[] = {
"static get #a() {} static get #a() {}",
"static get #a() {} static #a() {}",
"static get #a() {} get #a() {}",
"static get #a() {} set #a(val) {}",
"static get #a() {} #a() {}",
"static set #a(val) {} static set #a(val) {}",
"static set #a(val) {} static #a() {}",
"static set #a(val) {} get #a() {}",
"static set #a(val) {} set #a(val) {}",
"static set #a(val) {} #a() {}",
"static #a() {} static #a() {}",
"static #a() {} #a(val) {}",
"static #a() {} set #a(val) {}",
"static #a() {} get #a() {}",
nullptr
};
// clang-format on
RunParserSyncTest(context_data, class_body_data, kError);
static const ParserFlag private_methods[] = {kAllowHarmonyPrivateMethods};
RunParserSyncTest(context_data, class_body_data, kError, nullptr, 0,
private_methods, arraysize(private_methods));
}
TEST(PrivateClassFieldsNoErrors) {
// clang-format off
// Tests proposed class fields syntax.
......@@ -6216,14 +6280,6 @@ TEST(PrivateStaticClassFieldsErrors) {
"#a; static #a",
"static #a; #a",
// TODO(joyee): support static private methods
"static #a() { }",
"static get #a() { }",
"static set #a() { }",
"static *#a() { }",
"static async #a() { }",
"static async *#a() { }",
// ASI
"static #['a'] = 0\n",
"static #['a'] = 0\n b",
......
// Copyright 2019 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Flags: --harmony-private-methods
"use strict";
// Static private methods
{
let store = 1;
class C {
static #a() { return store; }
}
}
// Complementary static private accessors.
{
let store = 1;
class C {
static get #a() { return store; }
static set #a(val) { store = val; }
}
}
// Duplicate static private accessors and methods.
{
assertThrows('class C { static get #a() {} static get #a() {} }', SyntaxError);
assertThrows('class C { static get #a() {} static #a() {} }', SyntaxError);
assertThrows('class C { static get #a() {} get #a() {} }', SyntaxError);
assertThrows('class C { static get #a() {} set #a(val) {} }', SyntaxError);
assertThrows('class C { static get #a() {} #a() {} }', SyntaxError);
assertThrows('class C { static set #a(val) {} static set #a(val) {} }', SyntaxError);
assertThrows('class C { static set #a(val) {} static #a() {} }', SyntaxError);
assertThrows('class C { static set #a(val) {} get #a() {} }', SyntaxError);
assertThrows('class C { static set #a(val) {} set #a(val) {} }', SyntaxError);
assertThrows('class C { static set #a(val) {} #a() {} }', SyntaxError);
assertThrows('class C { static #a() {} static #a() {} }', SyntaxError);
assertThrows('class C { static #a() {} #a(val) {} }', SyntaxError);
assertThrows('class C { static #a() {} set #a(val) {} }', SyntaxError);
assertThrows('class C { static #a() {} get #a() {} }', SyntaxError);
}
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