[JSC] Remove gcc warnings on mips and armv7
authorguijemont@igalia.com <guijemont@igalia.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 12 Oct 2018 02:51:45 +0000 (02:51 +0000)
committerguijemont@igalia.com <guijemont@igalia.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 12 Oct 2018 02:51:45 +0000 (02:51 +0000)
https://bugs.webkit.org/show_bug.cgi?id=188598

Reviewed by Mark Lam.

Source/bmalloc:

Add bitwise_cast (from WTF) and use it instead of reinterpret_cast in
a couple places where reinterpret_cast triggers a warning about
alignment even though we know that alignment is correct.

* bmalloc/Algorithm.h:
(bmalloc::bitwise_cast): Copied from WTF/wtf/StdLibextras.h
* bmalloc/IsoDirectoryPageInlines.h:
(bmalloc::IsoDirectoryPage<Config>::pageFor):
* bmalloc/IsoPageInlines.h:
(bmalloc::IsoPage<Config>::startAllocating):

Source/JavaScriptCore:

Fix many gcc/clang warnings that are false positives, mostly alignment
issues.

* assembler/MacroAssemblerPrinter.cpp:
(JSC::Printer::printMemory):
Use bitwise_cast instead of reinterpret_cast.
* assembler/testmasm.cpp:
(JSC::floatOperands):
marked as potentially unused as it is not used on all platforms.
(JSC::testProbeModifiesStackValues):
modifiedFlags is not used on mips, so don't declare it.
* bytecode/CodeBlock.h:
Make ScriptExecutable::prepareForExecution() return an
std::optional<Exception*> instead of a JSObject*.
* interpreter/Interpreter.cpp:
(JSC::Interpreter::executeProgram):
(JSC::Interpreter::executeCall):
(JSC::Interpreter::executeConstruct):
(JSC::Interpreter::prepareForRepeatCall):
(JSC::Interpreter::execute):
(JSC::Interpreter::executeModuleProgram):
Update calling code for the prototype change of
ScriptExecutable::prepareForExecution().
* jit/JITOperations.cpp: Same as for Interpreter.cpp.
* llint/LLIntSlowPaths.cpp:
(JSC::LLInt::setUpCall): Same as for Interpreter.cpp.
* runtime/JSBigInt.cpp:
(JSC::JSBigInt::dataStorage):
Use bitwise_cast instead of reinterpret_cast.
* runtime/ScriptExecutable.cpp:
* runtime/ScriptExecutable.h:
Make ScriptExecutable::prepareForExecution() return an
std::optional<Exception*> instead of a JSObject*.
* tools/JSDollarVM.cpp:
(JSC::codeBlockFromArg): Use bitwise_cast instead of reinterpret_cast.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@237063 268f45cc-cd09-0410-ab3c-d52691b4dbfc

15 files changed:
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/assembler/MacroAssemblerPrinter.cpp
Source/JavaScriptCore/assembler/testmasm.cpp
Source/JavaScriptCore/bytecode/CodeBlock.h
Source/JavaScriptCore/interpreter/Interpreter.cpp
Source/JavaScriptCore/jit/JITOperations.cpp
Source/JavaScriptCore/llint/LLIntSlowPaths.cpp
Source/JavaScriptCore/runtime/JSBigInt.cpp
Source/JavaScriptCore/runtime/ScriptExecutable.cpp
Source/JavaScriptCore/runtime/ScriptExecutable.h
Source/JavaScriptCore/tools/JSDollarVM.cpp
Source/bmalloc/ChangeLog
Source/bmalloc/bmalloc/Algorithm.h
Source/bmalloc/bmalloc/IsoDirectoryPageInlines.h
Source/bmalloc/bmalloc/IsoPageInlines.h

