RecyclableObject* ForInObjectEnumerator::GetFirstPrototypeWithEnumerableProperties(RecyclableObject* object)
    {
        RecyclableObject* firstPrototype = nullptr;
        if (JavascriptOperators::GetTypeId(object) != TypeIds_HostDispatch)
        {
            firstPrototype = object;
            while (true)
            {
                firstPrototype = firstPrototype->GetPrototype();

                if (JavascriptOperators::GetTypeId(firstPrototype) == TypeIds_Null)
                {
                    firstPrototype = nullptr;
                    break;
                }

                if (!DynamicType::Is(firstPrototype->GetTypeId())
                    || !DynamicObject::FromVar(firstPrototype)->GetHasNoEnumerableProperties())
                {
                    break;
                }
            }
        }

        return firstPrototype;
    }
예제 #2
0
 DynamicObject* DynamicObject::FromVar(Var aValue)
 {
     RecyclableObject* obj = RecyclableObject::FromVar(aValue);
     AssertMsg(obj->DbgIsDynamicObject(), "Ensure instance is actually a DynamicObject");
     Assert(DynamicType::Is(obj->GetTypeId()));
     return static_cast<DynamicObject*>(obj);
 }
예제 #3
0
    Var JavascriptReflect::EntryPreventExtensions(RecyclableObject* function, CallInfo callInfo, ...)
    {
        PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);

        ARGUMENTS(args, callInfo);
        ScriptContext* scriptContext = function->GetScriptContext();
        AUTO_TAG_NATIVE_LIBRARY_ENTRY(function, callInfo, _u("Reflect.preventExtensions"));

        AssertMsg(args.Info.Count > 0, "Should always have implicit 'this'");
        if (args.Info.Flags & CallFlags_New)
        {
            JavascriptError::ThrowTypeError(scriptContext, JSERR_ErrorOnNew, _u("Reflect.preventExtensions"));
        }

        if (args.Info.Count < 2 || !JavascriptOperators::IsObject(args[1]))
        {
            JavascriptError::ThrowTypeError(scriptContext, JSERR_FunctionArgument_NeedObject, _u("Reflect.preventExtensions"));
        }
        Var target = args[1];

        RecyclableObject* targetObj = RecyclableObject::FromVar(target);
        GlobalObject* globalObject = targetObj->GetLibrary()->GetGlobalObject();
        if (globalObject != targetObj && globalObject && (globalObject->ToThis() == targetObj))
        {
            globalObject->PreventExtensions();
        }

        return  scriptContext->GetLibrary()->GetTrueOrFalse(targetObj->PreventExtensions());
    }
예제 #4
0
    BOOL DynamicObject::CallToPrimitiveFunction(Var toPrimitiveFunction, PropertyId propertyId, Var* result, ScriptContext * requestContext)
    {
        if (JavascriptConversion::IsCallable(toPrimitiveFunction))
        {
            RecyclableObject* toStringFunction = RecyclableObject::FromVar(toPrimitiveFunction);

            ThreadContext * threadContext = requestContext->GetThreadContext();
            Var aResult = threadContext->ExecuteImplicitCall(toStringFunction, ImplicitCall_ToPrimitive, [=]() -> Js::Var
            {
                // Stack object should have a pre-op bail on implicit call.  We shouldn't see them here.
                Assert(!ThreadContext::IsOnStack(this) || threadContext->HasNoSideEffect(toStringFunction));
                return toStringFunction->GetEntryPoint()(toStringFunction, CallInfo(CallFlags_Value, 1), this);
            });
 
            if (!aResult)
            {
                // There was an implicit call and implicit calls are disabled. This would typically cause a bailout.
                Assert(threadContext->IsDisableImplicitCall());
                *result = requestContext->GetLibrary()->GetNull();
                return true;
            }

            if (JavascriptOperators::GetTypeId(aResult) <= TypeIds_LastToPrimitiveType)
            {
                *result = aResult;
                return true;
            }
        }
        return false;
    }
