LCOV - code coverage report
Current view: top level - js/src/vm - ForOfIterator.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 57 114 50.0 %
Date: 2017-07-14 16:53:18 Functions: 3 5 60.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             :  * This Source Code Form is subject to the terms of the Mozilla Public
       4             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       5             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : #include "jsapi.h"
       8             : #include "jscntxt.h"
       9             : #include "jscompartment.h"
      10             : #include "jsobj.h"
      11             : 
      12             : #include "vm/Interpreter.h"
      13             : #include "vm/PIC.h"
      14             : 
      15             : #include "jsobjinlines.h"
      16             : 
      17             : using namespace js;
      18             : using JS::ForOfIterator;
      19             : 
      20             : bool
      21           4 : ForOfIterator::init(HandleValue iterable, NonIterableBehavior nonIterableBehavior)
      22             : {
      23           4 :     JSContext* cx = cx_;
      24           8 :     RootedObject iterableObj(cx, ToObject(cx, iterable));
      25           4 :     if (!iterableObj)
      26           0 :         return false;
      27             : 
      28           4 :     MOZ_ASSERT(index == NOT_ARRAY);
      29             : 
      30             :     // Check the PIC first for a match.
      31           4 :     if (iterableObj->is<ArrayObject>()) {
      32           3 :         ForOfPIC::Chain* stubChain = ForOfPIC::getOrCreate(cx);
      33           3 :         if (!stubChain)
      34           3 :             return false;
      35             : 
      36             :         bool optimized;
      37           3 :         if (!stubChain->tryOptimizeArray(cx, iterableObj.as<ArrayObject>(), &optimized))
      38           0 :             return false;
      39             : 
      40           3 :         if (optimized) {
      41             :             // Got optimized stub.  Array is optimizable.
      42           3 :             index = 0;
      43           3 :             iterator = iterableObj;
      44           3 :             return true;
      45             :         }
      46             :     }
      47             : 
      48           1 :     MOZ_ASSERT(index == NOT_ARRAY);
      49             : 
      50           2 :     RootedValue callee(cx);
      51           2 :     RootedId iteratorId(cx, SYMBOL_TO_JSID(cx->wellKnownSymbols().iterator));
      52           1 :     if (!GetProperty(cx, iterableObj, iterableObj, iteratorId, &callee))
      53           0 :         return false;
      54             : 
      55             :     // If obj[@@iterator] is undefined and we were asked to allow non-iterables,
      56             :     // bail out now without setting iterator.  This will make valueIsIterable(),
      57             :     // which our caller should check, return false.
      58           1 :     if (nonIterableBehavior == AllowNonIterable && callee.isUndefined())
      59           0 :         return true;
      60             : 
      61             :     // Throw if obj[@@iterator] isn't callable.
      62             :     // js::Invoke is about to check for this kind of error anyway, but it would
      63             :     // throw an inscrutable error message about |method| rather than this nice
      64             :     // one about |obj|.
      65           1 :     if (!callee.isObject() || !callee.toObject().isCallable()) {
      66           0 :         UniqueChars bytes = DecompileValueGenerator(cx, JSDVG_SEARCH_STACK, iterable, nullptr);
      67           0 :         if (!bytes)
      68           0 :             return false;
      69           0 :         JS_ReportErrorNumberLatin1(cx, GetErrorMessage, nullptr, JSMSG_NOT_ITERABLE, bytes.get());
      70           0 :         return false;
      71             :     }
      72             : 
      73           2 :     RootedValue res(cx);
      74           1 :     if (!js::Call(cx, callee, iterable, &res))
      75           0 :         return false;
      76             : 
      77           1 :     if (!res.isObject())
      78           0 :         return ThrowCheckIsObject(cx, CheckIsObjectKind::GetIterator);
      79             : 
      80           1 :     iterator = &res.toObject();
      81           1 :     return true;
      82             : }
      83             : 
      84             : inline bool
      85           8 : ForOfIterator::nextFromOptimizedArray(MutableHandleValue vp, bool* done)
      86             : {
      87           8 :     MOZ_ASSERT(index != NOT_ARRAY);
      88             : 
      89           8 :     if (!CheckForInterrupt(cx_))
      90           0 :         return false;
      91             : 
      92           8 :     ArrayObject* arr = &iterator->as<ArrayObject>();
      93             : 
      94           8 :     if (index >= arr->length()) {
      95           3 :         vp.setUndefined();
      96           3 :         *done = true;
      97           3 :         return true;
      98             :     }
      99           5 :     *done = false;
     100             : 
     101             :     // Try to get array element via direct access.
     102           5 :     if (index < arr->getDenseInitializedLength()) {
     103           5 :         vp.set(arr->getDenseElement(index));
     104           5 :         if (!vp.isMagic(JS_ELEMENTS_HOLE)) {
     105           5 :             ++index;
     106           5 :             return true;
     107             :         }
     108             :     }
     109             : 
     110           0 :     return GetElement(cx_, iterator, iterator, index++, vp);
     111             : }
     112             : 
     113             : bool
     114          12 : ForOfIterator::next(MutableHandleValue vp, bool* done)
     115             : {
     116          12 :     MOZ_ASSERT(iterator);
     117          12 :     if (index != NOT_ARRAY) {
     118           8 :         ForOfPIC::Chain* stubChain = ForOfPIC::getOrCreate(cx_);
     119           8 :         if (!stubChain)
     120           0 :             return false;
     121             : 
     122           8 :         if (stubChain->isArrayNextStillSane())
     123           8 :             return nextFromOptimizedArray(vp, done);
     124             : 
     125             :         // ArrayIterator.prototype.next changed, materialize a proper
     126             :         // ArrayIterator instance and fall through to slowpath case.
     127           0 :         if (!materializeArrayIterator())
     128           0 :             return false;
     129             :     }
     130             : 
     131           8 :     RootedValue v(cx_);
     132           4 :     if (!GetProperty(cx_, iterator, iterator, cx_->names().next, &v))
     133           0 :         return false;
     134             : 
     135           4 :     if (!js::Call(cx_, v, iterator, &v))
     136           0 :         return false;
     137             : 
     138           4 :     if (!v.isObject())
     139           0 :         return ThrowCheckIsObject(cx_, CheckIsObjectKind::IteratorNext);
     140             : 
     141           8 :     RootedObject resultObj(cx_, &v.toObject());
     142           4 :     if (!GetProperty(cx_, resultObj, resultObj, cx_->names().done, &v))
     143           0 :         return false;
     144             : 
     145           4 :     *done = ToBoolean(v);
     146           4 :     if (*done) {
     147           1 :         vp.setUndefined();
     148           1 :         return true;
     149             :     }
     150             : 
     151           3 :     return GetProperty(cx_, resultObj, resultObj, cx_->names().value, vp);
     152             : }
     153             : 
     154             : // ES 2017 draft 0f10dba4ad18de92d47d421f378233a2eae8f077 7.4.6.
     155             : // When completion.[[Type]] is throw.
     156             : void
     157           0 : ForOfIterator::closeThrow()
     158             : {
     159           0 :     MOZ_ASSERT(iterator);
     160             : 
     161           0 :     RootedValue completionException(cx_);
     162           0 :     if (cx_->isExceptionPending()) {
     163           0 :         if (!GetAndClearException(cx_, &completionException))
     164           0 :             completionException.setUndefined();
     165             :     }
     166             : 
     167             :     // Steps 1-2 (implicit)
     168             : 
     169             :     // Step 3 (partial).
     170           0 :     RootedValue returnVal(cx_);
     171           0 :     if (!GetProperty(cx_, iterator, iterator, cx_->names().return_, &returnVal))
     172           0 :         return;
     173             : 
     174             :     // Step 4.
     175           0 :     if (returnVal.isUndefined()) {
     176           0 :         cx_->setPendingException(completionException);
     177           0 :         return;
     178             :     }
     179             : 
     180             :     // Step 3 (remaining part)
     181           0 :     if (!returnVal.isObject()) {
     182           0 :         JS_ReportErrorNumberASCII(cx_, GetErrorMessage, nullptr, JSMSG_RETURN_NOT_CALLABLE);
     183           0 :         return;
     184             :     }
     185           0 :     RootedObject returnObj(cx_, &returnVal.toObject());
     186           0 :     if (!returnObj->isCallable()) {
     187           0 :         JS_ReportErrorNumberASCII(cx_, GetErrorMessage, nullptr, JSMSG_RETURN_NOT_CALLABLE);
     188           0 :         return;
     189             :     }
     190             : 
     191             :     // Step 5.
     192           0 :     RootedValue innerResultValue(cx_);
     193           0 :     if (!js::Call(cx_, returnVal, iterator, &innerResultValue)) {
     194           0 :         if (cx_->isExceptionPending())
     195           0 :             cx_->clearPendingException();
     196             :     }
     197             : 
     198             :     // Step 6.
     199           0 :     cx_->setPendingException(completionException);
     200             : 
     201             :     // Steps 7-9 (skipped).
     202           0 :     return;
     203             : }
     204             : 
     205             : bool
     206           0 : ForOfIterator::materializeArrayIterator()
     207             : {
     208           0 :     MOZ_ASSERT(index != NOT_ARRAY);
     209             : 
     210           0 :     HandlePropertyName name = cx_->names().ArrayValuesAt;
     211           0 :     RootedValue val(cx_);
     212           0 :     if (!GlobalObject::getSelfHostedFunction(cx_, cx_->global(), name, name, 1, &val))
     213           0 :         return false;
     214             : 
     215           0 :     RootedValue indexOrRval(cx_, Int32Value(index));
     216           0 :     if (!js::Call(cx_, val, iterator, indexOrRval, &indexOrRval))
     217           0 :         return false;
     218             : 
     219           0 :     index = NOT_ARRAY;
     220             :     // Result of call to ArrayValuesAt must be an object.
     221           0 :     iterator = &indexOrRval.toObject();
     222           0 :     return true;
     223             : }

Generated by: LCOV version 1.13