Commit e768bcca authored by oth's avatar oth Committed by Commit bot

[interpreter] Support for ES6 super keyword.

Adds support for ES6 super keyword and performing loads, stores, and
calls to super class members.

Implements SetHomeObject and enables ThisFunctionVariable.

BUG=v8:4280,v8:4682
LOG=N

Review URL: https://codereview.chromium.org/1689573004

Cr-Commit-Position: refs/heads/master@{#33977}
parent f0561ac5
......@@ -1136,33 +1136,34 @@ void BytecodeGraphBuilder::VisitCallRuntimeForPairWide() {
BuildCallRuntimeForPair();
}
Node* BytecodeGraphBuilder::ProcessCallNewArguments(
const Operator* call_new_op, interpreter::Register callee,
const Operator* call_new_op, Node* callee, Node* new_target,
interpreter::Register first_arg, size_t arity) {
Node** all = info()->zone()->NewArray<Node*>(arity);
all[0] = environment()->LookupRegister(callee);
all[0] = new_target;
int first_arg_index = first_arg.index();
for (int i = 1; i < static_cast<int>(arity) - 1; ++i) {
all[i] = environment()->LookupRegister(
interpreter::Register(first_arg_index + i - 1));
}
// Original constructor is the same as the callee.
all[arity - 1] = environment()->LookupRegister(callee);
all[arity - 1] = callee;
Node* value = MakeNode(call_new_op, static_cast<int>(arity), all, false);
return value;
}
void BytecodeGraphBuilder::BuildCallConstruct() {
FrameStateBeforeAndAfter states(this);
interpreter::Register callee = bytecode_iterator().GetRegisterOperand(0);
interpreter::Register callee_reg = bytecode_iterator().GetRegisterOperand(0);
interpreter::Register first_arg = bytecode_iterator().GetRegisterOperand(1);
size_t arg_count = bytecode_iterator().GetRegisterCountOperand(2);
Node* new_target = environment()->LookupAccumulator();
Node* callee = environment()->LookupRegister(callee_reg);
// TODO(turbofan): Pass the feedback here.
const Operator* call = javascript()->CallConstruct(
static_cast<int>(arg_count) + 2, VectorSlotPair());
Node* value = ProcessCallNewArguments(call, callee, first_arg, arg_count + 2);
Node* value = ProcessCallNewArguments(call, callee, new_target, first_arg,
arg_count + 2);
environment()->BindAccumulator(value, &states);
}
......
......@@ -103,8 +103,8 @@ class BytecodeGraphBuilder {
Node* ProcessCallArguments(const Operator* call_op, Node* callee,
interpreter::Register receiver, size_t arity);
Node* ProcessCallNewArguments(const Operator* call_new_op,
interpreter::Register callee,
Node* ProcessCallNewArguments(const Operator* call_new_op, Node* callee,
Node* new_target,
interpreter::Register first_arg, size_t arity);
Node* ProcessCallRuntimeArguments(const Operator* call_runtime_op,
interpreter::Register first_arg,
......
......@@ -484,9 +484,8 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::StoreLookupSlot(
return *this;
}
BytecodeArrayBuilder& BytecodeArrayBuilder::LoadNamedProperty(
Register object, const Handle<String> name, int feedback_slot,
Register object, const Handle<Name> name, int feedback_slot,
LanguageMode language_mode) {
Bytecode bytecode = BytecodeForLoadIC(language_mode);
size_t name_index = GetConstantPoolEntry(name);
......@@ -520,9 +519,8 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::LoadKeyedProperty(
return *this;
}
BytecodeArrayBuilder& BytecodeArrayBuilder::StoreNamedProperty(
Register object, const Handle<String> name, int feedback_slot,
Register object, const Handle<Name> name, int feedback_slot,
LanguageMode language_mode) {
Bytecode bytecode = BytecodeForStoreIC(language_mode);
size_t name_index = GetConstantPoolEntry(name);
......@@ -1107,7 +1105,6 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::Call(Register callable,
return *this;
}
BytecodeArrayBuilder& BytecodeArrayBuilder::New(Register constructor,
Register first_arg,
size_t arg_count) {
......
......@@ -114,7 +114,7 @@ class BytecodeArrayBuilder final : public ZoneObject, private RegisterMover {
// Named load property.
BytecodeArrayBuilder& LoadNamedProperty(Register object,
const Handle<String> name,
const Handle<Name> name,
int feedback_slot,
LanguageMode language_mode);
// Keyed load property. The key should be in the accumulator.
......@@ -123,7 +123,7 @@ class BytecodeArrayBuilder final : public ZoneObject, private RegisterMover {
// Store properties. The value to be stored should be in the accumulator.
BytecodeArrayBuilder& StoreNamedProperty(Register object,
const Handle<String> name,
const Handle<Name> name,
int feedback_slot,
LanguageMode language_mode);
BytecodeArrayBuilder& StoreKeyedProperty(Register object, Register key,
......@@ -167,9 +167,10 @@ class BytecodeArrayBuilder final : public ZoneObject, private RegisterMover {
BytecodeArrayBuilder& Call(Register callable, Register receiver_args,
size_t receiver_arg_count, int feedback_slot);
// Call the new operator. The |constructor| register is followed by
// |arg_count| consecutive registers containing arguments to be
// applied to the constructor.
// Call the new operator. The accumulator holds the |new_target|.
// The |constructor| is in a register followed by |arg_count|
// consecutive arguments starting at |first_arg| for the constuctor
// invocation.
BytecodeArrayBuilder& New(Register constructor, Register first_arg,
size_t arg_count);
......
This diff is collapsed.
......@@ -42,6 +42,7 @@ class BytecodeGenerator final : public AstVisitor {
class AccumulatorResultScope;
class RegisterResultScope;
class RegisterAllocationScope;
class SuperPropertyArguments;
void MakeBytecodeBody();
......@@ -65,6 +66,20 @@ class BytecodeGenerator final : public AstVisitor {
// Helper visitors which perform common operations.
Register VisitArguments(ZoneList<Expression*>* arguments);
// Visit a keyed super property load. The optional
// |opt_receiver_out| register will have the receiver stored to it
// if it's a valid register. The loaded value is placed in the
// accumulator.
void VisitKeyedSuperPropertyLoad(Property* property,
Register opt_receiver_out);
// Visit a named super property load. The optional
// |opt_receiver_out| register will have the receiver stored to it
// if it's a valid register. The loaded value is placed in the
// accumulator.
void VisitNamedSuperPropertyLoad(Property* property,
Register opt_receiver_out);
void VisitPropertyLoad(Register obj, Property* expr);
void VisitPropertyLoadForAccumulator(Register obj, Property* expr);
......@@ -79,6 +94,19 @@ class BytecodeGenerator final : public AstVisitor {
void VisitVariableAssignment(Variable* variable, Token::Value op,
FeedbackVectorSlot slot);
void PrepareNamedSuperPropertyArguments(
SuperPropertyReference* super_property, Handle<Name> name,
SuperPropertyArguments* super_property_args);
void PrepareKeyedSuperPropertyArguments(
SuperPropertyReference* super_property, Expression* key,
SuperPropertyArguments* super_property_args);
void BuildNamedSuperPropertyLoad(SuperPropertyArguments* super_property_args);
void BuildKeyedSuperPropertyLoad(SuperPropertyArguments* super_property_args);
void BuildNamedSuperPropertyStore(
SuperPropertyArguments* super_property_args);
void BuildKeyedSuperPropertyStore(
SuperPropertyArguments* super_property_args);
void BuildThrowIfHole(Handle<String> name);
void BuildThrowIfNotHole(Handle<String> name);
void BuildThrowReassignConstant(Handle<String> name);
......@@ -88,6 +116,7 @@ class BytecodeGenerator final : public AstVisitor {
void VisitArgumentsObject(Variable* variable);
void VisitRestArgumentsArray(Variable* rest);
void VisitCallSuper(Call* call);
void VisitClassLiteralContents(ClassLiteral* expr);
void VisitClassLiteralForRuntimeDefinition(ClassLiteral* expr);
void VisitClassLiteralProperties(ClassLiteral* expr, Register literal,
......@@ -130,6 +159,10 @@ class BytecodeGenerator final : public AstVisitor {
bool IsInsideTryCatch() const { return try_catch_nesting_level_ > 0; }
bool IsInsideTryFinally() const { return try_finally_nesting_level_ > 0; }
// Initialize an array of temporary registers with consecutive registers.
template <size_t N>
void InitializeWithConsecutiveRegisters(Register (&registers)[N]);
inline void set_builder(BytecodeArrayBuilder* builder) { builder_ = builder; }
inline BytecodeArrayBuilder* builder() const { return builder_; }
......
......@@ -224,6 +224,14 @@ Register BytecodeRegisterAllocator::NextConsecutiveRegister() {
return Register(next_consecutive_register_++);
}
void BytecodeRegisterAllocator::PrepareAndInitializeConsecutiveAllocations(
Register* registers, size_t count) {
PrepareForConsecutiveAllocations(count);
for (size_t i = 0; i < count; i++) {
registers[i] = NextConsecutiveRegister();
}
}
} // namespace interpreter
} // namespace internal
} // namespace v8
......@@ -74,11 +74,22 @@ class BytecodeRegisterAllocator final {
~BytecodeRegisterAllocator();
Register NewRegister();
// Ensure |count| consecutive allocations are available.
void PrepareForConsecutiveAllocations(size_t count);
// Get the next consecutive allocation after calling
// PrepareForConsecutiveAllocations.
Register NextConsecutiveRegister();
// Prepare consecutive register allocations and initialize an array
// of registers with the allocations.
void PrepareAndInitializeConsecutiveAllocations(Register* registers,
size_t count);
// Returns true if |reg| is allocated in this allocator.
bool RegisterIsAllocatedInThisScope(Register reg) const;
// Returns true if unused consecutive allocations remain.
bool HasConsecutiveAllocations() const { return next_consecutive_count_ > 0; }
private:
......
......@@ -1166,14 +1166,15 @@ void Interpreter::DoCallJSRuntimeWide(InterpreterAssembler* assembler) {
void Interpreter::DoCallConstruct(InterpreterAssembler* assembler) {
Callable ic = CodeFactory::InterpreterPushArgsAndConstruct(isolate_);
Node* new_target = __ GetAccumulator();
Node* constructor_reg = __ BytecodeOperandReg(0);
Node* constructor = __ LoadRegister(constructor_reg);
Node* first_arg_reg = __ BytecodeOperandReg(1);
Node* first_arg = __ RegisterLocation(first_arg_reg);
Node* args_count = __ BytecodeOperandCount(2);
Node* context = __ GetContext();
Node* result = __ CallConstruct(constructor, context, constructor, first_arg,
args_count);
Node* result =
__ CallConstruct(constructor, context, new_target, first_arg, args_count);
__ SetAccumulator(result);
__ Dispatch();
}
......@@ -1183,6 +1184,7 @@ void Interpreter::DoCallConstruct(InterpreterAssembler* assembler) {
//
// Call operator new with |constructor| and the first argument in
// register |first_arg| and |arg_count| arguments in subsequent
// registers. The new.target is in the accumulator.
//
void Interpreter::DoNew(InterpreterAssembler* assembler) {
DoCallConstruct(assembler);
......@@ -1193,6 +1195,7 @@ void Interpreter::DoNew(InterpreterAssembler* assembler) {
//
// Call operator new with |constructor| and the first argument in
// register |first_arg| and |arg_count| arguments in subsequent
// registers. The new.target is in the accumulator.
//
void Interpreter::DoNewWide(InterpreterAssembler* assembler) {
DoCallConstruct(assembler);
......
......@@ -504,45 +504,6 @@
# TODO(rmcilroy,4680): Check failed: toplevel_test_code_event_found.
'test-serialize/SerializeToplevelIsolates': [FAIL],
# TODO(rmcilroy,4682): Requires support for classes.
'test-inobject-slack-tracking/SubclassBasicNoBaseClassInstancesNoInlineNew': [FAIL],
'test-inobject-slack-tracking/SubclassBasicNoBaseClassInstances': [FAIL],
'test-inobject-slack-tracking/LongSubclassChain2': [FAIL],
'test-inobject-slack-tracking/LongSubclassChain1': [FAIL],
'test-inobject-slack-tracking/LongSubclassChain3': [FAIL],
'test-inobject-slack-tracking/SubclassBasicNoInlineNew': [FAIL],
'test-inobject-slack-tracking/InobjectPropetiesCountOverflowInSubclass': [FAIL],
'test-inobject-slack-tracking/SlowModeSubclass': [FAIL],
'test-inobject-slack-tracking/SubclassObjectBuiltin': [FAIL],
'test-inobject-slack-tracking/SubclassObjectBuiltinNoInlineNew': [FAIL],
'test-inobject-slack-tracking/SubclassFunctionBuiltin': [FAIL],
'test-inobject-slack-tracking/SubclassBasic': [FAIL],
'test-inobject-slack-tracking/SubclassFunctionBuiltinNoInlineNew': [FAIL],
'test-inobject-slack-tracking/SubclassNumberBuiltin': [FAIL],
'test-inobject-slack-tracking/SubclassBooleanBuiltinNoInlineNew': [FAIL],
'test-inobject-slack-tracking/SubclassErrorBuiltinNoInlineNew': [FAIL],
'test-inobject-slack-tracking/SubclassErrorBuiltin': [FAIL],
'test-inobject-slack-tracking/SubclassStringBuiltin': [FAIL],
'test-inobject-slack-tracking/SubclassDateBuiltin': [FAIL],
'test-inobject-slack-tracking/SubclassRegExpBuiltin': [FAIL],
'test-inobject-slack-tracking/SubclassStringBuiltinNoInlineNew': [FAIL],
'test-inobject-slack-tracking/SubclassBooleanBuiltin': [FAIL],
'test-inobject-slack-tracking/SubclassDateBuiltinNoInlineNew': [FAIL],
'test-inobject-slack-tracking/SubclassArrayBuiltin': [FAIL],
'test-inobject-slack-tracking/SubclassRegExpBuiltinNoInlineNew': [FAIL],
'test-inobject-slack-tracking/SubclassNumberBuiltinNoInlineNew': [FAIL],
'test-inobject-slack-tracking/SubclassArrayBuiltinNoInlineNew': [FAIL],
'test-inobject-slack-tracking/SubclassTypedArrayBuiltin': [FAIL],
'test-inobject-slack-tracking/SubclassTypedArrayBuiltinNoInlineNew': [FAIL],
'test-inobject-slack-tracking/SubclassCollectionBuiltin': [FAIL],
'test-inobject-slack-tracking/SubclassCollectionBuiltinNoInlineNew': [FAIL],
'test-inobject-slack-tracking/SubclassArrayBufferBuiltin': [FAIL],
'test-inobject-slack-tracking/SubclassArrayBufferBuiltinNoInlineNew': [FAIL],
'test-inobject-slack-tracking/SubclassPromiseBuiltinNoInlineNew': [FAIL],
'test-inobject-slack-tracking/SubclassPromiseBuiltin': [FAIL],
'test-api/Regress470113': [FAIL],
'test-api/SubclassGetConstructorName': [FAIL],
# BUG(4333). Function name inferrer does not work for ES6 clases.
'test-func-name-inference/UpperCaseClass': [TIMEOUT],
'test-func-name-inference/LowerCaseClass': [TIMEOUT],
......@@ -649,6 +610,7 @@
['ignition == True and arch == arm64', {
# TODO(rmcilroy,4680): Arm64 specific crashes.
'test-api/ExternalWrap': [SKIP],
'test-api/Regress470113': [SKIP],
'test-heap/NoWeakHashTableLeakWithIncrementalMarking': [SKIP],
# TODO(rmcilroy,4680): Arm64 flakes.
......
......@@ -5048,13 +5048,14 @@ TEST(CallNew) {
"f()",
2 * kPointerSize,
1,
15,
17,
{
B(StackCheck), //
B(LdaGlobalSloppy), U8(0), U8(vector->GetIndex(slot2)), //
B(Star), R(0), //
B(LdaSmi8), U8(3), //
B(Star), R(1), //
B(Ldar), R(0), //
B(New), R(0), R(1), U8(1), //
B(Return), //
},
......@@ -5070,7 +5071,7 @@ TEST(CallNew) {
"f()",
4 * kPointerSize,
1,
23,
25,
{
B(StackCheck), //
B(LdaGlobalSloppy), U8(0), U8(vector->GetIndex(slot2)), //
......@@ -5081,6 +5082,7 @@ TEST(CallNew) {
B(Star), R(2), //
B(LdaSmi8), U8(5), //
B(Star), R(3), //
B(Ldar), R(0), //
B(New), R(0), R(1), U8(3), //
B(Return), //
},
......@@ -9232,6 +9234,8 @@ TEST(ClassDeclarations) {
}
}
// TODO(oth): Add tests for super keyword.
} // namespace interpreter
} // namespace internal
} // namespace v8
......@@ -3865,6 +3865,65 @@ TEST(InterpreterClassLiterals) {
}
}
TEST(InterpreterClassAndSuperClass) {
HandleAndZoneScope handles;
i::Isolate* isolate = handles.main_isolate();
std::pair<const char*, Handle<Object>> examples[] = {
{"class A {\n"
" constructor(x) { this.x_ = x; }\n"
" method() { return this.x_; }\n"
"}\n"
"class B extends A {\n"
" constructor(x, y) { super(x); this.y_ = y; }\n"
" method() { return super.method() + 1; }\n"
"}\n"
"return new B(998, 0).method();\n",
handle(Smi::FromInt(999), isolate)},
{"class A {\n"
" constructor() { this.x_ = 2; this.y_ = 3; }\n"
"}\n"
"class B extends A {\n"
" constructor() { super(); }"
" method() { this.x_++; this.y_++; return this.x_ + this.y_; }\n"
"}\n"
"return new B().method();\n",
handle(Smi::FromInt(7), isolate)},
{"var calls = 0;\n"
"class B {}\n"
"B.prototype.x = 42;\n"
"class C extends B {\n"
" constructor() {\n"
" super();\n"
" calls++;\n"
" }\n"
"}\n"
"new C;\n"
"return calls;\n",
handle(Smi::FromInt(1), isolate)},
{"class A {\n"
" method() { return 1; }\n"
" get x() { return 2; }\n"
"}\n"
"class B extends A {\n"
" method() { return super.x === 2 ? super.method() : -1; }\n"
"}\n"
"return new B().method();\n",
handle(Smi::FromInt(1), isolate)},
{"var object = { setY(v) { super.y = v; }};\n"
"object.setY(10);\n"
"return object.y;\n",
handle(Smi::FromInt(10), isolate)},
};
for (size_t i = 0; i < arraysize(examples); ++i) {
std::string source(InterpreterTester::SourceForBody(examples[i].first));
InterpreterTester tester(handles.main_isolate(), source.c_str());
auto callable = tester.GetCallable<>();
Handle<i::Object> return_value = callable().ToHandleChecked();
CHECK(return_value->SameValue(*examples[i].second));
}
}
TEST(InterpreterConstDeclaration) {
HandleAndZoneScope handles;
i::Isolate* isolate = handles.main_isolate();
......
......@@ -800,6 +800,7 @@
'es6/iterator-prototype': [FAIL],
'es6/generators-mirror': [FAIL],
'es6/object-literals-method': [FAIL],
'es6/object-literals-super': [FAIL],
'es6/generators-relocation': [FAIL],
'es6/spread-array': [FAIL],
'es6/generators-debug-liveedit': [FAIL],
......@@ -828,46 +829,6 @@
'es6/promises': [FAIL],
'deserialize-optimize-inner': [FAIL],
# TODO(oth,4682): Requires VisitThisFunctionVariable support.
'es6/classes-maps': [FAIL],
'es6/array-concat': [FAIL],
'es6/classes-subclass-arrays': [FAIL],
'es6/classes-derived-return-type': [FAIL],
'es6/classes-experimental': [FAIL],
'es6/legacy-subclassing': [FAIL],
'es6/new-target': [FAIL],
'es6/promise-internal-setter': [FAIL],
'es6/regexp-constructor': [FAIL],
'es6/rest-params': [FAIL],
'es6/spread-call-new-class': [FAIL],
'es6/typedarray-of': [FAIL],
'harmony/array-species': [FAIL],
'harmony/arraybuffer-species': [FAIL],
'harmony/promise-species': [FAIL],
'es6/debug-break-default-constructor': [FAIL],
'harmony/typedarray-species': [FAIL],
'regress/regress-544991': [FAIL],
'regress/regress-crbug-498022': [FAIL],
'regress/regress-crbug-575080': [FAIL],
'regress/regress-crbug-580506': [FAIL],
'regress/regress-typedarray-length': [FAIL],
# TODO(oth,4682): Requires VisitSetHomeObject support.
'es6/class-computed-property-names-super': [FAIL],
'es6/classes-lazy-parsing': [FAIL],
'es6/computed-property-names-super': [FAIL],
'es6/classes': [FAIL],
'es6/object-literals-super': [FAIL],
'es6/spread-call-super-property': [FAIL],
'es6/super': [FAIL],
'es6/regress/regress-4097': [FAIL],
'es6/regress/regress-4466': [FAIL],
'es6/regress/regress-4522': [FAIL],
'es6/regress/regress-cr493566': [FAIL],
'harmony/regress/regress-4395': [FAIL],
'regress/regress-4525': [FAIL],
'regress/regress-4521': [FAIL],
# TODO(rmcilroy,4680): Check failed in
# BytecodeGenerator::VisitFunctionLiteral - !shared_info.is_null().
'regress/regress-crbug-429159': [FAIL],
......@@ -888,12 +849,10 @@
'es6/tail-call': [FAIL],
'es6/tail-call-simple': [FAIL],
'es6/mirror-collections': [FAIL],
'es6/block-const-assign': [FAIL],
'es6/regress/regress-468661': [FAIL],
'harmony/string-replace': [FAIL],
'harmony/string-match': [FAIL],
'harmony/string-split': [FAIL],
'harmony/block-const-assign-sloppy': [FAIL],
'regress/regress-2618': [FAIL],
'regress/regress-4121': [FAIL],
'regress/regress-4266': [FAIL],
......@@ -941,9 +900,9 @@
# TODO(rmcilroy,4680): Arm64 specific failures.
'apply': [SKIP],
'array-constructor': [SKIP],
'array-store-and-grow': [SKIP],
'array-functions-prototype-misc': [SKIP],
'array-sort': [SKIP],
'array-store-and-grow': [SKIP],
'asm/construct-double': [SKIP],
'compiler/division-by-constant': [SKIP],
'compiler/osr-big': [SKIP],
......@@ -952,17 +911,24 @@
'compiler/osr-two': [SKIP],
'copy-on-write-assert': [SKIP],
'es6/block-conflicts': [SKIP],
'es6/block-const-assign': [SKIP],
'es6/block-let-declaration': [SKIP],
'es6/block-scoping-top-level': [SKIP],
'es6/classes-derived-return-type': [SKIP],
'es6/regress/regress-2506': [SKIP],
'es6/regress/regress-474783': [SKIP],
'es6/typedarray-proto': [SKIP],
'es6/unscopables': [SKIP],
'harmony/arraybuffer-species': [SKIP],
'harmony/array-species': [SKIP],
'harmony/block-conflicts-sloppy': [SKIP],
'harmony/block-const-assign-sloppy': [SKIP],
'harmony/block-let-declaration-sloppy': [SKIP],
'harmony/block-scoping-top-level-sloppy': [SKIP],
'harmony/species': [SKIP],
'harmony/typedarray-species': [SKIP],
'mirror-object': [SKIP],
'mul-exhaustive-part*': [SKIP],
'readonly': [SKIP],
'regress/regress-165637': [SKIP],
'regress/regress-2185': [SKIP],
......@@ -972,20 +938,21 @@
'regress/regress-347914': [SKIP],
'regress/regress-411210': [SKIP],
'regress/regress-4509-Class-constructor-typeerror-realm': [SKIP],
'regress/regress-4521': [SKIP],
'regress/regress-568765': [SKIP],
'regress/regress-85177': [SKIP],
'regress/regress-crbug-405517': [SKIP],
'regress/regress-crbug-474297': [SKIP],
'regress/regress-crbug-498022': [SKIP],
'regress/regress-crbug-505007-1': [SKIP],
'regress/regress-crbug-505007-2': [SKIP],
'regress/regress-crbug-514081': [SKIP],
'regress/regress-crbug-513507': [SKIP],
'regress/regress-crbug-514081': [SKIP],
'regress/regress-deep-proto': [SKIP],
'regress/regress-put-prototype-transition': [SKIP],
'regress/regress-transcendental': [SKIP],
'stack-traces-overflow': [SKIP],
'try': [SKIP],
'mul-exhaustive-part*': [SKIP],
'unicodelctest': [SKIP],
'unicodelctest-no-optimization': [SKIP],
}], # ignition == True and arch == arm64
......
This diff is collapsed.
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