예제 #5
0
    Var CrossSite::MarshalFrameDisplay(ScriptContext* scriptContext, FrameDisplay *display)
    {
        TTD_XSITE_LOG(scriptContext, "MarshalFrameDisplay", nullptr);

        uint16 length = display->GetLength();
        FrameDisplay *newDisplay =
            RecyclerNewPlus(scriptContext->GetRecycler(), length * sizeof(Var), FrameDisplay, length);
        for (uint16 i = 0; i < length; i++)
        {
            Var value = display->GetItem(i);
            if (WithScopeObject::Is(value))
            {
                // Here we are marshalling the wrappedObject and then ReWrapping th object in the new context.
                RecyclableObject* wrappedObject = WithScopeObject::FromVar(value)->GetWrappedObject();
                ScriptContext* wrappedObjectScriptContext = wrappedObject->GetScriptContext();
                value = JavascriptOperators::ToWithObject(CrossSite::MarshalVar(scriptContext,
                  wrappedObject, wrappedObjectScriptContext), scriptContext);
            }
            else
            {
                value = CrossSite::MarshalVar(scriptContext, value);
            }
            newDisplay->SetItem(i, value);
        }

        return (Var)newDisplay;
    }
 BOOL ForInObjectEnumerator::InitializeCurrentEnumerator(RecyclableObject * object, ForInCache * forInCache)
 {
     EnumeratorFlags flags = enumerator.GetFlags();
     RecyclableObject * prototype = object->GetPrototype();
     if (prototype == nullptr || prototype->GetTypeId() == TypeIds_Null)
     {
         // If this is the last object on the prototype chain, we don't need to get the non-enumerable properties any more to track shadowing
         flags &= ~EnumeratorFlags::EnumNonEnumerable;
     }
     return InitializeCurrentEnumerator(object, flags, GetScriptContext(), forInCache);
 }
예제 #7
0
 BOOL CrossSite::NeedMarshalVar(Var instance, ScriptContext * requestContext)
 {
     if (TaggedNumber::Is(instance))
     {
         return FALSE;
     }
     RecyclableObject * object = RecyclableObject::UnsafeFromVar(instance);
     if (object->GetScriptContext() == requestContext)
     {
         return FALSE;
     }
     if (DynamicType::Is(object->GetTypeId()))
     {
         return !DynamicObject::UnsafeFromVar(object)->IsCrossSiteObject() && !object->IsExternal();
     }
     return TRUE;
 }
예제 #8
0
 void CrossSite::MarshalPrototypeChain(ScriptContext* scriptContext, DynamicObject * object)
 {
     RecyclableObject * prototype = object->GetPrototype();
     while (prototype->GetTypeId() != TypeIds_Null && prototype->GetTypeId() != TypeIds_HostDispatch)
     {
         // We should not see any static type or host dispatch here
         DynamicObject * prototypeObject = DynamicObject::FromVar(prototype);
         if (prototypeObject->IsCrossSiteObject())
         {
             break;
         }
         if (scriptContext != prototypeObject->GetScriptContext() && !prototypeObject->IsExternal())
         {
             MarshalDynamicObject(scriptContext, prototypeObject);
         }
         prototype = prototypeObject->GetPrototype();
     }
 }
