EncodedJSValue JSC_HOST_CALL mapProtoFuncForEach(CallFrame* callFrame) { MapData* data = getMapData(callFrame, callFrame->thisValue()); if (!data) return JSValue::encode(jsUndefined()); JSValue callBack = callFrame->argument(0); CallData callData; CallType callType = getCallData(callBack, callData); if (callType == CallTypeNone) return JSValue::encode(throwTypeError(callFrame, WTF::ASCIILiteral("Map.prototype.forEach called without callback"))); JSValue thisValue = callFrame->argument(1); VM* vm = &callFrame->vm(); if (callType == CallTypeJS) { JSFunction* function = jsCast<JSFunction*>(callBack); CachedCall cachedCall(callFrame, function, 2); for (auto ptr = data->begin(), end = data->end(); ptr != end && !vm->exception(); ++ptr) { cachedCall.setThis(thisValue); cachedCall.setArgument(0, ptr.value()); cachedCall.setArgument(1, ptr.key()); cachedCall.call(); } } else { for (auto ptr = data->begin(), end = data->end(); ptr != end && !vm->exception(); ++ptr) { MarkedArgumentBuffer args; args.append(ptr.value()); args.append(ptr.key()); JSC::call(callFrame, callBack, callType, callData, thisValue, args); } } return JSValue::encode(jsUndefined()); }
static void* handleHostCall(ExecState* execCallee, JSValue callee, CodeSpecializationKind kind) { ExecState* exec = execCallee->callerFrame(); VM* vm = &exec->vm(); execCallee->setScope(exec->scope()); execCallee->setCodeBlock(0); if (kind == CodeForCall) { CallData callData; CallType callType = getCallData(callee, callData); ASSERT(callType != CallTypeJS); if (callType == CallTypeHost) { NativeCallFrameTracer tracer(vm, execCallee); execCallee->setCallee(asObject(callee)); vm->hostCallReturnValue = JSValue::decode(callData.native.function(execCallee)); if (vm->exception()) return vm->getCTIStub(throwExceptionFromCallSlowPathGenerator).code().executableAddress(); return reinterpret_cast<void*>(getHostCallReturnValue); } ASSERT(callType == CallTypeNone); exec->vm().throwException(exec, createNotAFunctionError(exec, callee)); return vm->getCTIStub(throwExceptionFromCallSlowPathGenerator).code().executableAddress(); } ASSERT(kind == CodeForConstruct); ConstructData constructData; ConstructType constructType = getConstructData(callee, constructData); ASSERT(constructType != ConstructTypeJS); if (constructType == ConstructTypeHost) { NativeCallFrameTracer tracer(vm, execCallee); execCallee->setCallee(asObject(callee)); vm->hostCallReturnValue = JSValue::decode(constructData.native.function(execCallee)); if (vm->exception()) return vm->getCTIStub(throwExceptionFromCallSlowPathGenerator).code().executableAddress(); return reinterpret_cast<void*>(getHostCallReturnValue); } ASSERT(constructType == ConstructTypeNone); exec->vm().throwException(exec, createNotAConstructorError(exec, callee)); return vm->getCTIStub(throwExceptionFromCallSlowPathGenerator).code().executableAddress(); }
ALWAYS_INLINE static void JIT_OPERATION operationPutByValInternal(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedProperty, EncodedJSValue encodedValue) { VM* vm = &exec->vm(); NativeCallFrameTracer tracer(vm, exec); JSValue baseValue = JSValue::decode(encodedBase); JSValue property = JSValue::decode(encodedProperty); JSValue value = JSValue::decode(encodedValue); if (LIKELY(property.isUInt32())) { putByVal<strict, direct>(exec, baseValue, property.asUInt32(), value); return; } if (property.isDouble()) { double propertyAsDouble = property.asDouble(); uint32_t propertyAsUInt32 = static_cast<uint32_t>(propertyAsDouble); if (propertyAsDouble == propertyAsUInt32) { putByVal<strict, direct>(exec, baseValue, propertyAsUInt32, value); return; } } // Don't put to an object if toString throws an exception. PropertyName propertyName = property.toPropertyKey(exec); if (!vm->exception()) { PutPropertySlot slot(baseValue, strict); if (direct) { RELEASE_ASSERT(baseValue.isObject()); asObject(baseValue)->putDirect(*vm, propertyName, value, slot); } else baseValue.put(exec, propertyName, value, slot); } }
void* callToThrow(ExecState* exec, Instruction* pc) { #if LLINT_SLOW_PATH_TRACING VM* vm = &exec->vm(); dataLog("Throwing exception ", vm->exception(), " (callToThrow).\n"); #endif doThrow(exec, pc); return LLInt::getCodePtr(llint_throw_during_call_trampoline); }
Instruction* returnToThrow(ExecState* exec, Instruction* pc) { #if LLINT_SLOW_PATH_TRACING VM* vm = &exec->vm(); dataLog("Throwing exception ", vm->exception(), " (returnToThrow).\n"); #endif doThrow(exec, pc); return LLInt::exceptionInstructions(); }
void interpreterThrowInCaller(ExecState* exec, JSObject* error) { VM* vm = &exec->vm(); NativeCallFrameTracer tracer(vm, exec); auto scope = DECLARE_THROW_SCOPE(*vm); throwException(exec, scope, error); #if LLINT_SLOW_PATH_TRACING dataLog("Throwing exception ", vm->exception(), ".\n"); #endif }
EncodedJSValue JSC_HOST_CALL mapProtoFuncForEach(CallFrame* callFrame) { JSMap* map = getMap(callFrame, callFrame->thisValue()); if (!map) return JSValue::encode(jsUndefined()); JSValue callBack = callFrame->argument(0); CallData callData; CallType callType = getCallData(callBack, callData); if (callType == CallTypeNone) return JSValue::encode(throwTypeError(callFrame, WTF::ASCIILiteral("Map.prototype.forEach called without callback"))); JSValue thisValue = callFrame->argument(1); VM* vm = &callFrame->vm(); JSMapIterator* iterator = JSMapIterator::create(*vm, callFrame->callee()->globalObject()->mapIteratorStructure(), map, MapIterateKeyValue); JSValue key, value; if (callType == CallTypeJS) { JSFunction* function = jsCast<JSFunction*>(callBack); CachedCall cachedCall(callFrame, function, 3); while (iterator->nextKeyValue(key, value) && !vm->exception()) { cachedCall.setThis(thisValue); cachedCall.setArgument(0, value); cachedCall.setArgument(1, key); cachedCall.setArgument(2, map); cachedCall.call(); } iterator->finish(); } else { while (iterator->nextKeyValue(key, value) && !vm->exception()) { MarkedArgumentBuffer args; args.append(value); args.append(key); args.append(map); JSC::call(callFrame, callBack, callType, callData, thisValue, args); } iterator->finish(); } return JSValue::encode(jsUndefined()); }
ALWAYS_INLINE static void JIT_OPERATION operationPutByValInternal(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedProperty, EncodedJSValue encodedValue) { VM* vm = &exec->vm(); NativeCallFrameTracer tracer(vm, exec); JSValue baseValue = JSValue::decode(encodedBase); JSValue property = JSValue::decode(encodedProperty); JSValue value = JSValue::decode(encodedValue); if (LIKELY(property.isUInt32())) { // Despite its name, JSValue::isUInt32 will return true only for positive boxed int32_t; all those values are valid array indices. ASSERT(isIndex(property.asUInt32())); putByVal<strict, direct>(exec, baseValue, property.asUInt32(), value); return; } if (property.isDouble()) { double propertyAsDouble = property.asDouble(); uint32_t propertyAsUInt32 = static_cast<uint32_t>(propertyAsDouble); if (propertyAsDouble == propertyAsUInt32 && isIndex(propertyAsUInt32)) { putByVal<strict, direct>(exec, baseValue, propertyAsUInt32, value); return; } } // Don't put to an object if toString throws an exception. auto propertyName = property.toPropertyKey(exec); if (vm->exception()) return; PutPropertySlot slot(baseValue, strict); if (direct) { RELEASE_ASSERT(baseValue.isObject()); if (Optional<uint32_t> index = parseIndex(propertyName)) asObject(baseValue)->putDirectIndex(exec, index.value(), value, 0, strict ? PutDirectIndexShouldThrow : PutDirectIndexShouldNotThrow); else asObject(baseValue)->putDirect(*vm, propertyName, value, slot); } else baseValue.put(exec, propertyName, value, slot); }
JSValue collectMatches(VM& vm, ExecState* exec, JSString* string, const String& s, RegExpConstructor* constructor, RegExp* regExp, const FixEndFunc& fixEnd) { auto scope = DECLARE_THROW_SCOPE(vm); MatchResult result = constructor->performMatch(vm, regExp, string, s, 0); if (!result) return jsNull(); static unsigned maxSizeForDirectPath = 100000; JSArray* array = constructEmptyArray(exec, nullptr); if (UNLIKELY(vm.exception())) return jsUndefined(); auto iterate = [&] () { size_t end = result.end; size_t length = end - result.start; array->push(exec, JSRopeString::createSubstringOfResolved(vm, string, result.start, length)); if (!length) end = fixEnd(end); result = constructor->performMatch(vm, regExp, string, s, end); }; do { if (array->length() >= maxSizeForDirectPath) { // First do a throw-away match to see how many matches we'll get. unsigned matchCount = 0; MatchResult savedResult = result; do { if (array->length() + matchCount >= MAX_STORAGE_VECTOR_LENGTH) { throwOutOfMemoryError(exec, scope); return jsUndefined(); } size_t end = result.end; matchCount++; if (result.empty()) end = fixEnd(end); // Using RegExpConstructor::performMatch() instead of calling RegExp::match() // directly is a surprising but profitable choice: it means that when we do OOM, we // will leave the cached result in the state it ought to have had just before the // OOM! On the other hand, if this loop concludes that the result is small enough, // then the iterate() loop below will overwrite the cached result anyway. result = constructor->performMatch(vm, regExp, string, s, end); } while (result); // OK, we have a sensible number of matches. Now we can create them for reals. result = savedResult; do iterate(); while (result); return array; } iterate(); } while (result); return array; }
static void doThrow(ExecState* exec, Instruction* pc) { VM* vm = &exec->vm(); NativeCallFrameTracer tracer(vm, exec); genericThrow(vm, exec, vm->exception(), pc - exec->codeBlock()->instructions().begin()); }
void compileOSRExit(ExecState* exec) { if (exec->vm().callFrameForCatch) RELEASE_ASSERT(exec->vm().callFrameForCatch == exec); CodeBlock* codeBlock = exec->codeBlock(); ASSERT(codeBlock); ASSERT(codeBlock->jitType() == JITCode::DFGJIT); VM* vm = &exec->vm(); // It's sort of preferable that we don't GC while in here. Anyways, doing so wouldn't // really be profitable. DeferGCForAWhile deferGC(vm->heap); uint32_t exitIndex = vm->osrExitIndex; OSRExit& exit = codeBlock->jitCode()->dfg()->osrExit[exitIndex]; if (vm->callFrameForCatch) ASSERT(exit.m_kind == GenericUnwind); if (exit.isExceptionHandler()) ASSERT(!!vm->exception()); prepareCodeOriginForOSRExit(exec, exit.m_codeOrigin); // Compute the value recoveries. Operands<ValueRecovery> operands; codeBlock->jitCode()->dfg()->variableEventStream.reconstruct(codeBlock, exit.m_codeOrigin, codeBlock->jitCode()->dfg()->minifiedDFG, exit.m_streamIndex, operands); SpeculationRecovery* recovery = 0; if (exit.m_recoveryIndex != UINT_MAX) recovery = &codeBlock->jitCode()->dfg()->speculationRecovery[exit.m_recoveryIndex]; { CCallHelpers jit(vm, codeBlock); OSRExitCompiler exitCompiler(jit); if (exit.m_kind == GenericUnwind) { // We are acting as a defacto op_catch because we arrive here from genericUnwind(). // So, we must restore our call frame and stack pointer. jit.restoreCalleeSavesFromVMEntryFrameCalleeSavesBuffer(); jit.loadPtr(vm->addressOfCallFrameForCatch(), GPRInfo::callFrameRegister); jit.addPtr(CCallHelpers::TrustedImm32(codeBlock->stackPointerOffset() * sizeof(Register)), GPRInfo::callFrameRegister, CCallHelpers::stackPointerRegister); } jit.jitAssertHasValidCallFrame(); if (vm->m_perBytecodeProfiler && codeBlock->jitCode()->dfgCommon()->compilation) { Profiler::Database& database = *vm->m_perBytecodeProfiler; Profiler::Compilation* compilation = codeBlock->jitCode()->dfgCommon()->compilation.get(); Profiler::OSRExit* profilerExit = compilation->addOSRExit( exitIndex, Profiler::OriginStack(database, codeBlock, exit.m_codeOrigin), exit.m_kind, exit.m_kind == UncountableInvalidation); jit.add64(CCallHelpers::TrustedImm32(1), CCallHelpers::AbsoluteAddress(profilerExit->counterAddress())); } exitCompiler.compileExit(exit, operands, recovery); LinkBuffer patchBuffer(*vm, jit, codeBlock); exit.m_code = FINALIZE_CODE_IF( shouldDumpDisassembly() || Options::verboseOSR(), patchBuffer, ("DFG OSR exit #%u (%s, %s) from %s, with operands = %s", exitIndex, toCString(exit.m_codeOrigin).data(), exitKindToString(exit.m_kind), toCString(*codeBlock).data(), toCString(ignoringContext<DumpContext>(operands)).data())); } MacroAssembler::repatchJump(exit.codeLocationForRepatch(codeBlock), CodeLocationLabel(exit.m_code.code())); vm->osrExitJumpDestination = exit.m_code.code().executableAddress(); }