Revert "[class] implement reparsing of class instance member initializers"
This reverts commit 91f08378bc
.
Reason for revert: It's a fairly big change, and the clusterfuzz
found some bugs. Will reland with the fix after M98 branch point.
Original change's description:
> [class] implement reparsing of class instance member initializers
>
> Previously, since the source code for the synthetic class instance
> member initializer function was recorded as the span from the first
> initializer to the last initializer, there was no way to reparse the
> class and recompile the initializer function. It was working for
> most use cases because the code for the initializer function was
> generated eagarly and it was usually alive as long as the class was
> alive, so the initializer wouldn't normally be lazily parsed. This
> didn't work, however, when the class was snapshotted with
> v8::SnapshotCreator::FunctionCodeHandling::kClear,
> becuase then we needed to recompile the initializer when the class
> was instantiated. This patch implements the reparsing so that
> these classes can work with FunctionCodeHandling::kClear.
>
> This patch refactors ParserBase::ParseClassLiteral() so that we can
> reuse it for both parsing the class body normally and reparsing it
> to collect initializers. When reparsing the synthetic initializer
> function, we rewind the scanner to the beginning of the class, and
> parse the class body to collect the initializers. During the
> reparsing, field initializers are parsed with the full parser while
> methods of the class are pre-parsed.
>
> A few notable changes:
>
> - Extended the source range of the initializer function to cover the
> entire class so that we can rewind the scanner to parse the class
> body to collect initializers (previously, it starts from the first
> field initializer and ends at the last initializer). This resulted
> some expectation changes in the debugger tests, though the
> initializers remain debuggable.
> - A temporary ClassScope is created during reparsing. After the class
> is reparsed, we use the information from the ScopeInfo to update
> the allocated indices of the variables in the ClassScope.
>
> Bug: v8:10704
> Change-Id: Ifb6431a1447d8844f2a548283d59158742fe9027
> Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2988830
> Reviewed-by: Leszek Swirski <leszeks@chromium.org>
> Reviewed-by: Toon Verwaest <verwaest@chromium.org>
> Commit-Queue: Joyee Cheung <joyee@igalia.com>
> Cr-Commit-Position: refs/heads/main@{#78299}
Bug: v8:10704
Change-Id: I039cb728ebf0ada438a8f26c7d2c2547dbe3bf2d
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3325328
Auto-Submit: Joyee Cheung <joyee@igalia.com>
Bot-Commit: Rubber Stamper <rubber-stamper@appspot.gserviceaccount.com>
Reviewed-by: Marja Hölttä <marja@chromium.org>
Reviewed-by: Leszek Swirski <leszeks@chromium.org>
Commit-Queue: Leszek Swirski <leszeks@chromium.org>
Cr-Commit-Position: refs/heads/main@{#78315}
This commit is contained in:
parent
e8ea622d20
commit
f668e9f7ae
@ -521,15 +521,6 @@ template EXPORT_TEMPLATE_DEFINE(V8_EXPORT_PRIVATE)
|
||||
DeclarationScope* script_scope, AstValueFactory* ast_value_factory,
|
||||
DeserializationMode deserialization_mode);
|
||||
|
||||
#ifdef DEBUG
|
||||
bool Scope::IsReparsedMemberInitializerScope() const {
|
||||
return is_declaration_scope() &&
|
||||
IsClassMembersInitializerFunction(
|
||||
AsDeclarationScope()->function_kind()) &&
|
||||
outer_scope()->AsClassScope()->is_reparsed_class_scope();
|
||||
}
|
||||
#endif
|
||||
|
||||
DeclarationScope* Scope::AsDeclarationScope() {
|
||||
DCHECK(is_declaration_scope());
|
||||
return static_cast<DeclarationScope*>(this);
|
||||
@ -673,10 +664,8 @@ bool DeclarationScope::Analyze(ParseInfo* info) {
|
||||
// We are compiling one of four cases:
|
||||
// 1) top-level code,
|
||||
// 2) a function/eval/module on the top-level
|
||||
// 4) a class member initializer function scope
|
||||
// 3) 4 function/eval in a scope that was already resolved.
|
||||
// 3) a function/eval in a scope that was already resolved.
|
||||
DCHECK(scope->is_script_scope() || scope->outer_scope()->is_script_scope() ||
|
||||
scope->IsReparsedMemberInitializerScope() ||
|
||||
scope->outer_scope()->already_resolved_);
|
||||
|
||||
// The outer scope is never lazy.
|
||||
@ -1904,8 +1893,6 @@ void Scope::Print(int n) {
|
||||
if (scope->needs_private_name_context_chain_recalc()) {
|
||||
Indent(n1, "// needs #-name context chain recalc\n");
|
||||
}
|
||||
Indent(n1, "// ");
|
||||
PrintF("%s\n", FunctionKind2String(scope->function_kind()));
|
||||
}
|
||||
if (num_stack_slots_ > 0) {
|
||||
Indent(n1, "// ");
|
||||
@ -2695,55 +2682,6 @@ bool IsComplementaryAccessorPair(VariableMode a, VariableMode b) {
|
||||
}
|
||||
}
|
||||
|
||||
void ClassScope::ReplaceReparsedClassScope(Isolate* isolate,
|
||||
AstValueFactory* ast_value_factory,
|
||||
ClassScope* old_scope) {
|
||||
DCHECK_EQ(outer_scope_, old_scope->outer_scope());
|
||||
Scope* outer = outer_scope_;
|
||||
|
||||
outer->RemoveInnerScope(old_scope);
|
||||
// The outer scope should only have this deserialized inner scope,
|
||||
// otherwise we have to update the sibling scopes.
|
||||
DCHECK_EQ(outer->inner_scope_, this);
|
||||
DCHECK_NULL(sibling_);
|
||||
|
||||
DCHECK_NULL(old_scope->inner_scope_);
|
||||
|
||||
Handle<ScopeInfo> scope_info = old_scope->scope_info_;
|
||||
DCHECK(!scope_info.is_null());
|
||||
DCHECK(!scope_info->IsEmpty());
|
||||
|
||||
// Restore variable allocation results for context-allocated variables in
|
||||
// the class scope from ScopeInfo, so that we don't need to run
|
||||
// resolution and allocation on these variables again when generating
|
||||
// code for the initializer function.
|
||||
int context_local_count = scope_info->ContextLocalCount();
|
||||
int context_header_length = scope_info->ContextHeaderLength();
|
||||
DisallowGarbageCollection no_gc;
|
||||
for (int i = 0; i < context_local_count; ++i) {
|
||||
int slot_index = context_header_length + i;
|
||||
DCHECK_LT(slot_index, scope_info->ContextLength());
|
||||
|
||||
String name = scope_info->ContextLocalName(i);
|
||||
const AstRawString* string = ast_value_factory->GetString(
|
||||
name, SharedStringAccessGuardIfNeeded(isolate));
|
||||
Variable* var = nullptr;
|
||||
|
||||
var = string->IsPrivateName() ? LookupLocalPrivateName(string)
|
||||
: LookupLocal(string);
|
||||
DCHECK_NOT_NULL(var);
|
||||
var->AllocateTo(VariableLocation::CONTEXT, slot_index);
|
||||
}
|
||||
|
||||
scope_info_ = scope_info;
|
||||
|
||||
// Set this bit so that DelcarationScope::Analyze recognizes
|
||||
// the reparsed instance member initializer scope.
|
||||
#ifdef DEBUG
|
||||
is_reparsed_class_scope_ = true;
|
||||
#endif
|
||||
}
|
||||
|
||||
Variable* ClassScope::DeclarePrivateName(const AstRawString* name,
|
||||
VariableMode mode,
|
||||
IsStaticFlag is_static_flag,
|
||||
|
@ -424,9 +424,6 @@ class V8_EXPORT_PRIVATE Scope : public NON_EXPORTED_BASE(ZoneObject) {
|
||||
return num_heap_slots() > 0;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
bool IsReparsedMemberInitializerScope() const;
|
||||
#endif
|
||||
// Use Scope::ForEach for depth first traversal of scopes.
|
||||
// Before:
|
||||
// void Scope::VisitRecursively() {
|
||||
@ -1477,13 +1474,6 @@ class V8_EXPORT_PRIVATE ClassScope : public Scope {
|
||||
should_save_class_variable_index_ = true;
|
||||
}
|
||||
|
||||
void ReplaceReparsedClassScope(Isolate* isolate,
|
||||
AstValueFactory* ast_value_factory,
|
||||
ClassScope* old_scope);
|
||||
#ifdef DEBUG
|
||||
bool is_reparsed_class_scope() const { return is_reparsed_class_scope_; }
|
||||
#endif
|
||||
|
||||
private:
|
||||
friend class Scope;
|
||||
friend class PrivateNameScopeIterator;
|
||||
@ -1529,9 +1519,6 @@ class V8_EXPORT_PRIVATE ClassScope : public Scope {
|
||||
// This is only maintained during reparsing, restored from the
|
||||
// preparsed data.
|
||||
bool should_save_class_variable_index_ = false;
|
||||
#ifdef DEBUG
|
||||
bool is_reparsed_class_scope_ = false;
|
||||
#endif
|
||||
};
|
||||
|
||||
// Iterate over the private name scope chain. The iteration proceeds from the
|
||||
|
@ -196,7 +196,7 @@
|
||||
V(_, dot_home_object_string, ".home_object") \
|
||||
V(_, dot_result_string, ".result") \
|
||||
V(_, dot_repl_result_string, ".repl_result") \
|
||||
V(_, dot_static_home_object_string, ".static_home_object") \
|
||||
V(_, dot_static_home_object_string, "._static_home_object") \
|
||||
V(_, dot_string, ".") \
|
||||
V(_, dot_switch_tag_string, ".switch_tag") \
|
||||
V(_, dotAll_string, "dotAll") \
|
||||
|
@ -2813,7 +2813,6 @@ void BytecodeGenerator::BuildClassProperty(ClassLiteral::Property* property) {
|
||||
// Private methods are not initialized in BuildClassProperty.
|
||||
DCHECK_IMPLIES(property->is_private(),
|
||||
property->kind() == ClassLiteral::Property::FIELD);
|
||||
builder()->SetExpressionPosition(property->key());
|
||||
|
||||
bool is_literal_store = property->key()->IsPropertyName() &&
|
||||
!property->is_computed_name() &&
|
||||
|
@ -1238,10 +1238,6 @@ class ParserBase {
|
||||
Scanner::Location class_name_location,
|
||||
bool name_is_strict_reserved,
|
||||
int class_token_pos);
|
||||
ExpressionT DoParseClassLiteral(ClassScope* class_scope, IdentifierT name,
|
||||
Scanner::Location class_name_location,
|
||||
bool is_anonymous, int class_token_pos);
|
||||
|
||||
ExpressionT ParseTemplateLiteral(ExpressionT tag, int start, bool tagged);
|
||||
ExpressionT ParseSuperExpression();
|
||||
ExpressionT ParseImportExpressions();
|
||||
@ -2526,6 +2522,8 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseMemberInitializer(
|
||||
|
||||
if (initializer_scope == nullptr) {
|
||||
initializer_scope = NewFunctionScope(function_kind);
|
||||
// TODO(gsathya): Make scopes be non contiguous.
|
||||
initializer_scope->set_start_position(beg_pos);
|
||||
initializer_scope->SetLanguageMode(LanguageMode::kStrict);
|
||||
}
|
||||
|
||||
@ -2540,13 +2538,8 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseMemberInitializer(
|
||||
initializer = factory()->NewUndefinedLiteral(kNoSourcePosition);
|
||||
}
|
||||
|
||||
initializer_scope->set_end_position(end_position());
|
||||
if (is_static) {
|
||||
// For the instance initializer, we will save the positions
|
||||
// later with the positions of the class body so that we can reparse
|
||||
// it later.
|
||||
// TODO(joyee): Make scopes be non contiguous.
|
||||
initializer_scope->set_start_position(beg_pos);
|
||||
initializer_scope->set_end_position(end_position());
|
||||
class_info->static_elements_scope = initializer_scope;
|
||||
class_info->has_static_elements = true;
|
||||
} else {
|
||||
@ -4688,15 +4681,6 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseClassLiteral(
|
||||
}
|
||||
|
||||
ClassScope* class_scope = NewClassScope(scope(), is_anonymous);
|
||||
return DoParseClassLiteral(class_scope, name, class_name_location,
|
||||
is_anonymous, class_token_pos);
|
||||
}
|
||||
|
||||
template <typename Impl>
|
||||
typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::DoParseClassLiteral(
|
||||
ClassScope* class_scope, IdentifierT name,
|
||||
Scanner::Location class_name_location, bool is_anonymous,
|
||||
int class_token_pos) {
|
||||
BlockState block_state(&scope_, class_scope);
|
||||
RaiseLanguageMode(LanguageMode::kStrict);
|
||||
|
||||
@ -4783,12 +4767,6 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::DoParseClassLiteral(
|
||||
Expect(Token::RBRACE);
|
||||
int end_pos = end_position();
|
||||
class_scope->set_end_position(end_pos);
|
||||
if (class_info.instance_members_scope != nullptr) {
|
||||
// Use the positions of the class body for the instance initializer
|
||||
// function so that we can reparse it later.
|
||||
class_info.instance_members_scope->set_start_position(class_token_pos);
|
||||
class_info.instance_members_scope->set_end_position(end_pos);
|
||||
}
|
||||
|
||||
VariableProxy* unresolvable = class_scope->ResolvePrivateNamesPartially();
|
||||
if (unresolvable != nullptr) {
|
||||
|
@ -863,13 +863,11 @@ void Parser::ParseFunction(Isolate* isolate, ParseInfo* info,
|
||||
// function is in heritage position. Otherwise the function scope's skip bit
|
||||
// will be correctly inherited from the outer scope.
|
||||
ClassScope::HeritageParsingScope heritage(original_scope_->AsClassScope());
|
||||
result = DoParseDeserializedFunction(
|
||||
isolate, shared_info, info, start_position, end_position,
|
||||
function_literal_id, info->function_name());
|
||||
result = DoParseFunction(isolate, info, start_position, end_position,
|
||||
function_literal_id, info->function_name());
|
||||
} else {
|
||||
result = DoParseDeserializedFunction(
|
||||
isolate, shared_info, info, start_position, end_position,
|
||||
function_literal_id, info->function_name());
|
||||
result = DoParseFunction(isolate, info, start_position, end_position,
|
||||
function_literal_id, info->function_name());
|
||||
}
|
||||
MaybeProcessSourceRanges(info, result, stack_limit_);
|
||||
if (result != nullptr) {
|
||||
@ -1032,103 +1030,6 @@ FunctionLiteral* Parser::DoParseFunction(Isolate* isolate, ParseInfo* info,
|
||||
return result;
|
||||
}
|
||||
|
||||
FunctionLiteral* Parser::DoParseDeserializedFunction(
|
||||
Isolate* isolate, Handle<SharedFunctionInfo> shared_info, ParseInfo* info,
|
||||
int start_position, int end_position, int function_literal_id,
|
||||
const AstRawString* raw_name) {
|
||||
if (flags().function_kind() !=
|
||||
FunctionKind::kClassMembersInitializerFunction) {
|
||||
return DoParseFunction(isolate, info, start_position, end_position,
|
||||
function_literal_id, raw_name);
|
||||
}
|
||||
|
||||
// Reparse the outer class while skipping the non-fields to get a list of
|
||||
// ClassLiteralProperty and create a InitializeClassMembersStatement for
|
||||
// the synthetic instance initializer function.
|
||||
FunctionLiteral* result = ParseClassForInstanceMemberInitialization(
|
||||
isolate, original_scope_->AsClassScope(), start_position,
|
||||
function_literal_id);
|
||||
DCHECK_EQ(result->kind(), FunctionKind::kClassMembersInitializerFunction);
|
||||
DCHECK_EQ(result->function_literal_id(), function_literal_id);
|
||||
DCHECK_EQ(result->end_position(), shared_info->EndPosition());
|
||||
|
||||
// The private_name_lookup_skips_outer_class bit should be set by
|
||||
// PostProcessParseResult() during scope analysis later.
|
||||
return result;
|
||||
}
|
||||
|
||||
FunctionLiteral* Parser::ParseClassForInstanceMemberInitialization(
|
||||
Isolate* isolate, ClassScope* original_scope, int initializer_pos,
|
||||
int initializer_id) {
|
||||
int class_token_pos = initializer_pos;
|
||||
|
||||
// Insert a FunctionState with the closest outer Declaration scope
|
||||
DeclarationScope* nearest_decl_scope = original_scope->GetDeclarationScope();
|
||||
DCHECK_NOT_NULL(nearest_decl_scope);
|
||||
FunctionState function_state(&function_state_, &scope_, nearest_decl_scope);
|
||||
// We will reindex the function literals later.
|
||||
ResetFunctionLiteralId();
|
||||
|
||||
// We preparse the class members that are not fields with initializers
|
||||
// in order to collect the function literal ids.
|
||||
ParsingModeScope mode(this, PARSE_LAZILY);
|
||||
|
||||
ExpressionParsingScope no_expression_scope(impl());
|
||||
|
||||
// We will reparse the entire class because we want to know if
|
||||
// the class is anonymous.
|
||||
// When the function is a kClassMembersInitializerFunction, we record the
|
||||
// source range of the entire class as its positions in its SFI, so at this
|
||||
// point the scanner should be rewound to the position of the class token.
|
||||
DCHECK_EQ(peek(), Token::CLASS);
|
||||
Expect(Token::CLASS);
|
||||
|
||||
const AstRawString* class_name = NullIdentifier();
|
||||
const AstRawString* variable_name = NullIdentifier();
|
||||
// It's a reparse so we don't need to check for default export or
|
||||
// whether the names are reserved.
|
||||
if (peek() == Token::EXTENDS || peek() == Token::LBRACE) {
|
||||
GetDefaultStrings(&class_name, &variable_name);
|
||||
} else {
|
||||
class_name = ParseIdentifier();
|
||||
variable_name = class_name;
|
||||
}
|
||||
bool is_anonymous = class_name == nullptr || class_name->IsEmpty();
|
||||
|
||||
// Create a new ClassScope for the parser to create the inner scopes,
|
||||
// the variable resolution would be done in the original scope, however.
|
||||
// TODO(joyee): see if we can reset the original scope to a state that
|
||||
// can be reused directly and avoid creating this temporary scope.
|
||||
ClassScope* reparsed_scope =
|
||||
NewClassScope(original_scope->outer_scope(), is_anonymous);
|
||||
|
||||
#ifdef DEBUG
|
||||
original_scope->SetScopeName(class_name);
|
||||
#endif
|
||||
|
||||
Expression* expr =
|
||||
DoParseClassLiteral(reparsed_scope, class_name, scanner()->location(),
|
||||
is_anonymous, class_token_pos);
|
||||
DCHECK(expr->IsClassLiteral());
|
||||
ClassLiteral* literal = expr->AsClassLiteral();
|
||||
FunctionLiteral* initializer =
|
||||
literal->instance_members_initializer_function();
|
||||
|
||||
// Reindex so that the function literal ids match.
|
||||
AstFunctionLiteralIdReindexer reindexer(
|
||||
stack_limit_, initializer_id - initializer->function_literal_id());
|
||||
reindexer.Reindex(expr);
|
||||
|
||||
no_expression_scope.ValidateExpression();
|
||||
|
||||
// Fix up the scope chain and the references used by the instance member
|
||||
// initializer.
|
||||
reparsed_scope->ReplaceReparsedClassScope(isolate, ast_value_factory(),
|
||||
original_scope);
|
||||
original_scope_ = reparsed_scope;
|
||||
return initializer;
|
||||
}
|
||||
|
||||
Statement* Parser::ParseModuleItem() {
|
||||
// ecma262/#prod-ModuleItem
|
||||
// ModuleItem :
|
||||
@ -3221,9 +3122,7 @@ FunctionLiteral* Parser::CreateInitializerFunction(
|
||||
FunctionSyntaxKind::kAccessorOrMethod,
|
||||
FunctionLiteral::kShouldEagerCompile, scope->start_position(), false,
|
||||
GetNextFunctionLiteralId());
|
||||
#ifdef DEBUG
|
||||
scope->SetScopeName(ast_value_factory()->GetOneByteString(name));
|
||||
#endif
|
||||
|
||||
RecordFunctionLiteralSourceRange(result);
|
||||
|
||||
return result;
|
||||
|
@ -237,15 +237,6 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) {
|
||||
int function_literal_id,
|
||||
const AstRawString* raw_name);
|
||||
|
||||
FunctionLiteral* DoParseDeserializedFunction(
|
||||
Isolate* isolate, Handle<SharedFunctionInfo> shared_info, ParseInfo* info,
|
||||
int start_position, int end_position, int function_literal_id,
|
||||
const AstRawString* raw_name);
|
||||
|
||||
FunctionLiteral* ParseClassForInstanceMemberInitialization(
|
||||
Isolate* isolate, ClassScope* scope, int initializer_pos,
|
||||
int initializer_id);
|
||||
|
||||
// Called by ParseProgram after setting up the scanner.
|
||||
FunctionLiteral* DoParseProgram(Isolate* isolate, ParseInfo* info);
|
||||
|
||||
|
@ -4156,583 +4156,6 @@ UNINITIALIZED_TEST(ReinitializeHashSeedRehashable) {
|
||||
FreeCurrentEmbeddedBlob();
|
||||
}
|
||||
|
||||
UNINITIALIZED_TEST(ClassFields) {
|
||||
DisableAlwaysOpt();
|
||||
i::FLAG_rehash_snapshot = true;
|
||||
i::FLAG_hash_seed = 42;
|
||||
i::FLAG_allow_natives_syntax = true;
|
||||
DisableEmbeddedBlobRefcounting();
|
||||
v8::StartupData blob;
|
||||
{
|
||||
v8::SnapshotCreator creator;
|
||||
v8::Isolate* isolate = creator.GetIsolate();
|
||||
{
|
||||
v8::HandleScope handle_scope(isolate);
|
||||
v8::Local<v8::Context> context = v8::Context::New(isolate);
|
||||
v8::Context::Scope context_scope(context);
|
||||
CompileRun(
|
||||
"class ClassWithFieldInitializer {"
|
||||
" #field = 1;"
|
||||
" constructor(val) {"
|
||||
" this.#field = val;"
|
||||
" }"
|
||||
" get field() {"
|
||||
" return this.#field;"
|
||||
" }"
|
||||
"}"
|
||||
"class ClassWithDefaultConstructor {"
|
||||
" #field = 42;"
|
||||
" get field() {"
|
||||
" return this.#field;"
|
||||
" }"
|
||||
"}"
|
||||
"class ClassWithFieldDeclaration {"
|
||||
" #field;"
|
||||
" constructor(val) {"
|
||||
" this.#field = val;"
|
||||
" }"
|
||||
" get field() {"
|
||||
" return this.#field;"
|
||||
" }"
|
||||
"}"
|
||||
"class ClassWithPublicField {"
|
||||
" field = 1;"
|
||||
" constructor(val) {"
|
||||
" this.field = val;"
|
||||
" }"
|
||||
"}"
|
||||
"class ClassWithFunctionField {"
|
||||
" field = 123;"
|
||||
" func = () => { return this.field; }"
|
||||
"}"
|
||||
"class ClassWithThisInInitializer {"
|
||||
" #field = 123;"
|
||||
" field = this.#field;"
|
||||
"}");
|
||||
creator.SetDefaultContext(context);
|
||||
}
|
||||
blob =
|
||||
creator.CreateBlob(v8::SnapshotCreator::FunctionCodeHandling::kClear);
|
||||
}
|
||||
|
||||
v8::Isolate::CreateParams create_params;
|
||||
create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
|
||||
create_params.snapshot_blob = &blob;
|
||||
v8::Isolate* isolate = v8::Isolate::New(create_params);
|
||||
{
|
||||
v8::Isolate::Scope isolate_scope(isolate);
|
||||
v8::HandleScope handle_scope(isolate);
|
||||
v8::Local<v8::Context> context = v8::Context::New(isolate);
|
||||
CHECK(!context.IsEmpty());
|
||||
v8::Context::Scope context_scope(context);
|
||||
ExpectInt32("(new ClassWithFieldInitializer(123)).field", 123);
|
||||
ExpectInt32("(new ClassWithDefaultConstructor()).field", 42);
|
||||
ExpectInt32("(new ClassWithFieldDeclaration(123)).field", 123);
|
||||
ExpectInt32("(new ClassWithPublicField(123)).field", 123);
|
||||
ExpectInt32("(new ClassWithFunctionField()).func()", 123);
|
||||
ExpectInt32("(new ClassWithThisInInitializer()).field", 123);
|
||||
}
|
||||
isolate->Dispose();
|
||||
delete[] blob.data;
|
||||
FreeCurrentEmbeddedBlob();
|
||||
}
|
||||
|
||||
UNINITIALIZED_TEST(ClassFieldsReferencePrivateInInitializer) {
|
||||
DisableAlwaysOpt();
|
||||
i::FLAG_rehash_snapshot = true;
|
||||
i::FLAG_hash_seed = 42;
|
||||
i::FLAG_allow_natives_syntax = true;
|
||||
DisableEmbeddedBlobRefcounting();
|
||||
v8::StartupData blob;
|
||||
{
|
||||
v8::SnapshotCreator creator;
|
||||
v8::Isolate* isolate = creator.GetIsolate();
|
||||
{
|
||||
v8::HandleScope handle_scope(isolate);
|
||||
v8::Local<v8::Context> context = v8::Context::New(isolate);
|
||||
v8::Context::Scope context_scope(context);
|
||||
CompileRun(
|
||||
"class A {"
|
||||
" #a = 42;"
|
||||
" a = this.#a;"
|
||||
"}"
|
||||
"let str;"
|
||||
"class ClassWithEval {"
|
||||
" field = eval(str);"
|
||||
"}"
|
||||
"class ClassWithPrivateAndEval {"
|
||||
" #field = 42;"
|
||||
" field = eval(str);"
|
||||
"}");
|
||||
creator.SetDefaultContext(context);
|
||||
}
|
||||
blob =
|
||||
creator.CreateBlob(v8::SnapshotCreator::FunctionCodeHandling::kClear);
|
||||
}
|
||||
|
||||
v8::Isolate::CreateParams create_params;
|
||||
create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
|
||||
create_params.snapshot_blob = &blob;
|
||||
v8::Isolate* isolate = v8::Isolate::New(create_params);
|
||||
{
|
||||
v8::Isolate::Scope isolate_scope(isolate);
|
||||
v8::HandleScope handle_scope(isolate);
|
||||
v8::Local<v8::Context> context = v8::Context::New(isolate);
|
||||
CHECK(!context.IsEmpty());
|
||||
v8::Context::Scope context_scope(context);
|
||||
ExpectInt32("(new A()).a", 42);
|
||||
v8::TryCatch try_catch(isolate);
|
||||
CompileRun("str = 'this.#nonexistent'; (new ClassWithEval()).field");
|
||||
CHECK(try_catch.HasCaught());
|
||||
ExpectInt32("str = 'this.#field'; (new ClassWithPrivateAndEval()).field",
|
||||
42);
|
||||
}
|
||||
isolate->Dispose();
|
||||
delete[] blob.data;
|
||||
FreeCurrentEmbeddedBlob();
|
||||
}
|
||||
|
||||
UNINITIALIZED_TEST(ClassFieldsReferenceClassVariable) {
|
||||
DisableAlwaysOpt();
|
||||
i::FLAG_rehash_snapshot = true;
|
||||
i::FLAG_hash_seed = 42;
|
||||
i::FLAG_allow_natives_syntax = true;
|
||||
DisableEmbeddedBlobRefcounting();
|
||||
v8::StartupData blob;
|
||||
{
|
||||
v8::SnapshotCreator creator;
|
||||
v8::Isolate* isolate = creator.GetIsolate();
|
||||
{
|
||||
v8::HandleScope handle_scope(isolate);
|
||||
v8::Local<v8::Context> context = v8::Context::New(isolate);
|
||||
v8::Context::Scope context_scope(context);
|
||||
CompileRun(
|
||||
"class Klass {"
|
||||
" #consturctor = Klass;"
|
||||
" func() {"
|
||||
" return this.#consturctor;"
|
||||
" }"
|
||||
"}");
|
||||
creator.SetDefaultContext(context);
|
||||
}
|
||||
blob =
|
||||
creator.CreateBlob(v8::SnapshotCreator::FunctionCodeHandling::kClear);
|
||||
}
|
||||
|
||||
v8::Isolate::CreateParams create_params;
|
||||
create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
|
||||
create_params.snapshot_blob = &blob;
|
||||
v8::Isolate* isolate = v8::Isolate::New(create_params);
|
||||
{
|
||||
v8::Isolate::Scope isolate_scope(isolate);
|
||||
v8::HandleScope handle_scope(isolate);
|
||||
v8::Local<v8::Context> context = v8::Context::New(isolate);
|
||||
CHECK(!context.IsEmpty());
|
||||
v8::Context::Scope context_scope(context);
|
||||
ExpectTrue("new Klass().func() === Klass");
|
||||
}
|
||||
isolate->Dispose();
|
||||
delete[] blob.data;
|
||||
FreeCurrentEmbeddedBlob();
|
||||
}
|
||||
|
||||
UNINITIALIZED_TEST(ClassFieldsNested) {
|
||||
DisableAlwaysOpt();
|
||||
i::FLAG_rehash_snapshot = true;
|
||||
i::FLAG_hash_seed = 42;
|
||||
i::FLAG_allow_natives_syntax = true;
|
||||
DisableEmbeddedBlobRefcounting();
|
||||
v8::StartupData blob;
|
||||
{
|
||||
v8::SnapshotCreator creator;
|
||||
v8::Isolate* isolate = creator.GetIsolate();
|
||||
{
|
||||
v8::HandleScope handle_scope(isolate);
|
||||
v8::Local<v8::Context> context = v8::Context::New(isolate);
|
||||
v8::Context::Scope context_scope(context);
|
||||
CompileRun(
|
||||
"class Outer {"
|
||||
" #odata = 42;"
|
||||
" #inner;"
|
||||
" static getInner() {"
|
||||
" class Inner {"
|
||||
" #idata = 42;"
|
||||
" #outer;"
|
||||
" constructor(outer) {"
|
||||
" this.#outer = outer;"
|
||||
" outer.#inner = this;"
|
||||
" }"
|
||||
" check() {"
|
||||
" return this.#idata === this.#outer.#odata &&"
|
||||
" this === this.#outer.#inner;"
|
||||
" }"
|
||||
" }"
|
||||
" return Inner;"
|
||||
" }"
|
||||
" check() {"
|
||||
" return this.#inner.check();"
|
||||
" }"
|
||||
"}"
|
||||
"const Inner = Outer.getInner();");
|
||||
creator.SetDefaultContext(context);
|
||||
}
|
||||
blob =
|
||||
creator.CreateBlob(v8::SnapshotCreator::FunctionCodeHandling::kClear);
|
||||
}
|
||||
|
||||
v8::Isolate::CreateParams create_params;
|
||||
create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
|
||||
create_params.snapshot_blob = &blob;
|
||||
v8::Isolate* isolate = v8::Isolate::New(create_params);
|
||||
{
|
||||
v8::Isolate::Scope isolate_scope(isolate);
|
||||
v8::HandleScope handle_scope(isolate);
|
||||
v8::Local<v8::Context> context = v8::Context::New(isolate);
|
||||
CHECK(!context.IsEmpty());
|
||||
v8::Context::Scope context_scope(context);
|
||||
ExpectTrue("(new Inner(new Outer)).check()");
|
||||
}
|
||||
isolate->Dispose();
|
||||
delete[] blob.data;
|
||||
FreeCurrentEmbeddedBlob();
|
||||
}
|
||||
|
||||
UNINITIALIZED_TEST(ClassPrivateMethods) {
|
||||
DisableAlwaysOpt();
|
||||
i::FLAG_rehash_snapshot = true;
|
||||
i::FLAG_hash_seed = 42;
|
||||
i::FLAG_allow_natives_syntax = true;
|
||||
DisableEmbeddedBlobRefcounting();
|
||||
v8::StartupData blob;
|
||||
{
|
||||
v8::SnapshotCreator creator;
|
||||
v8::Isolate* isolate = creator.GetIsolate();
|
||||
{
|
||||
v8::HandleScope handle_scope(isolate);
|
||||
v8::Local<v8::Context> context = v8::Context::New(isolate);
|
||||
v8::Context::Scope context_scope(context);
|
||||
CompileRun(
|
||||
"class JustPrivateMethods {"
|
||||
" #method() { return this.val; }"
|
||||
" get #accessor() { return this.val; };"
|
||||
" set #accessor(val) { this.val = val; }"
|
||||
" method() { return this.#method(); } "
|
||||
" getter() { return this.#accessor; } "
|
||||
" setter(val) { this.#accessor = val } "
|
||||
"}"
|
||||
"class PrivateMethodsAndFields {"
|
||||
" #val = 1;"
|
||||
" #method() { return this.#val; }"
|
||||
" get #accessor() { return this.#val; };"
|
||||
" set #accessor(val) { this.#val = val; }"
|
||||
" method() { return this.#method(); } "
|
||||
" getter() { return this.#accessor; } "
|
||||
" setter(val) { this.#accessor = val } "
|
||||
"}"
|
||||
"class Nested {"
|
||||
" #val = 42;"
|
||||
" static #method(obj) { return obj.#val; }"
|
||||
" getInner() {"
|
||||
" class Inner {"
|
||||
" runEval(obj, str) {"
|
||||
" return eval(str);"
|
||||
" }"
|
||||
" }"
|
||||
" return Inner;"
|
||||
" }"
|
||||
"}");
|
||||
creator.SetDefaultContext(context);
|
||||
}
|
||||
blob =
|
||||
creator.CreateBlob(v8::SnapshotCreator::FunctionCodeHandling::kClear);
|
||||
}
|
||||
|
||||
v8::Isolate::CreateParams create_params;
|
||||
create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
|
||||
create_params.snapshot_blob = &blob;
|
||||
v8::Isolate* isolate = v8::Isolate::New(create_params);
|
||||
{
|
||||
v8::Isolate::Scope isolate_scope(isolate);
|
||||
v8::HandleScope handle_scope(isolate);
|
||||
v8::Local<v8::Context> context = v8::Context::New(isolate);
|
||||
CHECK(!context.IsEmpty());
|
||||
v8::Context::Scope context_scope(context);
|
||||
CompileRun("const a = new JustPrivateMethods(); a.setter(42);");
|
||||
ExpectInt32("a.method()", 42);
|
||||
ExpectInt32("a.getter()", 42);
|
||||
CompileRun("const b = new PrivateMethodsAndFields(); b.setter(42);");
|
||||
ExpectInt32("b.method()", 42);
|
||||
ExpectInt32("b.getter()", 42);
|
||||
CompileRun("const c = new (new Nested().getInner());");
|
||||
ExpectInt32("c.runEval(new Nested(), 'Nested.#method(obj)')", 42);
|
||||
}
|
||||
isolate->Dispose();
|
||||
delete[] blob.data;
|
||||
FreeCurrentEmbeddedBlob();
|
||||
}
|
||||
|
||||
UNINITIALIZED_TEST(ClassFieldsWithInheritance) {
|
||||
DisableAlwaysOpt();
|
||||
i::FLAG_rehash_snapshot = true;
|
||||
i::FLAG_hash_seed = 42;
|
||||
i::FLAG_allow_natives_syntax = true;
|
||||
DisableEmbeddedBlobRefcounting();
|
||||
v8::StartupData blob;
|
||||
{
|
||||
v8::SnapshotCreator creator;
|
||||
v8::Isolate* isolate = creator.GetIsolate();
|
||||
{
|
||||
v8::HandleScope handle_scope(isolate);
|
||||
v8::Local<v8::Context> context = v8::Context::New(isolate);
|
||||
v8::Context::Scope context_scope(context);
|
||||
CompileRun(
|
||||
"class Base {"
|
||||
" #a = 'test';"
|
||||
" getA() { return this.#a; }"
|
||||
"}"
|
||||
"class Derived extends Base {"
|
||||
" #b = 1;"
|
||||
" constructor() {"
|
||||
" super();"
|
||||
" this.#b = this.getA();"
|
||||
" }"
|
||||
" check() {"
|
||||
" return this.#b === this.getA();"
|
||||
" }"
|
||||
"}"
|
||||
"class DerivedDefaultConstructor extends Base {"
|
||||
" #b = 1;"
|
||||
" check() {"
|
||||
" return this.#b === 1;"
|
||||
" }"
|
||||
"}"
|
||||
"class NestedSuper extends Base {"
|
||||
" #b = 1;"
|
||||
" constructor() {"
|
||||
" const t = () => {"
|
||||
" super();"
|
||||
" };"
|
||||
" t();"
|
||||
" }"
|
||||
" check() {"
|
||||
" return this.#b === 1;"
|
||||
" }"
|
||||
"}"
|
||||
"class EvaledSuper extends Base {"
|
||||
" #b = 1;"
|
||||
" constructor() {"
|
||||
" eval('super()');"
|
||||
" }"
|
||||
" check() {"
|
||||
" return this.#b === 1;"
|
||||
" }"
|
||||
"}"
|
||||
"class NestedEvaledSuper extends Base {"
|
||||
" #b = 1;"
|
||||
" constructor() {"
|
||||
" const t = () => {"
|
||||
" eval('super()');"
|
||||
" };"
|
||||
" t();"
|
||||
" }"
|
||||
" check() {"
|
||||
" return this.#b === 1;"
|
||||
" }"
|
||||
"}");
|
||||
creator.SetDefaultContext(context);
|
||||
}
|
||||
blob =
|
||||
creator.CreateBlob(v8::SnapshotCreator::FunctionCodeHandling::kClear);
|
||||
}
|
||||
|
||||
v8::Isolate::CreateParams create_params;
|
||||
create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
|
||||
create_params.snapshot_blob = &blob;
|
||||
v8::Isolate* isolate = v8::Isolate::New(create_params);
|
||||
{
|
||||
v8::Isolate::Scope isolate_scope(isolate);
|
||||
v8::HandleScope handle_scope(isolate);
|
||||
v8::Local<v8::Context> context = v8::Context::New(isolate);
|
||||
CHECK(!context.IsEmpty());
|
||||
v8::Context::Scope context_scope(context);
|
||||
ExpectBoolean("(new Derived()).check()", true);
|
||||
ExpectBoolean("(new DerivedDefaultConstructor()).check()", true);
|
||||
ExpectBoolean("(new NestedSuper()).check()", true);
|
||||
ExpectBoolean("(new EvaledSuper()).check()", true);
|
||||
ExpectBoolean("(new NestedEvaledSuper()).check()", true);
|
||||
}
|
||||
isolate->Dispose();
|
||||
delete[] blob.data;
|
||||
FreeCurrentEmbeddedBlob();
|
||||
}
|
||||
|
||||
UNINITIALIZED_TEST(ClassFieldsRecalcPrivateNames) {
|
||||
DisableAlwaysOpt();
|
||||
i::FLAG_rehash_snapshot = true;
|
||||
i::FLAG_hash_seed = 42;
|
||||
i::FLAG_allow_natives_syntax = true;
|
||||
DisableEmbeddedBlobRefcounting();
|
||||
v8::StartupData blob;
|
||||
{
|
||||
v8::SnapshotCreator creator;
|
||||
v8::Isolate* isolate = creator.GetIsolate();
|
||||
{
|
||||
v8::HandleScope handle_scope(isolate);
|
||||
v8::Local<v8::Context> context = v8::Context::New(isolate);
|
||||
v8::Context::Scope context_scope(context);
|
||||
CompileRun(
|
||||
"let heritageFn;"
|
||||
"class Outer {"
|
||||
" #f = 'Outer.#f';"
|
||||
" static Inner = class Inner extends (heritageFn = function () {"
|
||||
" return class Nested {"
|
||||
" exfil(obj) { return obj.#f; }"
|
||||
" exfilEval(obj) { return eval('obj.#f'); }"
|
||||
" };"
|
||||
" }) {"
|
||||
" #f = 'Inner.#f';"
|
||||
" };"
|
||||
"};");
|
||||
creator.SetDefaultContext(context);
|
||||
}
|
||||
blob =
|
||||
creator.CreateBlob(v8::SnapshotCreator::FunctionCodeHandling::kClear);
|
||||
}
|
||||
|
||||
v8::Isolate::CreateParams create_params;
|
||||
create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
|
||||
create_params.snapshot_blob = &blob;
|
||||
v8::Isolate* isolate = v8::Isolate::New(create_params);
|
||||
{
|
||||
v8::Isolate::Scope isolate_scope(isolate);
|
||||
v8::HandleScope handle_scope(isolate);
|
||||
v8::Local<v8::Context> context = v8::Context::New(isolate);
|
||||
CHECK(!context.IsEmpty());
|
||||
v8::Context::Scope context_scope(context);
|
||||
CompileRun(
|
||||
"const o = new Outer;"
|
||||
"const c = new Outer.Inner;"
|
||||
"const D = heritageFn();"
|
||||
"const d = new D;"
|
||||
"let error1;"
|
||||
"let error2;");
|
||||
ExpectString("d.exfil(o)", "Outer.#f");
|
||||
ExpectString("d.exfilEval(o)", "Outer.#f");
|
||||
CompileRun("try { d.exfil(c) } catch(e) { error1 = e; }");
|
||||
ExpectBoolean("error1 instanceof TypeError", true);
|
||||
CompileRun("try { d.exfilEval(c) } catch(e) { error2 = e; }");
|
||||
ExpectBoolean("error2 instanceof TypeError", true);
|
||||
}
|
||||
isolate->Dispose();
|
||||
delete[] blob.data;
|
||||
FreeCurrentEmbeddedBlob();
|
||||
}
|
||||
|
||||
UNINITIALIZED_TEST(ClassFieldsWithBindings) {
|
||||
DisableAlwaysOpt();
|
||||
i::FLAG_rehash_snapshot = true;
|
||||
i::FLAG_hash_seed = 42;
|
||||
i::FLAG_allow_natives_syntax = true;
|
||||
DisableEmbeddedBlobRefcounting();
|
||||
v8::StartupData blob;
|
||||
{
|
||||
v8::SnapshotCreator creator;
|
||||
v8::Isolate* isolate = creator.GetIsolate();
|
||||
{
|
||||
v8::HandleScope handle_scope(isolate);
|
||||
v8::Local<v8::Context> context = v8::Context::New(isolate);
|
||||
v8::Context::Scope context_scope(context);
|
||||
CompileRun(
|
||||
"function testVarBinding() {"
|
||||
" function FuncWithVar() {"
|
||||
" this.getPrivate = () => 'test';"
|
||||
" }"
|
||||
" class Derived extends FuncWithVar {"
|
||||
" ['computed'] = FuncWithVar;"
|
||||
" #private = FuncWithVar;"
|
||||
" public = FuncWithVar;"
|
||||
" constructor() {"
|
||||
" super();"
|
||||
" this.#private = this.getPrivate();"
|
||||
" }"
|
||||
" check() {"
|
||||
" return this.#private === this.getPrivate() &&"
|
||||
" this.computed === FuncWithVar &&"
|
||||
" this.public === FuncWithVar;"
|
||||
" }"
|
||||
" }"
|
||||
""
|
||||
" return((new Derived()).check());"
|
||||
"}"
|
||||
"class ClassWithLet {"
|
||||
" #private = 'test';"
|
||||
" getPrivate() { return this.#private; }"
|
||||
"}"
|
||||
"function testLetBinding() {"
|
||||
" class Derived extends ClassWithLet {"
|
||||
" ['computed'] = ClassWithLet;"
|
||||
" #private = ClassWithLet;"
|
||||
" public = ClassWithLet;"
|
||||
" constructor() {"
|
||||
" super();"
|
||||
" this.#private = this.getPrivate();"
|
||||
" }"
|
||||
" check() {"
|
||||
" return this.#private === this.getPrivate() &&"
|
||||
" this.computed === ClassWithLet &&"
|
||||
" this.public === ClassWithLet;"
|
||||
" }"
|
||||
" }"
|
||||
""
|
||||
" return((new Derived()).check());"
|
||||
"}"
|
||||
"const ClassWithConst = class {"
|
||||
" #private = 'test';"
|
||||
" getPrivate() { return this.#private; }"
|
||||
"};"
|
||||
"function testConstBinding() {"
|
||||
" class Derived extends ClassWithConst {"
|
||||
" ['computed'] = ClassWithConst;"
|
||||
" #private = ClassWithConst;"
|
||||
" public = ClassWithConst;"
|
||||
" constructor() {"
|
||||
" super();"
|
||||
" this.#private = this.getPrivate();"
|
||||
" }"
|
||||
" check() {"
|
||||
" return this.#private === this.getPrivate() &&"
|
||||
" this.computed === ClassWithConst &&"
|
||||
" this.public === ClassWithConst;"
|
||||
" }"
|
||||
" }"
|
||||
""
|
||||
" return((new Derived()).check());"
|
||||
"}");
|
||||
creator.SetDefaultContext(context);
|
||||
}
|
||||
blob =
|
||||
creator.CreateBlob(v8::SnapshotCreator::FunctionCodeHandling::kClear);
|
||||
}
|
||||
|
||||
v8::Isolate::CreateParams create_params;
|
||||
create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
|
||||
create_params.snapshot_blob = &blob;
|
||||
v8::Isolate* isolate = v8::Isolate::New(create_params);
|
||||
{
|
||||
v8::Isolate::Scope isolate_scope(isolate);
|
||||
v8::HandleScope handle_scope(isolate);
|
||||
v8::Local<v8::Context> context = v8::Context::New(isolate);
|
||||
CHECK(!context.IsEmpty());
|
||||
v8::Context::Scope context_scope(context);
|
||||
ExpectBoolean("testVarBinding()", true);
|
||||
ExpectBoolean("testLetBinding()", true);
|
||||
ExpectBoolean("testConstBinding()", true);
|
||||
}
|
||||
isolate->Dispose();
|
||||
delete[] blob.data;
|
||||
FreeCurrentEmbeddedBlob();
|
||||
}
|
||||
|
||||
void CheckSFIsAreWeak(WeakFixedArray sfis, Isolate* isolate) {
|
||||
CHECK_GT(sfis.length(), 0);
|
||||
int no_of_weak = 0;
|
||||
|
@ -22,41 +22,41 @@ var b1, b2, b3;
|
||||
// y = [B1]2;
|
||||
// z = [B2]3;
|
||||
// }
|
||||
b1 = Debug.setBreakPoint(initializer, 1, 0);
|
||||
assertTrue(Debug.showBreakPoints(initializer).indexOf("x = [B0]1;") > 0);
|
||||
b1 = Debug.setBreakPoint(initializer, 0, 0);
|
||||
assertTrue(Debug.showBreakPoints(initializer).indexOf("x = [B0]1;") === 0);
|
||||
Debug.clearBreakPoint(b1);
|
||||
assertTrue(Debug.showBreakPoints(initializer).indexOf("x = [B0]1;") === -1);
|
||||
|
||||
b2 = Debug.setBreakPoint(initializer, 2, 0);
|
||||
b2 = Debug.setBreakPoint(initializer, 1, 0);
|
||||
assertTrue(Debug.showBreakPoints(initializer).indexOf("y = [B0]2;") > 0);
|
||||
Debug.clearBreakPoint(b2);
|
||||
assertTrue(Debug.showBreakPoints(initializer).indexOf("y = [B0]2;") === -1);
|
||||
|
||||
b3 = Debug.setBreakPoint(initializer, 3, 0);
|
||||
b3 = Debug.setBreakPoint(initializer, 2, 0);
|
||||
assertTrue(Debug.showBreakPoints(initializer).indexOf("z = [B0]3") > 0);
|
||||
Debug.clearBreakPoint(b3);
|
||||
assertTrue(Debug.showBreakPoints(initializer).indexOf("z = [B0]3") === -1);
|
||||
|
||||
b1 = Debug.setBreakPoint(initializer, 1, 0);
|
||||
b2 = Debug.setBreakPoint(initializer, 2, 0);
|
||||
assertTrue(Debug.showBreakPoints(initializer).indexOf("x = [B0]1;") > 0);
|
||||
b1 = Debug.setBreakPoint(initializer, 0, 0);
|
||||
b2 = Debug.setBreakPoint(initializer, 1, 0);
|
||||
assertTrue(Debug.showBreakPoints(initializer).indexOf("x = [B0]1;") === 0);
|
||||
assertTrue(Debug.showBreakPoints(initializer).indexOf("y = [B1]2;") > 0);
|
||||
Debug.clearBreakPoint(b1);
|
||||
assertTrue(Debug.showBreakPoints(initializer).indexOf("x = [B0]1;") === -1);
|
||||
Debug.clearBreakPoint(b2);
|
||||
assertTrue(Debug.showBreakPoints(initializer).indexOf("y = [B1]2;") === -1);
|
||||
|
||||
b1 = Debug.setBreakPoint(initializer, 1, 0);
|
||||
b3 = Debug.setBreakPoint(initializer, 3, 0);
|
||||
assertTrue(Debug.showBreakPoints(initializer).indexOf("x = [B0]1;") > 0);
|
||||
b1 = Debug.setBreakPoint(initializer, 0, 0);
|
||||
b3 = Debug.setBreakPoint(initializer, 2, 0);
|
||||
assertTrue(Debug.showBreakPoints(initializer).indexOf("x = [B0]1;") === 0);
|
||||
assertTrue(Debug.showBreakPoints(initializer).indexOf("z = [B1]3") > 0);
|
||||
Debug.clearBreakPoint(b1);
|
||||
assertTrue(Debug.showBreakPoints(initializer).indexOf("x = [B0]1;") === -1);
|
||||
Debug.clearBreakPoint(b3);
|
||||
assertTrue(Debug.showBreakPoints(initializer).indexOf("z = [B1]3") === -1);
|
||||
|
||||
b2 = Debug.setBreakPoint(initializer, 2, 0);
|
||||
b3 = Debug.setBreakPoint(initializer, 3, 0);
|
||||
b2 = Debug.setBreakPoint(initializer, 1, 0);
|
||||
b3 = Debug.setBreakPoint(initializer, 2, 0);
|
||||
assertTrue(Debug.showBreakPoints(initializer).indexOf("y = [B0]2;") > 0);
|
||||
assertTrue(Debug.showBreakPoints(initializer).indexOf("z = [B1]3") > 0);
|
||||
Debug.clearBreakPoint(b2);
|
||||
@ -83,11 +83,11 @@ class X {
|
||||
// }
|
||||
|
||||
initializer = %GetInitializerFunction(X);
|
||||
b1 = Debug.setBreakPoint(initializer, 1, 0);
|
||||
assertTrue(Debug.showBreakPoints(initializer).indexOf('[foo()] = 1;') > 0);
|
||||
b1 = Debug.setBreakPoint(initializer, 0, 0);
|
||||
assertTrue(Debug.showBreakPoints(initializer).indexOf('[foo()] = 1;') === 0);
|
||||
Debug.clearBreakPoint(b1);
|
||||
|
||||
b1 = Debug.setBreakPoint(initializer, 2, 0);
|
||||
b1 = Debug.setBreakPoint(initializer, 1, 0);
|
||||
assertTrue(Debug.showBreakPoints(initializer).indexOf('baz = [B0]foo()') > 0);
|
||||
Debug.clearBreakPoint(b1);
|
||||
|
||||
|
@ -90,8 +90,8 @@ Running test: testScopesPaused
|
||||
scopeChain : [
|
||||
[0] : {
|
||||
endLocation : {
|
||||
columnNumber : 3
|
||||
lineNumber : 15
|
||||
columnNumber : 13
|
||||
lineNumber : 14
|
||||
scriptId : <scriptId>
|
||||
}
|
||||
name : run
|
||||
@ -102,8 +102,8 @@ Running test: testScopesPaused
|
||||
type : object
|
||||
}
|
||||
startLocation : {
|
||||
columnNumber : 2
|
||||
lineNumber : 11
|
||||
columnNumber : 4
|
||||
lineNumber : 12
|
||||
scriptId : <scriptId>
|
||||
}
|
||||
type : local
|
||||
@ -183,8 +183,8 @@ Running test: testScopesPaused
|
||||
[0] : {
|
||||
callFrameId : <callFrameId>
|
||||
functionLocation : {
|
||||
columnNumber : 2
|
||||
lineNumber : 11
|
||||
columnNumber : 4
|
||||
lineNumber : 12
|
||||
scriptId : <scriptId>
|
||||
}
|
||||
functionName : <instance_members_initializer>
|
||||
@ -364,8 +364,8 @@ Running test: testScopesPaused
|
||||
[0] : {
|
||||
callFrameId : <callFrameId>
|
||||
functionLocation : {
|
||||
columnNumber : 2
|
||||
lineNumber : 11
|
||||
columnNumber : 4
|
||||
lineNumber : 12
|
||||
scriptId : <scriptId>
|
||||
}
|
||||
functionName : <instance_members_initializer>
|
||||
@ -545,8 +545,8 @@ Running test: testScopesPaused
|
||||
[0] : {
|
||||
callFrameId : <callFrameId>
|
||||
functionLocation : {
|
||||
columnNumber : 2
|
||||
lineNumber : 11
|
||||
columnNumber : 4
|
||||
lineNumber : 12
|
||||
scriptId : <scriptId>
|
||||
}
|
||||
functionName : <instance_members_initializer>
|
||||
@ -798,8 +798,8 @@ Running test: testScopesPaused
|
||||
[1] : {
|
||||
callFrameId : <callFrameId>
|
||||
functionLocation : {
|
||||
columnNumber : 2
|
||||
lineNumber : 11
|
||||
columnNumber : 4
|
||||
lineNumber : 12
|
||||
scriptId : <scriptId>
|
||||
}
|
||||
functionName : <instance_members_initializer>
|
||||
|
@ -7,23 +7,23 @@ let x = |R|class {}
|
||||
|
||||
|_|x = |R|class {
|
||||
x = |_|1;
|
||||
y = |_|2;
|
||||
}|R|
|
||||
y = |_|2|R|;
|
||||
}
|
||||
|
||||
|_|x = |R|class {
|
||||
x = |C|foo();
|
||||
y = |_|2;
|
||||
z = |C|bar();
|
||||
}|R|
|
||||
z = |C|bar()|R|;
|
||||
}
|
||||
|
||||
|_|x = class {
|
||||
x = |C|foo();
|
||||
y = |_|2;
|
||||
z = |C|bar();
|
||||
z = |C|bar()|R|;
|
||||
constructor() {
|
||||
this.|_|x;
|
||||
|R|}
|
||||
}|R|
|
||||
}
|
||||
|
||||
|_|x = class {
|
||||
x = |C|foo();
|
||||
@ -31,8 +31,8 @@ let x = |R|class {}
|
||||
constructor() {
|
||||
this.|_|x;
|
||||
|R|}
|
||||
z = |C|bar();
|
||||
}|R|
|
||||
z = |C|bar()|R|;
|
||||
}
|
||||
|
||||
|_|x = class {
|
||||
x = |C|foo();
|
||||
@ -40,14 +40,14 @@ let x = |R|class {}
|
||||
constructor() {
|
||||
this.|_|x;
|
||||
|R|}
|
||||
z = |C|bar();
|
||||
}|R|
|
||||
z = |C|bar()|R|;
|
||||
}
|
||||
|
||||
|_|x = |R|class {
|
||||
x = |_|1;
|
||||
foo() {|R|}
|
||||
y = |_|2;
|
||||
}|R|
|
||||
y = |_|2|R|;
|
||||
}
|
||||
|
||||
|_|x = |R|class {
|
||||
x = (function() {
|
||||
@ -55,54 +55,54 @@ let x = |R|class {}
|
||||
|R|})|C|();
|
||||
y = (() => {
|
||||
|C|bar();
|
||||
|R|})|C|();
|
||||
}|R|
|
||||
|R|})|C|()|R|;
|
||||
}
|
||||
|
||||
|_|x = |R|class {
|
||||
x = |_|function() {
|
||||
|C|foo();
|
||||
|R|};
|
||||
}|R|
|
||||
|R|}|R|;
|
||||
}
|
||||
|
||||
|_|x = |R|class {
|
||||
x = |_|async function() {
|
||||
|_|await |C|foo();
|
||||
|R|};
|
||||
}|R|
|
||||
|R|}|R|;
|
||||
}
|
||||
|
||||
|_|x = |R|class {
|
||||
x = |_|() => {
|
||||
|C|foo();
|
||||
|R|};
|
||||
y = |_|() => |C|bar()|R|;
|
||||
}|R|
|
||||
}
|
||||
|
||||
|_|x = |R|class {
|
||||
x = |_|async () => {
|
||||
|_|await |C|foo();
|
||||
|R|};
|
||||
y = |_|async () => |_|await |C|bar()|R|;
|
||||
}|R|
|
||||
}
|
||||
|
||||
|_|x = |R|class {
|
||||
[|_|x] = |_|1;
|
||||
[|C|foo()] = |_|2;
|
||||
}|R|
|
||||
[|C|foo()] = |_|2|R|;
|
||||
}
|
||||
|
||||
|_|x = |R|class {
|
||||
[|_|x] = |_|[...this];
|
||||
}|R|
|
||||
[|_|x] = |_|[...this]|R|;
|
||||
}
|
||||
|
||||
|_|x = |R|class {
|
||||
x;
|
||||
[|C|foo()];
|
||||
}|R|
|
||||
[|C|foo()]|R|;
|
||||
}
|
||||
|
||||
|_|x = |R|class {
|
||||
x = |_|function*|_|() {
|
||||
|_|yield 1;
|
||||
|R|};
|
||||
}|R|
|
||||
|R|}|R|;
|
||||
}
|
||||
|
||||
|_|x = |R|class {
|
||||
static x = |_|1;
|
||||
@ -201,6 +201,6 @@ let x = |R|class {}
|
||||
static [|_|z] = |_|3;
|
||||
[|_|p] = |_|4;
|
||||
static [|C|foo()] = |_|5|R|;
|
||||
[|C|bar()] = |_|6;
|
||||
}|R|
|
||||
[|C|bar()] = |_|6|R|;
|
||||
}
|
||||
|R|
|
||||
|
@ -25,7 +25,7 @@ class X { // 000
|
||||
}; // 100
|
||||
`,
|
||||
[{"start":0,"end":149,"count":1},
|
||||
{"start":0,"end":101,"count":0}]
|
||||
{"start":52,"end":70,"count":0}]
|
||||
);
|
||||
|
||||
TestCoverage(
|
||||
@ -37,7 +37,7 @@ class X { // 000
|
||||
let x = new X(); // 150
|
||||
`,
|
||||
[{"start":0,"end":199,"count":1},
|
||||
{"start":0,"end":101,"count":1},
|
||||
{"start":52,"end":70,"count":1},
|
||||
{"start":56,"end":70,"count":0}]
|
||||
);
|
||||
|
||||
@ -51,7 +51,7 @@ let x = new X(); // 150
|
||||
x.x(); // 200
|
||||
`,
|
||||
[{"start":0,"end":249,"count":1},
|
||||
{"start":0,"end":101,"count":1},
|
||||
{"start":52,"end":70,"count":1},
|
||||
{"start":56,"end":70,"count":1}]
|
||||
);
|
||||
|
||||
@ -68,7 +68,7 @@ x.x(); // 300
|
||||
x.y(); // 350
|
||||
`,
|
||||
[{"start":0,"end":399,"count":1},
|
||||
{"start":0,"end":201,"count":1},
|
||||
{"start":52,"end":169,"count":1},
|
||||
{"start":56,"end":70,"count":1},
|
||||
{"start":102,"end":111,"count":0},
|
||||
{"start":156,"end":169,"count":1}]
|
||||
@ -88,7 +88,7 @@ x.y(); // 350
|
||||
x.foo(); // 400
|
||||
`,
|
||||
[{"start":0,"end":449,"count":1},
|
||||
{"start":0,"end":201,"count":1},
|
||||
{"start":52,"end":169,"count":1},
|
||||
{"start":56,"end":70,"count":1},
|
||||
{"start":102,"end":111,"count":1},
|
||||
{"start":156,"end":169,"count":1}]
|
||||
@ -103,7 +103,7 @@ class X { // 000
|
||||
let x = new X(); // 150
|
||||
`,
|
||||
[{"start":0,"end":199,"count":1},
|
||||
{"start":0,"end":101,"count":1},
|
||||
{"start":52,"end":74,"count":1},
|
||||
{"start":57,"end":71,"count":1}]
|
||||
);
|
||||
|
||||
@ -118,7 +118,7 @@ let x = new X(); // 200
|
||||
`,
|
||||
[{"start":0,"end":249,"count":1},
|
||||
{"start":0,"end":15,"count":1},
|
||||
{"start":50,"end":151,"count":1},
|
||||
{"start":102,"end":128,"count":1},
|
||||
{"start":111,"end":125,"count":1}]
|
||||
);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user