Exemplo n.º 1
0
JSFunction* JSFunction::createBuiltinFunction(VM& vm, FunctionExecutable* executable, JSGlobalObject* globalObject)
{
    JSFunction* function = create(vm, executable, globalObject);
    function->putDirect(vm, vm.propertyNames->name, jsString(&vm, executable->name().string()), DontDelete | ReadOnly | DontEnum);
    function->putDirect(vm, vm.propertyNames->length, jsNumber(executable->parameterCount()), DontDelete | ReadOnly | DontEnum);
    return function;
}
Exemplo n.º 2
0
static EncodedJSValue JSC_HOST_CALL constructPromise(ExecState* exec)
{
    // NOTE: We ignore steps 1-4 as they only matter if you support subclassing, which we do not yet.
    // 1. Let promise be the this value.
    // 2. If Type(promise) is not Object, then throw a TypeError exception.
    // 3. If promise does not have a [[PromiseStatus]] internal slot, then throw a TypeError exception.
    // 4. If promise's [[PromiseStatus]] internal slot is not undefined, then throw a TypeError exception.

    JSValue resolver = exec->argument(0);

    // 5. IsCallable(resolver) is false, then throw a TypeError exception
    CallData callData;
    CallType callType = getCallData(resolver, callData);
    if (callType == CallTypeNone)
        return JSValue::encode(throwTypeError(exec, ASCIILiteral("Promise constructor takes a function argument")));

    VM& vm = exec->vm();
    JSGlobalObject* globalObject = exec->callee()->globalObject();

    JSPromise* promise = JSPromise::create(vm, globalObject, jsCast<JSPromiseConstructor*>(exec->callee()));

    // NOTE: Steps 6-8 are handled by JSPromise::create().
    // 6. Set promise's [[PromiseStatus]] internal slot to "unresolved".
    // 7. Set promise's [[ResolveReactions]] internal slot to a new empty List.
    // 8. Set promise's [[RejectReactions]] internal slot to a new empty List.
    
    // 9. Let 'resolve' be a new built-in function object as defined in Resolve Promise Functions.
    JSFunction* resolve = createResolvePromiseFunction(vm, globalObject);

    // 10. Set the [[Promise]] internal slot of 'resolve' to 'promise'.
    resolve->putDirect(vm, vm.propertyNames->promisePrivateName, promise);
    
    // 11. Let 'reject' be a new built-in function object as defined in Reject Promise Functions
    JSFunction* reject = createRejectPromiseFunction(vm, globalObject);

    // 12. Set the [[Promise]] internal slot of 'reject' to 'promise'.
    reject->putDirect(vm, vm.propertyNames->promisePrivateName, promise);

    // 13. Let 'result' be the result of calling the [[Call]] internal method of resolver with
    //     undefined as thisArgument and a List containing resolve and reject as argumentsList.
    MarkedArgumentBuffer arguments;
    arguments.append(resolve);
    arguments.append(reject);
    call(exec, resolver, callType, callData, jsUndefined(), arguments);

    // 14. If result is an abrupt completion, call PromiseReject(promise, result.[[value]]).
    if (exec->hadException()) {
        JSValue exception = exec->exception()->value();
        exec->clearException();

        promise->reject(vm, exception);
    }

    // 15. Return promise.
    return JSValue::encode(promise);
}
Exemplo n.º 3
0
bool JSFunction::getOwnPropertySlot(JSCell* cell, ExecState* exec, PropertyName propertyName, PropertySlot& slot)
{
    JSFunction* thisObject = jsCast<JSFunction*>(cell);
    if (thisObject->isHostFunction())
        return Base::getOwnPropertySlot(thisObject, exec, propertyName, slot);

    if (propertyName == exec->propertyNames().prototype) {
        JSGlobalData& globalData = exec->globalData();
        PropertyOffset offset = thisObject->getDirectOffset(globalData, propertyName);
        if (!isValidOffset(offset)) {
            JSObject* prototype = constructEmptyObject(exec);
            prototype->putDirect(globalData, exec->propertyNames().constructor, thisObject, DontEnum);
            thisObject->putDirect(globalData, exec->propertyNames().prototype, prototype, DontDelete | DontEnum);
            offset = thisObject->getDirectOffset(globalData, exec->propertyNames().prototype);
            ASSERT(isValidOffset(offset));
        }

        slot.setValue(thisObject, thisObject->getDirect(offset), offset);
    }

    if (propertyName == exec->propertyNames().arguments) {
        if (thisObject->jsExecutable()->isStrictMode()) {
            bool result = Base::getOwnPropertySlot(thisObject, exec, propertyName, slot);
            if (!result) {
                thisObject->putDirectAccessor(exec, propertyName, thisObject->globalObject()->throwTypeErrorGetterSetter(exec), DontDelete | DontEnum | Accessor);
                result = Base::getOwnPropertySlot(thisObject, exec, propertyName, slot);
                ASSERT(result);
            }
            return result;
        }
        slot.setCacheableCustom(thisObject, argumentsGetter);
        return true;
    }

    if (propertyName == exec->propertyNames().length) {
        slot.setCacheableCustom(thisObject, lengthGetter);
        return true;
    }

    if (propertyName == exec->propertyNames().name) {
        slot.setCacheableCustom(thisObject, nameGetter);
        return true;
    }

    if (propertyName == exec->propertyNames().caller) {
        if (thisObject->jsExecutable()->isStrictMode()) {
            bool result = Base::getOwnPropertySlot(thisObject, exec, propertyName, slot);
            if (!result) {
                thisObject->putDirectAccessor(exec, propertyName, thisObject->globalObject()->throwTypeErrorGetterSetter(exec), DontDelete | DontEnum | Accessor);
                result = Base::getOwnPropertySlot(thisObject, exec, propertyName, slot);
                ASSERT(result);
            }
            return result;
        }
        slot.setCacheableCustom(thisObject, callerGetter);
        return true;
    }

    return Base::getOwnPropertySlot(thisObject, exec, propertyName, slot);
}
Exemplo n.º 4
0
bool JSFunction::getOwnPropertySlot(JSCell* cell, ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
{
    JSFunction* thisObject = static_cast<JSFunction*>(cell);
    if (thisObject->isHostFunction())
        return Base::getOwnPropertySlot(thisObject, exec, propertyName, slot);

    if (propertyName == exec->propertyNames().prototype) {
        WriteBarrierBase<Unknown>* location = thisObject->getDirectLocation(exec->globalData(), propertyName);

        if (!location) {
            JSObject* prototype = constructEmptyObject(exec, thisObject->globalObject()->emptyObjectStructure());
            prototype->putDirect(exec->globalData(), exec->propertyNames().constructor, thisObject, DontEnum);
            PutPropertySlot slot;
            thisObject->putDirect(exec->globalData(), exec->propertyNames().prototype, prototype, DontDelete | DontEnum, false, slot);
            location = thisObject->getDirectLocation(exec->globalData(), exec->propertyNames().prototype);
        }

        slot.setValue(thisObject, location->get(), thisObject->offsetForLocation(location));
    }

    if (propertyName == exec->propertyNames().arguments) {
        if (thisObject->jsExecutable()->isStrictMode()) {
            bool result = Base::getOwnPropertySlot(thisObject, exec, propertyName, slot);
            if (!result) {
                thisObject->initializeGetterSetterProperty(exec, propertyName, thisObject->globalObject()->throwTypeErrorGetterSetter(exec), DontDelete | DontEnum | Getter | Setter);
                result = Base::getOwnPropertySlot(thisObject, exec, propertyName, slot);
                ASSERT(result);
            }
            return result;
        }
        slot.setCacheableCustom(thisObject, argumentsGetter);
        return true;
    }

    if (propertyName == exec->propertyNames().length) {
        slot.setCacheableCustom(thisObject, lengthGetter);
        return true;
    }

    if (propertyName == exec->propertyNames().caller) {
        if (thisObject->jsExecutable()->isStrictMode()) {
            bool result = Base::getOwnPropertySlot(thisObject, exec, propertyName, slot);
            if (!result) {
                thisObject->initializeGetterSetterProperty(exec, propertyName, thisObject->globalObject()->throwTypeErrorGetterSetter(exec), DontDelete | DontEnum | Getter | Setter);
                result = Base::getOwnPropertySlot(thisObject, exec, propertyName, slot);
                ASSERT(result);
            }
            return result;
        }
        slot.setCacheableCustom(thisObject, callerGetter);
        return true;
    }

    return Base::getOwnPropertySlot(thisObject, exec, propertyName, slot);
}
Exemplo n.º 5
0
// ECMA 15.3.2 The Function Constructor
JSObject* constructFunction(ExecState* exec, const ArgList& args, const Identifier& functionName, const UString& sourceURL, int lineNumber)
{
    UString p("");
    UString body;
    int argsSize = args.size();
    if (argsSize == 0)
        body = "";
    else if (argsSize == 1)
        body = args[0]->toString(exec);
    else {
        p = args[0]->toString(exec);
        for (int k = 1; k < argsSize - 1; k++)
            p += "," + args[k]->toString(exec);
        body = args[argsSize - 1]->toString(exec);
    }

    // parse the source code
    int sourceId;
    int errLine;
    UString errMsg;
    RefPtr<SourceProvider> source = UStringSourceProvider::create(body);
    RefPtr<FunctionBodyNode> functionBody = exec->parser()->parse<FunctionBodyNode>(exec, sourceURL, lineNumber, source, &sourceId, &errLine, &errMsg);

    // No program node == syntax error - throw a syntax error
    if (!functionBody)
        // We can't return a Completion(Throw) here, so just set the exception
        // and return it
        return throwError(exec, SyntaxError, errMsg, errLine, sourceId, sourceURL);
    
    functionBody->setSource(SourceRange(source, 0, source->length()));
    ScopeChain scopeChain(exec->lexicalGlobalObject(), exec->globalThisValue());

    JSFunction* function = new (exec) JSFunction(exec, functionName, functionBody.get(), scopeChain.node());

    // parse parameter list. throw syntax error on illegal identifiers
    int len = p.size();
    const UChar* c = p.data();
    int i = 0, params = 0;
    UString param;
    while (i < len) {
        while (*c == ' ' && i < len)
            c++, i++;
        if (Lexer::isIdentStart(c[0])) {  // else error
            param = UString(c, 1);
            c++, i++;
            while (i < len && (Lexer::isIdentPart(c[0]))) {
                param.append(*c);
                c++, i++;
            }
            while (i < len && *c == ' ')
                c++, i++;
            if (i == len) {
                functionBody->parameters().append(Identifier(exec, param));
                params++;
                break;
            } else if (*c == ',') {
                functionBody->parameters().append(Identifier(exec, param));
                params++;
                c++, i++;
                continue;
            } // else error
        }
        return throwError(exec, SyntaxError, "Syntax error in parameter list");
    }
  
    JSObject* prototype = constructEmptyObject(exec);
    prototype->putDirect(exec->propertyNames().constructor, function, DontEnum);
    function->putDirect(exec->propertyNames().prototype, prototype, DontDelete);
    return function;
}
Exemplo n.º 6
0
bool JSFunction::getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot& slot)
{
    JSFunction* thisObject = jsCast<JSFunction*>(object);
    if (thisObject->isHostOrBuiltinFunction())
        return Base::getOwnPropertySlot(thisObject, exec, propertyName, slot);

    if (propertyName == exec->propertyNames().prototype) {
        VM& vm = exec->vm();
        unsigned attributes;
        PropertyOffset offset = thisObject->getDirectOffset(vm, propertyName, attributes);
        if (!isValidOffset(offset)) {
            JSObject* prototype = constructEmptyObject(exec);
            prototype->putDirect(vm, exec->propertyNames().constructor, thisObject, DontEnum);
            thisObject->putDirect(vm, exec->propertyNames().prototype, prototype, DontDelete | DontEnum);
            offset = thisObject->getDirectOffset(vm, exec->propertyNames().prototype, attributes);
            ASSERT(isValidOffset(offset));
        }

        slot.setValue(thisObject, attributes, thisObject->getDirect(offset), offset);
    }

    if (propertyName == exec->propertyNames().arguments) {
        if (thisObject->jsExecutable()->isStrictMode()) {
            bool result = Base::getOwnPropertySlot(thisObject, exec, propertyName, slot);
            if (!result) {
                thisObject->putDirectAccessor(exec, propertyName, thisObject->globalObject()->throwTypeErrorGetterSetter(exec->vm()), DontDelete | DontEnum | Accessor);
                result = Base::getOwnPropertySlot(thisObject, exec, propertyName, slot);
                ASSERT(result);
            }
            return result;
        }
        slot.setCacheableCustom(thisObject, ReadOnly | DontEnum | DontDelete, argumentsGetter);
        return true;
    }

    if (propertyName == exec->propertyNames().length) {
        slot.setCacheableCustom(thisObject, ReadOnly | DontEnum | DontDelete, lengthGetter);
        return true;
    }

    if (propertyName == exec->propertyNames().name) {
        slot.setCacheableCustom(thisObject, ReadOnly | DontEnum | DontDelete, nameGetter);
        return true;
    }

    if (propertyName == exec->propertyNames().caller) {
        if (thisObject->jsExecutable()->isStrictMode()) {
            bool result = Base::getOwnPropertySlot(thisObject, exec, propertyName, slot);
            if (!result) {
                thisObject->putDirectAccessor(exec, propertyName, thisObject->globalObject()->throwTypeErrorGetterSetter(exec->vm()), DontDelete | DontEnum | Accessor);
                result = Base::getOwnPropertySlot(thisObject, exec, propertyName, slot);
                ASSERT(result);
            }
            return result;
        }
        slot.setCacheableCustom(thisObject, ReadOnly | DontEnum | DontDelete, callerGetter);
        return true;
    }

    return Base::getOwnPropertySlot(thisObject, exec, propertyName, slot);
}
Exemplo n.º 7
0
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();
}