blob: 0553bd1506e612b552b767434f7f3885742e88c2 [file] [log] [blame]
/*
* Copyright 2015 Google Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef COBALT_SCRIPT_SCRIPT_VALUE_H_
#define COBALT_SCRIPT_SCRIPT_VALUE_H_
#include "base/basictypes.h"
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
namespace cobalt {
namespace script {
class Wrappable;
// ScriptValue is a wrapper around raw JavaScript values that are being passed
// into Cobalt. These are values that do not correspond to Cobalt Wrappable
// objects. Specifically, this could include objects that implement the
// EventListener interface, callback functions, promises, or any Javascript
// value at all. As long as Cobalt maintains a handle to such an value, it
// should not be garbage collected, if it is a garbage-collectible thing (GC
// thing). Web API implementations should hold on to a reference to a
// ScriptValue implementation by constructing a ScriptValue::Reference object.
//
// The Reference class takes as a constructor parameter a pointer to the
// Wrappable that is holding onto the ScriptValue. This ensures that the
// JavaScript engine's garbage collection is aware of the relationship between
// the ScriptValue and the Wrappable's corresponding JavaScript wrapper. This
// will ensure that the garbage collector can detect when these values are
// detached from the rest of the graph of JavaScript GC things, and can safely
// be garbage collected.
template <class T>
class ScriptValue {
public:
// The Reference class maintains the ownership relationship between a
// Wrappable and the JavaScript value wrapped by a ScriptValue. This is an
// RAII object in that creation of a Reference instance will mark the
// underlying value as owned by this wrappable, and the underlying object will
// be unmarked when this Reference is destructed. The lifetime of a Reference
// must be at least as long as the Wrappable that has been passed into the
// constructor.
class Reference {
public:
Reference(Wrappable* wrappable, const ScriptValue& script_value)
: owner_(wrappable), referenced_value_(script_value.MakeCopy()) {
DCHECK(referenced_value_);
referenced_value_->RegisterOwner(owner_);
}
const T& value() const { return *(referenced_value_->GetScriptValue()); }
// Return the referenced ScriptValue. This ScriptValue can
// be passed back into the JavaScript bindings layer where the referenced
// JavaScript object can be extracted from the ScriptValue.
const ScriptValue<T>& referenced_value() const {
return *(referenced_value_.get());
}
~Reference() { referenced_value_->DeregisterOwner(owner_); }
private:
Wrappable* const owner_;
scoped_ptr<ScriptValue> referenced_value_;
DISALLOW_COPY_AND_ASSIGN(Reference);
};
// Prevent garbage collection of the ScriptValue. This should be used with
// care as it can result in resource leaks if not managed appropriately.
// A common use case is to create a StrongReference on the stack when a
// ScriptValue is passed into a function, but a reference to the ScriptValue
// doesn't need to be retained past the scope of the function.
class StrongReference {
public:
explicit StrongReference(const ScriptValue& script_value)
: referenced_value_(script_value.MakeCopy()) {
DCHECK(referenced_value_);
referenced_value_->PreventGarbageCollection();
}
const T& value() const { return *(referenced_value_->GetScriptValue()); }
// Return the referenced ScriptValue. This ScriptValue can
// be passed back into the JavaScript bindings layer where the referenced
// JavaScript object can be extracted from the ScriptValue.
const ScriptValue<T>& referenced_value() const {
return *(referenced_value_.get());
}
~StrongReference() { referenced_value_->AllowGarbageCollection(); }
private:
scoped_ptr<ScriptValue> referenced_value_;
DISALLOW_COPY_AND_ASSIGN(StrongReference);
};
// Return true iff |other| refers to the same underlying JavaScript object.
virtual bool EqualTo(const ScriptValue& other) const = 0;
// Returns true if this ScriptValue is referring to a NULL JavaScript object.
bool IsNull() const { return GetScriptValue() == NULL; }
// Creates a new ScriptValue that contains a weak reference to the same
// underlying JavaScript object. Note that this will not prevent the object
// from being garbage collected, one must create a Reference to do that.
scoped_ptr<ScriptValue> MakeWeakCopy() const {
return MakeCopy().Pass();
}
protected:
virtual ~ScriptValue() {}
private:
// Mark/unmark this Wrappable as owning a handle to the underlying JavaScript
// object.
virtual void RegisterOwner(Wrappable* owner) = 0;
virtual void DeregisterOwner(Wrappable* owner) = 0;
// Prevent/Allow garbage collection of the underlying ScriptValue. Calls must
// be balanced and are not idempodent. While the number of calls to |Prevent|
// are greater than the number of calls to |Allow|, the underlying object
// will never be garbage collected.
virtual void PreventGarbageCollection() = 0;
virtual void AllowGarbageCollection() = 0;
// Return a pointer to the object that wraps the underlying JavaScript object.
virtual const T* GetScriptValue() const = 0;
// Make a new ScriptValue instance that holds a handle to the same underlying
// JavaScript object. This should not be called for a ScriptValue that has a
// NULL script object (that is, GetScriptValue() returns NULL).
virtual scoped_ptr<ScriptValue> MakeCopy() const = 0;
friend class scoped_ptr<ScriptValue>;
};
} // namespace script
} // namespace cobalt
#endif // COBALT_SCRIPT_SCRIPT_VALUE_H_