/* * Copyright (c) 2020, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. *
*/
bool vmIntrinsics::preserves_state(vmIntrinsics::ID id) {
assert(id != vmIntrinsics::_none, "must be a VM intrinsic"); switch(id) { #ifdef JFR_HAVE_INTRINSICS case vmIntrinsics::_counterTime: #endif case vmIntrinsics::_currentTimeMillis: case vmIntrinsics::_nanoTime: case vmIntrinsics::_floatToRawIntBits: case vmIntrinsics::_intBitsToFloat: case vmIntrinsics::_doubleToRawLongBits: case vmIntrinsics::_longBitsToDouble: case vmIntrinsics::_getClass: case vmIntrinsics::_isInstance: case vmIntrinsics::_currentCarrierThread: case vmIntrinsics::_currentThread: case vmIntrinsics::_scopedValueCache: case vmIntrinsics::_dabs: case vmIntrinsics::_fabs: case vmIntrinsics::_iabs: case vmIntrinsics::_labs: case vmIntrinsics::_dsqrt: case vmIntrinsics::_dsqrt_strict: case vmIntrinsics::_dsin: case vmIntrinsics::_dcos: case vmIntrinsics::_dtan: case vmIntrinsics::_dlog: case vmIntrinsics::_dlog10: case vmIntrinsics::_dexp: case vmIntrinsics::_dpow: case vmIntrinsics::_Preconditions_checkIndex: case vmIntrinsics::_Preconditions_checkLongIndex: case vmIntrinsics::_Reference_get: case vmIntrinsics::_Continuation_doYield: case vmIntrinsics::_updateCRC32: case vmIntrinsics::_updateBytesCRC32: case vmIntrinsics::_updateByteBufferCRC32: case vmIntrinsics::_updateBytesAdler32: case vmIntrinsics::_vectorizedMismatch: case vmIntrinsics::_fmaD: case vmIntrinsics::_fmaF: case vmIntrinsics::_isDigit: case vmIntrinsics::_isLowerCase: case vmIntrinsics::_isUpperCase: case vmIntrinsics::_isWhitespace: returntrue; default: returnfalse;
}
}
bool vmIntrinsics::can_trap(vmIntrinsics::ID id) {
assert(id != vmIntrinsics::_none, "must be a VM intrinsic"); switch(id) { #ifdef JFR_HAVE_INTRINSICS case vmIntrinsics::_counterTime: #endif case vmIntrinsics::_currentTimeMillis: case vmIntrinsics::_nanoTime: case vmIntrinsics::_floatToRawIntBits: case vmIntrinsics::_intBitsToFloat: case vmIntrinsics::_doubleToRawLongBits: case vmIntrinsics::_longBitsToDouble: case vmIntrinsics::_currentCarrierThread: case vmIntrinsics::_currentThread: case vmIntrinsics::_setCurrentThread: case vmIntrinsics::_scopedValueCache: case vmIntrinsics::_setScopedValueCache: case vmIntrinsics::_dabs: case vmIntrinsics::_fabs: case vmIntrinsics::_iabs: case vmIntrinsics::_labs: case vmIntrinsics::_dsqrt: case vmIntrinsics::_dsqrt_strict: case vmIntrinsics::_dsin: case vmIntrinsics::_dcos: case vmIntrinsics::_dtan: case vmIntrinsics::_dlog: case vmIntrinsics::_dlog10: case vmIntrinsics::_dexp: case vmIntrinsics::_dpow: case vmIntrinsics::_updateCRC32: case vmIntrinsics::_updateBytesCRC32: case vmIntrinsics::_updateByteBufferCRC32: case vmIntrinsics::_vectorizedMismatch: case vmIntrinsics::_fmaD: case vmIntrinsics::_fmaF: returnfalse; default: returntrue;
}
}
// Some intrinsics produce different results if they are not pinned bool vmIntrinsics::should_be_pinned(vmIntrinsics::ID id) {
assert(id != vmIntrinsics::_none, "must be a VM intrinsic"); switch(id) { #ifdef JFR_HAVE_INTRINSICS case vmIntrinsics::_counterTime: #endif case vmIntrinsics::_currentTimeMillis: case vmIntrinsics::_nanoTime: case vmIntrinsics::_blackhole: returntrue; default: returnfalse;
}
}
bool vmIntrinsics::does_virtual_dispatch(vmIntrinsics::ID id) {
assert(id != vmIntrinsics::_none, "must be a VM intrinsic"); switch(id) { case vmIntrinsics::_hashCode: case vmIntrinsics::_clone: returntrue; break; default: returnfalse;
}
}
int vmIntrinsics::predicates_needed(vmIntrinsics::ID id) {
assert(id != vmIntrinsics::_none, "must be a VM intrinsic"); switch (id) { case vmIntrinsics::_cipherBlockChaining_encryptAESCrypt: case vmIntrinsics::_cipherBlockChaining_decryptAESCrypt: case vmIntrinsics::_electronicCodeBook_encryptAESCrypt: case vmIntrinsics::_electronicCodeBook_decryptAESCrypt: case vmIntrinsics::_counterMode_AESCrypt: case vmIntrinsics::_galoisCounterMode_AESCrypt: return 1; case vmIntrinsics::_digestBase_implCompressMB: return 5; default: return 0;
}
}
bool vmIntrinsics::disabled_by_jvm_flags(vmIntrinsics::ID id) {
assert(id != vmIntrinsics::_none, "must be a VM intrinsic");
// -XX:-InlineNatives disables nearly all intrinsics except the ones listed in // the following switch statement. if (!InlineNatives) { switch (id) { case vmIntrinsics::_indexOfL: case vmIntrinsics::_indexOfU: case vmIntrinsics::_indexOfUL: case vmIntrinsics::_indexOfIL: case vmIntrinsics::_indexOfIU: case vmIntrinsics::_indexOfIUL: case vmIntrinsics::_indexOfU_char: case vmIntrinsics::_indexOfL_char: case vmIntrinsics::_compareToL: case vmIntrinsics::_compareToU: case vmIntrinsics::_compareToLU: case vmIntrinsics::_compareToUL: case vmIntrinsics::_equalsL: case vmIntrinsics::_equalsU: case vmIntrinsics::_equalsC: case vmIntrinsics::_getCharStringU: case vmIntrinsics::_putCharStringU: case vmIntrinsics::_compressStringC: case vmIntrinsics::_compressStringB: case vmIntrinsics::_inflateStringC: case vmIntrinsics::_inflateStringB: case vmIntrinsics::_getAndAddInt: case vmIntrinsics::_getAndAddLong: case vmIntrinsics::_getAndSetInt: case vmIntrinsics::_getAndSetLong: case vmIntrinsics::_getAndSetReference: case vmIntrinsics::_loadFence: case vmIntrinsics::_storeFence: case vmIntrinsics::_fullFence: case vmIntrinsics::_countPositives: case vmIntrinsics::_Reference_get: case vmIntrinsics::_Continuation_doYield: case vmIntrinsics::_Continuation_enterSpecial: break; default: returntrue;
}
}
switch (id) { case vmIntrinsics::_isInstance: case vmIntrinsics::_isAssignableFrom: case vmIntrinsics::_getModifiers: case vmIntrinsics::_isInterface: case vmIntrinsics::_isArray: case vmIntrinsics::_isPrimitive: case vmIntrinsics::_isHidden: case vmIntrinsics::_getSuperclass: case vmIntrinsics::_Class_cast: case vmIntrinsics::_getLength: case vmIntrinsics::_newArray: case vmIntrinsics::_getClass: if (!InlineClassNatives) returntrue; break; case vmIntrinsics::_currentCarrierThread: case vmIntrinsics::_currentThread: if (!InlineThreadNatives) returntrue; break; case vmIntrinsics::_setCurrentThread: case vmIntrinsics::_scopedValueCache: case vmIntrinsics::_setScopedValueCache: case vmIntrinsics::_floatToRawIntBits: case vmIntrinsics::_intBitsToFloat: case vmIntrinsics::_doubleToRawLongBits: case vmIntrinsics::_longBitsToDouble: case vmIntrinsics::_ceil: case vmIntrinsics::_floor: case vmIntrinsics::_rint: case vmIntrinsics::_dabs: case vmIntrinsics::_fabs: case vmIntrinsics::_iabs: case vmIntrinsics::_labs: case vmIntrinsics::_dsqrt: case vmIntrinsics::_dsqrt_strict: case vmIntrinsics::_dsin: case vmIntrinsics::_dcos: case vmIntrinsics::_dtan: case vmIntrinsics::_dlog: case vmIntrinsics::_dexp: case vmIntrinsics::_dpow: case vmIntrinsics::_dlog10: case vmIntrinsics::_datan2: case vmIntrinsics::_floatToIntBits: case vmIntrinsics::_doubleToLongBits: case vmIntrinsics::_min: case vmIntrinsics::_max: case vmIntrinsics::_maxF: case vmIntrinsics::_minF: case vmIntrinsics::_maxD: case vmIntrinsics::_minD: case vmIntrinsics::_min_strict: case vmIntrinsics::_max_strict: case vmIntrinsics::_maxF_strict: case vmIntrinsics::_minF_strict: case vmIntrinsics::_maxD_strict: case vmIntrinsics::_minD_strict: if (!InlineMathNatives) returntrue; break; case vmIntrinsics::_fmaD: case vmIntrinsics::_fmaF: if (!InlineMathNatives || !UseFMA) returntrue; break; case vmIntrinsics::_arraycopy: if (!InlineArrayCopy) returntrue; break; case vmIntrinsics::_updateCRC32: case vmIntrinsics::_updateBytesCRC32: case vmIntrinsics::_updateByteBufferCRC32: if (!UseCRC32Intrinsics) returntrue; break; case vmIntrinsics::_getReference: case vmIntrinsics::_getBoolean: case vmIntrinsics::_getByte: case vmIntrinsics::_getShort: case vmIntrinsics::_getChar: case vmIntrinsics::_getInt: case vmIntrinsics::_getLong: case vmIntrinsics::_getFloat: case vmIntrinsics::_getDouble: case vmIntrinsics::_putReference: case vmIntrinsics::_putBoolean: case vmIntrinsics::_putByte: case vmIntrinsics::_putShort: case vmIntrinsics::_putChar: case vmIntrinsics::_putInt: case vmIntrinsics::_putLong: case vmIntrinsics::_putFloat: case vmIntrinsics::_putDouble: case vmIntrinsics::_getReferenceVolatile: case vmIntrinsics::_getBooleanVolatile: case vmIntrinsics::_getByteVolatile: case vmIntrinsics::_getShortVolatile: case vmIntrinsics::_getCharVolatile: case vmIntrinsics::_getIntVolatile: case vmIntrinsics::_getLongVolatile: case vmIntrinsics::_getFloatVolatile: case vmIntrinsics::_getDoubleVolatile: case vmIntrinsics::_putReferenceVolatile: case vmIntrinsics::_putBooleanVolatile: case vmIntrinsics::_putByteVolatile: case vmIntrinsics::_putShortVolatile: case vmIntrinsics::_putCharVolatile: case vmIntrinsics::_putIntVolatile: case vmIntrinsics::_putLongVolatile: case vmIntrinsics::_putFloatVolatile: case vmIntrinsics::_putDoubleVolatile: case vmIntrinsics::_getReferenceAcquire: case vmIntrinsics::_getBooleanAcquire: case vmIntrinsics::_getByteAcquire: case vmIntrinsics::_getShortAcquire: case vmIntrinsics::_getCharAcquire: case vmIntrinsics::_getIntAcquire: case vmIntrinsics::_getLongAcquire: case vmIntrinsics::_getFloatAcquire: case vmIntrinsics::_getDoubleAcquire: case vmIntrinsics::_putReferenceRelease: case vmIntrinsics::_putBooleanRelease: case vmIntrinsics::_putByteRelease: case vmIntrinsics::_putShortRelease: case vmIntrinsics::_putCharRelease: case vmIntrinsics::_putIntRelease: case vmIntrinsics::_putLongRelease: case vmIntrinsics::_putFloatRelease: case vmIntrinsics::_putDoubleRelease: case vmIntrinsics::_getReferenceOpaque: case vmIntrinsics::_getBooleanOpaque: case vmIntrinsics::_getByteOpaque: case vmIntrinsics::_getShortOpaque: case vmIntrinsics::_getCharOpaque: case vmIntrinsics::_getIntOpaque: case vmIntrinsics::_getLongOpaque: case vmIntrinsics::_getFloatOpaque: case vmIntrinsics::_getDoubleOpaque: case vmIntrinsics::_putReferenceOpaque: case vmIntrinsics::_putBooleanOpaque: case vmIntrinsics::_putByteOpaque: case vmIntrinsics::_putShortOpaque: case vmIntrinsics::_putCharOpaque: case vmIntrinsics::_putIntOpaque: case vmIntrinsics::_putLongOpaque: case vmIntrinsics::_putFloatOpaque: case vmIntrinsics::_putDoubleOpaque: case vmIntrinsics::_getAndAddInt: case vmIntrinsics::_getAndAddLong: case vmIntrinsics::_getAndSetInt: case vmIntrinsics::_getAndSetLong: case vmIntrinsics::_getAndSetReference: case vmIntrinsics::_loadFence: case vmIntrinsics::_storeFence: case vmIntrinsics::_fullFence: case vmIntrinsics::_compareAndSetLong: case vmIntrinsics::_weakCompareAndSetLong: case vmIntrinsics::_weakCompareAndSetLongPlain: case vmIntrinsics::_weakCompareAndSetLongAcquire: case vmIntrinsics::_weakCompareAndSetLongRelease: case vmIntrinsics::_compareAndSetInt: case vmIntrinsics::_weakCompareAndSetInt: case vmIntrinsics::_weakCompareAndSetIntPlain: case vmIntrinsics::_weakCompareAndSetIntAcquire: case vmIntrinsics::_weakCompareAndSetIntRelease: case vmIntrinsics::_compareAndSetReference: case vmIntrinsics::_weakCompareAndSetReference: case vmIntrinsics::_weakCompareAndSetReferencePlain: case vmIntrinsics::_weakCompareAndSetReferenceAcquire: case vmIntrinsics::_weakCompareAndSetReferenceRelease: case vmIntrinsics::_compareAndExchangeInt: case vmIntrinsics::_compareAndExchangeIntAcquire: case vmIntrinsics::_compareAndExchangeIntRelease: case vmIntrinsics::_compareAndExchangeLong: case vmIntrinsics::_compareAndExchangeLongAcquire: case vmIntrinsics::_compareAndExchangeLongRelease: case vmIntrinsics::_compareAndExchangeReference: case vmIntrinsics::_compareAndExchangeReferenceAcquire: case vmIntrinsics::_compareAndExchangeReferenceRelease: case vmIntrinsics::_allocateInstance: if (!InlineUnsafeOps) returntrue; break; case vmIntrinsics::_getShortUnaligned: case vmIntrinsics::_getCharUnaligned: case vmIntrinsics::_getIntUnaligned: case vmIntrinsics::_getLongUnaligned: case vmIntrinsics::_putShortUnaligned: case vmIntrinsics::_putCharUnaligned: case vmIntrinsics::_putIntUnaligned: case vmIntrinsics::_putLongUnaligned: if (!InlineUnsafeOps || !UseUnalignedAccesses) returntrue; break; case vmIntrinsics::_hashCode: if (!InlineObjectHash) returntrue; break; case vmIntrinsics::_aescrypt_encryptBlock: case vmIntrinsics::_aescrypt_decryptBlock: if (!UseAESIntrinsics) returntrue; break; case vmIntrinsics::_cipherBlockChaining_encryptAESCrypt: case vmIntrinsics::_cipherBlockChaining_decryptAESCrypt: if (!UseAESIntrinsics) returntrue; break; case vmIntrinsics::_electronicCodeBook_encryptAESCrypt: case vmIntrinsics::_electronicCodeBook_decryptAESCrypt: if (!UseAESIntrinsics) returntrue; break; case vmIntrinsics::_counterMode_AESCrypt: if (!UseAESCTRIntrinsics) returntrue; break; case vmIntrinsics::_galoisCounterMode_AESCrypt: if (!UseAESIntrinsics) returntrue; break; case vmIntrinsics::_md5_implCompress: if (!UseMD5Intrinsics) returntrue; break; case vmIntrinsics::_sha_implCompress: if (!UseSHA1Intrinsics) returntrue; break; case vmIntrinsics::_sha2_implCompress: if (!UseSHA256Intrinsics) returntrue; break; case vmIntrinsics::_sha5_implCompress: if (!UseSHA512Intrinsics) returntrue; break; case vmIntrinsics::_sha3_implCompress: if (!UseSHA3Intrinsics) returntrue; break; case vmIntrinsics::_digestBase_implCompressMB: if (!(UseMD5Intrinsics || UseSHA1Intrinsics || UseSHA256Intrinsics || UseSHA512Intrinsics || UseSHA3Intrinsics)) returntrue; break; case vmIntrinsics::_ghash_processBlocks: if (!UseGHASHIntrinsics) returntrue; break; case vmIntrinsics::_chacha20Block: if (!UseChaCha20Intrinsics) returntrue; break; case vmIntrinsics::_base64_encodeBlock: case vmIntrinsics::_base64_decodeBlock: if (!UseBASE64Intrinsics) returntrue; break; case vmIntrinsics::_poly1305_processBlocks: if (!UsePoly1305Intrinsics) returntrue; break; case vmIntrinsics::_updateBytesCRC32C: case vmIntrinsics::_updateDirectByteBufferCRC32C: if (!UseCRC32CIntrinsics) returntrue; break; case vmIntrinsics::_vectorizedMismatch: if (!UseVectorizedMismatchIntrinsic) returntrue; break; case vmIntrinsics::_updateBytesAdler32: case vmIntrinsics::_updateByteBufferAdler32: if (!UseAdler32Intrinsics) returntrue; break; case vmIntrinsics::_copyMemory: if (!InlineArrayCopy || !InlineUnsafeOps) returntrue; break; #ifdef COMPILER2 case vmIntrinsics::_clone: case vmIntrinsics::_copyOf: case vmIntrinsics::_copyOfRange: // These intrinsics use both the objectcopy and the arraycopy // intrinsic mechanism. if (!InlineObjectCopy || !InlineArrayCopy) returntrue; break; case vmIntrinsics::_compareToL: case vmIntrinsics::_compareToU: case vmIntrinsics::_compareToLU: case vmIntrinsics::_compareToUL: if (!SpecialStringCompareTo) returntrue; break; case vmIntrinsics::_indexOfL: case vmIntrinsics::_indexOfU: case vmIntrinsics::_indexOfUL: case vmIntrinsics::_indexOfIL: case vmIntrinsics::_indexOfIU: case vmIntrinsics::_indexOfIUL: case vmIntrinsics::_indexOfU_char: case vmIntrinsics::_indexOfL_char: if (!SpecialStringIndexOf) returntrue; break; case vmIntrinsics::_equalsL: case vmIntrinsics::_equalsU: if (!SpecialStringEquals) returntrue; break; case vmIntrinsics::_equalsB: case vmIntrinsics::_equalsC: if (!SpecialArraysEquals) returntrue; break; case vmIntrinsics::_encodeISOArray: case vmIntrinsics::_encodeAsciiArray: case vmIntrinsics::_encodeByteISOArray: if (!SpecialEncodeISOArray) returntrue; break; case vmIntrinsics::_getCallerClass: if (!InlineReflectionGetCallerClass) returntrue; break; case vmIntrinsics::_multiplyToLen: if (!UseMultiplyToLenIntrinsic) returntrue; break; case vmIntrinsics::_squareToLen: if (!UseSquareToLenIntrinsic) returntrue; break; case vmIntrinsics::_mulAdd: if (!UseMulAddIntrinsic) returntrue; break; case vmIntrinsics::_montgomeryMultiply: if (!UseMontgomeryMultiplyIntrinsic) returntrue; break; case vmIntrinsics::_montgomerySquare: if (!UseMontgomerySquareIntrinsic) returntrue; break; case vmIntrinsics::_bigIntegerRightShiftWorker: case vmIntrinsics::_bigIntegerLeftShiftWorker: break; case vmIntrinsics::_addExactI: case vmIntrinsics::_addExactL: case vmIntrinsics::_decrementExactI: case vmIntrinsics::_decrementExactL: case vmIntrinsics::_incrementExactI: case vmIntrinsics::_incrementExactL: case vmIntrinsics::_multiplyExactI: case vmIntrinsics::_multiplyExactL: case vmIntrinsics::_negateExactI: case vmIntrinsics::_negateExactL: case vmIntrinsics::_subtractExactI: case vmIntrinsics::_subtractExactL: if (!UseMathExactIntrinsics || !InlineMathNatives) returntrue; break; case vmIntrinsics::_isDigit: case vmIntrinsics::_isLowerCase: case vmIntrinsics::_isUpperCase: case vmIntrinsics::_isWhitespace: if (!UseCharacterCompareIntrinsics) returntrue; break; case vmIntrinsics::_dcopySign: case vmIntrinsics::_fcopySign: if (!InlineMathNatives || !UseCopySignIntrinsic) returntrue; break; case vmIntrinsics::_dsignum: case vmIntrinsics::_fsignum: if (!InlineMathNatives || !UseSignumIntrinsic) returntrue; break; #endif// COMPILER2 default: returnfalse;
}
bool vmIntrinsics::is_disabled_by_flags(vmIntrinsics::ID id) {
assert(id > _none && id < ID_LIMIT, "must be a VM intrinsic");
// not initialized yet, process Control/DisableIntrinsic if (vm_intrinsic_control_words[as_int(_none)].is_default()) { for (ControlIntrinsicIter iter(ControlIntrinsic); *iter != NULL; ++iter) {
vmIntrinsics::ID id = vmIntrinsics::find_id(*iter);
if (id != vmIntrinsics::_none) {
vm_intrinsic_control_words[as_int(id)] = iter.is_enabled() && !disabled_by_jvm_flags(id);
}
}
// Order matters, DisableIntrinsic can overwrite ControlIntrinsic for (ControlIntrinsicIter iter(DisableIntrinsic, true/*disable_all*/); *iter != NULL; ++iter) {
vmIntrinsics::ID id = vmIntrinsics::find_id(*iter);
if (id != vmIntrinsics::_none) {
vm_intrinsic_control_words[as_int(id)] = false;
}
}
TriBool b = vm_intrinsic_control_words[as_int(id)]; if (b.is_default()) { // unknown yet, query and cache it
b = vm_intrinsic_control_words[as_int(id)] = !disabled_by_jvm_flags(id);
}
return !b;
}
// These are for forming case labels: #define ID3(x, y, z) (( jlong)(z) + \
((jlong)(y) << vmSymbols::log2_SID_LIMIT) + \
((jlong)(x) << (2*vmSymbols::log2_SID_LIMIT)) ) #define SID_ENUM(n) VM_SYMBOL_ENUM_NAME(n)
class vmIntrinsicsLookup { bool _class_map[vmSymbols::number_of_symbols()];
constexpr int as_index(vmSymbolID id) const { int index = vmSymbols::as_int(id);
assert(0 <= index && index < int(sizeof(_class_map)), "must be"); return index;
}
// A few slightly irregular cases. See Method::init_intrinsic_id
set_class_map(SID_ENUM(java_lang_StrictMath));
set_class_map(SID_ENUM(java_lang_invoke_MethodHandle));
set_class_map(SID_ENUM(java_lang_invoke_VarHandle));
}
¤ Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.0.17Bemerkung:
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.