806void JIT_OPERATION operationHandleWatchdogTimer(ExecState* exec)
807{
808 VM& vm = exec->vm();
809 NativeCallFrameTracer tracer(&vm, exec);
810
811 if (UNLIKELY(vm.watchdog.didFire(exec)))
812 vm.throwException(exec, createTerminatedExecutionException(&vm));
813}
814
815void JIT_OPERATION operationThrowStaticError(ExecState* exec, EncodedJSValue encodedValue, int32_t referenceErrorFlag)
816{
817 VM& vm = exec->vm();
818 NativeCallFrameTracer tracer(&vm, exec);
819
820 String message = errorDescriptionForValue(exec, JSValue::decode(encodedValue))->value(exec);
821 if (referenceErrorFlag)
822 vm.throwException(exec, createReferenceError(exec, message));
823 else
824 vm.throwException(exec, createTypeError(exec, message));
825}
826
827void JIT_OPERATION operationDebug(ExecState* exec, int32_t debugHookID)
828{
829 VM& vm = exec->vm();
830 NativeCallFrameTracer tracer(&vm, exec);
831
832 vm.interpreter->debug(exec, static_cast<DebugHookID>(debugHookID));
833}
834
835#if ENABLE(DFG_JIT)
836char* JIT_OPERATION operationOptimize(ExecState* exec, int32_t bytecodeIndex)
837{
838 VM& vm = exec->vm();
839 NativeCallFrameTracer tracer(&vm, exec);
840
841 // Defer GC so that it doesn't run between when we enter into this slow path and
842 // when we figure out the state of our code block. This prevents a number of
843 // awkward reentrancy scenarios, including:
844 //
845 // - The optimized version of our code block being jettisoned by GC right after
846 // we concluded that we wanted to use it.
847 //
848 // - An optimized version of our code block being installed just as we decided
849 // that it wasn't ready yet.
850 //
851 // This still leaves the following: anytime we return from cti_optimize, we may
852 // GC, and the GC may either jettison the optimized version of our code block,
853 // or it may install the optimized version of our code block even though we
854 // concluded that it wasn't ready yet.
855 //
856 // Note that jettisoning won't happen if we already initiated OSR, because in
857 // that case we would have already planted the optimized code block into the JS
858 // stack.
859 DeferGC deferGC(vm.heap);
860
861 CodeBlock* codeBlock = exec->codeBlock();
862
863 if (bytecodeIndex) {
864 // If we're attempting to OSR from a loop, assume that this should be
865 // separately optimized.
866 codeBlock->m_shouldAlwaysBeInlined = false;
867 }
868
869 if (Options::verboseOSR()) {
870 dataLog(
871 *codeBlock, ": Entered optimize with bytecodeIndex = ", bytecodeIndex,
872 ", executeCounter = ", codeBlock->jitExecuteCounter(),
873 ", optimizationDelayCounter = ", codeBlock->reoptimizationRetryCounter(),
874 ", exitCounter = ");
875 if (codeBlock->hasOptimizedReplacement())
876 dataLog(codeBlock->replacement()->osrExitCounter());
877 else
878 dataLog("N/A");
879 dataLog("\n");
880 }
881
882 if (!codeBlock->checkIfOptimizationThresholdReached()) {
883 codeBlock->updateAllPredictions();
884 if (Options::verboseOSR())
885 dataLog("Choosing not to optimize ", *codeBlock, " yet, because the threshold hasn't been reached.\n");
886 return 0;
887 }
888
889 if (codeBlock->m_shouldAlwaysBeInlined) {
890 codeBlock->updateAllPredictions();
891 codeBlock->optimizeAfterWarmUp();
892 if (Options::verboseOSR())
893 dataLog("Choosing not to optimize ", *codeBlock, " yet, because m_shouldAlwaysBeInlined == true.\n");
894 return 0;
895 }
896
897 // We cannot be in the process of asynchronous compilation and also have an optimized
898 // replacement.
899 ASSERT(
900 !vm.worklist
901 || !(vm.worklist->compilationState(DFG::CompilationKey(codeBlock, DFG::DFGMode)) != DFG::Worklist::NotKnown
902 && codeBlock->hasOptimizedReplacement()));
903
904 DFG::Worklist::State worklistState;
905 if (vm.worklist) {
906 // The call to DFG::Worklist::completeAllReadyPlansForVM() will complete all ready
907 // (i.e. compiled) code blocks. But if it completes ours, we also need to know
908 // what the result was so that we don't plow ahead and attempt OSR or immediate
909 // reoptimization. This will have already also set the appropriate JIT execution
910 // count threshold depending on what happened, so if the compilation was anything
911 // but successful we just want to return early. See the case for worklistState ==
912 // DFG::Worklist::Compiled, below.
913
914 // Note that we could have alternatively just called Worklist::compilationState()
915 // here, and if it returned Compiled, we could have then called
916 // completeAndScheduleOSR() below. But that would have meant that it could take
917 // longer for code blocks to be completed: they would only complete when *their*
918 // execution count trigger fired; but that could take a while since the firing is
919 // racy. It could also mean that code blocks that never run again after being
920 // compiled would sit on the worklist until next GC. That's fine, but it's
921 // probably a waste of memory. Our goal here is to complete code blocks as soon as
922 // possible in order to minimize the chances of us executing baseline code after
923 // optimized code is already available.
924 worklistState = vm.worklist->completeAllReadyPlansForVM(
925 vm, DFG::CompilationKey(codeBlock, DFG::DFGMode));
926 } else
927 worklistState = DFG::Worklist::NotKnown;
928
929 if (worklistState == DFG::Worklist::Compiling) {
930 // We cannot be in the process of asynchronous compilation and also have an optimized
931 // replacement.
932 RELEASE_ASSERT(!codeBlock->hasOptimizedReplacement());
933 codeBlock->setOptimizationThresholdBasedOnCompilationResult(CompilationDeferred);
934 return 0;
935 }
936
937 if (worklistState == DFG::Worklist::Compiled) {
938 // If we don't have an optimized replacement but we did just get compiled, then
939 // the compilation failed or was invalidated, in which case the execution count
940 // thresholds have already been set appropriately by
941 // CodeBlock::setOptimizationThresholdBasedOnCompilationResult() and we have
942 // nothing left to do.
943 if (!codeBlock->hasOptimizedReplacement()) {
944 codeBlock->updateAllPredictions();
945 if (Options::verboseOSR())
946 dataLog("Code block ", *codeBlock, " was compiled but it doesn't have an optimized replacement.\n");
947 return 0;
948 }
949 } else if (codeBlock->hasOptimizedReplacement()) {
950 if (Options::verboseOSR())
951 dataLog("Considering OSR ", *codeBlock, " -> ", *codeBlock->replacement(), ".\n");
952 // If we have an optimized replacement, then it must be the case that we entered
953 // cti_optimize from a loop. That's because if there's an optimized replacement,
954 // then all calls to this function will be relinked to the replacement and so
955 // the prologue OSR will never fire.
956
957 // This is an interesting threshold check. Consider that a function OSR exits
958 // in the middle of a loop, while having a relatively low exit count. The exit
959 // will reset the execution counter to some target threshold, meaning that this
960 // code won't be reached until that loop heats up for >=1000 executions. But then
961 // we do a second check here, to see if we should either reoptimize, or just
962 // attempt OSR entry. Hence it might even be correct for
963 // shouldReoptimizeFromLoopNow() to always return true. But we make it do some
964 // additional checking anyway, to reduce the amount of recompilation thrashing.
965 if (codeBlock->replacement()->shouldReoptimizeFromLoopNow()) {
966 if (Options::verboseOSR()) {
967 dataLog(
968 "Triggering reoptimization of ", *codeBlock,
969 "(", *codeBlock->replacement(), ") (in loop).\n");
970 }
971 codeBlock->reoptimize();
972 return 0;
973 }
974 } else {
975 if (!codeBlock->shouldOptimizeNow()) {
976 if (Options::verboseOSR()) {
977 dataLog(
978 "Delaying optimization for ", *codeBlock,
979 " because of insufficient profiling.\n");
980 }
981 return 0;
982 }
983
984 if (Options::verboseOSR())
985 dataLog("Triggering optimized compilation of ", *codeBlock, "\n");
986
987 unsigned numVarsWithValues;
988 if (bytecodeIndex)
989 numVarsWithValues = codeBlock->m_numVars;
990 else
991 numVarsWithValues = 0;
992 Operands<JSValue> mustHandleValues(codeBlock->numParameters(), numVarsWithValues);
993 for (size_t i = 0; i < mustHandleValues.size(); ++i) {
994 int operand = mustHandleValues.operandForIndex(i);
995 if (operandIsArgument(operand)
996 && !VirtualRegister(operand).toArgument()
997 && codeBlock->codeType() == FunctionCode
998 && codeBlock->specializationKind() == CodeForConstruct) {
999 // Ugh. If we're in a constructor, the 'this' argument may hold garbage. It will
1000 // also never be used. It doesn't matter what we put into the value for this,
1001 // but it has to be an actual value that can be grokked by subsequent DFG passes,
1002 // so we sanitize it here by turning it into Undefined.
1003 mustHandleValues[i] = jsUndefined();
1004 } else
1005 mustHandleValues[i] = exec->uncheckedR(operand).jsValue();
1006 }
1007
1008 CompilationResult result = DFG::compile(
1009 vm, codeBlock->newReplacement().get(), DFG::DFGMode, bytecodeIndex,
1010 mustHandleValues, JITToDFGDeferredCompilationCallback::create(),
1011 vm.ensureWorklist());
1012
1013 if (result != CompilationSuccessful)
1014 return 0;
1015 }
1016
1017 CodeBlock* optimizedCodeBlock = codeBlock->replacement();
1018 ASSERT(JITCode::isOptimizingJIT(optimizedCodeBlock->jitType()));
1019
1020 if (void* address = DFG::prepareOSREntry(exec, optimizedCodeBlock, bytecodeIndex)) {
1021 if (Options::verboseOSR()) {
1022 dataLog(
1023 "Performing OSR ", *codeBlock, " -> ", *optimizedCodeBlock, ", address ",
1024 RawPointer(OUR_RETURN_ADDRESS), " -> ", RawPointer(address), ".\n");
1025 }
1026
1027 codeBlock->optimizeSoon();
1028 return static_cast<char*>(address);
1029 }
1030
1031 if (Options::verboseOSR()) {
1032 dataLog(
1033 "Optimizing ", *codeBlock, " -> ", *codeBlock->replacement(),
1034 " succeeded, OSR failed, after a delay of ",
1035 codeBlock->optimizationDelayCounter(), ".\n");
1036 }
1037
1038 // Count the OSR failure as a speculation failure. If this happens a lot, then
1039 // reoptimize.
1040 optimizedCodeBlock->countOSRExit();
1041
1042 // We are a lot more conservative about triggering reoptimization after OSR failure than
1043 // before it. If we enter the optimize_from_loop trigger with a bucket full of fail
1044 // already, then we really would like to reoptimize immediately. But this case covers
1045 // something else: there weren't many (or any) speculation failures before, but we just
1046 // failed to enter the speculative code because some variable had the wrong value or
1047 // because the OSR code decided for any spurious reason that it did not want to OSR
1048 // right now. So, we only trigger reoptimization only upon the more conservative (non-loop)
1049 // reoptimization trigger.
1050 if (optimizedCodeBlock->shouldReoptimizeNow()) {
1051 if (Options::verboseOSR()) {
1052 dataLog(
1053 "Triggering reoptimization of ", *codeBlock, " -> ",
1054 *codeBlock->replacement(), " (after OSR fail).\n");
1055 }
1056 codeBlock->reoptimize();
1057 return 0;
1058 }
1059
1060 // OSR failed this time, but it might succeed next time! Let the code run a bit
1061 // longer and then try again.
1062 codeBlock->optimizeAfterWarmUp();
1063
1064 return 0;
1065}
1066#endif
1067
1068void JIT_OPERATION operationPutByIndex(ExecState* exec, EncodedJSValue encodedArrayValue, int32_t index, EncodedJSValue encodedValue)
1069{
1070 VM& vm = exec->vm();
1071 NativeCallFrameTracer tracer(&vm, exec);
1072
1073 JSValue arrayValue = JSValue::decode(encodedArrayValue);
1074 ASSERT(isJSArray(arrayValue));
1075 asArray(arrayValue)->putDirectIndex(exec, index, JSValue::decode(encodedValue));
1076}
1077
1078#if USE(JSVALUE64)
1079void JIT_OPERATION operationPutGetterSetter(ExecState* exec, EncodedJSValue encodedObjectValue, Identifier* identifier, EncodedJSValue encodedGetterValue, EncodedJSValue encodedSetterValue)
1080{
1081 VM& vm = exec->vm();
1082 NativeCallFrameTracer tracer(&vm, exec);
1083
1084 ASSERT(JSValue::decode(encodedObjectValue).isObject());
1085 JSObject* baseObj = asObject(JSValue::decode(encodedObjectValue));
1086
1087 GetterSetter* accessor = GetterSetter::create(vm);
1088
1089 JSValue getter = JSValue::decode(encodedGetterValue);
1090 JSValue setter = JSValue::decode(encodedSetterValue);
1091 ASSERT(getter.isObject() || getter.isUndefined());
1092 ASSERT(setter.isObject() || setter.isUndefined());
1093 ASSERT(getter.isObject() || setter.isObject());
1094
1095 if (!getter.isUndefined())
1096 accessor->setGetter(vm, asObject(getter));
1097 if (!setter.isUndefined())
1098 accessor->setSetter(vm, asObject(setter));
1099 baseObj->putDirectAccessor(exec, *identifier, accessor, Accessor);
1100}
1101#else
1102void JIT_OPERATION operationPutGetterSetter(ExecState* exec, JSCell* object, Identifier* identifier, JSCell* getter, JSCell* setter)
1103{
1104 VM& vm = exec->vm();
1105 NativeCallFrameTracer tracer(&vm, exec);
1106
1107 ASSERT(object && object->isObject());
1108 JSObject* baseObj = object->getObject();
1109
1110 GetterSetter* accessor = GetterSetter::create(vm);
1111
1112 ASSERT(!getter || getter->isObject());
1113 ASSERT(!setter || setter->isObject());
1114 ASSERT(getter || setter);
1115
1116 if (getter)
1117 accessor->setGetter(vm, getter->getObject());
1118 if (setter)
1119 accessor->setSetter(vm, setter->getObject());
1120 baseObj->putDirectAccessor(exec, *identifier, accessor, Accessor);
1121}
1122#endif
1123
1124void JIT_OPERATION operationPushNameScope(ExecState* exec, Identifier* identifier, EncodedJSValue encodedValue, int32_t attibutes)
1125{
1126 VM& vm = exec->vm();
1127 NativeCallFrameTracer tracer(&vm, exec);
1128
1129 JSNameScope* scope = JSNameScope::create(exec, *identifier, JSValue::decode(encodedValue), attibutes);
1130
1131 exec->setScope(scope);
1132}
1133
1134void JIT_OPERATION operationPushWithScope(ExecState* exec, EncodedJSValue encodedValue)
1135{
1136 VM& vm = exec->vm();
1137 NativeCallFrameTracer tracer(&vm, exec);
1138
1139 JSObject* o = JSValue::decode(encodedValue).toObject(exec);
1140 if (vm.exception())
1141 return;
1142
1143 exec->setScope(JSWithScope::create(exec, o));
1144}
1145
1146void JIT_OPERATION operationPopScope(ExecState* exec)
1147{
1148 VM& vm = exec->vm();
1149 NativeCallFrameTracer tracer(&vm, exec);
1150
1151 exec->setScope(exec->scope()->next());
1152}
1153
1154void JIT_OPERATION operationProfileDidCall(ExecState* exec, EncodedJSValue encodedValue)
1155{
1156 VM& vm = exec->vm();
1157 NativeCallFrameTracer tracer(&vm, exec);
1158
1159 if (LegacyProfiler* profiler = vm.enabledProfiler())
1160 profiler->didExecute(exec, JSValue::decode(encodedValue));
1161}
1162
1163void JIT_OPERATION operationProfileWillCall(ExecState* exec, EncodedJSValue encodedValue)
1164{
1165 VM& vm = exec->vm();
1166 NativeCallFrameTracer tracer(&vm, exec);
1167
1168 if (LegacyProfiler* profiler = vm.enabledProfiler())
1169 profiler->willExecute(exec, JSValue::decode(encodedValue));
1170}
1171