LCOV - code coverage report
Current view: top level - js/src/wasm - WasmTable.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 90 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 12 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
       2             :  * vim: set ts=8 sts=4 et sw=4 tw=99:
       3             :  *
       4             :  * Copyright 2016 Mozilla Foundation
       5             :  *
       6             :  * Licensed under the Apache License, Version 2.0 (the "License");
       7             :  * you may not use this file except in compliance with the License.
       8             :  * You may obtain a copy of the License at
       9             :  *
      10             :  *     http://www.apache.org/licenses/LICENSE-2.0
      11             :  *
      12             :  * Unless required by applicable law or agreed to in writing, software
      13             :  * distributed under the License is distributed on an "AS IS" BASIS,
      14             :  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      15             :  * See the License for the specific language governing permissions and
      16             :  * limitations under the License.
      17             :  */
      18             : 
      19             : #include "wasm/WasmTable.h"
      20             : 
      21             : #include "mozilla/CheckedInt.h"
      22             : 
      23             : #include "jscntxt.h"
      24             : #include "jscompartment.h"
      25             : 
      26             : #include "wasm/WasmInstance.h"
      27             : #include "wasm/WasmJS.h"
      28             : 
      29             : using namespace js;
      30             : using namespace js::wasm;
      31             : using mozilla::CheckedInt;
      32             : 
      33           0 : Table::Table(JSContext* cx, const TableDesc& desc, HandleWasmTableObject maybeObject,
      34           0 :              UniqueByteArray array)
      35             :   : maybeObject_(maybeObject),
      36             :     observers_(cx->zone()),
      37           0 :     array_(Move(array)),
      38           0 :     kind_(desc.kind),
      39           0 :     length_(desc.limits.initial),
      40             :     maximum_(desc.limits.maximum),
      41           0 :     external_(desc.external)
      42           0 : {}
      43             : 
      44             : /* static */ SharedTable
      45           0 : Table::create(JSContext* cx, const TableDesc& desc, HandleWasmTableObject maybeObject)
      46             : {
      47             :     // The raw element type of a Table depends on whether it is external: an
      48             :     // external table can contain functions from multiple instances and thus
      49             :     // must store an additional instance pointer in each element.
      50           0 :     UniqueByteArray array;
      51           0 :     if (desc.external)
      52           0 :         array.reset((uint8_t*)cx->pod_calloc<ExternalTableElem>(desc.limits.initial));
      53             :     else
      54           0 :         array.reset((uint8_t*)cx->pod_calloc<void*>(desc.limits.initial));
      55           0 :     if (!array)
      56           0 :         return nullptr;
      57             : 
      58           0 :     return SharedTable(cx->new_<Table>(cx, desc, maybeObject, Move(array)));
      59             : }
      60             : 
      61             : void
      62           0 : Table::tracePrivate(JSTracer* trc)
      63             : {
      64             :     // If this table has a WasmTableObject, then this method is only called by
      65             :     // WasmTableObject's trace hook so maybeObject_ must already be marked.
      66             :     // TraceEdge is called so that the pointer can be updated during a moving
      67             :     // GC. TraceWeakEdge may sound better, but it is less efficient given that
      68             :     // we know object_ is already marked.
      69           0 :     if (maybeObject_) {
      70           0 :         MOZ_ASSERT(!gc::IsAboutToBeFinalized(&maybeObject_));
      71           0 :         TraceEdge(trc, &maybeObject_, "wasm table object");
      72             :     }
      73             : 
      74           0 :     if (external_) {
      75           0 :         ExternalTableElem* array = externalArray();
      76           0 :         for (uint32_t i = 0; i < length_; i++) {
      77           0 :             if (array[i].tls)
      78           0 :                 array[i].tls->instance->trace(trc);
      79             :             else
      80           0 :                 MOZ_ASSERT(!array[i].code);
      81             :         }
      82             :     }
      83           0 : }
      84             : 
      85             : void
      86           0 : Table::trace(JSTracer* trc)
      87             : {
      88             :     // The trace hook of WasmTableObject will call Table::tracePrivate at
      89             :     // which point we can mark the rest of the children. If there is no
      90             :     // WasmTableObject, call Table::tracePrivate directly. Redirecting through
      91             :     // the WasmTableObject avoids marking the entire Table on each incoming
      92             :     // edge (once per dependent Instance).
      93           0 :     if (maybeObject_)
      94           0 :         TraceEdge(trc, &maybeObject_, "wasm table object");
      95             :     else
      96           0 :         tracePrivate(trc);
      97           0 : }
      98             : 
      99             : void**
     100           0 : Table::internalArray() const
     101             : {
     102           0 :     MOZ_ASSERT(!external_);
     103           0 :     return (void**)array_.get();
     104             : }
     105             : 
     106             : ExternalTableElem*
     107           0 : Table::externalArray() const
     108             : {
     109           0 :     MOZ_ASSERT(external_);
     110           0 :     return (ExternalTableElem*)array_.get();
     111             : }
     112             : 
     113             : void
     114           0 : Table::set(uint32_t index, void* code, Instance& instance)
     115             : {
     116           0 :     if (external_) {
     117           0 :         ExternalTableElem& elem = externalArray()[index];
     118           0 :         if (elem.tls)
     119           0 :             JSObject::writeBarrierPre(elem.tls->instance->objectUnbarriered());
     120             : 
     121           0 :         elem.code = code;
     122           0 :         elem.tls = instance.tlsData();
     123             : 
     124           0 :         MOZ_ASSERT(elem.tls->instance->objectUnbarriered()->isTenured(), "no writeBarrierPost");
     125             :     } else {
     126           0 :         internalArray()[index] = code;
     127             :     }
     128           0 : }
     129             : 
     130             : void
     131           0 : Table::setNull(uint32_t index)
     132             : {
     133             :     // Only external tables can set elements to null after initialization.
     134           0 :     ExternalTableElem& elem = externalArray()[index];
     135           0 :     if (elem.tls)
     136           0 :         JSObject::writeBarrierPre(elem.tls->instance->objectUnbarriered());
     137             : 
     138           0 :     elem.code = nullptr;
     139           0 :     elem.tls = nullptr;
     140           0 : }
     141             : 
     142             : uint32_t
     143           0 : Table::grow(uint32_t delta, JSContext* cx)
     144             : {
     145             :     // This isn't just an optimization: movingGrowable() assumes that
     146             :     // onMovingGrowTable does not fire when length == maximum.
     147           0 :     if (!delta)
     148           0 :         return length_;
     149             : 
     150           0 :     uint32_t oldLength = length_;
     151             : 
     152           0 :     CheckedInt<uint32_t> newLength = oldLength;
     153           0 :     newLength += delta;
     154           0 :     if (!newLength.isValid())
     155           0 :         return -1;
     156             : 
     157           0 :     if (maximum_ && newLength.value() > maximum_.value())
     158           0 :         return -1;
     159             : 
     160           0 :     MOZ_ASSERT(movingGrowable());
     161             : 
     162           0 :     JSRuntime* rt = cx->runtime();  // Use JSRuntime's MallocProvider to avoid throwing.
     163             : 
     164             :     // Note that realloc does not release array_'s pointee (which is returned by
     165             :     // externalArray()) on failure which is exactly what we need here.
     166           0 :     ExternalTableElem* newArray = rt->pod_realloc(externalArray(), length_, newLength.value());
     167           0 :     if (!newArray)
     168           0 :         return -1;
     169           0 :     Unused << array_.release();
     170           0 :     array_.reset((uint8_t*)newArray);
     171             : 
     172             :     // Realloc does not zero the delta for us.
     173           0 :     PodZero(newArray + length_, delta);
     174           0 :     length_ = newLength.value();
     175             : 
     176           0 :     if (observers_.initialized()) {
     177           0 :         for (InstanceSet::Range r = observers_.all(); !r.empty(); r.popFront())
     178           0 :             r.front()->instance().onMovingGrowTable();
     179             :     }
     180             : 
     181           0 :     return oldLength;
     182             : }
     183             : 
     184             : bool
     185           0 : Table::movingGrowable() const
     186             : {
     187           0 :     return !maximum_ || length_ < maximum_.value();
     188             : }
     189             : 
     190             : bool
     191           0 : Table::addMovingGrowObserver(JSContext* cx, WasmInstanceObject* instance)
     192             : {
     193           0 :     MOZ_ASSERT(movingGrowable());
     194             : 
     195           0 :     if (!observers_.initialized() && !observers_.init()) {
     196           0 :         ReportOutOfMemory(cx);
     197           0 :         return false;
     198             :     }
     199             : 
     200           0 :     if (!observers_.putNew(instance)) {
     201           0 :         ReportOutOfMemory(cx);
     202           0 :         return false;
     203             :     }
     204             : 
     205           0 :     return true;
     206             : }
     207             : 
     208             : size_t
     209           0 : Table::sizeOfExcludingThis(MallocSizeOf mallocSizeOf) const
     210             : {
     211           0 :     return mallocSizeOf(array_.get());
     212             : }

Generated by: LCOV version 1.13