Diff
Modified: trunk/Source/_javascript_Core/ChangeLog (204161 => 204162)
--- trunk/Source/_javascript_Core/ChangeLog 2016-08-05 02:59:13 UTC (rev 204161)
+++ trunk/Source/_javascript_Core/ChangeLog 2016-08-05 06:46:55 UTC (rev 204162)
@@ -1,3 +1,52 @@
+2016-08-04 Saam Barati <sbar...@apple.com>
+
+ Restore CodeBlock jettison code to jettison when a CodeBlock has been alive for a long time
+ https://bugs.webkit.org/show_bug.cgi?id=151241
+
+ Reviewed by Benjamin Poulain.
+
+ This patch rolls back in the jettisoning policy from https://bugs.webkit.org/show_bug.cgi?id=149727.
+ We can now jettison a CodeBlock when it has been alive for a long time
+ and is only pointed to by its owner executable. I haven't been able to get this
+ patch to crash on anything it used to crash on, so I suspect we've fixed the bugs that
+ were causing this before. I've also added some stress options for this feature that
+ will cause us to either eagerly old-age jettison or to old-age jettison whenever it's legal.
+ These options helped me find a bug where we would ask an Executable to create a CodeBlock,
+ and then the Executable would do some other allocations, causing a GC, immediately causing
+ the CodeBlock to jettison. There is a small chance that this was the bug we were seeing before,
+ however, it's unlikely given that the previous timing metrics require at least 5 second between
+ compiling to jettisoning.
+
+ This patch also enables the stress options for various modes
+ of JSC stress tests.
+
+ * bytecode/CodeBlock.cpp:
+ (JSC::CodeBlock::shouldJettisonDueToWeakReference):
+ (JSC::timeToLive):
+ (JSC::CodeBlock::shouldJettisonDueToOldAge):
+ * interpreter/CallFrame.h:
+ (JSC::ExecState::callee):
+ (JSC::ExecState::unsafeCallee):
+ (JSC::ExecState::codeBlock):
+ (JSC::ExecState::addressOfCodeBlock):
+ (JSC::ExecState::unsafeCodeBlock):
+ (JSC::ExecState::scope):
+ * interpreter/Interpreter.cpp:
+ (JSC::Interpreter::execute):
+ (JSC::Interpreter::executeCall):
+ (JSC::Interpreter::executeConstruct):
+ (JSC::Interpreter::prepareForRepeatCall):
+ * jit/JITOperations.cpp:
+ * llint/LLIntSlowPaths.cpp:
+ (JSC::LLInt::setUpCall):
+ * runtime/Executable.cpp:
+ (JSC::ScriptExecutable::installCode):
+ (JSC::setupJIT):
+ (JSC::ScriptExecutable::prepareForExecutionImpl):
+ * runtime/Executable.h:
+ (JSC::ScriptExecutable::prepareForExecution):
+ * runtime/Options.h:
+
2016-08-04 Yusuke Suzuki <utatane....@gmail.com>
[ES6] JSModuleNamespaceObject's Symbol.iterator function should have name
Modified: trunk/Source/_javascript_Core/bytecode/CodeBlock.cpp (204161 => 204162)
--- trunk/Source/_javascript_Core/bytecode/CodeBlock.cpp 2016-08-05 02:59:13 UTC (rev 204161)
+++ trunk/Source/_javascript_Core/bytecode/CodeBlock.cpp 2016-08-05 06:46:55 UTC (rev 204162)
@@ -2651,9 +2651,51 @@
return !Heap::isMarked(this);
}
+static std::chrono::milliseconds timeToLive(JITCode::JITType jitType)
+{
+ if (UNLIKELY(Options::useEagerCodeBlockJettisonTiming())) {
+ switch (jitType) {
+ case JITCode::InterpreterThunk:
+ return std::chrono::milliseconds(10);
+ case JITCode::BaselineJIT:
+ return std::chrono::milliseconds(10 + 20);
+ case JITCode::DFGJIT:
+ return std::chrono::milliseconds(40);
+ case JITCode::FTLJIT:
+ return std::chrono::milliseconds(120);
+ default:
+ return std::chrono::milliseconds::max();
+ }
+ }
+
+ switch (jitType) {
+ case JITCode::InterpreterThunk:
+ return std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::seconds(5));
+ case JITCode::BaselineJIT:
+ // Effectively 10 additional seconds, since BaselineJIT and
+ // InterpreterThunk share a CodeBlock.
+ return std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::seconds(5 + 10));
+ case JITCode::DFGJIT:
+ return std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::seconds(20));
+ case JITCode::FTLJIT:
+ return std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::seconds(60));
+ default:
+ return std::chrono::milliseconds::max();
+ }
+}
+
bool CodeBlock::shouldJettisonDueToOldAge()
{
- return false;
+ if (Heap::isMarked(this))
+ return false;
+
+ if (UNLIKELY(Options::forceCodeBlockToJettisonDueToOldAge()))
+ return true;
+
+ if (timeSinceCreation() < timeToLive(jitType()))
+ return false;
+
+ return true;
}
#if ENABLE(DFG_JIT)
Modified: trunk/Source/_javascript_Core/interpreter/CallFrame.h (204161 => 204162)
--- trunk/Source/_javascript_Core/interpreter/CallFrame.h 2016-08-05 02:59:13 UTC (rev 204161)
+++ trunk/Source/_javascript_Core/interpreter/CallFrame.h 2016-08-05 06:46:55 UTC (rev 204162)
@@ -90,6 +90,7 @@
JSObject* callee() const { return this[CallFrameSlot::callee].object(); }
SUPPRESS_ASAN JSValue unsafeCallee() const { return this[CallFrameSlot::callee].asanUnsafeJSValue(); }
CodeBlock* codeBlock() const { return this[CallFrameSlot::codeBlock].Register::codeBlock(); }
+ CodeBlock** addressOfCodeBlock() const { return bitwise_cast<CodeBlock**>(this + CallFrameSlot::codeBlock); }
SUPPRESS_ASAN CodeBlock* unsafeCodeBlock() const { return this[CallFrameSlot::codeBlock].Register::asanUnsafeCodeBlock(); }
JSScope* scope(int scopeRegisterOffset) const
{
Modified: trunk/Source/_javascript_Core/interpreter/Interpreter.cpp (204161 => 204162)
--- trunk/Source/_javascript_Core/interpreter/Interpreter.cpp 2016-08-05 02:59:13 UTC (rev 204161)
+++ trunk/Source/_javascript_Core/interpreter/Interpreter.cpp 2016-08-05 06:46:55 UTC (rev 204162)
@@ -944,11 +944,14 @@
if (JSObject* error = program->initializeGlobalProperties(vm, callFrame, scope))
return checkedReturn(callFrame->vm().throwException(callFrame, error));
- if (JSObject* error = program->prepareForExecution(callFrame, nullptr, scope, CodeForCall))
- return checkedReturn(callFrame->vm().throwException(callFrame, error));
+ ProgramCodeBlock* codeBlock;
+ {
+ CodeBlock* tempCodeBlock;
+ if (JSObject* error = program->prepareForExecution<ProgramExecutable>(callFrame, nullptr, scope, CodeForCall, tempCodeBlock))
+ return checkedReturn(callFrame->vm().throwException(callFrame, error));
+ codeBlock = jsCast<ProgramCodeBlock*>(tempCodeBlock);
+ }
- ProgramCodeBlock* codeBlock = program->codeBlock();
-
if (UNLIKELY(vm.shouldTriggerTermination(callFrame)))
return throwTerminatedExecutionException(callFrame);
@@ -995,11 +998,10 @@
if (isJSCall) {
// Compile the callee:
- JSObject* compileError = callData.js.functionExecutable->prepareForExecution(callFrame, jsCast<JSFunction*>(function), scope, CodeForCall);
- if (UNLIKELY(!!compileError)) {
+ JSObject* compileError = callData.js.functionExecutable->prepareForExecution<FunctionExecutable>(callFrame, jsCast<JSFunction*>(function), scope, CodeForCall, newCodeBlock);
+ if (UNLIKELY(!!compileError))
return checkedReturn(callFrame->vm().throwException(callFrame, compileError));
- }
- newCodeBlock = callData.js.functionExecutable->codeBlockForCall();
+
ASSERT(!!newCodeBlock);
newCodeBlock->m_shouldAlwaysBeInlined = false;
} else
@@ -1057,11 +1059,10 @@
if (isJSConstruct) {
// Compile the callee:
- JSObject* compileError = constructData.js.functionExecutable->prepareForExecution(callFrame, jsCast<JSFunction*>(constructor), scope, CodeForConstruct);
- if (UNLIKELY(!!compileError)) {
+ JSObject* compileError = constructData.js.functionExecutable->prepareForExecution<FunctionExecutable>(callFrame, jsCast<JSFunction*>(constructor), scope, CodeForConstruct, newCodeBlock);
+ if (UNLIKELY(!!compileError))
return checkedReturn(callFrame->vm().throwException(callFrame, compileError));
- }
- newCodeBlock = constructData.js.functionExecutable->codeBlockForConstruct();
+
ASSERT(!!newCodeBlock);
newCodeBlock->m_shouldAlwaysBeInlined = false;
} else
@@ -1101,12 +1102,12 @@
return CallFrameClosure();
// Compile the callee:
- JSObject* error = functionExecutable->prepareForExecution(callFrame, function, scope, CodeForCall);
+ CodeBlock* newCodeBlock;
+ JSObject* error = functionExecutable->prepareForExecution<FunctionExecutable>(callFrame, function, scope, CodeForCall, newCodeBlock);
if (error) {
callFrame->vm().throwException(callFrame, error);
return CallFrameClosure();
}
- CodeBlock* newCodeBlock = functionExecutable->codeBlockForCall();
newCodeBlock->m_shouldAlwaysBeInlined = false;
size_t argsCount = argumentCountIncludingThis;
@@ -1176,10 +1177,14 @@
}
}
- JSObject* compileError = eval->prepareForExecution(callFrame, nullptr, scope, CodeForCall);
- if (UNLIKELY(!!compileError))
- return checkedReturn(callFrame->vm().throwException(callFrame, compileError));
- EvalCodeBlock* codeBlock = eval->codeBlock();
+ EvalCodeBlock* codeBlock;
+ {
+ CodeBlock* tempCodeBlock;
+ JSObject* compileError = eval->prepareForExecution<EvalExecutable>(callFrame, nullptr, scope, CodeForCall, tempCodeBlock);
+ if (UNLIKELY(!!compileError))
+ return checkedReturn(callFrame->vm().throwException(callFrame, compileError));
+ codeBlock = jsCast<EvalCodeBlock*>(tempCodeBlock);
+ }
// We can't declare a "var"/"function" that overwrites a global "let"/"const"/"class" in a sloppy-mode eval.
if (variableObject->isGlobalObject() && !eval->isStrictMode() && (numVariables || numFunctions)) {
@@ -1253,10 +1258,14 @@
if (UNLIKELY(!vm.isSafeToRecurseSoft()))
return checkedReturn(throwStackOverflowError(callFrame));
- JSObject* compileError = executable->prepareForExecution(callFrame, nullptr, scope, CodeForCall);
- if (UNLIKELY(!!compileError))
- return checkedReturn(callFrame->vm().throwException(callFrame, compileError));
- ModuleProgramCodeBlock* codeBlock = executable->codeBlock();
+ ModuleProgramCodeBlock* codeBlock;
+ {
+ CodeBlock* tempCodeBlock;
+ JSObject* compileError = executable->prepareForExecution<ModuleProgramExecutable>(callFrame, nullptr, scope, CodeForCall, tempCodeBlock);
+ if (UNLIKELY(!!compileError))
+ return checkedReturn(callFrame->vm().throwException(callFrame, compileError));
+ codeBlock = jsCast<ModuleProgramCodeBlock*>(tempCodeBlock);
+ }
if (UNLIKELY(vm.shouldTriggerTermination(callFrame)))
return throwTerminatedExecutionException(callFrame);
Modified: trunk/Source/_javascript_Core/jit/JITOperations.cpp (204161 => 204162)
--- trunk/Source/_javascript_Core/jit/JITOperations.cpp 2016-08-05 02:59:13 UTC (rev 204161)
+++ trunk/Source/_javascript_Core/jit/JITOperations.cpp 2016-08-05 06:46:55 UTC (rev 204162)
@@ -900,7 +900,8 @@
reinterpret_cast<void*>(KeepTheFrame));
}
- JSObject* error = functionExecutable->prepareForExecution(execCallee, callee, scope, kind);
+ CodeBlock** codeBlockSlot = execCallee->addressOfCodeBlock();
+ JSObject* error = functionExecutable->prepareForExecution<FunctionExecutable>(execCallee, callee, scope, kind, *codeBlockSlot);
if (error) {
exec->vm().throwException(exec, error);
return encodeResult(
@@ -907,7 +908,7 @@
vm->getCTIStub(throwExceptionFromCallSlowPathGenerator).code().executableAddress(),
reinterpret_cast<void*>(KeepTheFrame));
}
- codeBlock = functionExecutable->codeBlockFor(kind);
+ codeBlock = *codeBlockSlot;
ArityCheckMode arity;
if (execCallee->argumentCountIncludingThis() < static_cast<size_t>(codeBlock->numParameters()) || callLinkInfo->isVarargs())
arity = MustCheckArity;
@@ -954,7 +955,8 @@
reinterpret_cast<void*>(KeepTheFrame));
}
- JSObject* error = functionExecutable->prepareForExecution(execCallee, function, scope, kind);
+ CodeBlock** codeBlockSlot = execCallee->addressOfCodeBlock();
+ JSObject* error = functionExecutable->prepareForExecution<FunctionExecutable>(execCallee, function, scope, kind, *codeBlockSlot);
if (error) {
exec->vm().throwException(exec, error);
return encodeResult(
Modified: trunk/Source/_javascript_Core/llint/LLIntSlowPaths.cpp (204161 => 204162)
--- trunk/Source/_javascript_Core/llint/LLIntSlowPaths.cpp 2016-08-05 02:59:13 UTC (rev 204161)
+++ trunk/Source/_javascript_Core/llint/LLIntSlowPaths.cpp 2016-08-05 06:46:55 UTC (rev 204162)
@@ -1266,10 +1266,11 @@
if (!isCall(kind) && functionExecutable->constructAbility() == ConstructAbility::CannotConstruct)
LLINT_CALL_THROW(exec, createNotAConstructorError(exec, callee));
- JSObject* error = functionExecutable->prepareForExecution(execCallee, callee, scope, kind);
+ CodeBlock** codeBlockSlot = execCallee->addressOfCodeBlock();
+ JSObject* error = functionExecutable->prepareForExecution<FunctionExecutable>(execCallee, callee, scope, kind, *codeBlockSlot);
if (error)
LLINT_CALL_THROW(exec, error);
- codeBlock = functionExecutable->codeBlockFor(kind);
+ codeBlock = *codeBlockSlot;
ASSERT(codeBlock);
ArityCheckMode arity;
if (execCallee->argumentCountIncludingThis() < static_cast<size_t>(codeBlock->numParameters()))
Modified: trunk/Source/_javascript_Core/runtime/Executable.cpp (204161 => 204162)
--- trunk/Source/_javascript_Core/runtime/Executable.cpp 2016-08-05 02:59:13 UTC (rev 204161)
+++ trunk/Source/_javascript_Core/runtime/Executable.cpp 2016-08-05 06:46:55 UTC (rev 204162)
@@ -177,7 +177,8 @@
{
ASSERT(vm.heap.isDeferred());
- CODEBLOCK_LOG_EVENT(genericCodeBlock, "installCode", ());
+ if (genericCodeBlock)
+ CODEBLOCK_LOG_EVENT(genericCodeBlock, "installCode", ());
CodeBlock* oldCodeBlock = nullptr;
@@ -399,10 +400,10 @@
}
JSObject* ScriptExecutable::prepareForExecutionImpl(
- ExecState* exec, JSFunction* function, JSScope* scope, CodeSpecializationKind kind)
+ ExecState* exec, JSFunction* function, JSScope* scope, CodeSpecializationKind kind, CodeBlock*& resultCodeBlock)
{
VM& vm = exec->vm();
- DeferGC deferGC(vm.heap);
+ DeferGCForAWhile deferGC(vm.heap);
if (vm.getAndClearFailNextNewCodeBlock())
return createError(exec->callerFrame(), ASCIILiteral("Forced Failure"));
@@ -409,6 +410,7 @@
JSObject* exception = 0;
CodeBlock* codeBlock = newCodeBlockFor(kind, function, scope, exception);
+ resultCodeBlock = codeBlock;
if (!codeBlock) {
RELEASE_ASSERT(exception);
return exception;
@@ -423,7 +425,7 @@
setupJIT(vm, codeBlock);
installCode(*codeBlock->vm(), codeBlock, codeBlock->codeType(), codeBlock->specializationKind());
- return 0;
+ return nullptr;
}
const ClassInfo EvalExecutable::s_info = { "EvalExecutable", &ScriptExecutable::s_info, 0, CREATE_METHOD_TABLE(EvalExecutable) };
Modified: trunk/Source/_javascript_Core/runtime/Executable.h (204161 => 204162)
--- trunk/Source/_javascript_Core/runtime/Executable.h 2016-08-05 02:59:13 UTC (rev 204161)
+++ trunk/Source/_javascript_Core/runtime/Executable.h 2016-08-05 06:46:55 UTC (rev 204162)
@@ -367,19 +367,21 @@
void installCode(VM&, CodeBlock*, CodeType, CodeSpecializationKind);
CodeBlock* newCodeBlockFor(CodeSpecializationKind, JSFunction*, JSScope*, JSObject*& exception);
CodeBlock* newReplacementCodeBlockFor(CodeSpecializationKind);
-
- JSObject* prepareForExecution(ExecState* exec, JSFunction* function, JSScope* scope, CodeSpecializationKind kind)
- {
- if (hasJITCodeFor(kind))
- return 0;
- return prepareForExecutionImpl(exec, function, scope, kind);
- }
+ // This function has an interesting GC story. Callers of this function are asking us to create a CodeBlock
+ // that is not jettisoned before this function returns. Callers are essentially asking for a strong reference
+ // to the CodeBlock. Because the Executable may be allocating the CodeBlock, we require callers to pass in
+ // their CodeBlock*& reference because it's safe for CodeBlock to be jettisoned if Executable is the only thing
+ // to point to it. This forces callers to have a CodeBlock* in a register or on the stack that will be marked
+ // by conservative GC if a GC happens after we create the CodeBlock.
+ template <typename ExecutableType>
+ JSObject* prepareForExecution(ExecState*, JSFunction*, JSScope*, CodeSpecializationKind, CodeBlock*& resultCodeBlock);
+
template <typename Functor> void forEachCodeBlock(Functor&&);
private:
friend class ExecutableBase;
- JSObject* prepareForExecutionImpl(ExecState*, JSFunction*, JSScope*, CodeSpecializationKind);
+ JSObject* prepareForExecutionImpl(ExecState*, JSFunction*, JSScope*, CodeSpecializationKind, CodeBlock*&);
protected:
ScriptExecutable(Structure*, VM&, const SourceCode&, bool isInStrictContext, DerivedContextType, bool isInArrowFunctionContext, EvalContextType, Intrinsic);
@@ -739,6 +741,25 @@
};
#endif
+template <typename ExecutableType>
+JSObject* ScriptExecutable::prepareForExecution(ExecState* exec, JSFunction* function, JSScope* scope, CodeSpecializationKind kind, CodeBlock*& resultCodeBlock)
+{
+ if (hasJITCodeFor(kind)) {
+ if (std::is_same<ExecutableType, EvalExecutable>::value)
+ resultCodeBlock = jsCast<CodeBlock*>(jsCast<EvalExecutable*>(this)->codeBlock());
+ else if (std::is_same<ExecutableType, ProgramExecutable>::value)
+ resultCodeBlock = jsCast<CodeBlock*>(jsCast<ProgramExecutable*>(this)->codeBlock());
+ else if (std::is_same<ExecutableType, ModuleProgramExecutable>::value)
+ resultCodeBlock = jsCast<CodeBlock*>(jsCast<ModuleProgramExecutable*>(this)->codeBlock());
+ else if (std::is_same<ExecutableType, FunctionExecutable>::value)
+ resultCodeBlock = jsCast<CodeBlock*>(jsCast<FunctionExecutable*>(this)->codeBlockFor(kind));
+ else
+ RELEASE_ASSERT_NOT_REACHED();
+ return nullptr;
+ }
+ return prepareForExecutionImpl(exec, function, scope, kind, resultCodeBlock);
+}
+
} // namespace JSC
#endif // Executable_h
Modified: trunk/Source/_javascript_Core/runtime/Options.h (204161 => 204162)
--- trunk/Source/_javascript_Core/runtime/Options.h 2016-08-05 02:59:13 UTC (rev 204161)
+++ trunk/Source/_javascript_Core/runtime/Options.h 2016-08-05 06:46:55 UTC (rev 204162)
@@ -322,6 +322,8 @@
v(unsigned, forceRAMSize, 0, Normal, nullptr) \
v(bool, recordGCPauseTimes, false, Normal, nullptr) \
v(bool, logHeapStatisticsAtExit, false, Normal, nullptr) \
+ v(bool, forceCodeBlockToJettisonDueToOldAge, false, Normal, "If true, this means that anytime we can jettison a CodeBlock due to old age, we do.") \
+ v(bool, useEagerCodeBlockJettisonTiming, false, Normal, "If true, the time slices for jettisoning a CodeBlock due to old age are shrunk significantly.") \
\
v(bool, useTypeProfiler, false, Normal, nullptr) \
v(bool, useControlFlowProfiler, false, Normal, nullptr) \
Modified: trunk/Tools/ChangeLog (204161 => 204162)
--- trunk/Tools/ChangeLog 2016-08-05 02:59:13 UTC (rev 204161)
+++ trunk/Tools/ChangeLog 2016-08-05 06:46:55 UTC (rev 204162)
@@ -1,3 +1,12 @@
+2016-08-04 Saam Barati <sbar...@apple.com>
+
+ Restore CodeBlock jettison code to jettison when a CodeBlock has been alive for a long time
+ https://bugs.webkit.org/show_bug.cgi?id=151241
+
+ Reviewed by Benjamin Poulain.
+
+ * Scripts/run-jsc-stress-tests:
+
2016-08-04 Dean Johnson <dean_john...@apple.com>
UI improvements to Flakiness Dashboard.
Modified: trunk/Tools/Scripts/run-jsc-stress-tests (204161 => 204162)
--- trunk/Tools/Scripts/run-jsc-stress-tests 2016-08-05 02:59:13 UTC (rev 204161)
+++ trunk/Tools/Scripts/run-jsc-stress-tests 2016-08-05 06:46:55 UTC (rev 204162)
@@ -419,7 +419,7 @@
# We force all tests to use a smaller (1.5M) stack so that stack overflow tests can run faster.
BASE_OPTIONS = ["--useFTLJIT=false", "--useFunctionDotArguments=true", "--maxPerThreadStackUsage=1572864"]
-EAGER_OPTIONS = ["--thresholdForJITAfterWarmUp=10", "--thresholdForJITSoon=10", "--thresholdForOptimizeAfterWarmUp=20", "--thresholdForOptimizeAfterLongWarmUp=20", "--thresholdForOptimizeSoon=20", "--thresholdForFTLOptimizeAfterWarmUp=20", "--thresholdForFTLOptimizeSoon=20", "--maximumEvalCacheableSourceLength=150000"]
+EAGER_OPTIONS = ["--thresholdForJITAfterWarmUp=10", "--thresholdForJITSoon=10", "--thresholdForOptimizeAfterWarmUp=20", "--thresholdForOptimizeAfterLongWarmUp=20", "--thresholdForOptimizeSoon=20", "--thresholdForFTLOptimizeAfterWarmUp=20", "--thresholdForFTLOptimizeSoon=20", "--maximumEvalCacheableSourceLength=150000", "--useEagerCodeBlockJettisonTiming=true"]
NO_CJIT_OPTIONS = ["--useConcurrentJIT=false", "--thresholdForJITAfterWarmUp=100"]
FTL_OPTIONS = ["--useFTLJIT=true"]
@@ -876,7 +876,7 @@
end
def runDFGMaximalFlushPhase
- run("dfg-maximal-flush-validate-no-cjit", "--validateGraph=true", "--useMaximalFlushInsertionPhase=true", *NO_CJIT_OPTIONS)
+ run("dfg-maximal-flush-validate-no-cjit", "--forceCodeBlockToJettisonDueToOldAge=true", "--validateGraph=true", "--useMaximalFlushInsertionPhase=true", *NO_CJIT_OPTIONS)
end
def runShadowChicken