// FIXME: Use the enumeration cache.
EncodedJSValue JSC_HOST_CALL objectConstructorKeys(ExecState* exec)
{
    if (!exec->argument(0).isObject())
        return throwVMError(exec, createTypeError(exec, ASCIILiteral("Requested keys of a value that is not an object.")));
    PropertyNameArray properties(exec);
    asObject(exec->argument(0))->methodTable(exec->vm())->getOwnPropertyNames(asObject(exec->argument(0)), exec, properties, ExcludeDontEnumProperties);
    JSArray* keys = constructEmptyArray(exec, 0);
    size_t numProperties = properties.size();
    for (size_t i = 0; i < numProperties; i++)
        keys->push(exec, jsOwnedString(exec, properties[i].string()));
    return JSValue::encode(keys);
}
Beispiel #2
0
// FIXME: Use the enumeration cache.
EncodedJSValue JSC_HOST_CALL objectConstructorGetOwnPropertyNames(ExecState* exec)
{
    if (!exec->argument(0).isObject())
        return throwVMError(exec, createTypeError(exec, "Requested property names of a value that is not an object."));
    PropertyNameArray properties(exec);
    asObject(exec->argument(0))->getOwnPropertyNames(exec, properties, IncludeDontEnumProperties);
    JSArray* names = constructEmptyArray(exec);
    size_t numProperties = properties.size();
    for (size_t i = 0; i < numProperties; i++)
        names->push(exec, jsOwnedString(exec, properties[i].ustring()));
    return JSValue::encode(names);
}
JSArray* ShadowChicken::functionsOnStack(ExecState* exec)
{
    JSArray* result = constructEmptyArray(exec, 0);

    iterate(
        exec->vm(), exec,
        [&] (const Frame& frame) -> bool {
            result->push(exec, frame.callee);
            return true;
        });
    
    return result;
}
Beispiel #4
0
JSArray* ShadowChicken::functionsOnStack(ExecState* exec)
{
    VM& vm = exec->vm();
    auto scope = DECLARE_THROW_SCOPE(vm);
    JSArray* result = constructEmptyArray(exec, 0);
    RETURN_IF_EXCEPTION(scope, nullptr);

    iterate(
        vm, exec,
        [&] (const Frame& frame) -> bool {
            result->push(exec, frame.callee);
            RELEASE_ASSERT(!scope.exception()); // This function is only called from tests.
            return true;
        });
    
    return result;
}
JSValue Compilation::toJS(ExecState* exec) const
{
    JSObject* result = constructEmptyObject(exec);

    result->putDirect(exec->vm(), exec->propertyNames().bytecodesID, jsNumber(m_bytecodes->id()));
    result->putDirect(exec->vm(), exec->propertyNames().compilationKind, jsString(exec, String::fromUTF8(toCString(m_kind))));

    JSArray* profiledBytecodes = constructEmptyArray(exec, 0);
    for (unsigned i = 0; i < m_profiledBytecodes.size(); ++i)
        profiledBytecodes->putDirectIndex(exec, i, m_profiledBytecodes[i].toJS(exec));
    result->putDirect(exec->vm(), exec->propertyNames().profiledBytecodes, profiledBytecodes);

    JSArray* descriptions = constructEmptyArray(exec, 0);
    for (unsigned i = 0; i < m_descriptions.size(); ++i)
        descriptions->putDirectIndex(exec, i, m_descriptions[i].toJS(exec));
    result->putDirect(exec->vm(), exec->propertyNames().descriptions, descriptions);

    JSArray* counters = constructEmptyArray(exec, 0);
    for (auto it = m_counters.begin(), end = m_counters.end(); it != end; ++it) {
        JSObject* counterEntry = constructEmptyObject(exec);
        counterEntry->putDirect(exec->vm(), exec->propertyNames().origin, it->key.toJS(exec));
        counterEntry->putDirect(exec->vm(), exec->propertyNames().executionCount, jsNumber(it->value->count()));
        counters->push(exec, counterEntry);
    }
    result->putDirect(exec->vm(), exec->propertyNames().counters, counters);

    JSArray* exitSites = constructEmptyArray(exec, 0);
    for (unsigned i = 0; i < m_osrExitSites.size(); ++i)
        exitSites->putDirectIndex(exec, i, m_osrExitSites[i].toJS(exec));
    result->putDirect(exec->vm(), exec->propertyNames().osrExitSites, exitSites);

    JSArray* exits = constructEmptyArray(exec, 0);
    for (unsigned i = 0; i < m_osrExits.size(); ++i)
        exits->putDirectIndex(exec, i, m_osrExits[i].toJS(exec));
    result->putDirect(exec->vm(), exec->propertyNames().osrExits, exits);

    result->putDirect(exec->vm(), exec->propertyNames().numInlinedGetByIds, jsNumber(m_numInlinedGetByIds));
    result->putDirect(exec->vm(), exec->propertyNames().numInlinedPutByIds, jsNumber(m_numInlinedPutByIds));
    result->putDirect(exec->vm(), exec->propertyNames().numInlinedCalls, jsNumber(m_numInlinedCalls));
    result->putDirect(exec->vm(), exec->propertyNames().jettisonReason, jsString(exec, String::fromUTF8(toCString(m_jettisonReason))));
    if (!m_additionalJettisonReason.isNull())
        result->putDirect(exec->vm(), exec->propertyNames().additionalJettisonReason, jsString(exec, String::fromUTF8(m_additionalJettisonReason)));

    return result;
}
Beispiel #6
0
JSValue Compilation::toJS(ExecState* exec) const
{
    JSObject* result = constructEmptyObject(exec);
    
    result->putDirect(exec->globalData(), exec->propertyNames().bytecodesID, jsNumber(m_bytecodes->id()));
    result->putDirect(exec->globalData(), exec->propertyNames().compilationKind, jsString(exec, String::fromUTF8(toCString(m_kind))));
    
    JSArray* profiledBytecodes = constructEmptyArray(exec, 0);
    for (unsigned i = 0; i < m_profiledBytecodes.size(); ++i)
        profiledBytecodes->putDirectIndex(exec, i, m_profiledBytecodes[i].toJS(exec));
    result->putDirect(exec->globalData(), exec->propertyNames().profiledBytecodes, profiledBytecodes);
    
    JSArray* descriptions = constructEmptyArray(exec, 0);
    for (unsigned i = 0; i < m_descriptions.size(); ++i)
        descriptions->putDirectIndex(exec, i, m_descriptions[i].toJS(exec));
    result->putDirect(exec->globalData(), exec->propertyNames().descriptions, descriptions);
    
    JSArray* counters = constructEmptyArray(exec, 0);
    HashMap<OriginStack, OwnPtr<ExecutionCounter> >::const_iterator end = m_counters.end();
    for (HashMap<OriginStack, OwnPtr<ExecutionCounter> >::const_iterator iter = m_counters.begin(); iter != end; ++iter) {
        JSObject* counterEntry = constructEmptyObject(exec);
        counterEntry->putDirect(exec->globalData(), exec->propertyNames().origin, iter->key.toJS(exec));
        counterEntry->putDirect(exec->globalData(), exec->propertyNames().executionCount, jsNumber(iter->value->count()));
        counters->push(exec, counterEntry);
    }
    result->putDirect(exec->globalData(), exec->propertyNames().counters, counters);
    
    JSArray* exitSites = constructEmptyArray(exec, 0);
    for (unsigned i = 0; i < m_osrExitSites.size(); ++i)
        exitSites->putDirectIndex(exec, i, m_osrExitSites[i].toJS(exec));
    result->putDirect(exec->globalData(), exec->propertyNames().osrExitSites, exitSites);
    
    JSArray* exits = constructEmptyArray(exec, 0);
    for (unsigned i = 0; i < m_osrExits.size(); ++i)
        exits->putDirectIndex(exec, i, m_osrExits[i].toJS(exec));
    result->putDirect(exec->globalData(), exec->propertyNames().osrExits, exits);
    
    return result;
}
Beispiel #7
0
JSValue LiteralParser::parseArray()
{
    StackGuard guard(this);
    if (!guard.isSafe())
        return abortParse();
    JSArray* array = constructEmptyArray(m_exec);
    while (true) {
        m_lexer.next();
        JSValue value = parseExpression();
        if (m_aborted)
            return JSValue();
        if (!value)
            break;
        array->push(m_exec, value);

        if (m_lexer.currentToken().type != TokComma)
            break;
    }
    if (m_lexer.currentToken().type != TokRBracket)
        return abortParse();

    m_lexer.next();
    return array;
}
Beispiel #8
0
JSValue collectMatches(VM& vm, ExecState* exec, JSString* string, const String& s, RegExpConstructor* constructor, RegExp* regExp, const FixEndFunc& fixEnd)
{
    auto scope = DECLARE_THROW_SCOPE(vm);

    MatchResult result = constructor->performMatch(vm, regExp, string, s, 0);
    if (!result)
        return jsNull();
    
    static unsigned maxSizeForDirectPath = 100000;
    
    JSArray* array = constructEmptyArray(exec, nullptr);
    if (UNLIKELY(vm.exception()))
        return jsUndefined();

    auto iterate = [&] () {
        size_t end = result.end;
        size_t length = end - result.start;
        array->push(exec, JSRopeString::createSubstringOfResolved(vm, string, result.start, length));
        if (!length)
            end = fixEnd(end);
        result = constructor->performMatch(vm, regExp, string, s, end);
    };
    
    do {
        if (array->length() >= maxSizeForDirectPath) {
            // First do a throw-away match to see how many matches we'll get.
            unsigned matchCount = 0;
            MatchResult savedResult = result;
            do {
                if (array->length() + matchCount >= MAX_STORAGE_VECTOR_LENGTH) {
                    throwOutOfMemoryError(exec, scope);
                    return jsUndefined();
                }
                
                size_t end = result.end;
                matchCount++;
                if (result.empty())
                    end = fixEnd(end);
                
                // Using RegExpConstructor::performMatch() instead of calling RegExp::match()
                // directly is a surprising but profitable choice: it means that when we do OOM, we
                // will leave the cached result in the state it ought to have had just before the
                // OOM! On the other hand, if this loop concludes that the result is small enough,
                // then the iterate() loop below will overwrite the cached result anyway.
                result = constructor->performMatch(vm, regExp, string, s, end);
            } while (result);
            
            // OK, we have a sensible number of matches. Now we can create them for reals.
            result = savedResult;
            do
                iterate();
            while (result);
            
            return array;
        }
        
        iterate();
    } while (result);
    
    return array;
}
JSValue Compilation::toJS(ExecState* exec) const
{
    VM& vm = exec->vm();
    auto scope = DECLARE_THROW_SCOPE(vm);
    JSObject* result = constructEmptyObject(exec);
    RETURN_IF_EXCEPTION(scope, { });
    result->putDirect(vm, vm.propertyNames->bytecodesID, jsNumber(m_bytecodes->id()));
    result->putDirect(vm, vm.propertyNames->compilationKind, jsString(exec, String::fromUTF8(toCString(m_kind))));
    
    JSArray* profiledBytecodes = constructEmptyArray(exec, 0);
    RETURN_IF_EXCEPTION(scope, { });
    for (unsigned i = 0; i < m_profiledBytecodes.size(); ++i) {
        auto value = m_profiledBytecodes[i].toJS(exec);
        RETURN_IF_EXCEPTION(scope, { });
        profiledBytecodes->putDirectIndex(exec, i, value);
        RETURN_IF_EXCEPTION(scope, { });
    }
    result->putDirect(vm, vm.propertyNames->profiledBytecodes, profiledBytecodes);
    
    JSArray* descriptions = constructEmptyArray(exec, 0);
    RETURN_IF_EXCEPTION(scope, { });
    for (unsigned i = 0; i < m_descriptions.size(); ++i) {
        auto value = m_descriptions[i].toJS(exec);
        RETURN_IF_EXCEPTION(scope, { });
        descriptions->putDirectIndex(exec, i, value);
        RETURN_IF_EXCEPTION(scope, { });
    }
    result->putDirect(vm, vm.propertyNames->descriptions, descriptions);
    
    JSArray* counters = constructEmptyArray(exec, 0);
    RETURN_IF_EXCEPTION(scope, { });
    for (auto it = m_counters.begin(), end = m_counters.end(); it != end; ++it) {
        JSObject* counterEntry = constructEmptyObject(exec);
        RETURN_IF_EXCEPTION(scope, { });
        auto value = it->key.toJS(exec);
        RETURN_IF_EXCEPTION(scope, { });
        counterEntry->putDirect(vm, vm.propertyNames->origin, value);
        counterEntry->putDirect(vm, vm.propertyNames->executionCount, jsNumber(it->value->count()));
        counters->push(exec, counterEntry);
        RETURN_IF_EXCEPTION(scope, { });
    }
    result->putDirect(vm, vm.propertyNames->counters, counters);
    
    JSArray* exitSites = constructEmptyArray(exec, 0);
    RETURN_IF_EXCEPTION(scope, { });
    for (unsigned i = 0; i < m_osrExitSites.size(); ++i) {
        auto value = m_osrExitSites[i].toJS(exec);
        RETURN_IF_EXCEPTION(scope, { });
        exitSites->putDirectIndex(exec, i, value);
        RETURN_IF_EXCEPTION(scope, { });
    }
    result->putDirect(vm, vm.propertyNames->osrExitSites, exitSites);
    
    JSArray* exits = constructEmptyArray(exec, 0);
    RETURN_IF_EXCEPTION(scope, { });
    for (unsigned i = 0; i < m_osrExits.size(); ++i) {
        exits->putDirectIndex(exec, i, m_osrExits[i].toJS(exec));
        RETURN_IF_EXCEPTION(scope, { });
    }
    result->putDirect(vm, vm.propertyNames->osrExits, exits);
    
    result->putDirect(vm, vm.propertyNames->numInlinedGetByIds, jsNumber(m_numInlinedGetByIds));
    result->putDirect(vm, vm.propertyNames->numInlinedPutByIds, jsNumber(m_numInlinedPutByIds));
    result->putDirect(vm, vm.propertyNames->numInlinedCalls, jsNumber(m_numInlinedCalls));
    result->putDirect(vm, vm.propertyNames->jettisonReason, jsString(exec, String::fromUTF8(toCString(m_jettisonReason))));
    if (!m_additionalJettisonReason.isNull())
        result->putDirect(vm, vm.propertyNames->additionalJettisonReason, jsString(exec, String::fromUTF8(m_additionalJettisonReason)));
    
    result->putDirect(vm, vm.propertyNames->uid, m_uid.toJS(exec));
    
    return result;
}
static JSValue performPromiseAll(ExecState* exec, JSValue iterator, JSValue C, JSPromiseDeferred* deferred)
{
    JSObject* thisObject = asObject(C);
    VM& vm = exec->vm();

    // 6. Let 'values' be the result of calling ArrayCreate(0).
    JSArray* values = constructEmptyArray(exec, nullptr, thisObject->globalObject());

    // 7. Let 'countdownHolder' be Record { [[Countdown]]: 0 }.
    NumberObject* countdownHolder = constructNumber(exec, thisObject->globalObject(), JSValue(0));

    // 8. Let 'index' be 0.
    unsigned index = 0;

    // 9. Repeat.
    do {
        // i. Let 'next' be the result of calling IteratorStep(iterator).
        JSValue next = iteratorStep(exec, iterator);
        if (exec->hadException())
            return jsUndefined();

        // iii. If 'next' is false,
        if (next.isFalse()) {
            // a. If 'index' is 0,
            if (!index) {
                // a. Let 'resolveResult' be the result of calling the [[Call]] internal method
                //    of deferred.[[Resolve]] with undefined as thisArgument and a List containing
                //    values as argumentsList.
                performDeferredResolve(exec, deferred, values);

                // b. ReturnIfAbrupt(resolveResult).
                if (exec->hadException())
                    return jsUndefined();
            }

            // b. Return deferred.[[Promise]].
            return deferred->promise();
        }

        // iv. Let 'nextValue' be the result of calling IteratorValue(next).
        // v. RejectIfAbrupt(nextValue, deferred).
        JSValue nextValue = iteratorValue(exec, next);
        if (exec->hadException())
            return jsUndefined();

        values->push(exec, jsUndefined());

        // vi. Let 'nextPromise' be the result of calling Invoke(C, "resolve", (nextValue)).
        JSValue resolveFunction = C.get(exec, vm.propertyNames->resolve);
        if (exec->hadException())
            return jsUndefined();

        CallData resolveFunctionCallData;
        CallType resolveFunctionCallType = getCallData(resolveFunction, resolveFunctionCallData);
        if (resolveFunctionCallType == CallTypeNone) {
            throwTypeError(exec);
            return jsUndefined();
        }

        MarkedArgumentBuffer resolveFunctionArguments;
        resolveFunctionArguments.append(nextValue);
        JSValue nextPromise = call(exec, resolveFunction, resolveFunctionCallType, resolveFunctionCallData, C, resolveFunctionArguments);

        // vii. RejectIfAbrupt(nextPromise, deferred).
        if (exec->hadException())
            return jsUndefined();

        // viii. Let 'countdownFunction' be a new built-in function object as defined in Promise.all Countdown Functions.
        JSFunction* countdownFunction = createPromiseAllCountdownFunction(vm, thisObject->globalObject());

        // ix. Set the [[Index]] internal slot of 'countdownFunction' to 'index'.
        countdownFunction->putDirect(vm, vm.propertyNames->indexPrivateName, JSValue(index));

        // x. Set the [[Values]] internal slot of 'countdownFunction' to 'values'.
        countdownFunction->putDirect(vm, vm.propertyNames->valuesPrivateName, values);

        // xi. Set the [[Deferred]] internal slot of 'countdownFunction' to 'deferred'.
        countdownFunction->putDirect(vm, vm.propertyNames->deferredPrivateName, deferred);

        // xii. Set the [[CountdownHolder]] internal slot of 'countdownFunction' to 'countdownHolder'.
        countdownFunction->putDirect(vm, vm.propertyNames->countdownHolderPrivateName, countdownHolder);

        // xiii. Let 'result' be the result of calling Invoke(nextPromise, "then", (countdownFunction, deferred.[[Reject]])).
        JSValue thenFunction = nextPromise.get(exec, vm.propertyNames->then);
        if (exec->hadException())
            return jsUndefined();

        CallData thenFunctionCallData;
        CallType thenFunctionCallType = getCallData(thenFunction, thenFunctionCallData);
        if (thenFunctionCallType == CallTypeNone) {
            throwTypeError(exec);
            return jsUndefined();
        }

        MarkedArgumentBuffer thenFunctionArguments;
        thenFunctionArguments.append(countdownFunction);
        thenFunctionArguments.append(deferred->reject());

        call(exec, thenFunction, thenFunctionCallType, thenFunctionCallData, nextPromise, thenFunctionArguments);

        // xiv. RejectIfAbrupt(result, deferred).
        if (exec->hadException())
            return jsUndefined();

        // xv. Set index to index + 1.
        index++;

        // xvi. Set countdownHolder.[[Countdown]] to countdownHolder.[[Countdown]] + 1.
        uint32_t newCountdownValue = countdownHolder->internalValue().asUInt32() + 1;
        countdownHolder->setInternalValue(vm, JSValue(newCountdownValue));
    } while (true);
    ASSERT_NOT_REACHED();
    return jsUndefined();
}
Beispiel #11
0
JSObject* addErrorInfo(ExecState* exec, JSObject* error, int line, const SourceCode& source)
{
    JSGlobalData* globalData = &exec->globalData();

    addErrorInfo(globalData, error, line, source);

    UStringBuilder stackString;
    JSArray* stackArray = constructEmptyArray(exec);
    CallFrame* frame = exec;

    stackString.append(error->toString(exec));

    bool functionKnown;
    ReturnAddressPtr pc;

    while (!frame->hasHostCallFrameFlag()) {
        CodeBlock* codeBlock = frame->codeBlock();
        JSObject* arrayItem = constructEmptyObject(exec);

        stackString.append("\n    at ");

        JSObject* callee = frame->callee();
        UString functionName;

        if (callee && callee->inherits(&JSFunction::s_info)) {
            functionName = asFunction(callee)->calculatedDisplayName(exec);
            functionKnown = !functionName.isEmpty();
        } else {
            functionKnown = false;
        }

        if (functionKnown) {
            stackString.append(functionName);
            stackString.append(" (");

            arrayItem->putWithAttributes(
                globalData, Identifier(globalData, functionPropertyName),
                jsString(globalData, functionName), ReadOnly | DontDelete
            );
        }

        UString sourceURL = codeBlock->ownerExecutable()->sourceURL();

        arrayItem->putWithAttributes(
            globalData, Identifier(globalData, sourceURLPropertyName),
            jsString(globalData, sourceURL), ReadOnly | DontDelete
        );

        stackString.append(sourceURL);
        stackString.append(":");

        if (frame != exec) {
            line = codeBlock->lineNumberForBytecodeOffset(codeBlock->bytecodeOffset(pc));
        }

        arrayItem->putWithAttributes(
            globalData, Identifier(globalData, linePropertyName),
            jsNumber(line), ReadOnly | DontDelete
        );

        stackString.append(UString::number(line));

        if (functionKnown) {
            stackString.append(")");
        }

        stackArray->push(exec, JSValue(arrayItem));

        pc = frame->returnPC();
        frame = frame->callerFrame();
    }

    error->putWithAttributes(
        globalData, Identifier(globalData, stackPropertyName),
        jsString(globalData, stackString.toUString()), ReadOnly | DontDelete
    );

    error->putWithAttributes(
        globalData, Identifier(globalData, "stackArray"),
        stackArray, ReadOnly | DontDelete
    );

    return error;
}