aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/qml/jit/qv4assemblercommon.cpp45
-rw-r--r--src/qml/jit/qv4assemblercommon_p.h61
-rw-r--r--src/qml/jit/qv4baselineassembler.cpp24
-rw-r--r--src/qml/jit/qv4baselineassembler_p.h4
-rw-r--r--src/qml/jit/qv4baselinejit.cpp12
-rw-r--r--src/qml/jsruntime/qv4functionobject.cpp10
-rw-r--r--src/qml/jsruntime/qv4functionobject_p.h4
-rw-r--r--src/qml/jsruntime/qv4runtime.cpp25
-rw-r--r--src/qml/jsruntime/qv4runtimeapi_p.h8
-rw-r--r--src/qml/jsruntime/qv4stackframe_p.h6
-rw-r--r--src/qml/jsruntime/qv4vme_moth.cpp6
-rw-r--r--tests/auto/qml/ecmascripttests/TestExpectations31
12 files changed, 174 insertions, 62 deletions
diff --git a/src/qml/jit/qv4assemblercommon.cpp b/src/qml/jit/qv4assemblercommon.cpp
index 0ae4da17fa..fadb9dce08 100644
--- a/src/qml/jit/qv4assemblercommon.cpp
+++ b/src/qml/jit/qv4assemblercommon.cpp
@@ -212,6 +212,13 @@ PlatformAssemblerCommon::Address PlatformAssemblerCommon::argStackAddress(int ar
return Address(StackPointerRegister, offset * PointerSize);
}
+JSC::MacroAssemblerBase::Address PlatformAssemblerCommon::inArgStackAddress(int arg)
+{
+ int offset = arg - ArgInRegCount;
+ Q_ASSERT(offset >= 0);
+ return Address(FramePointerRegister, -(offset + 1) * PointerSize);
+}
+
void PlatformAssemblerCommon::passAccumulatorAsArg(int arg)
{
#ifndef QT_NO_DEBUG
@@ -329,12 +336,48 @@ void PlatformAssemblerCommon::callRuntime(const char *functionName, const void *
}
}
-void JIT::PlatformAssemblerCommon::callRuntimeUnchecked(const char *functionName, const void *funcPtr)
+void PlatformAssemblerCommon::callRuntimeUnchecked(const char *functionName, const void *funcPtr)
{
functions.insert(funcPtr, functionName);
callAbsolute(funcPtr);
}
+void PlatformAssemblerCommon::tailCallRuntime(const char *functionName, const void *funcPtr)
+{
+ functions.insert(funcPtr, functionName);
+ setTailCallArg(EngineRegister, 1);
+ setTailCallArg(CppStackFrameRegister, 0);
+ freeStackSpace();
+ generatePlatformFunctionExit(/*tailCall =*/ true);
+ jumpAbsolute(funcPtr);
+}
+
+void PlatformAssemblerCommon::setTailCallArg(RegisterID src, int arg)
+{
+ if (arg < ArgInRegCount)
+ move(src, registerForArg(arg));
+ else
+ storePtr(src, inArgStackAddress(arg));
+}
+
+JSC::MacroAssemblerBase::Address PlatformAssemblerCommon::jsAlloca(int slotCount)
+{
+ Address jsStackTopAddr(EngineRegister, offsetof(EngineBase, jsStackTop));
+ RegisterID jsStackTop = AccumulatorRegisterValue;
+ loadPtr(jsStackTopAddr, jsStackTop);
+ addPtr(TrustedImm32(sizeof(Value) * slotCount), jsStackTop);
+ storePtr(jsStackTop, jsStackTopAddr);
+ return Address(jsStackTop, 0);
+}
+
+void PlatformAssemblerCommon::storeInt32AsValue(int srcInt, Address destAddr)
+{
+ store32(TrustedImm32(srcInt),
+ Address(destAddr.base, destAddr.offset + QV4::Value::valueOffset()));
+ store32(TrustedImm32(int(QV4::Value::ValueTypeInternal::Integer)),
+ Address(destAddr.base, destAddr.offset + QV4::Value::tagOffset()));
+}
+
} // JIT namespace
} // QV4 namepsace
diff --git a/src/qml/jit/qv4assemblercommon_p.h b/src/qml/jit/qv4assemblercommon_p.h
index d64b9d0e5d..cbbd6464d9 100644
--- a/src/qml/jit/qv4assemblercommon_p.h
+++ b/src/qml/jit/qv4assemblercommon_p.h
@@ -116,14 +116,15 @@ public:
move(Arg1Reg, EngineRegister);
}
- void generatePlatformFunctionExit()
+ void generatePlatformFunctionExit(bool tailCall = false)
{
pop(EngineRegister);
pop(CppStackFrameRegister);
pop(JSStackFrameRegister);
pop(); // exceptionHandler
pop(FramePointerRegister);
- ret();
+ if (!tailCall)
+ ret();
}
void callAbsolute(const void *funcPtr)
@@ -132,6 +133,12 @@ public:
call(ScratchRegister);
}
+ void jumpAbsolute(const void *funcPtr)
+ {
+ move(TrustedImmPtr(funcPtr), ScratchRegister);
+ jump(ScratchRegister);
+ }
+
void pushAligned(RegisterID reg)
{
subPtr(TrustedImm32(PointerSize), StackPointerRegister);
@@ -195,14 +202,15 @@ public:
move(Arg1Reg, EngineRegister);
}
- void generatePlatformFunctionExit()
+ void generatePlatformFunctionExit(bool tailCall = false)
{
pop(EngineRegister);
pop(CppStackFrameRegister);
pop(JSStackFrameRegister);
pop(); // exceptionHandler
pop(FramePointerRegister);
- ret();
+ if (!tailCall)
+ ret();
}
void callAbsolute(const void *funcPtr)
@@ -213,6 +221,12 @@ public:
addPtr(TrustedImm32(4 * PointerSize), StackPointerRegister);
}
+ void jumpAbsolute(const void *funcPtr)
+ {
+ move(TrustedImmPtr(funcPtr), ScratchRegister);
+ jump(ScratchRegister);
+ }
+
void pushAligned(RegisterID reg)
{
subPtr(TrustedImm32(PointerSize), StackPointerRegister);
@@ -280,7 +294,7 @@ public:
loadPtr(Address(FramePointerRegister, 3 * PointerSize), EngineRegister);
}
- void generatePlatformFunctionExit()
+ void generatePlatformFunctionExit(bool tailCall = false)
{
addPtr(TrustedImm32(8), StackPointerRegister);
pop(EngineRegister);
@@ -288,7 +302,8 @@ public:
pop(JSStackFrameRegister);
pop(); // exceptionHandler
pop(RegisterID::ebp);
- ret();
+ if (!tailCall)
+ ret();
}
void callAbsolute(const void *funcPtr)
@@ -297,6 +312,12 @@ public:
call(ScratchRegister);
}
+ void jumpAbsolute(const void *funcPtr)
+ {
+ move(TrustedImmPtr(funcPtr), ScratchRegister);
+ jump(ScratchRegister);
+ }
+
void pushAligned(RegisterID reg)
{
subPtr(TrustedImm32(PointerSize), StackPointerRegister);
@@ -375,13 +396,14 @@ public:
move(Arg1Reg, EngineRegister);
}
- void generatePlatformFunctionExit()
+ void generatePlatformFunctionExit(bool tailCall = false)
{
move(AccumulatorRegister, ReturnValueRegister);
popPair(EngineRegister, CppStackFrameRegister);
popPair(JSStackFrameRegister, AccumulatorRegister);
popPair(JSC::ARM64Registers::fp, JSC::ARM64Registers::lr);
- ret();
+ if (!tailCall)
+ ret();
}
void callAbsolute(const void *funcPtr)
@@ -390,6 +412,12 @@ public:
call(ScratchRegister);
}
+ void jumpAbsolute(const void *funcPtr)
+ {
+ move(TrustedImmPtr(funcPtr), ScratchRegister);
+ jump(ScratchRegister);
+ }
+
void pushAligned(RegisterID reg)
{
pushToSave(reg);
@@ -462,7 +490,7 @@ public:
move(Arg1Reg, EngineRegister);
}
- void generatePlatformFunctionExit()
+ void generatePlatformFunctionExit(bool tailCall = false)
{
move(AccumulatorRegisterValue, ReturnValueRegisterValue);
move(AccumulatorRegisterTag, ReturnValueRegisterTag);
@@ -476,7 +504,8 @@ public:
pop(); // exceptionHandler
pop(FramePointerRegister);
pop(JSC::ARMRegisters::lr);
- ret();
+ if (!tailCall)
+ ret();
}
void callAbsolute(const void *funcPtr)
@@ -485,6 +514,12 @@ public:
call(dataTempRegister);
}
+ void jumpAbsolute(const void *funcPtr)
+ {
+ move(TrustedImmPtr(funcPtr), dataTempRegister);
+ jump(dataTempRegister);
+ }
+
void pushAligned(RegisterID reg)
{
subPtr(TrustedImm32(PointerSize), StackPointerRegister);
@@ -663,11 +698,15 @@ public:
void passInt32AsArg(int value, int arg);
void callRuntime(const char *functionName, const void *funcPtr);
void callRuntimeUnchecked(const char *functionName, const void *funcPtr);
-
+ void tailCallRuntime(const char *functionName, const void *funcPtr);
+ void setTailCallArg(RegisterID src, int arg);
+ Address jsAlloca(int slotCount);
+ void storeInt32AsValue(int srcInt, Address destAddr);
private:
void passAccumulatorAsArg_internal(int arg, bool doPush);
static Address argStackAddress(int arg);
+ static Address inArgStackAddress(int arg);
private:
const Value* constantTable;
diff --git a/src/qml/jit/qv4baselineassembler.cpp b/src/qml/jit/qv4baselineassembler.cpp
index d53bb84827..f6b745632b 100644
--- a/src/qml/jit/qv4baselineassembler.cpp
+++ b/src/qml/jit/qv4baselineassembler.cpp
@@ -1446,7 +1446,29 @@ void BaselineAssembler::callRuntime(const char *functionName, const void *funcPt
void BaselineAssembler::saveAccumulatorInFrame()
{
pasm()->storeAccumulator(PlatformAssembler::Address(PlatformAssembler::JSStackFrameRegister,
- offsetof(CallData, accumulator)));
+ offsetof(CallData, accumulator)));
+}
+
+static ReturnedValue TheJitIs__Tail_Calling__ToTheRuntimeSoTheJitFrameIsMissing(CppStackFrame *frame, ExecutionEngine *engine)
+{
+ return Runtime::method_tailCall(frame, engine);
+}
+
+void BaselineAssembler::jsTailCall(int func, int thisObject, int argc, int argv)
+{
+ Address tos = pasm()->jsAlloca(4);
+
+ int32_t argcOffset = tos.offset + int32_t(sizeof(Value)) * Runtime::StackOffsets::tailCall_argc;
+ int32_t argvOffset = tos.offset + int32_t(sizeof(Value)) * Runtime::StackOffsets::tailCall_argv;
+ int32_t thisOffset = tos.offset + int32_t(sizeof(Value)) * Runtime::StackOffsets::tailCall_thisObject;
+ int32_t funcOffset = tos.offset + int32_t(sizeof(Value)) * Runtime::StackOffsets::tailCall_function;
+
+ pasm()->storeInt32AsValue(argc, Address(tos.base, argcOffset));
+ pasm()->storeInt32AsValue(argv, Address(tos.base, argvOffset));
+ pasm()->moveReg(regAddr(thisObject), Address(tos.base, thisOffset));
+ pasm()->moveReg(regAddr(func), Address(tos.base, funcOffset));
+ pasm()->tailCallRuntime("TheJitIs__Tail_Calling__ToTheRuntimeSoTheJitFrameIsMissing",
+ reinterpret_cast<void *>(TheJitIs__Tail_Calling__ToTheRuntimeSoTheJitFrameIsMissing));
}
void BaselineAssembler::checkException()
diff --git a/src/qml/jit/qv4baselineassembler_p.h b/src/qml/jit/qv4baselineassembler_p.h
index a2140ce47b..0aa508ae71 100644
--- a/src/qml/jit/qv4baselineassembler_p.h
+++ b/src/qml/jit/qv4baselineassembler_p.h
@@ -67,6 +67,9 @@ namespace JIT {
callRuntime(JIT_STRINGIFY(function), \
reinterpret_cast<void *>(&function), \
destination)
+#define GENERATE_TAIL_CALL(function) \
+ tailCallRuntime(JIT_STRINGIFY(function), \
+ reinterpret_cast<void *>(&function))
class BaselineAssembler {
public:
@@ -149,6 +152,7 @@ public:
void passInt32AsArg(int value, int arg);
void callRuntime(const char *functionName, const void *funcPtr, CallResultDestination dest);
void saveAccumulatorInFrame();
+ void jsTailCall(int func, int thisObject, int argc, int argv);
// exception/context stuff
void checkException();
diff --git a/src/qml/jit/qv4baselinejit.cpp b/src/qml/jit/qv4baselinejit.cpp
index 70d1672689..bbbe0c69c5 100644
--- a/src/qml/jit/qv4baselinejit.cpp
+++ b/src/qml/jit/qv4baselinejit.cpp
@@ -77,6 +77,8 @@ void BaselineJIT::generate()
#define STORE_ACC() as->saveAccumulatorInFrame()
#define BASELINEJIT_GENERATE_RUNTIME_CALL(function, destination) \
as->GENERATE_RUNTIME_CALL(function, destination)
+#define BASELINEJIT_GENERATE_TAIL_CALL(function) \
+ as->GENERATE_TAIL_CALL(function)
void BaselineJIT::generate_Ret()
{
@@ -555,17 +557,9 @@ void BaselineJIT::generate_CallWithSpread(int func, int thisObject, int argc, in
void BaselineJIT::generate_TailCall(int func, int thisObject, int argc, int argv)
{
STORE_IP();
- as->prepareCallWithArgCount(5);
- as->passInt32AsArg(argc, 4);
- as->passJSSlotAsArg(argv, 3);
- as->passJSSlotAsArg(thisObject, 2);
- as->passJSSlotAsArg(func, 1);
- as->passEngineAsArg(0);
- BASELINEJIT_GENERATE_RUNTIME_CALL(Runtime::method_tailCall, CallResultDestination::InAccumulator);
- as->checkException();
+ as->jsTailCall(func, thisObject, argc, argv);
}
-
void BaselineJIT::generate_Construct(int func, int argc, int argv)
{
STORE_IP();
diff --git a/src/qml/jsruntime/qv4functionobject.cpp b/src/qml/jsruntime/qv4functionobject.cpp
index f6b279ddaf..93cc55f8ad 100644
--- a/src/qml/jsruntime/qv4functionobject.cpp
+++ b/src/qml/jsruntime/qv4functionobject.cpp
@@ -498,7 +498,7 @@ ReturnedValue ArrowFunction::virtualCall(const FunctionObject *fo, const Value *
{
ExecutionEngine *engine = fo->engine();
CppStackFrame frame;
- frame.init(engine, fo->function(), argv, argc);
+ frame.init(engine, fo->function(), argv, argc, true);
frame.setupJSFrame(engine->jsStackTop, *fo, fo->scope(),
thisObject ? *thisObject : Value::undefinedValue(),
Value::undefinedValue());
@@ -506,7 +506,12 @@ ReturnedValue ArrowFunction::virtualCall(const FunctionObject *fo, const Value *
frame.push();
engine->jsStackTop += frame.requiredJSStackFrameSize();
- ReturnedValue result = Moth::VME::exec(&frame, engine);
+ ReturnedValue result;
+
+ do {
+ frame.pendingTailCall = false;
+ result = Moth::VME::exec(&frame, engine);
+ } while (frame.pendingTailCall);
frame.pop();
@@ -530,6 +535,7 @@ void Heap::ArrowFunction::init(QV4::ExecutionContext *scope, Function *function,
Q_ASSERT(internalClass && internalClass->verifyIndex(s.engine->id_length()->propertyKey(), Index_Length));
setProperty(s.engine, Index_Length, Value::fromInt32(int(function->compiledFunction->length)));
+ canBeTailCalled = true;
}
void Heap::ScriptFunction::init(QV4::ExecutionContext *scope, Function *function)
diff --git a/src/qml/jsruntime/qv4functionobject_p.h b/src/qml/jsruntime/qv4functionobject_p.h
index b08b333411..e03d49c74d 100644
--- a/src/qml/jsruntime/qv4functionobject_p.h
+++ b/src/qml/jsruntime/qv4functionobject_p.h
@@ -71,7 +71,8 @@ namespace Heap {
Member(class, Pointer, ExecutionContext *, scope) \
Member(class, NoMark, Function *, function) \
Member(class, NoMark, VTable::Call, jsCall) \
- Member(class, NoMark, VTable::CallAsConstructor, jsConstruct)
+ Member(class, NoMark, VTable::CallAsConstructor, jsConstruct) \
+ Member(class, NoMark, bool, canBeTailCalled)
DECLARE_HEAP_OBJECT(FunctionObject, Object) {
DECLARE_MARKOBJECTS(FunctionObject);
@@ -175,6 +176,7 @@ struct Q_QML_EXPORT FunctionObject: Object {
V4_NEEDS_DESTROY
enum { NInlineProperties = 1 };
+ bool canBeTailCalled() const { return d()->canBeTailCalled; }
Heap::ExecutionContext *scope() const { return d()->scope; }
Function *function() const { return d()->function; }
diff --git a/src/qml/jsruntime/qv4runtime.cpp b/src/qml/jsruntime/qv4runtime.cpp
index 470629bd1f..66cd06ee1f 100644
--- a/src/qml/jsruntime/qv4runtime.cpp
+++ b/src/qml/jsruntime/qv4runtime.cpp
@@ -1536,13 +1536,32 @@ ReturnedValue Runtime::method_constructWithSpread(ExecutionEngine *engine, const
return static_cast<const FunctionObject &>(function).callAsConstructor(arguments.argv, arguments.argc, &newTarget);
}
-ReturnedValue Runtime::method_tailCall(ExecutionEngine *engine, const Value &function, const Value &thisObject, Value *argv, int argc)
+ReturnedValue Runtime::method_tailCall(CppStackFrame *frame, ExecutionEngine *engine)
{
- //### unwinding the stack, etc, is done in a subsequent patch
+ // IMPORTANT! The JIT assumes that this method has the same amount (or less) arguments than
+ // the jitted function, so it can safely do a tail call.
+
+ Value *tos = engine->jsStackTop;
+ const Value &function = tos[StackOffsets::tailCall_function];
+ const Value &thisObject = tos[StackOffsets::tailCall_thisObject];
+ Value *argv = reinterpret_cast<Value *>(frame->jsFrame) + tos[StackOffsets::tailCall_argv].int_32();
+ int argc = tos[StackOffsets::tailCall_argc].int_32();
+
if (!function.isFunctionObject())
return engine->throwTypeError();
- return static_cast<const FunctionObject &>(function).call(&thisObject, argv, argc);
+ const FunctionObject &fo = static_cast<const FunctionObject &>(function);
+ if (!frame->callerCanHandleTailCall || !fo.canBeTailCalled() || engine->debugger()) {
+ // Cannot tailcall, do a normal call:
+ return fo.call(&thisObject, argv, argc);
+ }
+
+ memcpy(frame->jsFrame->args, argv, argc * sizeof(Value));
+ frame->init(engine, fo.function(), frame->jsFrame->args, argc, frame->callerCanHandleTailCall);
+ frame->setupJSFrame(frame->savedStackTop, fo, fo.scope(), thisObject, Primitive::undefinedValue());
+ engine->jsStackTop = frame->savedStackTop + frame->requiredJSStackFrameSize();
+ frame->pendingTailCall = true;
+ return Encode::undefined();
}
void Runtime::method_throwException(ExecutionEngine *engine, const Value &value)
diff --git a/src/qml/jsruntime/qv4runtimeapi_p.h b/src/qml/jsruntime/qv4runtimeapi_p.h
index 826b371c1d..d64178a72f 100644
--- a/src/qml/jsruntime/qv4runtimeapi_p.h
+++ b/src/qml/jsruntime/qv4runtimeapi_p.h
@@ -101,7 +101,7 @@ struct ExceptionCheck<void (*)(QV4::NoThrowEngine *, A, B, C)> {
F(ReturnedValue, callWithReceiver, (ExecutionEngine *engine, const Value &func, const Value *thisObject, Value *argv, int argc)) \
F(ReturnedValue, callPossiblyDirectEval, (ExecutionEngine *engine, Value *argv, int argc)) \
F(ReturnedValue, callWithSpread, (ExecutionEngine *engine, const Value &func, const Value &thisObject, Value *argv, int argc)) \
- F(ReturnedValue, tailCall, (ExecutionEngine *engine, const Value &func, const Value &thisObject, Value *argv, int argc)) \
+ F(ReturnedValue, tailCall, (CppStackFrame *frame, ExecutionEngine *engine)) \
\
/* construct */ \
F(ReturnedValue, construct, (ExecutionEngine *engine, const Value &func, const Value &newTarget, Value *argv, int argc)) \
@@ -234,6 +234,12 @@ struct Q_QML_PRIVATE_EXPORT Runtime {
FOR_EACH_RUNTIME_METHOD(RUNTIME_METHOD)
#undef RUNTIME_METHOD
+ struct StackOffsets {
+ static const int tailCall_function = -1;
+ static const int tailCall_thisObject = -2;
+ static const int tailCall_argv = -3;
+ static const int tailCall_argc = -4;
+ };
};
static_assert(std::is_standard_layout<Runtime>::value, "Runtime needs to be standard layout in order for us to be able to use offsetof");
diff --git a/src/qml/jsruntime/qv4stackframe_p.h b/src/qml/jsruntime/qv4stackframe_p.h
index dd68c29a88..a97ae0e7c9 100644
--- a/src/qml/jsruntime/qv4stackframe_p.h
+++ b/src/qml/jsruntime/qv4stackframe_p.h
@@ -123,8 +123,10 @@ struct Q_QML_EXPORT CppStackFrame {
const char *unwindLabel;
int unwindLevel;
bool yieldIsIterator;
+ bool callerCanHandleTailCall;
+ bool pendingTailCall;
- void init(EngineBase *engine, Function *v4Function, const Value *argv, int argc) {
+ void init(EngineBase *engine, Function *v4Function, const Value *argv, int argc, bool callerCanHandleTailCall = false) {
this->engine = engine;
this->v4Function = v4Function;
@@ -136,6 +138,8 @@ struct Q_QML_EXPORT CppStackFrame {
unwindLabel = nullptr;
unwindLevel = 0;
yieldIsIterator = false;
+ this->callerCanHandleTailCall = callerCanHandleTailCall;
+ pendingTailCall = false;
}
void push() {
diff --git a/src/qml/jsruntime/qv4vme_moth.cpp b/src/qml/jsruntime/qv4vme_moth.cpp
index 7fd7be8e38..5d95c8c2ab 100644
--- a/src/qml/jsruntime/qv4vme_moth.cpp
+++ b/src/qml/jsruntime/qv4vme_moth.cpp
@@ -778,7 +778,11 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine,
MOTH_BEGIN_INSTR(TailCall)
STORE_IP();
- acc = Runtime::method_tailCall(engine, STACK_VALUE(func), STACK_VALUE(thisObject), stack + argv, argc);
+ *engine->jsAlloca(1) = Primitive::fromInt32(argc);
+ *engine->jsAlloca(1) = Primitive::fromInt32(argv);
+ *engine->jsAlloca(1) = STACK_VALUE(thisObject);
+ *engine->jsAlloca(1) = STACK_VALUE(func);
+ return Runtime::method_tailCall(frame, engine);
CHECK_EXCEPTION;
MOTH_END_INSTR(TailCall)
diff --git a/tests/auto/qml/ecmascripttests/TestExpectations b/tests/auto/qml/ecmascripttests/TestExpectations
index 6236fe5036..f5a31856b1 100644
--- a/tests/auto/qml/ecmascripttests/TestExpectations
+++ b/tests/auto/qml/ecmascripttests/TestExpectations
@@ -536,12 +536,6 @@ language/expressions/call/eval-spread-empty-leading.js fails
language/expressions/call/eval-spread-empty-trailing.js fails
language/expressions/call/eval-spread.js fails
language/expressions/call/scope-lex-open.js fails
-language/expressions/call/tco-call-args.js strictFails
-language/expressions/call/tco-member-args.js strictFails
-language/expressions/call/tco-non-eval-function-dynamic.js sloppyFails
-language/expressions/call/tco-non-eval-function.js sloppyFails
-language/expressions/call/tco-non-eval-global.js sloppyFails
-language/expressions/call/tco-non-eval-with.js sloppyFails
language/expressions/class/gen-meth-dflt-params-ref-later.js fails
language/expressions/class/gen-meth-dflt-params-ref-self.js fails
language/expressions/class/gen-meth-static-dflt-params-ref-later.js fails
@@ -557,7 +551,6 @@ language/expressions/class/scope-setter-paramsbody-var-open.js fails
language/expressions/class/scope-static-gen-meth-paramsbody-var-open.js fails
language/expressions/class/scope-static-meth-paramsbody-var-open.js fails
language/expressions/class/scope-static-setter-paramsbody-var-open.js fails
-language/expressions/comma/tco-final.js strictFails
language/expressions/compound-assignment/S11.13.2_A5.10_T1.js sloppyFails
language/expressions/compound-assignment/S11.13.2_A5.10_T2.js sloppyFails
language/expressions/compound-assignment/S11.13.2_A5.10_T3.js sloppyFails
@@ -636,8 +629,6 @@ language/expressions/compound-assignment/S11.13.2_A7.7_T4.js fails
language/expressions/compound-assignment/S11.13.2_A7.8_T4.js fails
language/expressions/compound-assignment/S11.13.2_A7.9_T4.js fails
language/expressions/delete/super-property.js fails
-language/expressions/conditional/tco-cond.js strictFails
-language/expressions/conditional/tco-pos.js strictFails
language/expressions/function/arguments-with-arguments-fn.js sloppyFails
language/expressions/function/arguments-with-arguments-lex.js sloppyFails
language/expressions/function/dflt-params-ref-later.js fails
@@ -672,8 +663,6 @@ language/expressions/generators/yield-as-identifier-in-nested-function.js sloppy
language/expressions/generators/yield-as-literal-property-name.js fails
language/expressions/generators/yield-as-property-name.js fails
language/expressions/generators/yield-identifier-non-strict.js sloppyFails
-language/expressions/logical-and/tco-right.js strictFails
-language/expressions/logical-or/tco-right.js strictFails
language/expressions/object/let-non-strict-access.js sloppyFails
language/expressions/object/let-non-strict-syntax.js sloppyFails
language/expressions/object/method-definition/gen-meth-dflt-params-ref-later.js fails
@@ -731,12 +720,10 @@ language/expressions/tagged-template/cache-eval-inner-function.js fails
language/expressions/tagged-template/cache-same-site-top-level.js fails
language/expressions/tagged-template/cache-same-site.js fails
language/expressions/tagged-template/invalid-escape-sequences.js fails
-language/expressions/tagged-template/tco-call.js strictFails
language/expressions/tagged-template/tco-member.js strictFails
language/expressions/tagged-template/template-object-frozen-non-strict.js sloppyFails
language/expressions/tagged-template/template-object-frozen-strict.js strictFails
language/expressions/tagged-template/template-object.js fails
-language/expressions/tco-pos.js strictFails
language/expressions/template-literal/tv-character-escape-sequence.js fails
language/expressions/template-literal/tv-hex-escape-sequence.js fails
language/expressions/template-literal/tv-line-continuation.js fails
@@ -771,8 +758,6 @@ language/statements/async-function/cptn-decl.js fails
language/statements/async-function/declaration-returns-promise.js fails
language/statements/async-function/evaluation-body.js fails
language/statements/async-function/syntax-declaration-line-terminators-allowed.js fails
-language/statements/block/tco-stmt-list.js strictFails
-language/statements/block/tco-stmt.js strictFails
language/statements/class/constructor-inferred-observable-iteration.js fails
language/statements/class/cptn-decl.js fails
language/statements/class/definition/class-method-returns-promise.js fails
@@ -804,7 +789,6 @@ language/statements/class/subclass/bound-function.js fails
language/statements/class/subclass/builtin-objects/Promise/regular-subclassing.js fails
language/statements/class/subclass/builtin-objects/Promise/super-must-be-called.js fails
language/statements/class/subclass/default-constructor-spread-override.js fails
-language/statements/do-while/tco-body.js strictFails
language/statements/for-in/head-lhs-let.js sloppyFails
language/statements/for-in/head-var-bound-names-let.js sloppyFails
language/statements/for-in/identifier-let-allowed-as-lefthandside-expression-not-strict.js sloppyFails
@@ -832,10 +816,6 @@ language/statements/for-of/head-var-bound-names-let.js sloppyFails
language/statements/for-of/iterator-next-reference.js fails
language/statements/for/head-lhs-let.js sloppyFails
language/statements/for/scope-body-lex-open.js fails
-language/statements/for/tco-const-body.js strictFails
-language/statements/for/tco-let-body.js strictFails
-language/statements/for/tco-lhs-body.js strictFails
-language/statements/for/tco-var-body.js strictFails
language/statements/function/13.2-30-s.js fails
language/statements/function/S13_A15_T4.js sloppyFails
language/statements/function/arguments-with-arguments-fn.js sloppyFails
@@ -865,23 +845,12 @@ language/statements/generators/yield-as-identifier-in-nested-function.js sloppyF
language/statements/generators/yield-as-literal-property-name.js fails
language/statements/generators/yield-as-property-name.js fails
language/statements/generators/yield-identifier-non-strict.js sloppyFails
-language/statements/if/tco-else-body.js strictFails
-language/statements/if/tco-if-body.js strictFails
-language/statements/labeled/tco.js strictFails
language/statements/let/block-local-closure-set-before-initialization.js fails
language/statements/let/function-local-closure-set-before-initialization.js fails
language/statements/let/global-closure-set-before-initialization.js fails
-language/statements/return/tco.js strictFails
-language/statements/switch/tco-case-body-dflt.js strictFails
-language/statements/switch/tco-case-body.js strictFails
-language/statements/switch/tco-dftl-body.js strictFails
language/statements/throw/S12.13_A2_T6.js strictFails
language/statements/try/S12.14_A18_T6.js strictFails
language/statements/try/scope-catch-block-lex-open.js fails
-language/statements/try/tco-catch-finally.js strictFails
-language/statements/try/tco-catch.js strictFails
-language/statements/try/tco-finally.js strictFails
language/statements/variable/binding-resolution.js sloppyFails
-language/statements/while/tco-body.js strictFails
language/statements/with/unscopables-inc-dec.js sloppyFails
language/types/reference/put-value-prop-base-primitive.js strictFails