index fab8c87..40f5ebb 100644 (file)
@@ -1,3 +1,46 @@
+2018-10-11  Guillaume Emont  <guijemont@igalia.com>
+
+        [JSC] Remove gcc warnings on mips and armv7
+        https://bugs.webkit.org/show_bug.cgi?id=188598
+
+        Reviewed by Mark Lam.
+
+        Fix many gcc/clang warnings that are false positives, mostly alignment
+        issues.
+
+        * assembler/MacroAssemblerPrinter.cpp:
+        (JSC::Printer::printMemory):
+        Use bitwise_cast instead of reinterpret_cast.
+        * assembler/testmasm.cpp:
+        (JSC::floatOperands):
+        marked as potentially unused as it is not used on all platforms.
+        (JSC::testProbeModifiesStackValues):
+        modifiedFlags is not used on mips, so don't declare it.
+        * bytecode/CodeBlock.h:
+        Make ScriptExecutable::prepareForExecution() return an
+        std::optional<Exception*> instead of a JSObject*.
+        * interpreter/Interpreter.cpp:
+        (JSC::Interpreter::executeProgram):
+        (JSC::Interpreter::executeCall):
+        (JSC::Interpreter::executeConstruct):
+        (JSC::Interpreter::prepareForRepeatCall):
+        (JSC::Interpreter::execute):
+        (JSC::Interpreter::executeModuleProgram):
+        Update calling code for the prototype change of
+        ScriptExecutable::prepareForExecution().
+        * jit/JITOperations.cpp: Same as for Interpreter.cpp.
+        * llint/LLIntSlowPaths.cpp:
+        (JSC::LLInt::setUpCall): Same as for Interpreter.cpp.
+        * runtime/JSBigInt.cpp:
+        (JSC::JSBigInt::dataStorage):
+        Use bitwise_cast instead of reinterpret_cast.
+        * runtime/ScriptExecutable.cpp:
+        * runtime/ScriptExecutable.h:
+        Make ScriptExecutable::prepareForExecution() return an
+        std::optional<Exception*> instead of a JSObject*.
+        * tools/JSDollarVM.cpp:
+        (JSC::codeBlockFromArg): Use bitwise_cast instead of reinterpret_cast.
+
 2018-10-11  Yusuke Suzuki  <yusukesuzuki@slowstart.org>
 
         Use currentStackPointer more
index 34019d1..4a9c421 100644 (file)
@@ -131,6 +131,9 @@ void printMemory(PrintStream& out, Context& context)
     }
     }
 
+    // assuming memory is not malformed, it originally pointed to a value
+    // of the size with which we use it below, so the bitwise_casts should
+    // be safe, including regarding alignment.
     if (memory.dumpStyle == Memory::SingleWordDump) {
         if (memory.numBytes == sizeof(int8_t)) {
             auto p = reinterpret_cast<int8_t*>(ptr);
@@ -138,17 +141,17 @@ void printMemory(PrintStream& out, Context& context)
             return;
         }
         if (memory.numBytes == sizeof(int16_t)) {
-            auto p = reinterpret_cast<int16_t*>(ptr);
+            auto p = bitwise_cast<int16_t*>(ptr);
             out.printf("%p:<0x%04x %d>", p, *p, *p);
             return;
         }
         if (memory.numBytes == sizeof(int32_t)) {
-            auto p = reinterpret_cast<int32_t*>(ptr);
+            auto p = bitwise_cast<int32_t*>(ptr);
             out.printf("%p:<0x%08x %d>", p, *p, *p);
             return;
         }
         if (memory.numBytes == sizeof(int64_t)) {
-            auto p = reinterpret_cast<int64_t*>(ptr);
+            auto p = bitwise_cast<int64_t*>(ptr);
             out.printf("%p:<0x%016" PRIx64 " %" PRId64 ">", p, *p, *p);
             return;
         }
index 1d77d80..4c54c5a 100644 (file)
@@ -246,7 +246,7 @@ static Vector<double> doubleOperands()
 }
 
 
