/* * Copyright (C) 2010 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef CachedTranscendentalFunction_h #define CachedTranscendentalFunction_h #include "JSValue.h" namespace JSC { extern const double NaN; typedef double (*TranscendentalFunctionPtr)(double); // CachedTranscendentalFunction provides a generic mechanism to cache results // for pure functions with the signature "double func(double)", and where NaN // maps to NaN. template<TranscendentalFunctionPtr orignalFunction> class CachedTranscendentalFunction { struct CacheEntry { double operand; double result; }; public: CachedTranscendentalFunction() : m_cache(0) { } ~CachedTranscendentalFunction() { if (m_cache) fastFree(m_cache); } JSValue operator() (double operand) { if (UNLIKELY(!m_cache)) initialize(); CacheEntry* entry = &m_cache[hash(operand)]; if (entry->operand == operand) return jsDoubleNumber(entry->result); double result = orignalFunction(operand); entry->operand = operand; entry->result = result; return jsDoubleNumber(result); } private: void initialize() { // Lazily allocate the table, populate with NaN->NaN mapping. m_cache = static_cast<CacheEntry*>(fastMalloc(s_cacheSize * sizeof(CacheEntry))); for (unsigned x = 0; x < s_cacheSize; ++x) { m_cache[x].operand = NaN; m_cache[x].result = NaN; } } static unsigned hash(double d) { union doubleAndUInt64 { double d; uint32_t is[2]; } u; u.d = d; unsigned x = u.is[0] ^ u.is[1]; x = (x >> 20) ^ (x >> 8); return x & (s_cacheSize - 1); } static const unsigned s_cacheSize = 0x1000; CacheEntry* m_cache; }; } #endif // CachedTranscendentalFunction_h