예제 #9
0
    Var JavascriptWeakMap::NewInstance(RecyclableObject* function, CallInfo callInfo, ...)
    {
        PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);

        ARGUMENTS(args, callInfo);
        ScriptContext* scriptContext = function->GetScriptContext();
        JavascriptLibrary* library = scriptContext->GetLibrary();

        Var newTarget = callInfo.Flags & CallFlags_NewTarget ? args.Values[args.Info.Count] : args[0];
        bool isCtorSuperCall = (callInfo.Flags & CallFlags_New) && newTarget != nullptr && RecyclableObject::Is(newTarget);
        Assert(isCtorSuperCall || !(callInfo.Flags & CallFlags_New) || args[0] == nullptr);
        CHAKRATEL_LANGSTATS_INC_BUILTINCOUNT(WeakMapCount);

        JavascriptWeakMap* weakMapObject = nullptr;

        if (callInfo.Flags & CallFlags_New)
        {
            weakMapObject = library->CreateWeakMap();
        }
        else
        {
            JavascriptError::ThrowTypeErrorVar(scriptContext, JSERR_NeedObjectOfType, _u("WeakMap"), _u("WeakMap"));
        }
        Assert(weakMapObject != nullptr);

        Var iterable = (args.Info.Count > 1) ? args[1] : library->GetUndefined();

        RecyclableObject* iter = nullptr;
        RecyclableObject* adder = nullptr;

        if (JavascriptConversion::CheckObjectCoercible(iterable, scriptContext))
        {
            iter = JavascriptOperators::GetIterator(iterable, scriptContext);
            Var adderVar = JavascriptOperators::GetProperty(weakMapObject, PropertyIds::set, scriptContext);
            if (!JavascriptConversion::IsCallable(adderVar))
            {
                JavascriptError::ThrowTypeError(scriptContext, JSERR_NeedFunction);
            }
            adder = RecyclableObject::FromVar(adderVar);
        }

        if (iter != nullptr)
        {
            Var nextItem;
            Var undefined = library->GetUndefined();

            while (JavascriptOperators::IteratorStepAndValue(iter, scriptContext, &nextItem))
            {
                if (!JavascriptOperators::IsObject(nextItem))
                {
                    JavascriptError::ThrowTypeError(scriptContext, JSERR_NeedObject);
                }

                RecyclableObject* obj = RecyclableObject::FromVar(nextItem);

                Var key, value;

                if (!JavascriptOperators::GetItem(obj, 0u, &key, scriptContext))
                {
                    key = undefined;
                }

                if (!JavascriptOperators::GetItem(obj, 1u, &value, scriptContext))
                {
                    value = undefined;
                }

                adder->GetEntryPoint()(adder, CallInfo(CallFlags_Value, 3), weakMapObject, key, value);
            }
        }

        return isCtorSuperCall ?
            JavascriptOperators::OrdinaryCreateFromConstructor(RecyclableObject::FromVar(newTarget), weakMapObject, nullptr, scriptContext) :
            weakMapObject;
    }