-static Vector<float> floatOperands()
+static Vector<float> UNUSED_FUNCTION floatOperands()
 {
     return Vector<float> {
         0,
@@ -747,7 +747,9 @@ void testProbeModifiesStackValues()
     CPUState originalState;
     void* originalSP { nullptr };
     void* newSP { nullptr };
+#if !(CPU(MIPS))
     uintptr_t modifiedFlags { 0 };
+#endif
     size_t numberOfExtraEntriesToWrite { 10 }; // ARM64 requires that this be 2 word aligned.
 
 #if CPU(X86) || CPU(X86_64)
index 3962576..2dd1fab 100644 (file)
@@ -1048,7 +1048,7 @@ inline Register& ExecState::uncheckedR(VirtualRegister reg)
 }
 
 template <typename ExecutableType>
-JSObject* ScriptExecutable::prepareForExecution(VM& vm, JSFunction* function, JSScope* scope, CodeSpecializationKind kind, CodeBlock*& resultCodeBlock)
+std::optional<Exception*> ScriptExecutable::prepareForExecution(VM& vm, JSFunction* function, JSScope* scope, CodeSpecializationKind kind, CodeBlock*& resultCodeBlock)
 {
     if (hasJITCodeFor(kind)) {
         if (std::is_same<ExecutableType, EvalExecutable>::value)
@@ -1061,7 +1061,7 @@ JSObject* ScriptExecutable::prepareForExecution(VM& vm, JSFunction* function, JS
             resultCodeBlock = jsCast<CodeBlock*>(jsCast<FunctionExecutable*>(this)->codeBlockFor(kind));
         else
             RELEASE_ASSERT_NOT_REACHED();
-        return nullptr;
+        return std::nullopt;
     }
     return prepareForExecutionImpl(vm, function, scope, kind, resultCodeBlock);
 }
index 6e668c7..3a8a872 100644 (file)
@@ -806,10 +806,11 @@ failedJSONP:
     ProgramCodeBlock* codeBlock;
     {
         CodeBlock* tempCodeBlock;
-        JSObject* error = program->prepareForExecution<ProgramExecutable>(vm, nullptr, scope, CodeForCall, tempCodeBlock);
-        EXCEPTION_ASSERT(throwScope.exception() == reinterpret_cast<Exception*>(error));
+        std::optional<Exception*> error = program->prepareForExecution<ProgramExecutable>(vm, nullptr, scope, CodeForCall, tempCodeBlock);
+        EXCEPTION_ASSERT(throwScope.exception() == error.value_or(nullptr));
+
         if (UNLIKELY(error))
-            return checkedReturn(error);
+            return checkedReturn(*error);
         codeBlock = jsCast<ProgramCodeBlock*>(tempCodeBlock);
     }
 
@@ -864,10 +865,10 @@ JSValue Interpreter::executeCall(CallFrame* callFrame, JSObject* function, CallT
 
     if (isJSCall) {
         // Compile the callee:
-        JSObject* compileError = callData.js.functionExecutable->prepareForExecution<FunctionExecutable>(vm, jsCast<JSFunction*>(function), scope, CodeForCall, newCodeBlock);
-        EXCEPTION_ASSERT(throwScope.exception() == reinterpret_cast<Exception*>(compileError));
+        std::optional<Exception*> compileError = callData.js.functionExecutable->prepareForExecution<FunctionExecutable>(vm, jsCast<JSFunction*>(function), scope, CodeForCall, newCodeBlock);
+        EXCEPTION_ASSERT(throwScope.exception() == compileError.value_or(nullptr));
         if (UNLIKELY(!!compileError))
-            return checkedReturn(compileError);
+            return checkedReturn(*compileError);
 
         ASSERT(!!newCodeBlock);
         newCodeBlock->m_shouldAlwaysBeInlined = false;
@@ -931,10 +932,10 @@ JSObject* Interpreter::executeConstruct(CallFrame* callFrame, JSObject* construc
 
     if (isJSConstruct) {
         // Compile the callee:
-        JSObject* compileError = constructData.js.functionExecutable->prepareForExecution<FunctionExecutable>(vm, jsCast<JSFunction*>(constructor), scope, CodeForConstruct, newCodeBlock);
-        EXCEPTION_ASSERT(throwScope.exception() == reinterpret_cast<Exception*>(compileError));
+        std::optional<Exception*> compileError = constructData.js.functionExecutable->prepareForExecution<FunctionExecutable>(vm, jsCast<JSFunction*>(constructor), scope, CodeForConstruct, newCodeBlock);
+        EXCEPTION_ASSERT(throwScope.exception() == compileError.value_or(nullptr));
         if (UNLIKELY(!!compileError))
-            return checkedReturn(compileError);
+            return checkedReturn(*compileError);
 
         ASSERT(!!newCodeBlock);
         newCodeBlock->m_shouldAlwaysBeInlined = false;
@@ -979,8 +980,8 @@ CallFrameClosure Interpreter::prepareForRepeatCall(FunctionExecutable* functionE
 
     // Compile the callee:
     CodeBlock* newCodeBlock;
-    JSObject* error = functionExecutable->prepareForExecution<FunctionExecutable>(vm, function, scope, CodeForCall, newCodeBlock);
-    EXCEPTION_ASSERT(throwScope.exception() == reinterpret_cast<Exception*>(error));
+    std::optional<Exception*> error = functionExecutable->prepareForExecution<FunctionExecutable>(vm, function, scope, CodeForCall, newCodeBlock);
+    EXCEPTION_ASSERT(throwScope.exception() == error.value_or(nullptr));
     if (UNLIKELY(error))
         return CallFrameClosure();
     newCodeBlock->m_shouldAlwaysBeInlined = false;
@@ -1037,10 +1038,10 @@ JSValue Interpreter::execute(EvalExecutable* eval, CallFrame* callFrame, JSValue
     EvalCodeBlock* codeBlock;
     {
         CodeBlock* tempCodeBlock;
-        JSObject* compileError = eval->prepareForExecution<EvalExecutable>(vm, nullptr, scope, CodeForCall, tempCodeBlock);
-        EXCEPTION_ASSERT(throwScope.exception() == reinterpret_cast<Exception*>(compileError));
+        std::optional<Exception*> compileError = eval->prepareForExecution<EvalExecutable>(vm, nullptr, scope, CodeForCall, tempCodeBlock);
+        EXCEPTION_ASSERT(throwScope.exception() == compileError.value_or(nullptr));
         if (UNLIKELY(!!compileError))
-            return checkedReturn(compileError);
+            return checkedReturn(*compileError);
         codeBlock = jsCast<EvalCodeBlock*>(tempCodeBlock);
     }
 
@@ -1160,10 +1161,10 @@ JSValue Interpreter::executeModuleProgram(ModuleProgramExecutable* executable, C
     ModuleProgramCodeBlock* codeBlock;
     {
         CodeBlock* tempCodeBlock;
-        JSObject* compileError = executable->prepareForExecution<ModuleProgramExecutable>(vm, nullptr, scope, CodeForCall, tempCodeBlock);
-        EXCEPTION_ASSERT(throwScope.exception() == reinterpret_cast<Exception*>(compileError));
+        std::optional<Exception*> compileError = executable->prepareForExecution<ModuleProgramExecutable>(vm, nullptr, scope, CodeForCall, tempCodeBlock);
+        EXCEPTION_ASSERT(throwScope.exception() == compileError.value_or(nullptr));
         if (UNLIKELY(!!compileError))
-            return checkedReturn(compileError);
+            return checkedReturn(*compileError);
         codeBlock = jsCast<ModuleProgramCodeBlock*>(tempCodeBlock);
     }
 
index b5e192c..ce10e72 100644 (file)
@@ -1040,8 +1040,8 @@ SlowPathReturnType JIT_OPERATION operationLinkCall(ExecState* execCallee, CallLi
         }
 
         CodeBlock** codeBlockSlot = execCallee->addressOfCodeBlock();
-        JSObject* error = functionExecutable->prepareForExecution<FunctionExecutable>(*vm, callee, scope, kind, *codeBlockSlot);
-        EXCEPTION_ASSERT(throwScope.exception() == reinterpret_cast<Exception*>(error));
+        std::optional<Exception*> error = functionExecutable->prepareForExecution<FunctionExecutable>(*vm, callee, scope, kind, *codeBlockSlot);
+        EXCEPTION_ASSERT(throwScope.exception() == error.value_or(nullptr));
         if (error)
             return handleThrowException();
         codeBlock = *codeBlockSlot;
@@ -1096,8 +1096,8 @@ void JIT_OPERATION operationLinkDirectCall(ExecState* exec, CallLinkInfo* callLi
 
         RELEASE_ASSERT(isCall(kind) || functionExecutable->constructAbility() != ConstructAbility::CannotConstruct);
         
-        JSObject* error = functionExecutable->prepareForExecution<FunctionExecutable>(*vm, callee, scope, kind, codeBlock);
-        EXCEPTION_ASSERT_UNUSED(throwScope, throwScope.exception() == reinterpret_cast<Exception*>(error));
+        std::optional<Exception*> error = functionExecutable->prepareForExecution<FunctionExecutable>(*vm, callee, scope, kind, codeBlock);
+        EXCEPTION_ASSERT_UNUSED(throwScope, throwScope.exception() == error.value_or(nullptr));
         if (error)
             return;
         unsigned argumentStackSlots = callLinkInfo->maxNumArguments();
@@ -1145,8 +1145,8 @@ inline SlowPathReturnType virtualForWithFunction(
         }
 
         CodeBlock** codeBlockSlot = execCallee->addressOfCodeBlock();
-        JSObject* error = functionExecutable->prepareForExecution<FunctionExecutable>(*vm, function, scope, kind, *codeBlockSlot);
-        EXCEPTION_ASSERT(throwScope.exception() == reinterpret_cast<Exception*>(error));
+        std::optional<Exception*> error = functionExecutable->prepareForExecution<FunctionExecutable>(*vm, function, scope, kind, *codeBlockSlot);
+        EXCEPTION_ASSERT(throwScope.exception() == error.value_or(nullptr));
         if (error) {
             return encodeResult(
                 vm->getCTIStub(throwExceptionFromCallSlowPathGenerator).retaggedCode<JSEntryPtrTag>().executableAddress(),
index eead24d..cc5e7c5 100644 (file)
@@ -1484,10 +1484,10 @@ inline SlowPathReturnType setUpCall(ExecState* execCallee, Instruction* pc, Code
             LLINT_CALL_THROW(exec, createNotAConstructorError(exec, callee));
 
         CodeBlock** codeBlockSlot = execCallee->addressOfCodeBlock();
-        JSObject* error = functionExecutable->prepareForExecution<FunctionExecutable>(vm, callee, scope, kind, *codeBlockSlot);
-        EXCEPTION_ASSERT(throwScope.exception() == error);
+        std::optional<Exception*> error = functionExecutable->prepareForExecution<FunctionExecutable>(vm, callee, scope, kind, *codeBlockSlot);
+        EXCEPTION_ASSERT(throwScope.exception() == error.value_or(nullptr));
         if (UNLIKELY(error))
-            LLINT_CALL_THROW(exec, error);
+            LLINT_CALL_THROW(exec, *error);
         codeBlock = *codeBlockSlot;
         ASSERT(codeBlock);
         ArityCheckMode arity;
index 3a6c1b7..ef091dc 100644 (file)
@@ -1550,7 +1550,10 @@ JSBigInt* JSBigInt::parseInt(ExecState* exec, VM& vm, CharType* data, unsigned l
 
 inline JSBigInt::Digit* JSBigInt::dataStorage()
 {
-    return reinterpret_cast<Digit*>(reinterpret_cast<char*>(this) + offsetOfData());
+    // offsetOfData() makes sure that its return value is aligned to the size
+    // of Digit, so even though we cast to char* for pointer arithmetics, the
+    // bitwise_cast to Digit* is correct and properly aligned.
+    return bitwise_cast<Digit*>(reinterpret_cast<char*>(this) + offsetOfData());
 }
 
 inline JSBigInt::Digit JSBigInt::digit(unsigned n)
index 5236096..407e3a1 100644 (file)
@@ -29,6 +29,7 @@
 #include "CodeBlock.h"
 #include "Debugger.h"
 #include "EvalCodeBlock.h"
+#include "Exception.h"
 #include "FunctionCodeBlock.h"
 #include "IsoCellSetInlines.h"
 #include "JIT.h"
@@ -337,7 +338,7 @@ static void setupJIT(VM& vm, CodeBlock* codeBlock)
 #endif
 }
 
-JSObject* ScriptExecutable::prepareForExecutionImpl(
+std::optional<Exception*> ScriptExecutable::prepareForExecutionImpl(
     VM& vm, JSFunction* function, JSScope* scope, CodeSpecializationKind kind, CodeBlock*& resultCodeBlock)
 {
     auto throwScope = DECLARE_THROW_SCOPE(vm);
@@ -345,7 +346,7 @@ JSObject* ScriptExecutable::prepareForExecutionImpl(
 
     if (vm.getAndClearFailNextNewCodeBlock()) {
         auto& state = *scope->globalObject(vm)->globalExec();
-        return throwException(&state, throwScope, createError(&state, "Forced Failure"_s));
+        return static_cast<Exception*>(throwException(&state, throwScope, createError(&state, "Forced Failure"_s)));
     }
 
     JSObject* exception = nullptr;
@@ -353,7 +354,7 @@ JSObject* ScriptExecutable::prepareForExecutionImpl(
     resultCodeBlock = codeBlock;
     EXCEPTION_ASSERT(!!throwScope.exception() == !codeBlock);
     if (UNLIKELY(!codeBlock))
-        return exception;
+        return static_cast<Exception*>(exception);
     
     if (Options::validateBytecode())
         codeBlock->validate();
@@ -364,7 +365,7 @@ JSObject* ScriptExecutable::prepareForExecutionImpl(
         setupJIT(vm, codeBlock);
     
     installCode(vm, codeBlock, codeBlock->codeType(), codeBlock->specializationKind());
-    return nullptr;
+    return std::nullopt;
 }
 
 CodeBlockHash ScriptExecutable::hashFor(CodeSpecializationKind kind) const
index 8d891bd..7b76598 100644 (file)
@@ -105,11 +105,11 @@ public:
     // 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(VM&, JSFunction*, JSScope*, CodeSpecializationKind, CodeBlock*& resultCodeBlock);
+    std::optional<Exception*> prepareForExecution(VM&, JSFunction*, JSScope*, CodeSpecializationKind, CodeBlock*& resultCodeBlock);
 
 private:
     friend class ExecutableBase;
-    JSObject* prepareForExecutionImpl(VM&, JSFunction*, JSScope*, CodeSpecializationKind, CodeBlock*&);
+    std::optional<Exception*> prepareForExecutionImpl(VM&, JSFunction*, JSScope*, CodeSpecializationKind, CodeBlock*&);
 
 protected:
     ScriptExecutable(Structure*, VM&, const SourceCode&, bool isInStrictContext, DerivedContextType, bool isInArrowFunctionContext, EvalContextType, Intrinsic);
index f967781..8cc7f1d 100644 (file)
@@ -1462,7 +1462,7 @@ static CodeBlock* codeBlockFromArg(ExecState* exec)
             else
                 candidateCodeBlock = func->jsExecutable()->eitherCodeBlock();
         } else
-            candidateCodeBlock = reinterpret_cast<CodeBlock*>(value.asCell());
+            candidateCodeBlock = static_cast<CodeBlock*>(value.asCell());
     }
 
     if (candidateCodeBlock && VMInspector::isValidCodeBlock(exec, candidateCodeBlock))
index 69b00e1..7e29cde 100644 (file)
@@ -1,3 +1,21 @@
+2018-10-11  Guillaume Emont  <guijemont@igalia.com>
+
+        [JSC] Remove gcc warnings on mips and armv7
+        https://bugs.webkit.org/show_bug.cgi?id=188598
+
+        Reviewed by Mark Lam.
+
+        Add bitwise_cast (from WTF) and use it instead of reinterpret_cast in
+        a couple places where reinterpret_cast triggers a warning about
+        alignment even though we know that alignment is correct.
+
+        * bmalloc/Algorithm.h:
+        (bmalloc::bitwise_cast): Copied from WTF/wtf/StdLibextras.h
+        * bmalloc/IsoDirectoryPageInlines.h:
+        (bmalloc::IsoDirectoryPage<Config>::pageFor):
+        * bmalloc/IsoPageInlines.h:
+        (bmalloc::IsoPage<Config>::startAllocating):
+
 2018-10-03  Dan Bernstein  <mitz@apple.com>
 
         bmalloc part of [Xcode] Update some build settings as recommended by Xcode 10
index e4e51a5..661c692 100644 (file)
@@ -30,6 +30,7 @@
 #include <algorithm>
 #include <cstdint>
 #include <cstddef>
+#include <cstring>
 #include <limits>
 #include <string.h>
 #include <type_traits>
@@ -181,6 +182,23 @@ bool findBitInWord(T word, size_t& index, size_t endIndex, bool value)
     return false;
 }
 
+// Copied from WTF/wtf/StdLibExtras.h
+template<typename ToType, typename FromType>
+inline ToType bitwise_cast(FromType from)
+{
+    static_assert(sizeof(FromType) == sizeof(ToType), "bitwise_cast size of FromType and ToType must be equal!");
+#if defined(__has_feature)
+#if __has_feature(is_trivially_copyable)
+    // Not all recent STL implementations support the std::is_trivially_copyable type trait. Work around this by only checking on toolchains which have the equivalent compiler intrinsic.
+    static_assert(__is_trivially_copyable(ToType), "bitwise_cast of non-trivially-copyable type!");
+    static_assert(__is_trivially_copyable(FromType), "bitwise_cast of non-trivially-copyable type!");
+#endif
+#endif
+    typename std::remove_const<ToType>::type to { };
+    std::memcpy(static_cast<void*>(&to), static_cast<void*>(&from), sizeof(to));
+    return to;
+}
+
 } // namespace bmalloc
 
 #endif // Algorithm_h
index a149e10..7ceab8b 100644 (file)
@@ -39,7 +39,10 @@ IsoDirectoryPage<Config>::IsoDirectoryPage(IsoHeapImpl<Config>& heap, unsigned i
 template<typename Config>
 IsoDirectoryPage<Config>* IsoDirectoryPage<Config>::pageFor(IsoDirectory<Config, numPages>* payload)
 {
-    return reinterpret_cast<IsoDirectoryPage<Config>*>(
+    // the char* cast is only used to do a pointer calculation, and said
+    // calculation results in a pointer to an existing, correctly aligned
+    // IsoDirectoryPage.
+    return bitwise_cast<IsoDirectoryPage<Config>*>(
         reinterpret_cast<char*>(payload) - BOFFSETOF(IsoDirectoryPage, payload));
 }
 
index 0c47864..ac57266 100644 (file)
@@ -188,7 +188,10 @@ FreeList IsoPage<Config>::startAllocating()
         char* cellByte = reinterpret_cast<char*>(this) + index * Config::objectSize;
         if (verbose)
             fprintf(stderr, "%p: putting %p on free list.\n", this, cellByte);
-        FreeCell* cell = reinterpret_cast<FreeCell*>(cellByte);
+
+        static_assert(!(Config::objectSize % alignof(FreeCell)), "Config::objectSize should respect alignment of FreeCell");
+        static_assert(!(alignof(IsoPage<Config>) % alignof(FreeCell)), "Alignment of IsoPage<Config> should match that of FreeCell");
+        FreeCell* cell = bitwise_cast<FreeCell*>(cellByte);
         cell->setNext(head, secret);
         head = cell;
         bytes += Config::objectSize;