예제 #10
0
    Var BoundFunction::NewInstance(RecyclableObject* function, CallInfo callInfo, ...)
    {
        RUNTIME_ARGUMENTS(args, callInfo);
        ScriptContext* scriptContext = function->GetScriptContext();

        if (args.Info.Count == 0)
        {
            JavascriptError::ThrowTypeError(scriptContext, JSERR_NeedFunction /* TODO-ERROR: get arg name - args[0] */);
        }

        BoundFunction *boundFunction = (BoundFunction *) function;
        Var targetFunction = boundFunction->targetFunction;

        //
        // var o = new boundFunction()
        // a new object should be created using the actual function object
        //
        Var newVarInstance = nullptr;
        if (callInfo.Flags & CallFlags_New)
        {
          if (JavascriptProxy::Is(targetFunction))
          {
            JavascriptProxy* proxy = JavascriptProxy::FromVar(targetFunction);
            Arguments proxyArgs(CallInfo(CallFlags_New, 1), &targetFunction);
            args.Values[0] = newVarInstance = proxy->ConstructorTrap(proxyArgs, scriptContext, 0);
          }
          else
          {
            args.Values[0] = newVarInstance = JavascriptOperators::NewScObjectNoCtor(targetFunction, scriptContext);
          }
        }

        Js::Arguments actualArgs = args;

        if (boundFunction->count > 0)
        {
            BOOL isCrossSiteObject = boundFunction->IsCrossSiteObject();
            // OACR thinks that this can change between here and the check in the for loop below
            const unsigned int argCount = args.Info.Count;

            if ((boundFunction->count + argCount) > CallInfo::kMaxCountArgs)
            {
                JavascriptError::ThrowRangeError(scriptContext, JSERR_ArgListTooLarge);
            }

            Var *newValues = RecyclerNewArray(scriptContext->GetRecycler(), Var, boundFunction->count + argCount);

            uint index = 0;

            //
            // For [[Construct]] use the newly created var instance
            // For [[Call]] use the "this" to which bind bound it.
            //
            if (callInfo.Flags & CallFlags_New)
            {
                newValues[index++] = args[0];
            }
            else
            {
                newValues[index++] = boundFunction->boundThis;
            }

            // Copy the bound args
            if (!isCrossSiteObject)
            {
                for (uint i = 0; i < boundFunction->count; i++)
                {
                    newValues[index++] = boundFunction->boundArgs[i];
                }
            }
            else
            {
                // it is possible that the bound arguments are not marshalled yet.
                for (uint i = 0; i < boundFunction->count; i++)
                {
                    newValues[index++] = CrossSite::MarshalVar(scriptContext, boundFunction->boundArgs[i]);
                }
            }

            // Copy the extra args
            for (uint i=1; i<argCount; i++)
            {
                newValues[index++] = args[i];
            }

            actualArgs = Arguments(args.Info, newValues);
            actualArgs.Info.Count = boundFunction->count + argCount;
        }
        else
        {
            if (!(callInfo.Flags & CallFlags_New))
            {
                actualArgs.Values[0] = boundFunction->boundThis;
            }
        }

        RecyclableObject* actualFunction = RecyclableObject::FromVar(targetFunction);
        Var aReturnValue = JavascriptFunction::CallFunction<true>(actualFunction, actualFunction->GetEntryPoint(), actualArgs);

        //
        // [[Construct]] and call returned a non-object
        // return the newly created var instance
        //
        if ((callInfo.Flags & CallFlags_New) && !JavascriptOperators::IsObject(aReturnValue))
        {
            aReturnValue = newVarInstance;
        }

        return aReturnValue;
    }
    JavascriptString * ForInObjectEnumerator::MoveAndGetNext(PropertyId& propertyId)
    {        
        PropertyRecord const * propRecord;
        PropertyAttributes attributes = PropertyNone;

        while (true)
        {
            propertyId = Constants::NoProperty;
            JavascriptString * currentIndex = enumerator.MoveAndGetNext(propertyId, &attributes);

            // The object type may have changed and we may not be able to use Jit fast path anymore.
            // canUseJitFastPath is determined in ForInObjectEnumerator::Initialize, once we decide we can't use
            // Jit fast path we will never go back to use fast path so && with current value  - if it's already
            // false we don't call CanUseJITFastPath()

            this->canUseJitFastPath = this->canUseJitFastPath && enumerator.CanUseJITFastPath();

            if (currentIndex)
            {
                if (this->shadowData == nullptr)
                {
                    // There are no prototype that has enumerable properties,
                    // don't need to keep track of the propertyIds we visited.

                    // We have asked for enumerable properties only, so don't need to check the attribute returned.
                    Assert(attributes & PropertyEnumerable);

                    return currentIndex;
                }

                // Property Id does not exist.
                if (propertyId == Constants::NoProperty)
                {
                    if (VirtualTableInfo<Js::PropertyString>::HasVirtualTable(currentIndex))
                    {
                        // If we have a property string, it is assumed that the propertyId is being
                        // kept alive with the object
                        PropertyString * propertyString = (PropertyString *)currentIndex;
                        propertyId = propertyString->GetPropertyRecord()->GetPropertyId();
                    }
                    else
                    {
                        ScriptContext* scriptContext = currentIndex->GetScriptContext();
                        scriptContext->GetOrAddPropertyRecord(currentIndex->GetString(), currentIndex->GetLength(), &propRecord);
                        propertyId = propRecord->GetPropertyId();

                        // We keep the track of what is enumerated using a bit vector of propertyID.
                        // so the propertyId can't be collected until the end of the for in enumerator
                        // Keep a list of the property string.
                        this->shadowData->newPropertyStrings.Prepend(GetScriptContext()->GetRecycler(), propRecord);
                    }
                }

                if (TestAndSetEnumerated(propertyId) //checks if the property is already enumerated or not
                    && (attributes & PropertyEnumerable))
                {
                    return currentIndex;
                }
            }
            else
            {
                if (this->shadowData == nullptr)
                {
                    Assert(!this->enumeratingPrototype);
                    return nullptr;
                }

                RecyclableObject * object;
                if (!this->enumeratingPrototype)
                {  
                    this->enumeratingPrototype = true;
                    object = this->shadowData->firstPrototype;
                    this->shadowData->currentObject = object;
                }
                else
                {
                    //walk the prototype chain
                    object = this->shadowData->currentObject->GetPrototype();
                    this->shadowData->currentObject = object;
                    if ((object == nullptr) || (JavascriptOperators::GetTypeId(object) == TypeIds_Null))
                    {
                        return nullptr;
                    }
                }

                do
                {
                    if (!InitializeCurrentEnumerator(object))
                    {
                        return nullptr;
                    }

                    if (!enumerator.IsNullEnumerator())
                    {
                        break;
                    }

                     //walk the prototype chain
                    object = object->GetPrototype();
                    this->shadowData->currentObject = object;
                    if ((object == nullptr) || (JavascriptOperators::GetTypeId(object) == TypeIds_Null))
                    {
                        return nullptr;
                    }
                }
                while (true);
            }
        }
    }