Version 3.21.15
Non-JSObject heap objects are now handled using slow-path IC stub guarded by the map. (Chromium issue 280632)
i18n Javascript code added to the snapshot. (V8 issue 2745)
Performance and stability improvements on all platforms.
git-svn-id: http://v8.googlecode.com/svn/trunk@16700 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
diff --git a/ChangeLog b/ChangeLog
index 27ff5d9..8084cc5 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,14 @@
+2013-09-13: Version 3.21.15
+
+ Non-JSObject heap objects are now handled using slow-path IC stub
+ guarded by the map.
+ (Chromium issue 280632)
+
+ i18n Javascript code added to the snapshot.
+ (V8 issue 2745)
+
+ Performance and stability improvements on all platforms.
+
2013-09-12: Version 3.21.14
Added access check for observed objects.
diff --git a/include/v8.h b/include/v8.h
index d98a768..de27338 100644
--- a/include/v8.h
+++ b/include/v8.h
@@ -211,7 +211,7 @@
/**
* Creates an empty handle.
*/
- V8_INLINE(Handle()) : val_(0) {}
+ V8_INLINE Handle() : val_(0) {}
/**
* Creates a handle for the contents of the specified handle. This
@@ -223,7 +223,7 @@
* Handle<String> to a variable declared as Handle<Value>, is legal
* because String is a subclass of Value.
*/
- template <class S> V8_INLINE(Handle(Handle<S> that))
+ template <class S> V8_INLINE Handle(Handle<S> that)
: val_(reinterpret_cast<T*>(*that)) {
/**
* This check fails when trying to convert between incompatible
@@ -236,16 +236,16 @@
/**
* Returns true if the handle is empty.
*/
- V8_INLINE(bool IsEmpty() const) { return val_ == 0; }
+ V8_INLINE bool IsEmpty() const { return val_ == 0; }
/**
* Sets the handle to be empty. IsEmpty() will then return true.
*/
- V8_INLINE(void Clear()) { val_ = 0; }
+ V8_INLINE void Clear() { val_ = 0; }
- V8_INLINE(T* operator->() const) { return val_; }
+ V8_INLINE T* operator->() const { return val_; }
- V8_INLINE(T* operator*() const) { return val_; }
+ V8_INLINE T* operator*() const { return val_; }
/**
* Checks whether two handles are the same.
@@ -253,7 +253,7 @@
* to which they refer are identical.
* The handles' references are not checked.
*/
- template <class S> V8_INLINE(bool operator==(const Handle<S>& that) const) {
+ template <class S> V8_INLINE bool operator==(const Handle<S>& that) const {
internal::Object** a = reinterpret_cast<internal::Object**>(**this);
internal::Object** b = reinterpret_cast<internal::Object**>(*that);
if (a == 0) return b == 0;
@@ -261,8 +261,8 @@
return *a == *b;
}
- template <class S> V8_INLINE(
- bool operator==(const Persistent<S>& that) const) {
+ template <class S> V8_INLINE bool operator==(
+ const Persistent<S>& that) const {
internal::Object** a = reinterpret_cast<internal::Object**>(**this);
internal::Object** b = reinterpret_cast<internal::Object**>(*that);
if (a == 0) return b == 0;
@@ -276,16 +276,16 @@
* the objects to which they refer are different.
* The handles' references are not checked.
*/
- template <class S> V8_INLINE(bool operator!=(const Handle<S>& that) const) {
+ template <class S> V8_INLINE bool operator!=(const Handle<S>& that) const {
return !operator==(that);
}
- template <class S> V8_INLINE(
- bool operator!=(const Persistent<S>& that) const) {
+ template <class S> V8_INLINE bool operator!=(
+ const Persistent<S>& that) const {
return !operator==(that);
}
- template <class S> V8_INLINE(static Handle<T> Cast(Handle<S> that)) {
+ template <class S> V8_INLINE static Handle<T> Cast(Handle<S> that) {
#ifdef V8_ENABLE_CHECKS
// If we're going to perform the type check then we have to check
// that the handle isn't empty before doing the checked cast.
@@ -294,14 +294,14 @@
return Handle<T>(T::Cast(*that));
}
- template <class S> V8_INLINE(Handle<S> As()) {
+ template <class S> V8_INLINE Handle<S> As() {
return Handle<S>::Cast(*this);
}
- V8_INLINE(static Handle<T> New(Isolate* isolate, Handle<T> that)) {
+ V8_INLINE static Handle<T> New(Isolate* isolate, Handle<T> that) {
return New(isolate, that.val_);
}
- V8_INLINE(static Handle<T> New(Isolate* isolate, const Persistent<T>& that)) {
+ V8_INLINE static Handle<T> New(Isolate* isolate, const Persistent<T>& that) {
return New(isolate, that.val_);
}
@@ -312,7 +312,7 @@
/**
* Creates a new handle for the specified value.
*/
- V8_INLINE(explicit Handle(T* val)) : val_(val) {}
+ V8_INLINE explicit Handle(T* val) : val_(val) {}
private:
friend class Utils;
@@ -328,7 +328,7 @@
friend class Context;
friend class HandleScope;
- V8_INLINE(static Handle<T> New(Isolate* isolate, T* that));
+ V8_INLINE static Handle<T> New(Isolate* isolate, T* that);
T* val_;
};
@@ -343,8 +343,8 @@
*/
template <class T> class Local : public Handle<T> {
public:
- V8_INLINE(Local());
- template <class S> V8_INLINE(Local(Local<S> that))
+ V8_INLINE Local();
+ template <class S> V8_INLINE Local(Local<S> that)
: Handle<T>(reinterpret_cast<T*>(*that)) {
/**
* This check fails when trying to convert between incompatible
@@ -355,7 +355,7 @@
}
- template <class S> V8_INLINE(static Local<T> Cast(Local<S> that)) {
+ template <class S> V8_INLINE static Local<T> Cast(Local<S> that) {
#ifdef V8_ENABLE_CHECKS
// If we're going to perform the type check then we have to check
// that the handle isn't empty before doing the checked cast.
@@ -363,12 +363,12 @@
#endif
return Local<T>(T::Cast(*that));
}
- template <class S> V8_INLINE(Local(Handle<S> that))
+ template <class S> V8_INLINE Local(Handle<S> that)
: Handle<T>(reinterpret_cast<T*>(*that)) {
TYPE_CHECK(T, S);
}
- template <class S> V8_INLINE(Local<S> As()) {
+ template <class S> V8_INLINE Local<S> As() {
return Local<S>::Cast(*this);
}
@@ -377,17 +377,17 @@
* The referee is kept alive by the local handle even when
* the original handle is destroyed/disposed.
*/
- V8_INLINE(static Local<T> New(Handle<T> that));
- V8_INLINE(static Local<T> New(Isolate* isolate, Handle<T> that));
+ V8_INLINE static Local<T> New(Handle<T> that);
+ V8_INLINE static Local<T> New(Isolate* isolate, Handle<T> that);
template<class M>
- V8_INLINE(static Local<T> New(Isolate* isolate,
- const Persistent<T, M>& that));
+ V8_INLINE static Local<T> New(Isolate* isolate,
+ const Persistent<T, M>& that);
#ifndef V8_ALLOW_ACCESS_TO_RAW_HANDLE_CONSTRUCTOR
private:
#endif
- template <class S> V8_INLINE(Local(S* that) : Handle<T>(that)) { }
+ template <class S> V8_INLINE Local(S* that) : Handle<T>(that) { }
private:
friend class Utils;
@@ -402,24 +402,22 @@
template<class F> friend class internal::CustomArguments;
friend class HandleScope;
- V8_INLINE(static Local<T> New(Isolate* isolate, T* that));
+ V8_INLINE static Local<T> New(Isolate* isolate, T* that);
};
// Eternal handles are set-once handles that live for the life of the isolate.
template <class T> class Eternal {
public:
- V8_INLINE(Eternal()) : index_(kInitialValue) { }
+ V8_INLINE Eternal() : index_(kInitialValue) { }
template<class S>
- V8_INLINE(Eternal(Isolate* isolate, Local<S> handle))
- : index_(kInitialValue) {
+ V8_INLINE Eternal(Isolate* isolate, Local<S> handle) : index_(kInitialValue) {
Set(isolate, handle);
}
// Can only be safely called if already set.
- V8_INLINE(Local<T> Get(Isolate* isolate));
- V8_INLINE(bool IsEmpty()) { return index_ == kInitialValue; }
- template<class S>
- V8_INLINE(void Set(Isolate* isolate, Local<S> handle));
+ V8_INLINE Local<T> Get(Isolate* isolate);
+ V8_INLINE bool IsEmpty() { return index_ == kInitialValue; }
+ template<class S> V8_INLINE void Set(Isolate* isolate, Local<S> handle);
private:
static const int kInitialValue = -1;
@@ -432,9 +430,9 @@
public:
typedef void (*Callback)(const WeakCallbackData<T, P>& data);
- V8_INLINE(Isolate* GetIsolate()) const { return isolate_; }
- V8_INLINE(Local<T> GetValue()) const { return handle_; }
- V8_INLINE(P* GetParameter()) const { return parameter_; }
+ V8_INLINE Isolate* GetIsolate() const { return isolate_; }
+ V8_INLINE Local<T> GetValue() const { return handle_; }
+ V8_INLINE P* GetParameter() const { return parameter_; }
private:
friend class internal::GlobalHandles;
@@ -470,13 +468,12 @@
typedef Persistent<T, NonCopyablePersistentTraits<T> > NonCopyablePersistent;
static const bool kResetInDestructor = false;
template<class S, class M>
- V8_INLINE(static void Copy(const Persistent<S, M>& source,
- NonCopyablePersistent* dest)) {
+ V8_INLINE static void Copy(const Persistent<S, M>& source,
+ NonCopyablePersistent* dest) {
Uncompilable<Object>();
}
// TODO(dcarney): come up with a good compile error here.
- template<class O>
- V8_INLINE(static void Uncompilable()) {
+ template<class O> V8_INLINE static void Uncompilable() {
TYPE_CHECK(O, Primitive);
}
};
@@ -502,13 +499,13 @@
/**
* A Persistent with no storage cell.
*/
- V8_INLINE(Persistent()) : val_(0) { }
+ V8_INLINE Persistent() : val_(0) { }
/**
* Construct a Persistent from a Handle.
* When the Handle is non-empty, a new storage cell is created
* pointing to the same object, and no flags are set.
*/
- template <class S> V8_INLINE(Persistent(Isolate* isolate, Handle<S> that))
+ template <class S> V8_INLINE Persistent(Isolate* isolate, Handle<S> that)
: val_(New(isolate, *that)) {
TYPE_CHECK(T, S);
}
@@ -518,7 +515,7 @@
* pointing to the same object, and no flags are set.
*/
template <class S, class M2>
- V8_INLINE(Persistent(Isolate* isolate, const Persistent<S, M2>& that))
+ V8_INLINE Persistent(Isolate* isolate, const Persistent<S, M2>& that)
: val_(New(isolate, *that)) {
TYPE_CHECK(T, S);
}
@@ -528,19 +525,19 @@
* traits class is called, allowing the setting of flags based on the
* copied Persistent.
*/
- V8_INLINE(Persistent(const Persistent& that)) : val_(0) {
+ V8_INLINE Persistent(const Persistent& that) : val_(0) {
Copy(that);
}
template <class S, class M2>
- V8_INLINE(Persistent(const Persistent<S, M2>& that)) : val_(0) {
+ V8_INLINE Persistent(const Persistent<S, M2>& that) : val_(0) {
Copy(that);
}
- V8_INLINE(Persistent& operator=(const Persistent& that)) { // NOLINT
+ V8_INLINE Persistent& operator=(const Persistent& that) { // NOLINT
Copy(that);
return *this;
}
template <class S, class M2>
- V8_INLINE(Persistent& operator=(const Persistent<S, M2>& that)) { // NOLINT
+ V8_INLINE Persistent& operator=(const Persistent<S, M2>& that) { // NOLINT
Copy(that);
return *this;
}
@@ -549,7 +546,7 @@
* kResetInDestructor flags in the traits class. Since not calling dispose
* can result in a memory leak, it is recommended to always set this flag.
*/
- V8_INLINE(~Persistent()) {
+ V8_INLINE ~Persistent() {
if (M::kResetInDestructor) Reset();
}
@@ -557,28 +554,28 @@
* If non-empty, destroy the underlying storage cell
* IsEmpty() will return true after this call.
*/
- V8_INLINE(void Reset());
- template <class S>
+ V8_INLINE void Reset();
/**
* If non-empty, destroy the underlying storage cell
* and create a new one with the contents of other if other is non empty
*/
- V8_INLINE(void Reset(Isolate* isolate, const Handle<S>& other));
+ template <class S>
+ V8_INLINE void Reset(Isolate* isolate, const Handle<S>& other);
/**
* If non-empty, destroy the underlying storage cell
* and create a new one with the contents of other if other is non empty
*/
template <class S, class M2>
- V8_INLINE(void Reset(Isolate* isolate, const Persistent<S, M2>& other));
+ V8_INLINE void Reset(Isolate* isolate, const Persistent<S, M2>& other);
// TODO(dcarney): deprecate
- V8_INLINE(void Dispose()) { Reset(); }
- V8_DEPRECATED(V8_INLINE(void Dispose(Isolate* isolate))) { Reset(); }
+ V8_INLINE void Dispose() { Reset(); }
+ V8_DEPRECATED(V8_INLINE void Dispose(Isolate* isolate)) { Reset(); }
- V8_INLINE(bool IsEmpty() const) { return val_ == 0; }
+ V8_INLINE bool IsEmpty() const { return val_ == 0; }
// TODO(dcarney): this is pretty useless, fix or remove
template <class S>
- V8_INLINE(static Persistent<T>& Cast(Persistent<S>& that)) { // NOLINT
+ V8_INLINE static Persistent<T>& Cast(Persistent<S>& that) { // NOLINT
#ifdef V8_ENABLE_CHECKS
// If we're going to perform the type check then we have to check
// that the handle isn't empty before doing the checked cast.
@@ -588,12 +585,12 @@
}
// TODO(dcarney): this is pretty useless, fix or remove
- template <class S> V8_INLINE(Persistent<S>& As()) { // NOLINT
+ template <class S> V8_INLINE Persistent<S>& As() { // NOLINT
return Persistent<S>::Cast(*this);
}
- template <class S, class M2> V8_INLINE(
- bool operator==(const Persistent<S, M2>& that) const) {
+ template <class S, class M2>
+ V8_INLINE bool operator==(const Persistent<S, M2>& that) const {
internal::Object** a = reinterpret_cast<internal::Object**>(**this);
internal::Object** b = reinterpret_cast<internal::Object**>(*that);
if (a == 0) return b == 0;
@@ -601,7 +598,7 @@
return *a == *b;
}
- template <class S> V8_INLINE(bool operator==(const Handle<S>& that) const) {
+ template <class S> V8_INLINE bool operator==(const Handle<S>& that) const {
internal::Object** a = reinterpret_cast<internal::Object**>(**this);
internal::Object** b = reinterpret_cast<internal::Object**>(*that);
if (a == 0) return b == 0;
@@ -609,40 +606,40 @@
return *a == *b;
}
- template <class S, class M2> V8_INLINE(
- bool operator!=(const Persistent<S, M2>& that) const) {
+ template <class S, class M2>
+ V8_INLINE bool operator!=(const Persistent<S, M2>& that) const {
return !operator==(that);
}
- template <class S> V8_INLINE(bool operator!=(const Handle<S>& that) const) {
+ template <class S> V8_INLINE bool operator!=(const Handle<S>& that) const {
return !operator==(that);
}
template<typename P>
- V8_INLINE(void SetWeak(
+ V8_INLINE void SetWeak(
P* parameter,
- typename WeakCallbackData<T, P>::Callback callback));
+ typename WeakCallbackData<T, P>::Callback callback);
template<typename S, typename P>
- V8_INLINE(void SetWeak(
+ V8_INLINE void SetWeak(
P* parameter,
- typename WeakCallbackData<S, P>::Callback callback));
+ typename WeakCallbackData<S, P>::Callback callback);
// TODO(dcarney): deprecate
template<typename S, typename P>
- V8_INLINE(void MakeWeak(
+ V8_INLINE void MakeWeak(
P* parameter,
- typename WeakReferenceCallbacks<S, P>::Revivable callback));
+ typename WeakReferenceCallbacks<S, P>::Revivable callback);
// TODO(dcarney): deprecate
template<typename P>
- V8_INLINE(void MakeWeak(
+ V8_INLINE void MakeWeak(
P* parameter,
- typename WeakReferenceCallbacks<T, P>::Revivable callback));
+ typename WeakReferenceCallbacks<T, P>::Revivable callback);
- V8_INLINE(void ClearWeak());
+ V8_INLINE void ClearWeak();
- V8_DEPRECATED(V8_INLINE(void ClearWeak(Isolate* isolate))) { ClearWeak(); }
+ V8_DEPRECATED(V8_INLINE void ClearWeak(Isolate* isolate)) { ClearWeak(); }
/**
* Marks the reference to this object independent. Garbage collector is free
@@ -650,9 +647,9 @@
* independent handle should not assume that it will be preceded by a global
* GC prologue callback or followed by a global GC epilogue callback.
*/
- V8_INLINE(void MarkIndependent());
+ V8_INLINE void MarkIndependent();
- V8_DEPRECATED(V8_INLINE(void MarkIndependent(Isolate* isolate))) {
+ V8_DEPRECATED(V8_INLINE void MarkIndependent(Isolate* isolate)) {
MarkIndependent();
}
@@ -664,29 +661,29 @@
* external dependencies. This mark is automatically cleared after each
* garbage collection.
*/
- V8_INLINE(void MarkPartiallyDependent());
+ V8_INLINE void MarkPartiallyDependent();
- V8_DEPRECATED(V8_INLINE(void MarkPartiallyDependent(Isolate* isolate))) {
+ V8_DEPRECATED(V8_INLINE void MarkPartiallyDependent(Isolate* isolate)) {
MarkPartiallyDependent();
}
- V8_INLINE(bool IsIndependent() const);
+ V8_INLINE bool IsIndependent() const;
- V8_DEPRECATED(V8_INLINE(bool IsIndependent(Isolate* isolate)) const) {
+ V8_DEPRECATED(V8_INLINE bool IsIndependent(Isolate* isolate) const) {
return IsIndependent();
}
/** Checks if the handle holds the only reference to an object. */
- V8_INLINE(bool IsNearDeath() const);
+ V8_INLINE bool IsNearDeath() const;
- V8_DEPRECATED(V8_INLINE(bool IsNearDeath(Isolate* isolate)) const) {
+ V8_DEPRECATED(V8_INLINE bool IsNearDeath(Isolate* isolate) const) {
return IsNearDeath();
}
/** Returns true if the handle's reference is weak. */
- V8_INLINE(bool IsWeak() const);
+ V8_INLINE bool IsWeak() const;
- V8_DEPRECATED(V8_INLINE(bool IsWeak(Isolate* isolate)) const) {
+ V8_DEPRECATED(V8_INLINE bool IsWeak(Isolate* isolate) const) {
return IsWeak();
}
@@ -694,10 +691,10 @@
* Assigns a wrapper class ID to the handle. See RetainedObjectInfo interface
* description in v8-profiler.h for details.
*/
- V8_INLINE(void SetWrapperClassId(uint16_t class_id));
+ V8_INLINE void SetWrapperClassId(uint16_t class_id);
V8_DEPRECATED(
- V8_INLINE(void SetWrapperClassId(Isolate * isolate, uint16_t class_id))) {
+ V8_INLINE void SetWrapperClassId(Isolate * isolate, uint16_t class_id)) {
SetWrapperClassId(class_id);
}
@@ -705,26 +702,26 @@
* Returns the class ID previously assigned to this handle or 0 if no class ID
* was previously assigned.
*/
- V8_INLINE(uint16_t WrapperClassId() const);
+ V8_INLINE uint16_t WrapperClassId() const;
- V8_DEPRECATED(V8_INLINE(uint16_t WrapperClassId(Isolate* isolate)) const) {
+ V8_DEPRECATED(V8_INLINE uint16_t WrapperClassId(Isolate* isolate) const) {
return WrapperClassId();
}
// TODO(dcarney): remove
- V8_INLINE(T* ClearAndLeak());
+ V8_INLINE T* ClearAndLeak();
// TODO(dcarney): remove
- V8_INLINE(void Clear()) { val_ = 0; }
+ V8_INLINE void Clear() { val_ = 0; }
// TODO(dcarney): remove
#ifndef V8_ALLOW_ACCESS_TO_RAW_HANDLE_CONSTRUCTOR
private:
#endif
- template <class S> V8_INLINE(Persistent(S* that)) : val_(that) { }
+ template <class S> V8_INLINE Persistent(S* that) : val_(that) { }
- V8_INLINE(T* operator*() const) { return val_; }
+ V8_INLINE T* operator*() const { return val_; }
private:
friend class Utils;
@@ -733,9 +730,9 @@
template<class F1, class F2> friend class Persistent;
template<class F> friend class ReturnValue;
- V8_INLINE(static T* New(Isolate* isolate, T* that));
+ V8_INLINE static T* New(Isolate* isolate, T* that);
template<class S, class M2>
- V8_INLINE(void Copy(const Persistent<S, M2>& that));
+ V8_INLINE void Copy(const Persistent<S, M2>& that);
T* val_;
};
@@ -795,7 +792,7 @@
internal::Object** next;
internal::Object** limit;
int level;
- V8_INLINE(void Initialize()) {
+ V8_INLINE void Initialize() {
next = limit = NULL;
level = 0;
}
@@ -904,19 +901,19 @@
*/
class ScriptOrigin {
public:
- V8_INLINE(ScriptOrigin(
+ V8_INLINE ScriptOrigin(
Handle<Value> resource_name,
Handle<Integer> resource_line_offset = Handle<Integer>(),
Handle<Integer> resource_column_offset = Handle<Integer>(),
- Handle<Boolean> resource_is_shared_cross_origin = Handle<Boolean>()))
+ Handle<Boolean> resource_is_shared_cross_origin = Handle<Boolean>())
: resource_name_(resource_name),
resource_line_offset_(resource_line_offset),
resource_column_offset_(resource_column_offset),
resource_is_shared_cross_origin_(resource_is_shared_cross_origin) { }
- V8_INLINE(Handle<Value> ResourceName() const);
- V8_INLINE(Handle<Integer> ResourceLineOffset() const);
- V8_INLINE(Handle<Integer> ResourceColumnOffset() const);
- V8_INLINE(Handle<Boolean> ResourceIsSharedCrossOrigin() const);
+ V8_INLINE Handle<Value> ResourceName() const;
+ V8_INLINE Handle<Integer> ResourceLineOffset() const;
+ V8_INLINE Handle<Integer> ResourceColumnOffset() const;
+ V8_INLINE Handle<Boolean> ResourceIsSharedCrossOrigin() const;
private:
Handle<Value> resource_name_;
Handle<Integer> resource_line_offset_;
@@ -1257,13 +1254,13 @@
* Returns true if this value is the undefined value. See ECMA-262
* 4.3.10.
*/
- V8_INLINE(bool IsUndefined() const);
+ V8_INLINE bool IsUndefined() const;
/**
* Returns true if this value is the null value. See ECMA-262
* 4.3.11.
*/
- V8_INLINE(bool IsNull() const);
+ V8_INLINE bool IsNull() const;
/**
* Returns true if this value is true.
@@ -1279,7 +1276,7 @@
* Returns true if this value is an instance of the String type.
* See ECMA-262 8.4.
*/
- V8_INLINE(bool IsString() const);
+ V8_INLINE bool IsString() const;
/**
* Returns true if this value is a symbol.
@@ -1467,12 +1464,12 @@
bool Equals(Handle<Value> that) const;
bool StrictEquals(Handle<Value> that) const;
- template <class T> V8_INLINE(static Value* Cast(T* value));
+ template <class T> V8_INLINE static Value* Cast(T* value);
private:
- V8_INLINE(bool QuickIsUndefined() const);
- V8_INLINE(bool QuickIsNull() const);
- V8_INLINE(bool QuickIsString() const);
+ V8_INLINE bool QuickIsUndefined() const;
+ V8_INLINE bool QuickIsNull() const;
+ V8_INLINE bool QuickIsString() const;
bool FullIsUndefined() const;
bool FullIsNull() const;
bool FullIsString() const;
@@ -1492,7 +1489,7 @@
class V8_EXPORT Boolean : public Primitive {
public:
bool Value() const;
- V8_INLINE(static Handle<Boolean> New(bool value));
+ V8_INLINE static Handle<Boolean> New(bool value);
};
@@ -1521,7 +1518,7 @@
/**
* This function is no longer useful.
*/
- V8_DEPRECATED(V8_INLINE(bool MayContainNonAscii()) const) { return true; }
+ V8_DEPRECATED(V8_INLINE bool MayContainNonAscii() const) { return true; }
/**
* Returns whether this string is known to contain only one byte data.
@@ -1593,7 +1590,7 @@
* A zero length string.
*/
static v8::Local<v8::String> Empty();
- V8_INLINE(static v8::Local<v8::String> Empty(Isolate* isolate));
+ V8_INLINE static v8::Local<v8::String> Empty(Isolate* isolate);
/**
* Returns true if the string is external
@@ -1691,14 +1688,14 @@
* regardless of the encoding, otherwise return NULL. The encoding of the
* string is returned in encoding_out.
*/
- V8_INLINE(ExternalStringResourceBase* GetExternalStringResourceBase(
- Encoding* encoding_out) const);
+ V8_INLINE ExternalStringResourceBase* GetExternalStringResourceBase(
+ Encoding* encoding_out) const;
/**
* Get the ExternalStringResource for an external string. Returns
* NULL if IsExternal() doesn't return true.
*/
- V8_INLINE(ExternalStringResource* GetExternalStringResource() const);
+ V8_INLINE ExternalStringResource* GetExternalStringResource() const;
/**
* Get the ExternalAsciiStringResource for an external ASCII string.
@@ -1706,7 +1703,7 @@
*/
const ExternalAsciiStringResource* GetExternalAsciiStringResource() const;
- V8_INLINE(static String* Cast(v8::Value* obj));
+ V8_INLINE static String* Cast(v8::Value* obj);
// TODO(dcarney): deprecate
/**
@@ -1714,18 +1711,18 @@
* The second parameter 'length' gives the buffer length. If omitted,
* the function calls 'strlen' to determine the buffer length.
*/
- V8_INLINE(static Local<String> New(const char* data, int length = -1));
+ V8_INLINE static Local<String> New(const char* data, int length = -1);
// TODO(dcarney): deprecate
/** Allocates a new string from 16-bit character codes.*/
- V8_INLINE(static Local<String> New(const uint16_t* data, int length = -1));
+ V8_INLINE static Local<String> New(const uint16_t* data, int length = -1);
// TODO(dcarney): deprecate
/**
* Creates an internalized string (historically called a "symbol",
* not to be confused with ES6 symbols). Returns one if it exists already.
*/
- V8_INLINE(static Local<String> NewSymbol(const char* data, int length = -1));
+ V8_INLINE static Local<String> NewSymbol(const char* data, int length = -1);
enum NewStringType {
kNormalString, kInternalizedString, kUndetectableString
@@ -1806,13 +1803,13 @@
// TODO(dcarney): deprecate
/** Creates an undetectable string from the supplied ASCII or UTF-8 data.*/
- V8_INLINE(
- static Local<String> NewUndetectable(const char* data, int length = -1));
+ V8_INLINE static Local<String> NewUndetectable(const char* data,
+ int length = -1);
// TODO(dcarney): deprecate
/** Creates an undetectable string from the supplied 16-bit character codes.*/
- V8_INLINE(static Local<String> NewUndetectable(
- const uint16_t* data, int length = -1));
+ V8_INLINE static Local<String> NewUndetectable(const uint16_t* data,
+ int length = -1);
/**
* Converts an object to a UTF-8-encoded character array. Useful if
@@ -1907,7 +1904,7 @@
// Create a symbol with a print name.
static Local<Symbol> New(Isolate *isolate, const char* data, int length = -1);
- V8_INLINE(static Symbol* Cast(v8::Value* obj));
+ V8_INLINE static Symbol* Cast(v8::Value* obj);
private:
Symbol();
static void CheckCast(v8::Value* obj);
@@ -1922,7 +1919,7 @@
double Value() const;
static Local<Number> New(double value);
static Local<Number> New(Isolate* isolate, double value);
- V8_INLINE(static Number* Cast(v8::Value* obj));
+ V8_INLINE static Number* Cast(v8::Value* obj);
private:
Number();
static void CheckCast(v8::Value* obj);
@@ -1939,7 +1936,7 @@
static Local<Integer> New(int32_t value, Isolate*);
static Local<Integer> NewFromUnsigned(uint32_t value, Isolate*);
int64_t Value() const;
- V8_INLINE(static Integer* Cast(v8::Value* obj));
+ V8_INLINE static Integer* Cast(v8::Value* obj);
private:
Integer();
static void CheckCast(v8::Value* obj);
@@ -2140,7 +2137,7 @@
int InternalFieldCount();
/** Gets the value from an internal field. */
- V8_INLINE(Local<Value> GetInternalField(int index));
+ V8_INLINE Local<Value> GetInternalField(int index);
/** Sets the value in an internal field. */
void SetInternalField(int index, Handle<Value> value);
@@ -2150,7 +2147,7 @@
* must have been set by SetAlignedPointerInInternalField, everything else
* leads to undefined behavior.
*/
- V8_INLINE(void* GetAlignedPointerFromInternalField(int index));
+ V8_INLINE void* GetAlignedPointerFromInternalField(int index);
/**
* Sets a 2-byte-aligned native pointer in an internal field. To retrieve such
@@ -2280,7 +2277,7 @@
Local<Value> CallAsConstructor(int argc, Handle<Value> argv[]);
static Local<Object> New();
- V8_INLINE(static Object* Cast(Value* obj));
+ V8_INLINE static Object* Cast(Value* obj);
private:
Object();
@@ -2309,7 +2306,7 @@
*/
static Local<Array> New(int length = 0);
- V8_INLINE(static Array* Cast(Value* obj));
+ V8_INLINE static Array* Cast(Value* obj);
private:
Array();
static void CheckCast(Value* obj);
@@ -2319,31 +2316,31 @@
template<typename T>
class ReturnValue {
public:
- template <class S> V8_INLINE(ReturnValue(const ReturnValue<S>& that))
+ template <class S> V8_INLINE ReturnValue(const ReturnValue<S>& that)
: value_(that.value_) {
TYPE_CHECK(T, S);
}
// Handle setters
- template <typename S> V8_INLINE(void Set(const Persistent<S>& handle));
- template <typename S> V8_INLINE(void Set(const Handle<S> handle));
+ template <typename S> V8_INLINE void Set(const Persistent<S>& handle);
+ template <typename S> V8_INLINE void Set(const Handle<S> handle);
// Fast primitive setters
- V8_INLINE(void Set(bool value));
- V8_INLINE(void Set(double i));
- V8_INLINE(void Set(int32_t i));
- V8_INLINE(void Set(uint32_t i));
+ V8_INLINE void Set(bool value);
+ V8_INLINE void Set(double i);
+ V8_INLINE void Set(int32_t i);
+ V8_INLINE void Set(uint32_t i);
// Fast JS primitive setters
- V8_INLINE(void SetNull());
- V8_INLINE(void SetUndefined());
- V8_INLINE(void SetEmptyString());
+ V8_INLINE void SetNull();
+ V8_INLINE void SetUndefined();
+ V8_INLINE void SetEmptyString();
// Convenience getter for Isolate
- V8_INLINE(Isolate* GetIsolate());
+ V8_INLINE Isolate* GetIsolate();
private:
template<class F> friend class ReturnValue;
template<class F> friend class FunctionCallbackInfo;
template<class F> friend class PropertyCallbackInfo;
- V8_INLINE(internal::Object* GetDefaultValue());
- V8_INLINE(explicit ReturnValue(internal::Object** slot));
+ V8_INLINE internal::Object* GetDefaultValue();
+ V8_INLINE explicit ReturnValue(internal::Object** slot);
internal::Object** value_;
};
@@ -2357,15 +2354,15 @@
template<typename T>
class FunctionCallbackInfo {
public:
- V8_INLINE(int Length() const);
- V8_INLINE(Local<Value> operator[](int i) const);
- V8_INLINE(Local<Function> Callee() const);
- V8_INLINE(Local<Object> This() const);
- V8_INLINE(Local<Object> Holder() const);
- V8_INLINE(bool IsConstructCall() const);
- V8_INLINE(Local<Value> Data() const);
- V8_INLINE(Isolate* GetIsolate() const);
- V8_INLINE(ReturnValue<T> GetReturnValue() const);
+ V8_INLINE int Length() const;
+ V8_INLINE Local<Value> operator[](int i) const;
+ V8_INLINE Local<Function> Callee() const;
+ V8_INLINE Local<Object> This() const;
+ V8_INLINE Local<Object> Holder() const;
+ V8_INLINE bool IsConstructCall() const;
+ V8_INLINE Local<Value> Data() const;
+ V8_INLINE Isolate* GetIsolate() const;
+ V8_INLINE ReturnValue<T> GetReturnValue() const;
// This shouldn't be public, but the arm compiler needs it.
static const int kArgsLength = 6;
@@ -2379,10 +2376,10 @@
static const int kCalleeIndex = -4;
static const int kHolderIndex = -5;
- V8_INLINE(FunctionCallbackInfo(internal::Object** implicit_args,
+ V8_INLINE FunctionCallbackInfo(internal::Object** implicit_args,
internal::Object** values,
int length,
- bool is_construct_call));
+ bool is_construct_call);
internal::Object** implicit_args_;
internal::Object** values_;
int length_;
@@ -2397,11 +2394,11 @@
template<typename T>
class PropertyCallbackInfo {
public:
- V8_INLINE(Isolate* GetIsolate() const);
- V8_INLINE(Local<Value> Data() const);
- V8_INLINE(Local<Object> This() const);
- V8_INLINE(Local<Object> Holder() const);
- V8_INLINE(ReturnValue<T> GetReturnValue() const);
+ V8_INLINE Isolate* GetIsolate() const;
+ V8_INLINE Local<Value> Data() const;
+ V8_INLINE Local<Object> This() const;
+ V8_INLINE Local<Object> Holder() const;
+ V8_INLINE ReturnValue<T> GetReturnValue() const;
// This shouldn't be public, but the arm compiler needs it.
static const int kArgsLength = 6;
@@ -2410,14 +2407,13 @@
friend class internal::PropertyCallbackArguments;
friend class internal::CustomArguments<PropertyCallbackInfo>;
static const int kThisIndex = 0;
- static const int kHolderIndex = -1;
- static const int kDataIndex = -2;
- static const int kReturnValueIndex = -3;
- static const int kReturnValueDefaultValueIndex = -4;
- static const int kIsolateIndex = -5;
+ static const int kDataIndex = -1;
+ static const int kReturnValueIndex = -2;
+ static const int kReturnValueDefaultValueIndex = -3;
+ static const int kIsolateIndex = -4;
+ static const int kHolderIndex = -5;
- V8_INLINE(PropertyCallbackInfo(internal::Object** args))
- : args_(args) { }
+ V8_INLINE PropertyCallbackInfo(internal::Object** args) : args_(args) {}
internal::Object** args_;
};
@@ -2476,7 +2472,7 @@
int ScriptId() const;
ScriptOrigin GetScriptOrigin() const;
- V8_INLINE(static Function* Cast(Value* obj));
+ V8_INLINE static Function* Cast(Value* obj);
static const int kLineOffsetNotFound;
private:
@@ -2595,7 +2591,7 @@
*/
Contents Externalize();
- V8_INLINE(static ArrayBuffer* Cast(Value* obj));
+ V8_INLINE static ArrayBuffer* Cast(Value* obj);
static const int kInternalFieldCount = V8_ARRAY_BUFFER_INTERNAL_FIELD_COUNT;
@@ -2636,7 +2632,7 @@
*/
void* BaseAddress();
- V8_INLINE(static ArrayBufferView* Cast(Value* obj));
+ V8_INLINE static ArrayBufferView* Cast(Value* obj);
static const int kInternalFieldCount =
V8_ARRAY_BUFFER_VIEW_INTERNAL_FIELD_COUNT;
@@ -2660,7 +2656,7 @@
*/
size_t Length();
- V8_INLINE(static TypedArray* Cast(Value* obj));
+ V8_INLINE static TypedArray* Cast(Value* obj);
private:
TypedArray();
@@ -2676,7 +2672,7 @@
public:
static Local<Uint8Array> New(Handle<ArrayBuffer> array_buffer,
size_t byte_offset, size_t length);
- V8_INLINE(static Uint8Array* Cast(Value* obj));
+ V8_INLINE static Uint8Array* Cast(Value* obj);
private:
Uint8Array();
@@ -2692,7 +2688,7 @@
public:
static Local<Uint8ClampedArray> New(Handle<ArrayBuffer> array_buffer,
size_t byte_offset, size_t length);
- V8_INLINE(static Uint8ClampedArray* Cast(Value* obj));
+ V8_INLINE static Uint8ClampedArray* Cast(Value* obj);
private:
Uint8ClampedArray();
@@ -2707,7 +2703,7 @@
public:
static Local<Int8Array> New(Handle<ArrayBuffer> array_buffer,
size_t byte_offset, size_t length);
- V8_INLINE(static Int8Array* Cast(Value* obj));
+ V8_INLINE static Int8Array* Cast(Value* obj);
private:
Int8Array();
@@ -2723,7 +2719,7 @@
public:
static Local<Uint16Array> New(Handle<ArrayBuffer> array_buffer,
size_t byte_offset, size_t length);
- V8_INLINE(static Uint16Array* Cast(Value* obj));
+ V8_INLINE static Uint16Array* Cast(Value* obj);
private:
Uint16Array();
@@ -2739,7 +2735,7 @@
public:
static Local<Int16Array> New(Handle<ArrayBuffer> array_buffer,
size_t byte_offset, size_t length);
- V8_INLINE(static Int16Array* Cast(Value* obj));
+ V8_INLINE static Int16Array* Cast(Value* obj);
private:
Int16Array();
@@ -2755,7 +2751,7 @@
public:
static Local<Uint32Array> New(Handle<ArrayBuffer> array_buffer,
size_t byte_offset, size_t length);
- V8_INLINE(static Uint32Array* Cast(Value* obj));
+ V8_INLINE static Uint32Array* Cast(Value* obj);
private:
Uint32Array();
@@ -2771,7 +2767,7 @@
public:
static Local<Int32Array> New(Handle<ArrayBuffer> array_buffer,
size_t byte_offset, size_t length);
- V8_INLINE(static Int32Array* Cast(Value* obj));
+ V8_INLINE static Int32Array* Cast(Value* obj);
private:
Int32Array();
@@ -2787,7 +2783,7 @@
public:
static Local<Float32Array> New(Handle<ArrayBuffer> array_buffer,
size_t byte_offset, size_t length);
- V8_INLINE(static Float32Array* Cast(Value* obj));
+ V8_INLINE static Float32Array* Cast(Value* obj);
private:
Float32Array();
@@ -2803,7 +2799,7 @@
public:
static Local<Float64Array> New(Handle<ArrayBuffer> array_buffer,
size_t byte_offset, size_t length);
- V8_INLINE(static Float64Array* Cast(Value* obj));
+ V8_INLINE static Float64Array* Cast(Value* obj);
private:
Float64Array();
@@ -2819,7 +2815,7 @@
public:
static Local<DataView> New(Handle<ArrayBuffer> array_buffer,
size_t byte_offset, size_t length);
- V8_INLINE(static DataView* Cast(Value* obj));
+ V8_INLINE static DataView* Cast(Value* obj);
private:
DataView();
@@ -2844,7 +2840,7 @@
*/
double ValueOf() const;
- V8_INLINE(static Date* Cast(v8::Value* obj));
+ V8_INLINE static Date* Cast(v8::Value* obj);
/**
* Notification that the embedder has changed the time zone,
@@ -2881,7 +2877,7 @@
*/
double ValueOf() const;
- V8_INLINE(static NumberObject* Cast(v8::Value* obj));
+ V8_INLINE static NumberObject* Cast(v8::Value* obj);
private:
static void CheckCast(v8::Value* obj);
@@ -2904,7 +2900,7 @@
*/
bool ValueOf() const;
- V8_INLINE(static BooleanObject* Cast(v8::Value* obj));
+ V8_INLINE static BooleanObject* Cast(v8::Value* obj);
private:
static void CheckCast(v8::Value* obj);
@@ -2927,7 +2923,7 @@
*/
Local<String> ValueOf() const;
- V8_INLINE(static StringObject* Cast(v8::Value* obj));
+ V8_INLINE static StringObject* Cast(v8::Value* obj);
private:
static void CheckCast(v8::Value* obj);
@@ -2952,7 +2948,7 @@
*/
Local<Symbol> ValueOf() const;
- V8_INLINE(static SymbolObject* Cast(v8::Value* obj));
+ V8_INLINE static SymbolObject* Cast(v8::Value* obj);
private:
static void CheckCast(v8::Value* obj);
@@ -2998,7 +2994,7 @@
*/
Flags GetFlags() const;
- V8_INLINE(static RegExp* Cast(v8::Value* obj));
+ V8_INLINE static RegExp* Cast(v8::Value* obj);
private:
static void CheckCast(v8::Value* obj);
@@ -3012,7 +3008,7 @@
class V8_EXPORT External : public Value {
public:
static Local<External> New(void* value);
- V8_INLINE(static External* Cast(Value* obj));
+ V8_INLINE static External* Cast(Value* obj);
void* Value() const;
private:
static void CheckCast(v8::Value* obj);
@@ -3030,7 +3026,7 @@
/** Adds a property to each instance created by this template.*/
void Set(Handle<String> name, Handle<Data> value,
PropertyAttribute attributes = None);
- V8_INLINE(void Set(const char* name, Handle<Data> value));
+ V8_INLINE void Set(const char* name, Handle<Data> value);
void SetAccessorProperty(
Local<String> name,
@@ -3707,7 +3703,7 @@
*/
class V8_EXPORT DeclareExtension {
public:
- V8_INLINE(DeclareExtension(Extension* extension)) {
+ V8_INLINE DeclareExtension(Extension* extension) {
RegisterExtension(extension);
}
};
@@ -3721,10 +3717,10 @@
Handle<Boolean> V8_EXPORT True();
Handle<Boolean> V8_EXPORT False();
-V8_INLINE(Handle<Primitive> Undefined(Isolate* isolate));
-V8_INLINE(Handle<Primitive> Null(Isolate* isolate));
-V8_INLINE(Handle<Boolean> True(Isolate* isolate));
-V8_INLINE(Handle<Boolean> False(Isolate* isolate));
+V8_INLINE Handle<Primitive> Undefined(Isolate* isolate);
+V8_INLINE Handle<Primitive> Null(Isolate* isolate);
+V8_INLINE Handle<Boolean> True(Isolate* isolate);
+V8_INLINE Handle<Boolean> False(Isolate* isolate);
/**
@@ -3982,13 +3978,13 @@
/**
* Associate embedder-specific data with the isolate
*/
- V8_INLINE(void SetData(void* data));
+ V8_INLINE void SetData(void* data);
/**
* Retrieve embedder-specific data from the isolate.
* Returns NULL if SetData has never been called.
*/
- V8_INLINE(void* GetData());
+ V8_INLINE void* GetData();
/**
* Get statistics about the heap memory usage.
@@ -4260,7 +4256,7 @@
class V8_EXPORT AssertNoGCScope {
#ifndef DEBUG
// TODO(yangguo): remove isolate argument.
- V8_INLINE(AssertNoGCScope(Isolate* isolate)) { }
+ V8_INLINE AssertNoGCScope(Isolate* isolate) {}
#else
AssertNoGCScope(Isolate* isolate);
~AssertNoGCScope();
@@ -4963,7 +4959,7 @@
* previous call to SetEmbedderData with the same index. Note that index 0
* currently has a special meaning for Chrome's debugger.
*/
- V8_INLINE(Local<Value> GetEmbedderData(int index));
+ V8_INLINE Local<Value> GetEmbedderData(int index);
/**
* Sets the embedder data with the given index, growing the data as
@@ -4978,7 +4974,7 @@
* SetAlignedPointerInEmbedderData with the same index. Note that index 0
* currently has a special meaning for Chrome's debugger.
*/
- V8_INLINE(void* GetAlignedPointerFromEmbedderData(int index));
+ V8_INLINE void* GetAlignedPointerFromEmbedderData(int index);
/**
* Sets a 2-byte-aligned native pointer in the embedder data with the given
@@ -5021,15 +5017,15 @@
*/
class Scope {
public:
- explicit V8_INLINE(Scope(Handle<Context> context)) : context_(context) {
+ explicit V8_INLINE Scope(Handle<Context> context) : context_(context) {
context_->Enter();
}
// TODO(dcarney): deprecate
- V8_INLINE(Scope(Isolate* isolate, Persistent<Context>& context)) // NOLINT
+ V8_INLINE Scope(Isolate* isolate, Persistent<Context>& context) // NOLINT
: context_(Handle<Context>::New(isolate, context)) {
context_->Enter();
}
- V8_INLINE(~Scope()) { context_->Exit(); }
+ V8_INLINE ~Scope() { context_->Exit(); }
private:
Handle<Context> context_;
@@ -5127,7 +5123,7 @@
/**
* Initialize Unlocker for a given Isolate.
*/
- V8_INLINE(explicit Unlocker(Isolate* isolate)) { Initialize(isolate); }
+ V8_INLINE explicit Unlocker(Isolate* isolate) { Initialize(isolate); }
/** Deprecated. Use Isolate version instead. */
V8_DEPRECATED(Unlocker());
@@ -5145,7 +5141,7 @@
/**
* Initialize Locker for a given Isolate.
*/
- V8_INLINE(explicit Locker(Isolate* isolate)) { Initialize(isolate); }
+ V8_INLINE explicit Locker(Isolate* isolate) { Initialize(isolate); }
/** Deprecated. Use Isolate version instead. */
V8_DEPRECATED(Locker());
@@ -5274,7 +5270,7 @@
template <size_t ptr_size> struct SmiTagging;
template<int kSmiShiftSize>
-V8_INLINE(internal::Object* IntToSmi(int value)) {
+V8_INLINE internal::Object* IntToSmi(int value) {
int smi_shift_bits = kSmiTagSize + kSmiShiftSize;
intptr_t tagged_value =
(static_cast<intptr_t>(value) << smi_shift_bits) | kSmiTag;
@@ -5285,15 +5281,15 @@
template <> struct SmiTagging<4> {
static const int kSmiShiftSize = 0;
static const int kSmiValueSize = 31;
- V8_INLINE(static int SmiToInt(internal::Object* value)) {
+ V8_INLINE static int SmiToInt(internal::Object* value) {
int shift_bits = kSmiTagSize + kSmiShiftSize;
// Throw away top 32 bits and shift down (requires >> to be sign extending).
return static_cast<int>(reinterpret_cast<intptr_t>(value)) >> shift_bits;
}
- V8_INLINE(static internal::Object* IntToSmi(int value)) {
+ V8_INLINE static internal::Object* IntToSmi(int value) {
return internal::IntToSmi<kSmiShiftSize>(value);
}
- V8_INLINE(static bool IsValidSmi(intptr_t value)) {
+ V8_INLINE static bool IsValidSmi(intptr_t value) {
// To be representable as an tagged small integer, the two
// most-significant bits of 'value' must be either 00 or 11 due to
// sign-extension. To check this we add 01 to the two
@@ -5313,15 +5309,15 @@
template <> struct SmiTagging<8> {
static const int kSmiShiftSize = 31;
static const int kSmiValueSize = 32;
- V8_INLINE(static int SmiToInt(internal::Object* value)) {
+ V8_INLINE static int SmiToInt(internal::Object* value) {
int shift_bits = kSmiTagSize + kSmiShiftSize;
// Shift down and throw away top 32 bits.
return static_cast<int>(reinterpret_cast<intptr_t>(value) >> shift_bits);
}
- V8_INLINE(static internal::Object* IntToSmi(int value)) {
+ V8_INLINE static internal::Object* IntToSmi(int value) {
return internal::IntToSmi<kSmiShiftSize>(value);
}
- V8_INLINE(static bool IsValidSmi(intptr_t value)) {
+ V8_INLINE static bool IsValidSmi(intptr_t value) {
// To be representable as a long smi, the value must be a 32-bit integer.
return (value == static_cast<int32_t>(value));
}
@@ -5330,8 +5326,8 @@
typedef SmiTagging<kApiPointerSize> PlatformSmiTagging;
const int kSmiShiftSize = PlatformSmiTagging::kSmiShiftSize;
const int kSmiValueSize = PlatformSmiTagging::kSmiValueSize;
-V8_INLINE(static bool SmiValuesAre31Bits()) { return kSmiValueSize == 31; }
-V8_INLINE(static bool SmiValuesAre32Bits()) { return kSmiValueSize == 32; }
+V8_INLINE static bool SmiValuesAre31Bits() { return kSmiValueSize == 31; }
+V8_INLINE static bool SmiValuesAre32Bits() { return kSmiValueSize == 32; }
/**
* This class exports constants and functionality from within v8 that
@@ -5383,94 +5379,93 @@
static const int kNullOddballKind = 3;
static void CheckInitializedImpl(v8::Isolate* isolate);
- V8_INLINE(static void CheckInitialized(v8::Isolate* isolate)) {
+ V8_INLINE static void CheckInitialized(v8::Isolate* isolate) {
#ifdef V8_ENABLE_CHECKS
CheckInitializedImpl(isolate);
#endif
}
- V8_INLINE(static bool HasHeapObjectTag(internal::Object* value)) {
+ V8_INLINE static bool HasHeapObjectTag(internal::Object* value) {
return ((reinterpret_cast<intptr_t>(value) & kHeapObjectTagMask) ==
kHeapObjectTag);
}
- V8_INLINE(static int SmiValue(internal::Object* value)) {
+ V8_INLINE static int SmiValue(internal::Object* value) {
return PlatformSmiTagging::SmiToInt(value);
}
- V8_INLINE(static internal::Object* IntToSmi(int value)) {
+ V8_INLINE static internal::Object* IntToSmi(int value) {
return PlatformSmiTagging::IntToSmi(value);
}
- V8_INLINE(static bool IsValidSmi(intptr_t value)) {
+ V8_INLINE static bool IsValidSmi(intptr_t value) {
return PlatformSmiTagging::IsValidSmi(value);
}
- V8_INLINE(static int GetInstanceType(internal::Object* obj)) {
+ V8_INLINE static int GetInstanceType(internal::Object* obj) {
typedef internal::Object O;
O* map = ReadField<O*>(obj, kHeapObjectMapOffset);
return ReadField<uint8_t>(map, kMapInstanceTypeOffset);
}
- V8_INLINE(static int GetOddballKind(internal::Object* obj)) {
+ V8_INLINE static int GetOddballKind(internal::Object* obj) {
typedef internal::Object O;
return SmiValue(ReadField<O*>(obj, kOddballKindOffset));
}
- V8_INLINE(static bool IsExternalTwoByteString(int instance_type)) {
+ V8_INLINE static bool IsExternalTwoByteString(int instance_type) {
int representation = (instance_type & kFullStringRepresentationMask);
return representation == kExternalTwoByteRepresentationTag;
}
- V8_INLINE(static uint8_t GetNodeFlag(internal::Object** obj, int shift)) {
+ V8_INLINE static uint8_t GetNodeFlag(internal::Object** obj, int shift) {
uint8_t* addr = reinterpret_cast<uint8_t*>(obj) + kNodeFlagsOffset;
return *addr & static_cast<uint8_t>(1U << shift);
}
- V8_INLINE(static void UpdateNodeFlag(internal::Object** obj,
- bool value, int shift)) {
+ V8_INLINE static void UpdateNodeFlag(internal::Object** obj,
+ bool value, int shift) {
uint8_t* addr = reinterpret_cast<uint8_t*>(obj) + kNodeFlagsOffset;
uint8_t mask = static_cast<uint8_t>(1 << shift);
*addr = static_cast<uint8_t>((*addr & ~mask) | (value << shift));
}
- V8_INLINE(static uint8_t GetNodeState(internal::Object** obj)) {
+ V8_INLINE static uint8_t GetNodeState(internal::Object** obj) {
uint8_t* addr = reinterpret_cast<uint8_t*>(obj) + kNodeFlagsOffset;
return *addr & kNodeStateMask;
}
- V8_INLINE(static void UpdateNodeState(internal::Object** obj,
- uint8_t value)) {
+ V8_INLINE static void UpdateNodeState(internal::Object** obj,
+ uint8_t value) {
uint8_t* addr = reinterpret_cast<uint8_t*>(obj) + kNodeFlagsOffset;
*addr = static_cast<uint8_t>((*addr & ~kNodeStateMask) | value);
}
- V8_INLINE(static void SetEmbedderData(v8::Isolate* isolate, void* data)) {
+ V8_INLINE static void SetEmbedderData(v8::Isolate* isolate, void* data) {
uint8_t* addr = reinterpret_cast<uint8_t*>(isolate) +
kIsolateEmbedderDataOffset;
*reinterpret_cast<void**>(addr) = data;
}
- V8_INLINE(static void* GetEmbedderData(v8::Isolate* isolate)) {
+ V8_INLINE static void* GetEmbedderData(v8::Isolate* isolate) {
uint8_t* addr = reinterpret_cast<uint8_t*>(isolate) +
kIsolateEmbedderDataOffset;
return *reinterpret_cast<void**>(addr);
}
- V8_INLINE(static internal::Object** GetRoot(v8::Isolate* isolate,
- int index)) {
+ V8_INLINE static internal::Object** GetRoot(v8::Isolate* isolate,
+ int index) {
uint8_t* addr = reinterpret_cast<uint8_t*>(isolate) + kIsolateRootsOffset;
return reinterpret_cast<internal::Object**>(addr + index * kApiPointerSize);
}
- template <typename T>
- V8_INLINE(static T ReadField(Object* ptr, int offset)) {
+ template <typename T> V8_INLINE static T ReadField(Object* ptr, int offset) {
uint8_t* addr = reinterpret_cast<uint8_t*>(ptr) + offset - kHeapObjectTag;
return *reinterpret_cast<T*>(addr);
}
template <typename T>
- V8_INLINE(static T ReadEmbedderData(Context* context, int index)) {
+ V8_INLINE static T ReadEmbedderData(Context* context, int index) {
typedef internal::Object O;
typedef internal::Internals I;
O* ctx = *reinterpret_cast<O**>(context);
@@ -5482,13 +5477,13 @@
return I::ReadField<T>(embedder_data, value_offset);
}
- V8_INLINE(static bool CanCastToHeapObject(void* o)) { return false; }
- V8_INLINE(static bool CanCastToHeapObject(Context* o)) { return true; }
- V8_INLINE(static bool CanCastToHeapObject(String* o)) { return true; }
- V8_INLINE(static bool CanCastToHeapObject(Object* o)) { return true; }
- V8_INLINE(static bool CanCastToHeapObject(Message* o)) { return true; }
- V8_INLINE(static bool CanCastToHeapObject(StackTrace* o)) { return true; }
- V8_INLINE(static bool CanCastToHeapObject(StackFrame* o)) { return true; }
+ V8_INLINE static bool CanCastToHeapObject(void* o) { return false; }
+ V8_INLINE static bool CanCastToHeapObject(Context* o) { return true; }
+ V8_INLINE static bool CanCastToHeapObject(String* o) { return true; }
+ V8_INLINE static bool CanCastToHeapObject(Object* o) { return true; }
+ V8_INLINE static bool CanCastToHeapObject(Message* o) { return true; }
+ V8_INLINE static bool CanCastToHeapObject(StackTrace* o) { return true; }
+ V8_INLINE static bool CanCastToHeapObject(StackFrame* o) { return true; }
};
} // namespace internal
diff --git a/include/v8config.h b/include/v8config.h
index 0993a9f..6fe5c5a 100644
--- a/include/v8config.h
+++ b/include/v8config.h
@@ -295,23 +295,27 @@
// Helper macros
// A macro used to make better inlining. Don't bother for debug builds.
+// Use like:
+// V8_INLINE int GetZero() { return 0; }
#if !defined(DEBUG) && V8_HAS_ATTRIBUTE_ALWAYS_INLINE
-# define V8_INLINE(declarator) inline __attribute__((always_inline)) declarator
+# define V8_INLINE inline __attribute__((always_inline))
#elif !defined(DEBUG) && V8_HAS___FORCEINLINE
-# define V8_INLINE(declarator) __forceinline declarator
+# define V8_INLINE __forceinline
#else
-# define V8_INLINE(declarator) inline declarator
+# define V8_INLINE inline
#endif
// A macro used to tell the compiler to never inline a particular function.
// Don't bother for debug builds.
+// Use like:
+// V8_NOINLINE int GetMinusOne() { return -1; }
#if !defined(DEBUG) && V8_HAS_ATTRIBUTE_NOINLINE
-# define V8_NOINLINE(declarator) __attribute__((noinline)) declarator
+# define V8_NOINLINE __attribute__((noinline))
#elif !defined(DEBUG) && V8_HAS_DECLSPEC_NOINLINE
-# define V8_NOINLINE(declarator) __declspec(noinline) declarator
+# define V8_NOINLINE __declspec(noinline)
#else
-# define V8_NOINLINE(declarator) declarator
+# define V8_NOINLINE /* NOT SUPPORTED */
#endif
diff --git a/src/accessors.cc b/src/accessors.cc
index f8cb0c8..669c02b 100644
--- a/src/accessors.cc
+++ b/src/accessors.cc
@@ -113,7 +113,7 @@
// object does not have a 'length' property. Calling SetProperty
// causes an infinite loop.
if (!object->IsJSArray()) {
- return object->SetLocalPropertyIgnoreAttributes(
+ return object->SetLocalPropertyIgnoreAttributesTrampoline(
isolate->heap()->length_string(), value, NONE);
}
@@ -531,9 +531,8 @@
if (function_raw == NULL) return heap->undefined_value();
if (!function_raw->should_have_prototype()) {
// Since we hit this accessor, object will have no prototype property.
- return object->SetLocalPropertyIgnoreAttributes(heap->prototype_string(),
- value_raw,
- NONE);
+ return object->SetLocalPropertyIgnoreAttributesTrampoline(
+ heap->prototype_string(), value_raw, NONE);
}
HandleScope scope(isolate);
diff --git a/src/api.cc b/src/api.cc
index f75a851..71a8f4a 100644
--- a/src/api.cc
+++ b/src/api.cc
@@ -403,9 +403,6 @@
kSnapshotContext,
kLibraries,
kExperimentalLibraries,
-#if defined(V8_I18N_SUPPORT)
- kI18NExtension,
-#endif
kCompressedStartupDataCount
};
@@ -446,17 +443,6 @@
exp_libraries_source.length();
compressed_data[kExperimentalLibraries].raw_size =
i::ExperimentalNatives::GetRawScriptsSize();
-
-#if defined(V8_I18N_SUPPORT)
- i::Vector<const ii:byte> i18n_extension_source =
- i::I18NNatives::GetScriptsSource();
- compressed_data[kI18NExtension].data =
- reinterpret_cast<const char*>(i18n_extension_source.start());
- compressed_data[kI18NExtension].compressed_size =
- i18n_extension_source.length();
- compressed_data[kI18NExtension].raw_size =
- i::I18NNatives::GetRawScriptsSize();
-#endif
#endif
}
@@ -486,15 +472,6 @@
decompressed_data[kExperimentalLibraries].data,
decompressed_data[kExperimentalLibraries].raw_size);
i::ExperimentalNatives::SetRawScriptsSource(exp_libraries_source);
-
-#if defined(V8_I18N_SUPPORT)
- ASSERT_EQ(i::I18NNatives::GetRawScriptsSize(),
- decompressed_data[kI18NExtension].raw_size);
- i::Vector<const char> i18n_extension_source(
- decompressed_data[kI18NExtension].data,
- decompressed_data[kI18NExtension].raw_size);
- i::I18NNatives::SetRawScriptsSource(i18n_extension_source);
-#endif
#endif
}
diff --git a/src/arguments.h b/src/arguments.h
index 169528b..c1db98b 100644
--- a/src/arguments.h
+++ b/src/arguments.h
@@ -175,6 +175,10 @@
static const int kArgsLength = T::kArgsLength;
static const int kThisIndex = T::kThisIndex;
static const int kHolderIndex = T::kHolderIndex;
+ static const int kDataIndex = T::kDataIndex;
+ static const int kReturnValueDefaultValueIndex =
+ T::kReturnValueDefaultValueIndex;
+ static const int kIsolateIndex = T::kIsolateIndex;
PropertyCallbackArguments(Isolate* isolate,
Object* data,
diff --git a/src/arm/assembler-arm.cc b/src/arm/assembler-arm.cc
index ed8639c..bd8b061 100644
--- a/src/arm/assembler-arm.cc
+++ b/src/arm/assembler-arm.cc
@@ -39,6 +39,7 @@
#if V8_TARGET_ARCH_ARM
#include "arm/assembler-arm-inl.h"
+#include "macro-assembler.h"
#include "serialize.h"
namespace v8 {
@@ -775,9 +776,9 @@
int Assembler::target_at(int pos) {
Instr instr = instr_at(pos);
- if ((instr & ~kImm24Mask) == 0) {
- // Emitted label constant, not part of a branch.
- return instr - (Code::kHeaderSize - kHeapObjectTag);
+ if (is_uint24(instr)) {
+ // Emitted link to a label, not part of a branch.
+ return instr;
}
ASSERT((instr & 7*B25) == 5*B25); // b, bl, or blx imm24
int imm26 = ((instr & kImm24Mask) << 8) >> 6;
@@ -792,11 +793,72 @@
void Assembler::target_at_put(int pos, int target_pos) {
Instr instr = instr_at(pos);
- if ((instr & ~kImm24Mask) == 0) {
+ if (is_uint24(instr)) {
ASSERT(target_pos == pos || target_pos >= 0);
- // Emitted label constant, not part of a branch.
- // Make label relative to Code* of generated Code object.
- instr_at_put(pos, target_pos + (Code::kHeaderSize - kHeapObjectTag));
+ // Emitted link to a label, not part of a branch.
+ // Load the position of the label relative to the generated code object
+ // pointer in a register.
+
+ // Here are the instructions we need to emit:
+ // For ARMv7: target24 => target16_1:target16_0
+ // movw dst, #target16_0
+ // movt dst, #target16_1
+ // For ARMv6: target24 => target8_2:target8_1:target8_0
+ // mov dst, #target8_0
+ // orr dst, dst, #target8_1 << 8
+ // orr dst, dst, #target8_2 << 16
+
+ // We extract the destination register from the emitted nop instruction.
+ Register dst = Register::from_code(
+ Instruction::RmValue(instr_at(pos + kInstrSize)));
+ ASSERT(IsNop(instr_at(pos + kInstrSize), dst.code()));
+ uint32_t target24 = target_pos + (Code::kHeaderSize - kHeapObjectTag);
+ ASSERT(is_uint24(target24));
+ if (is_uint8(target24)) {
+ // If the target fits in a byte then only patch with a mov
+ // instruction.
+ CodePatcher patcher(reinterpret_cast<byte*>(buffer_ + pos),
+ 1,
+ CodePatcher::DONT_FLUSH);
+ patcher.masm()->mov(dst, Operand(target24));
+ } else {
+ uint16_t target16_0 = target24 & kImm16Mask;
+ uint16_t target16_1 = target24 >> 16;
+ if (CpuFeatures::IsSupported(ARMv7)) {
+ // Patch with movw/movt.
+ if (target16_1 == 0) {
+ CodePatcher patcher(reinterpret_cast<byte*>(buffer_ + pos),
+ 1,
+ CodePatcher::DONT_FLUSH);
+ patcher.masm()->movw(dst, target16_0);
+ } else {
+ CodePatcher patcher(reinterpret_cast<byte*>(buffer_ + pos),
+ 2,
+ CodePatcher::DONT_FLUSH);
+ patcher.masm()->movw(dst, target16_0);
+ patcher.masm()->movt(dst, target16_1);
+ }
+ } else {
+ // Patch with a sequence of mov/orr/orr instructions.
+ uint8_t target8_0 = target16_0 & kImm8Mask;
+ uint8_t target8_1 = target16_0 >> 8;
+ uint8_t target8_2 = target16_1 & kImm8Mask;
+ if (target8_2 == 0) {
+ CodePatcher patcher(reinterpret_cast<byte*>(buffer_ + pos),
+ 2,
+ CodePatcher::DONT_FLUSH);
+ patcher.masm()->mov(dst, Operand(target8_0));
+ patcher.masm()->orr(dst, dst, Operand(target8_1 << 8));
+ } else {
+ CodePatcher patcher(reinterpret_cast<byte*>(buffer_ + pos),
+ 3,
+ CodePatcher::DONT_FLUSH);
+ patcher.masm()->mov(dst, Operand(target8_0));
+ patcher.masm()->orr(dst, dst, Operand(target8_1 << 8));
+ patcher.masm()->orr(dst, dst, Operand(target8_2 << 16));
+ }
+ }
+ }
return;
}
int imm26 = target_pos - (pos + kPcLoadDelta);
@@ -1229,21 +1291,6 @@
}
-void Assembler::label_at_put(Label* L, int at_offset) {
- int target_pos;
- ASSERT(!L->is_bound());
- if (L->is_linked()) {
- // Point to previous instruction that uses the link.
- target_pos = L->pos();
- } else {
- // First entry of the link chain points to itself.
- target_pos = at_offset;
- }
- L->link_to(at_offset);
- instr_at_put(at_offset, target_pos + (Code::kHeaderSize - kHeapObjectTag));
-}
-
-
// Branch instructions.
void Assembler::b(int branch_offset, Condition cond) {
ASSERT((branch_offset & 3) == 0);
@@ -1386,6 +1433,45 @@
}
+void Assembler::mov_label_offset(Register dst, Label* label) {
+ if (label->is_bound()) {
+ mov(dst, Operand(label->pos() + (Code::kHeaderSize - kHeapObjectTag)));
+ } else {
+ // Emit the link to the label in the code stream followed by extra nop
+ // instructions.
+ // If the label is not linked, then start a new link chain by linking it to
+ // itself, emitting pc_offset().
+ int link = label->is_linked() ? label->pos() : pc_offset();
+ label->link_to(pc_offset());
+
+ // When the label is bound, these instructions will be patched with a
+ // sequence of movw/movt or mov/orr/orr instructions. They will load the
+ // destination register with the position of the label from the beginning
+ // of the code.
+ //
+ // The link will be extracted from the first instruction and the destination
+ // register from the second.
+ // For ARMv7:
+ // link
+ // mov dst, dst
+ // For ARMv6:
+ // link
+ // mov dst, dst
+ // mov dst, dst
+ //
+ // When the label gets bound: target_at extracts the link and target_at_put
+ // patches the instructions.
+ ASSERT(is_uint24(link));
+ BlockConstPoolScope block_const_pool(this);
+ emit(link);
+ nop(dst.code());
+ if (!CpuFeatures::IsSupported(ARMv7)) {
+ nop(dst.code());
+ }
+ }
+}
+
+
void Assembler::movw(Register reg, uint32_t immediate, Condition cond) {
ASSERT(immediate < 0x10000);
// May use movw if supported, but on unsupported platforms will try to use
diff --git a/src/arm/assembler-arm.h b/src/arm/assembler-arm.h
index f647848..866b1c9 100644
--- a/src/arm/assembler-arm.h
+++ b/src/arm/assembler-arm.h
@@ -748,10 +748,6 @@
// Manages the jump elimination optimization if the second parameter is true.
int branch_offset(Label* L, bool jump_elimination_allowed);
- // Puts a labels target address at the given position.
- // The high 8 bits are set to zero.
- void label_at_put(Label* L, int at_offset);
-
// Return the address in the constant pool of the code target address used by
// the branch/call instruction at pc, or the object in a mov.
INLINE(static Address target_pointer_address_at(Address pc));
@@ -903,6 +899,10 @@
mov(dst, Operand(src), s, cond);
}
+ // Load the position of the label relative to the generated code object
+ // pointer in a register.
+ void mov_label_offset(Register dst, Label* label);
+
// ARMv7 instructions for loading a 32 bit immediate in two instructions.
// This may actually emit a different mov instruction, but on an ARMv7 it
// is guaranteed to only emit one instruction.
@@ -1561,7 +1561,6 @@
void RecordRelocInfo(double data);
void RecordRelocInfoConstantPoolEntryHelper(const RelocInfo& rinfo);
- friend class RegExpMacroAssemblerARM;
friend class RelocInfo;
friend class CodePatcher;
friend class BlockConstPoolScope;
diff --git a/src/arm/builtins-arm.cc b/src/arm/builtins-arm.cc
index e0c37e1..f60e1f8 100644
--- a/src/arm/builtins-arm.cc
+++ b/src/arm/builtins-arm.cc
@@ -291,68 +291,55 @@
}
+static void CallRuntimePassFunction(MacroAssembler* masm,
+ Runtime::FunctionId function_id) {
+ FrameScope scope(masm, StackFrame::INTERNAL);
+ // Push a copy of the function onto the stack.
+ __ push(r1);
+ // Push call kind information.
+ __ push(r5);
+ // Function is also the parameter to the runtime call.
+ __ push(r1);
+
+ __ CallRuntime(function_id, 1);
+ // Restore call kind information.
+ __ pop(r5);
+ // Restore receiver.
+ __ pop(r1);
+}
+
+
static void GenerateTailCallToSharedCode(MacroAssembler* masm) {
__ ldr(r2, FieldMemOperand(r1, JSFunction::kSharedFunctionInfoOffset));
__ ldr(r2, FieldMemOperand(r2, SharedFunctionInfo::kCodeOffset));
__ add(r2, r2, Operand(Code::kHeaderSize - kHeapObjectTag));
- __ mov(pc, r2);
-}
-
-
-void Builtins::Generate_InRecompileQueue(MacroAssembler* masm) {
- GenerateTailCallToSharedCode(masm);
-}
-
-
-void Builtins::Generate_InstallRecompiledCode(MacroAssembler* masm) {
- // Enter an internal frame.
- {
- FrameScope scope(masm, StackFrame::INTERNAL);
-
- // Preserve the function.
- __ push(r1);
- // Push call kind information.
- __ push(r5);
-
- // Push the function on the stack as the argument to the runtime function.
- __ push(r1);
- __ CallRuntime(Runtime::kInstallRecompiledCode, 1);
- // Calculate the entry point.
- __ add(r2, r0, Operand(Code::kHeaderSize - kHeapObjectTag));
-
- // Restore call kind information.
- __ pop(r5);
- // Restore saved function.
- __ pop(r1);
-
- // Tear down internal frame.
- }
-
- // Do a tail-call of the compiled function.
__ Jump(r2);
}
+void Builtins::Generate_InRecompileQueue(MacroAssembler* masm) {
+ // Checking whether the queued function is ready for install is optional,
+ // since we come across interrupts and stack checks elsewhere. However,
+ // not checking may delay installing ready functions, and always checking
+ // would be quite expensive. A good compromise is to first check against
+ // stack limit as a cue for an interrupt signal.
+ Label ok;
+ __ LoadRoot(ip, Heap::kStackLimitRootIndex);
+ __ cmp(sp, Operand(ip));
+ __ b(hs, &ok);
+
+ CallRuntimePassFunction(masm, Runtime::kTryInstallRecompiledCode);
+ // Tail call to returned code.
+ __ add(r0, r0, Operand(Code::kHeaderSize - kHeapObjectTag));
+ __ Jump(r0);
+
+ __ bind(&ok);
+ GenerateTailCallToSharedCode(masm);
+}
+
+
void Builtins::Generate_ConcurrentRecompile(MacroAssembler* masm) {
- {
- FrameScope scope(masm, StackFrame::INTERNAL);
-
- // Push a copy of the function onto the stack.
- __ push(r1);
- // Push call kind information.
- __ push(r5);
-
- __ push(r1); // Function is also the parameter to the runtime call.
- __ CallRuntime(Runtime::kConcurrentRecompile, 1);
-
- // Restore call kind information.
- __ pop(r5);
- // Restore receiver.
- __ pop(r1);
-
- // Tear down internal frame.
- }
-
+ CallRuntimePassFunction(masm, Runtime::kConcurrentRecompile);
GenerateTailCallToSharedCode(masm);
}
@@ -795,59 +782,17 @@
void Builtins::Generate_LazyCompile(MacroAssembler* masm) {
- // Enter an internal frame.
- {
- FrameScope scope(masm, StackFrame::INTERNAL);
-
- // Preserve the function.
- __ push(r1);
- // Push call kind information.
- __ push(r5);
-
- // Push the function on the stack as the argument to the runtime function.
- __ push(r1);
- __ CallRuntime(Runtime::kLazyCompile, 1);
- // Calculate the entry point.
- __ add(r2, r0, Operand(Code::kHeaderSize - kHeapObjectTag));
-
- // Restore call kind information.
- __ pop(r5);
- // Restore saved function.
- __ pop(r1);
-
- // Tear down internal frame.
- }
-
+ CallRuntimePassFunction(masm, Runtime::kLazyCompile);
// Do a tail-call of the compiled function.
+ __ add(r2, r0, Operand(Code::kHeaderSize - kHeapObjectTag));
__ Jump(r2);
}
void Builtins::Generate_LazyRecompile(MacroAssembler* masm) {
- // Enter an internal frame.
- {
- FrameScope scope(masm, StackFrame::INTERNAL);
-
- // Preserve the function.
- __ push(r1);
- // Push call kind information.
- __ push(r5);
-
- // Push the function on the stack as the argument to the runtime function.
- __ push(r1);
- __ CallRuntime(Runtime::kLazyRecompile, 1);
- // Calculate the entry point.
- __ add(r2, r0, Operand(Code::kHeaderSize - kHeapObjectTag));
-
- // Restore call kind information.
- __ pop(r5);
- // Restore saved function.
- __ pop(r1);
-
- // Tear down internal frame.
- }
-
+ CallRuntimePassFunction(masm, Runtime::kLazyRecompile);
// Do a tail-call of the compiled function.
+ __ add(r2, r0, Operand(Code::kHeaderSize - kHeapObjectTag));
__ Jump(r2);
}
diff --git a/src/arm/code-stubs-arm.cc b/src/arm/code-stubs-arm.cc
index 3a1d128..cd1809f 100644
--- a/src/arm/code-stubs-arm.cc
+++ b/src/arm/code-stubs-arm.cc
@@ -5790,7 +5790,6 @@
__ b(lt, &done);
// Check the number to string cache.
- Label not_cached;
__ bind(¬_string);
// Puts the cached result into scratch1.
NumberToStringStub::GenerateLookupNumberStringCache(masm,
@@ -5799,26 +5798,9 @@
scratch2,
scratch3,
scratch4,
- ¬_cached);
+ slow);
__ mov(arg, scratch1);
__ str(arg, MemOperand(sp, stack_offset));
- __ jmp(&done);
-
- // Check if the argument is a safe string wrapper.
- __ bind(¬_cached);
- __ JumpIfSmi(arg, slow);
- __ CompareObjectType(
- arg, scratch1, scratch2, JS_VALUE_TYPE); // map -> scratch1.
- __ b(ne, slow);
- __ ldrb(scratch2, FieldMemOperand(scratch1, Map::kBitField2Offset));
- __ and_(scratch2,
- scratch2, Operand(1 << Map::kStringWrapperSafeForDefaultValueOf));
- __ cmp(scratch2,
- Operand(1 << Map::kStringWrapperSafeForDefaultValueOf));
- __ b(ne, slow);
- __ ldr(arg, FieldMemOperand(arg, JSValue::kValueOffset));
- __ str(arg, MemOperand(sp, stack_offset));
-
__ bind(&done);
}
@@ -6855,90 +6837,128 @@
template<class T>
-static void CreateArrayDispatch(MacroAssembler* masm) {
- int last_index = GetSequenceIndexFromFastElementsKind(
- TERMINAL_FAST_ELEMENTS_KIND);
- for (int i = 0; i <= last_index; ++i) {
- Label next;
- ElementsKind kind = GetFastElementsKindFromSequenceIndex(i);
- __ cmp(r3, Operand(kind));
- __ b(ne, &next);
- T stub(kind);
+static void CreateArrayDispatch(MacroAssembler* masm,
+ AllocationSiteOverrideMode mode) {
+ if (mode == DISABLE_ALLOCATION_SITES) {
+ T stub(GetInitialFastElementsKind(),
+ CONTEXT_CHECK_REQUIRED,
+ mode);
__ TailCallStub(&stub);
- __ bind(&next);
- }
+ } else if (mode == DONT_OVERRIDE) {
+ int last_index = GetSequenceIndexFromFastElementsKind(
+ TERMINAL_FAST_ELEMENTS_KIND);
+ for (int i = 0; i <= last_index; ++i) {
+ Label next;
+ ElementsKind kind = GetFastElementsKindFromSequenceIndex(i);
+ __ cmp(r3, Operand(kind));
+ __ b(ne, &next);
+ T stub(kind);
+ __ TailCallStub(&stub);
+ __ bind(&next);
+ }
- // If we reached this point there is a problem.
- __ Abort(kUnexpectedElementsKindInArrayConstructor);
+ // If we reached this point there is a problem.
+ __ Abort(kUnexpectedElementsKindInArrayConstructor);
+ } else {
+ UNREACHABLE();
+ }
}
-static void CreateArrayDispatchOneArgument(MacroAssembler* masm) {
- // r2 - type info cell
- // r3 - kind
+static void CreateArrayDispatchOneArgument(MacroAssembler* masm,
+ AllocationSiteOverrideMode mode) {
+ // r2 - type info cell (if mode != DISABLE_ALLOCATION_SITES)
+ // r3 - kind (if mode != DISABLE_ALLOCATION_SITES)
// r0 - number of arguments
// r1 - constructor?
// sp[0] - last argument
- ASSERT(FAST_SMI_ELEMENTS == 0);
- ASSERT(FAST_HOLEY_SMI_ELEMENTS == 1);
- ASSERT(FAST_ELEMENTS == 2);
- ASSERT(FAST_HOLEY_ELEMENTS == 3);
- ASSERT(FAST_DOUBLE_ELEMENTS == 4);
- ASSERT(FAST_HOLEY_DOUBLE_ELEMENTS == 5);
-
- // is the low bit set? If so, we are holey and that is good.
- __ tst(r3, Operand(1));
Label normal_sequence;
- __ b(ne, &normal_sequence);
+ if (mode == DONT_OVERRIDE) {
+ ASSERT(FAST_SMI_ELEMENTS == 0);
+ ASSERT(FAST_HOLEY_SMI_ELEMENTS == 1);
+ ASSERT(FAST_ELEMENTS == 2);
+ ASSERT(FAST_HOLEY_ELEMENTS == 3);
+ ASSERT(FAST_DOUBLE_ELEMENTS == 4);
+ ASSERT(FAST_HOLEY_DOUBLE_ELEMENTS == 5);
+
+ // is the low bit set? If so, we are holey and that is good.
+ __ tst(r3, Operand(1));
+ __ b(ne, &normal_sequence);
+ }
// look at the first argument
__ ldr(r5, MemOperand(sp, 0));
__ cmp(r5, Operand::Zero());
__ b(eq, &normal_sequence);
- // We are going to create a holey array, but our kind is non-holey.
- // Fix kind and retry (only if we have an allocation site in the cell).
- __ add(r3, r3, Operand(1));
- __ CompareRoot(r2, Heap::kUndefinedValueRootIndex);
- __ b(eq, &normal_sequence);
- __ ldr(r5, FieldMemOperand(r2, Cell::kValueOffset));
- __ ldr(r5, FieldMemOperand(r5, 0));
- __ CompareRoot(r5, Heap::kAllocationSiteMapRootIndex);
- __ b(ne, &normal_sequence);
+ if (mode == DISABLE_ALLOCATION_SITES) {
+ ElementsKind initial = GetInitialFastElementsKind();
+ ElementsKind holey_initial = GetHoleyElementsKind(initial);
- // Save the resulting elements kind in type info
- __ SmiTag(r3);
- __ ldr(r5, FieldMemOperand(r2, Cell::kValueOffset));
- __ str(r3, FieldMemOperand(r5, AllocationSite::kTransitionInfoOffset));
- __ SmiUntag(r3);
+ ArraySingleArgumentConstructorStub stub_holey(holey_initial,
+ CONTEXT_CHECK_REQUIRED,
+ DISABLE_ALLOCATION_SITES);
+ __ TailCallStub(&stub_holey);
- __ bind(&normal_sequence);
- int last_index = GetSequenceIndexFromFastElementsKind(
- TERMINAL_FAST_ELEMENTS_KIND);
- for (int i = 0; i <= last_index; ++i) {
- Label next;
- ElementsKind kind = GetFastElementsKindFromSequenceIndex(i);
- __ cmp(r3, Operand(kind));
- __ b(ne, &next);
- ArraySingleArgumentConstructorStub stub(kind);
+ __ bind(&normal_sequence);
+ ArraySingleArgumentConstructorStub stub(initial,
+ CONTEXT_CHECK_REQUIRED,
+ DISABLE_ALLOCATION_SITES);
__ TailCallStub(&stub);
- __ bind(&next);
- }
+ } else if (mode == DONT_OVERRIDE) {
+ // We are going to create a holey array, but our kind is non-holey.
+ // Fix kind and retry (only if we have an allocation site in the cell).
+ __ add(r3, r3, Operand(1));
+ __ ldr(r5, FieldMemOperand(r2, Cell::kValueOffset));
- // If we reached this point there is a problem.
- __ Abort(kUnexpectedElementsKindInArrayConstructor);
+ if (FLAG_debug_code) {
+ __ ldr(r5, FieldMemOperand(r5, 0));
+ __ CompareRoot(r5, Heap::kAllocationSiteMapRootIndex);
+ __ Assert(eq, kExpectedAllocationSiteInCell);
+ __ ldr(r5, FieldMemOperand(r2, Cell::kValueOffset));
+ }
+
+ // Save the resulting elements kind in type info
+ __ SmiTag(r3);
+ __ ldr(r5, FieldMemOperand(r2, Cell::kValueOffset));
+ __ str(r3, FieldMemOperand(r5, AllocationSite::kTransitionInfoOffset));
+ __ SmiUntag(r3);
+
+ __ bind(&normal_sequence);
+ int last_index = GetSequenceIndexFromFastElementsKind(
+ TERMINAL_FAST_ELEMENTS_KIND);
+ for (int i = 0; i <= last_index; ++i) {
+ Label next;
+ ElementsKind kind = GetFastElementsKindFromSequenceIndex(i);
+ __ cmp(r3, Operand(kind));
+ __ b(ne, &next);
+ ArraySingleArgumentConstructorStub stub(kind);
+ __ TailCallStub(&stub);
+ __ bind(&next);
+ }
+
+ // If we reached this point there is a problem.
+ __ Abort(kUnexpectedElementsKindInArrayConstructor);
+ } else {
+ UNREACHABLE();
+ }
}
template<class T>
static void ArrayConstructorStubAheadOfTimeHelper(Isolate* isolate) {
+ ElementsKind initial_kind = GetInitialFastElementsKind();
+ ElementsKind initial_holey_kind = GetHoleyElementsKind(initial_kind);
+
int to_index = GetSequenceIndexFromFastElementsKind(
TERMINAL_FAST_ELEMENTS_KIND);
for (int i = 0; i <= to_index; ++i) {
ElementsKind kind = GetFastElementsKindFromSequenceIndex(i);
T stub(kind);
stub.GetCode(isolate)->set_is_pregenerated(true);
- if (AllocationSite::GetMode(kind) != DONT_TRACK_ALLOCATION_SITE) {
+ if (AllocationSite::GetMode(kind) != DONT_TRACK_ALLOCATION_SITE ||
+ (!FLAG_track_allocation_sites &&
+ (kind == initial_kind || kind == initial_holey_kind))) {
T stub1(kind, CONTEXT_CHECK_REQUIRED, DISABLE_ALLOCATION_SITES);
stub1.GetCode(isolate)->set_is_pregenerated(true);
}
@@ -6971,6 +6991,34 @@
}
+void ArrayConstructorStub::GenerateDispatchToArrayStub(
+ MacroAssembler* masm,
+ AllocationSiteOverrideMode mode) {
+ if (argument_count_ == ANY) {
+ Label not_zero_case, not_one_case;
+ __ tst(r0, r0);
+ __ b(ne, ¬_zero_case);
+ CreateArrayDispatch<ArrayNoArgumentConstructorStub>(masm, mode);
+
+ __ bind(¬_zero_case);
+ __ cmp(r0, Operand(1));
+ __ b(gt, ¬_one_case);
+ CreateArrayDispatchOneArgument(masm, mode);
+
+ __ bind(¬_one_case);
+ CreateArrayDispatch<ArrayNArgumentsConstructorStub>(masm, mode);
+ } else if (argument_count_ == NONE) {
+ CreateArrayDispatch<ArrayNoArgumentConstructorStub>(masm, mode);
+ } else if (argument_count_ == ONE) {
+ CreateArrayDispatchOneArgument(masm, mode);
+ } else if (argument_count_ == MORE_THAN_ONE) {
+ CreateArrayDispatch<ArrayNArgumentsConstructorStub>(masm, mode);
+ } else {
+ UNREACHABLE();
+ }
+}
+
+
void ArrayConstructorStub::Generate(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- r0 : argc (only if argument_count_ == ANY)
@@ -7002,50 +7050,24 @@
__ bind(&okay_here);
}
- Label no_info, switch_ready;
+ Label no_info;
// Get the elements kind and case on that.
__ CompareRoot(r2, Heap::kUndefinedValueRootIndex);
__ b(eq, &no_info);
__ ldr(r3, FieldMemOperand(r2, Cell::kValueOffset));
- // The type cell may have undefined in its value.
- __ CompareRoot(r3, Heap::kUndefinedValueRootIndex);
- __ b(eq, &no_info);
-
- // The type cell has either an AllocationSite or a JSFunction
+ // If the type cell is undefined, or contains anything other than an
+ // AllocationSite, call an array constructor that doesn't use AllocationSites.
__ ldr(r4, FieldMemOperand(r3, 0));
__ CompareRoot(r4, Heap::kAllocationSiteMapRootIndex);
__ b(ne, &no_info);
__ ldr(r3, FieldMemOperand(r3, AllocationSite::kTransitionInfoOffset));
__ SmiUntag(r3);
- __ jmp(&switch_ready);
+ GenerateDispatchToArrayStub(masm, DONT_OVERRIDE);
+
__ bind(&no_info);
- __ mov(r3, Operand(GetInitialFastElementsKind()));
- __ bind(&switch_ready);
-
- if (argument_count_ == ANY) {
- Label not_zero_case, not_one_case;
- __ tst(r0, r0);
- __ b(ne, ¬_zero_case);
- CreateArrayDispatch<ArrayNoArgumentConstructorStub>(masm);
-
- __ bind(¬_zero_case);
- __ cmp(r0, Operand(1));
- __ b(gt, ¬_one_case);
- CreateArrayDispatchOneArgument(masm);
-
- __ bind(¬_one_case);
- CreateArrayDispatch<ArrayNArgumentsConstructorStub>(masm);
- } else if (argument_count_ == NONE) {
- CreateArrayDispatch<ArrayNoArgumentConstructorStub>(masm);
- } else if (argument_count_ == ONE) {
- CreateArrayDispatchOneArgument(masm);
- } else if (argument_count_ == MORE_THAN_ONE) {
- CreateArrayDispatch<ArrayNArgumentsConstructorStub>(masm);
- } else {
- UNREACHABLE();
- }
+ GenerateDispatchToArrayStub(masm, DISABLE_ALLOCATION_SITES);
}
diff --git a/src/arm/constants-arm.h b/src/arm/constants-arm.h
index 9bfccf8..7036139 100644
--- a/src/arm/constants-arm.h
+++ b/src/arm/constants-arm.h
@@ -220,6 +220,8 @@
kCoprocessorMask = 15 << 8,
kOpCodeMask = 15 << 21, // In data-processing instructions.
kImm24Mask = (1 << 24) - 1,
+ kImm16Mask = (1 << 16) - 1,
+ kImm8Mask = (1 << 8) - 1,
kOff12Mask = (1 << 12) - 1,
kOff8Mask = (1 << 8) - 1
};
diff --git a/src/arm/full-codegen-arm.cc b/src/arm/full-codegen-arm.cc
index 28ec1a2..b6fb70b 100644
--- a/src/arm/full-codegen-arm.cc
+++ b/src/arm/full-codegen-arm.cc
@@ -3007,7 +3007,7 @@
VisitForAccumulatorValue(args->at(0));
- Label materialize_true, materialize_false;
+ Label materialize_true, materialize_false, skip_lookup;
Label* if_true = NULL;
Label* if_false = NULL;
Label* fall_through = NULL;
@@ -3019,7 +3019,7 @@
__ ldr(r1, FieldMemOperand(r0, HeapObject::kMapOffset));
__ ldrb(ip, FieldMemOperand(r1, Map::kBitField2Offset));
__ tst(ip, Operand(1 << Map::kStringWrapperSafeForDefaultValueOf));
- __ b(ne, if_true);
+ __ b(ne, &skip_lookup);
// Check for fast case object. Generate false result for slow case object.
__ ldr(r2, FieldMemOperand(r0, JSObject::kPropertiesOffset));
@@ -3065,6 +3065,14 @@
__ b(ne, &loop);
__ bind(&done);
+
+ // Set the bit in the map to indicate that there is no local valueOf field.
+ __ ldrb(r2, FieldMemOperand(r1, Map::kBitField2Offset));
+ __ orr(r2, r2, Operand(1 << Map::kStringWrapperSafeForDefaultValueOf));
+ __ strb(r2, FieldMemOperand(r1, Map::kBitField2Offset));
+
+ __ bind(&skip_lookup);
+
// If a valueOf property is not found on the object check that its
// prototype is the un-modified String prototype. If not result is false.
__ ldr(r2, FieldMemOperand(r1, Map::kPrototypeOffset));
@@ -3074,11 +3082,9 @@
__ ldr(r3, FieldMemOperand(r3, GlobalObject::kNativeContextOffset));
__ ldr(r3, ContextOperand(r3, Context::STRING_FUNCTION_PROTOTYPE_MAP_INDEX));
__ cmp(r2, r3);
- __ b(ne, if_false);
-
- __ jmp(if_true);
-
PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
+ Split(eq, if_true, if_false, fall_through);
+
context()->Plug(if_true, if_false);
}
diff --git a/src/arm/lithium-arm.cc b/src/arm/lithium-arm.cc
index 9695072..59a8818 100644
--- a/src/arm/lithium-arm.cc
+++ b/src/arm/lithium-arm.cc
@@ -1724,9 +1724,13 @@
LInstruction* LChunkBuilder::DoRandom(HRandom* instr) {
ASSERT(instr->representation().IsDouble());
ASSERT(instr->global_object()->representation().IsTagged());
- LOperand* global_object = UseFixed(instr->global_object(), r0);
- LRandom* result = new(zone()) LRandom(global_object);
- return MarkAsCall(DefineFixedDouble(result, d7), instr);
+ LOperand* global_object = UseTempRegister(instr->global_object());
+ LOperand* scratch = TempRegister();
+ LOperand* scratch2 = TempRegister();
+ LOperand* scratch3 = TempRegister();
+ LRandom* result = new(zone()) LRandom(
+ global_object, scratch, scratch2, scratch3);
+ return DefineFixedDouble(result, d7);
}
diff --git a/src/arm/lithium-arm.h b/src/arm/lithium-arm.h
index f90f3c4..98cacac 100644
--- a/src/arm/lithium-arm.h
+++ b/src/arm/lithium-arm.h
@@ -1462,13 +1462,22 @@
};
-class LRandom V8_FINAL : public LTemplateInstruction<1, 1, 0> {
+class LRandom V8_FINAL : public LTemplateInstruction<1, 1, 3> {
public:
- explicit LRandom(LOperand* global_object) {
+ LRandom(LOperand* global_object,
+ LOperand* scratch,
+ LOperand* scratch2,
+ LOperand* scratch3) {
inputs_[0] = global_object;
+ temps_[0] = scratch;
+ temps_[1] = scratch2;
+ temps_[2] = scratch3;
}
- LOperand* global_object() { return inputs_[0]; }
+ LOperand* global_object() const { return inputs_[0]; }
+ LOperand* scratch() const { return temps_[0]; }
+ LOperand* scratch2() const { return temps_[1]; }
+ LOperand* scratch3() const { return temps_[2]; }
DECLARE_CONCRETE_INSTRUCTION(Random, "random")
DECLARE_HYDROGEN_ACCESSOR(Random)
diff --git a/src/arm/lithium-codegen-arm.cc b/src/arm/lithium-codegen-arm.cc
index cf76a08..7f65023 100644
--- a/src/arm/lithium-codegen-arm.cc
+++ b/src/arm/lithium-codegen-arm.cc
@@ -3891,80 +3891,64 @@
void LCodeGen::DoRandom(LRandom* instr) {
- class DeferredDoRandom V8_FINAL : public LDeferredCode {
- public:
- DeferredDoRandom(LCodeGen* codegen, LRandom* instr)
- : LDeferredCode(codegen), instr_(instr) { }
- virtual void Generate() V8_OVERRIDE { codegen()->DoDeferredRandom(instr_); }
- virtual LInstruction* instr() V8_OVERRIDE { return instr_; }
- private:
- LRandom* instr_;
- };
-
- DeferredDoRandom* deferred = new(zone()) DeferredDoRandom(this, instr);
-
- // Having marked this instruction as a call we can use any
- // registers.
- ASSERT(ToDoubleRegister(instr->result()).is(d7));
- ASSERT(ToRegister(instr->global_object()).is(r0));
-
+ // Assert that the register size is indeed the size of each seed.
static const int kSeedSize = sizeof(uint32_t);
STATIC_ASSERT(kPointerSize == kSeedSize);
- __ ldr(r0, FieldMemOperand(r0, GlobalObject::kNativeContextOffset));
+ // Load native context
+ Register global_object = ToRegister(instr->global_object());
+ Register native_context = global_object;
+ __ ldr(native_context, FieldMemOperand(
+ global_object, GlobalObject::kNativeContextOffset));
+
+ // Load state (FixedArray of the native context's random seeds)
static const int kRandomSeedOffset =
FixedArray::kHeaderSize + Context::RANDOM_SEED_INDEX * kPointerSize;
- __ ldr(r2, FieldMemOperand(r0, kRandomSeedOffset));
- // r2: FixedArray of the native context's random seeds
+ Register state = native_context;
+ __ ldr(state, FieldMemOperand(native_context, kRandomSeedOffset));
// Load state[0].
- __ ldr(r1, FieldMemOperand(r2, ByteArray::kHeaderSize));
- __ cmp(r1, Operand::Zero());
- __ b(eq, deferred->entry());
+ Register state0 = ToRegister(instr->scratch());
+ __ ldr(state0, FieldMemOperand(state, ByteArray::kHeaderSize));
// Load state[1].
- __ ldr(r0, FieldMemOperand(r2, ByteArray::kHeaderSize + kSeedSize));
- // r1: state[0].
- // r0: state[1].
+ Register state1 = ToRegister(instr->scratch2());
+ __ ldr(state1, FieldMemOperand(state, ByteArray::kHeaderSize + kSeedSize));
// state[0] = 18273 * (state[0] & 0xFFFF) + (state[0] >> 16)
- __ and_(r3, r1, Operand(0xFFFF));
- __ mov(r4, Operand(18273));
- __ mul(r3, r3, r4);
- __ add(r1, r3, Operand(r1, LSR, 16));
+ Register scratch3 = ToRegister(instr->scratch3());
+ Register scratch4 = scratch0();
+ __ and_(scratch3, state0, Operand(0xFFFF));
+ __ mov(scratch4, Operand(18273));
+ __ mul(scratch3, scratch3, scratch4);
+ __ add(state0, scratch3, Operand(state0, LSR, 16));
// Save state[0].
- __ str(r1, FieldMemOperand(r2, ByteArray::kHeaderSize));
+ __ str(state0, FieldMemOperand(state, ByteArray::kHeaderSize));
// state[1] = 36969 * (state[1] & 0xFFFF) + (state[1] >> 16)
- __ and_(r3, r0, Operand(0xFFFF));
- __ mov(r4, Operand(36969));
- __ mul(r3, r3, r4);
- __ add(r0, r3, Operand(r0, LSR, 16));
+ __ and_(scratch3, state1, Operand(0xFFFF));
+ __ mov(scratch4, Operand(36969));
+ __ mul(scratch3, scratch3, scratch4);
+ __ add(state1, scratch3, Operand(state1, LSR, 16));
// Save state[1].
- __ str(r0, FieldMemOperand(r2, ByteArray::kHeaderSize + kSeedSize));
+ __ str(state1, FieldMemOperand(state, ByteArray::kHeaderSize + kSeedSize));
// Random bit pattern = (state[0] << 14) + (state[1] & 0x3FFFF)
- __ and_(r0, r0, Operand(0x3FFFF));
- __ add(r0, r0, Operand(r1, LSL, 14));
+ Register random = scratch4;
+ __ and_(random, state1, Operand(0x3FFFF));
+ __ add(random, random, Operand(state0, LSL, 14));
- __ bind(deferred->exit());
// 0x41300000 is the top half of 1.0 x 2^20 as a double.
// Create this constant using mov/orr to avoid PC relative load.
- __ mov(r1, Operand(0x41000000));
- __ orr(r1, r1, Operand(0x300000));
+ __ mov(scratch3, Operand(0x41000000));
+ __ orr(scratch3, scratch3, Operand(0x300000));
// Move 0x41300000xxxxxxxx (x = random bits) to VFP.
- __ vmov(d7, r0, r1);
+ DwVfpRegister result = ToDoubleRegister(instr->result());
+ __ vmov(result, random, scratch3);
// Move 0x4130000000000000 to VFP.
- __ mov(r0, Operand::Zero());
- __ vmov(d8, r0, r1);
- // Subtract and store the result in the heap number.
- __ vsub(d7, d7, d8);
-}
-
-
-void LCodeGen::DoDeferredRandom(LRandom* instr) {
- __ PrepareCallCFunction(1, scratch0());
- __ CallCFunction(ExternalReference::random_uint32_function(isolate()), 1);
- // Return value is in r0.
+ __ mov(scratch4, Operand::Zero());
+ DwVfpRegister scratch5 = double_scratch0();
+ __ vmov(scratch5, scratch4, scratch3);
+ __ vsub(result, result, scratch5);
}
diff --git a/src/arm/lithium-codegen-arm.h b/src/arm/lithium-codegen-arm.h
index 5826849..4b6b5ca 100644
--- a/src/arm/lithium-codegen-arm.h
+++ b/src/arm/lithium-codegen-arm.h
@@ -149,7 +149,6 @@
void DoDeferredTaggedToI(LTaggedToI* instr);
void DoDeferredMathAbsTaggedHeapNumber(LMathAbs* instr);
void DoDeferredStackCheck(LStackCheck* instr);
- void DoDeferredRandom(LRandom* instr);
void DoDeferredStringCharCodeAt(LStringCharCodeAt* instr);
void DoDeferredStringCharFromCode(LStringCharFromCode* instr);
void DoDeferredAllocate(LAllocate* instr);
diff --git a/src/arm/macro-assembler-arm.cc b/src/arm/macro-assembler-arm.cc
index 7628f23..7df7857 100644
--- a/src/arm/macro-assembler-arm.cc
+++ b/src/arm/macro-assembler-arm.cc
@@ -3845,10 +3845,13 @@
#endif
-CodePatcher::CodePatcher(byte* address, int instructions)
+CodePatcher::CodePatcher(byte* address,
+ int instructions,
+ FlushICache flush_cache)
: address_(address),
size_(instructions * Assembler::kInstrSize),
- masm_(NULL, address, size_ + Assembler::kGap) {
+ masm_(NULL, address, size_ + Assembler::kGap),
+ flush_cache_(flush_cache) {
// Create a new macro assembler pointing to the address of the code to patch.
// The size is adjusted with kGap on order for the assembler to generate size
// bytes of instructions without failing with buffer size constraints.
@@ -3858,7 +3861,9 @@
CodePatcher::~CodePatcher() {
// Indicate that code has changed.
- CPU::FlushICache(address_, size_);
+ if (flush_cache_ == FLUSH) {
+ CPU::FlushICache(address_, size_);
+ }
// Check that the code was patched as expected.
ASSERT(masm_.pc_ == address_ + size_);
diff --git a/src/arm/macro-assembler-arm.h b/src/arm/macro-assembler-arm.h
index cff9ac7..9abd5a0 100644
--- a/src/arm/macro-assembler-arm.h
+++ b/src/arm/macro-assembler-arm.h
@@ -1429,7 +1429,14 @@
// an assertion to fail.
class CodePatcher {
public:
- CodePatcher(byte* address, int instructions);
+ enum FlushICache {
+ FLUSH,
+ DONT_FLUSH
+ };
+
+ CodePatcher(byte* address,
+ int instructions,
+ FlushICache flush_cache = FLUSH);
virtual ~CodePatcher();
// Macro assembler to emit code.
@@ -1449,6 +1456,7 @@
byte* address_; // The address of the code being patched.
int size_; // Number of bytes of the expected patch size.
MacroAssembler masm_; // Macro assembler used to generate the code.
+ FlushICache flush_cache_; // Whether to flush the I cache after patching.
};
diff --git a/src/arm/regexp-macro-assembler-arm.cc b/src/arm/regexp-macro-assembler-arm.cc
index a26aa9e..cbc34e1 100644
--- a/src/arm/regexp-macro-assembler-arm.cc
+++ b/src/arm/regexp-macro-assembler-arm.cc
@@ -134,7 +134,6 @@
exit_label_() {
ASSERT_EQ(0, registers_to_save % 2);
__ jmp(&entry_label_); // We'll write the entry code later.
- EmitBacktrackConstantPool();
__ bind(&start_label_); // And then continue from here.
}
@@ -938,37 +937,8 @@
}
-static bool is_valid_memory_offset(int value) {
- if (value < 0) value = -value;
- return value < (1<<12);
-}
-
-
void RegExpMacroAssemblerARM::PushBacktrack(Label* label) {
- if (label->is_bound()) {
- int target = label->pos();
- __ mov(r0, Operand(target + Code::kHeaderSize - kHeapObjectTag));
- } else {
- int constant_offset = GetBacktrackConstantPoolEntry();
- masm_->label_at_put(label, constant_offset);
- // Reading pc-relative is based on the address 8 bytes ahead of
- // the current opcode.
- unsigned int offset_of_pc_register_read =
- masm_->pc_offset() + Assembler::kPcLoadDelta;
- int pc_offset_of_constant =
- constant_offset - offset_of_pc_register_read;
- ASSERT(pc_offset_of_constant < 0);
- if (is_valid_memory_offset(pc_offset_of_constant)) {
- Assembler::BlockConstPoolScope block_const_pool(masm_);
- __ ldr(r0, MemOperand(pc, pc_offset_of_constant));
- } else {
- // Not a 12-bit offset, so it needs to be loaded from the constant
- // pool.
- Assembler::BlockConstPoolScope block_const_pool(masm_);
- __ mov(r0, Operand(pc_offset_of_constant + Assembler::kInstrSize));
- __ ldr(r0, MemOperand(pc, r0));
- }
- }
+ __ mov_label_offset(r0, label);
Push(r0);
CheckStackLimit();
}
@@ -1279,38 +1249,6 @@
}
-void RegExpMacroAssemblerARM::EmitBacktrackConstantPool() {
- __ CheckConstPool(false, false);
- Assembler::BlockConstPoolScope block_const_pool(masm_);
- backtrack_constant_pool_offset_ = masm_->pc_offset();
- for (int i = 0; i < kBacktrackConstantPoolSize; i++) {
- __ emit(0);
- }
-
- backtrack_constant_pool_capacity_ = kBacktrackConstantPoolSize;
-}
-
-
-int RegExpMacroAssemblerARM::GetBacktrackConstantPoolEntry() {
- while (backtrack_constant_pool_capacity_ > 0) {
- int offset = backtrack_constant_pool_offset_;
- backtrack_constant_pool_offset_ += kPointerSize;
- backtrack_constant_pool_capacity_--;
- if (masm_->pc_offset() - offset < 2 * KB) {
- return offset;
- }
- }
- Label new_pool_skip;
- __ jmp(&new_pool_skip);
- EmitBacktrackConstantPool();
- __ bind(&new_pool_skip);
- int offset = backtrack_constant_pool_offset_;
- backtrack_constant_pool_offset_ += kPointerSize;
- backtrack_constant_pool_capacity_--;
- return offset;
-}
-
-
bool RegExpMacroAssemblerARM::CanReadUnaligned() {
return CpuFeatures::IsSupported(UNALIGNED_ACCESSES) && !slow_safe();
}
diff --git a/src/arm/regexp-macro-assembler-arm.h b/src/arm/regexp-macro-assembler-arm.h
index 0874ad1..9f07489 100644
--- a/src/arm/regexp-macro-assembler-arm.h
+++ b/src/arm/regexp-macro-assembler-arm.h
@@ -160,9 +160,6 @@
// Check whether we are exceeding the stack limit on the backtrack stack.
void CheckStackLimit();
- void EmitBacktrackConstantPool();
- int GetBacktrackConstantPoolEntry();
-
// Generate a call to CheckStackGuardState.
void CallCheckStackGuardState(Register scratch);
diff --git a/src/arm/stub-cache-arm.cc b/src/arm/stub-cache-arm.cc
index 5bab086..085af3f 100644
--- a/src/arm/stub-cache-arm.cc
+++ b/src/arm/stub-cache-arm.cc
@@ -785,6 +785,11 @@
Register holder,
Register name,
Handle<JSObject> holder_obj) {
+ STATIC_ASSERT(StubCache::kInterceptorArgsNameIndex == 0);
+ STATIC_ASSERT(StubCache::kInterceptorArgsInfoIndex == 1);
+ STATIC_ASSERT(StubCache::kInterceptorArgsThisIndex == 2);
+ STATIC_ASSERT(StubCache::kInterceptorArgsHolderIndex == 3);
+ STATIC_ASSERT(StubCache::kInterceptorArgsLength == 4);
__ push(name);
Handle<InterceptorInfo> interceptor(holder_obj->GetNamedInterceptor());
ASSERT(!masm->isolate()->heap()->InNewSpace(*interceptor));
@@ -793,10 +798,6 @@
__ push(scratch);
__ push(receiver);
__ push(holder);
- __ ldr(scratch, FieldMemOperand(scratch, InterceptorInfo::kDataOffset));
- __ push(scratch);
- __ mov(scratch, Operand(ExternalReference::isolate_address(masm->isolate())));
- __ push(scratch);
}
@@ -811,7 +812,7 @@
ExternalReference ref =
ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorOnly),
masm->isolate());
- __ mov(r0, Operand(6));
+ __ mov(r0, Operand(StubCache::kInterceptorArgsLength));
__ mov(r1, Operand(ref));
CEntryStub stub(1);
@@ -1110,7 +1111,7 @@
__ CallExternalReference(
ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorForCall),
masm->isolate()),
- 6);
+ StubCache::kInterceptorArgsLength);
// Restore the name_ register.
__ pop(name_);
// Leave the internal frame.
@@ -1420,6 +1421,15 @@
Handle<ExecutableAccessorInfo> callback) {
// Build AccessorInfo::args_ list on the stack and push property name below
// the exit frame to make GC aware of them and store pointers to them.
+ STATIC_ASSERT(PropertyCallbackArguments::kThisIndex == 0);
+ STATIC_ASSERT(PropertyCallbackArguments::kDataIndex == -1);
+ STATIC_ASSERT(PropertyCallbackArguments::kReturnValueOffset == -2);
+ STATIC_ASSERT(PropertyCallbackArguments::kReturnValueDefaultValueIndex == -3);
+ STATIC_ASSERT(PropertyCallbackArguments::kIsolateIndex == -4);
+ STATIC_ASSERT(PropertyCallbackArguments::kHolderIndex == -5);
+ ASSERT(!scratch2().is(reg));
+ ASSERT(!scratch3().is(reg));
+ ASSERT(!scratch4().is(reg));
__ push(receiver());
__ mov(scratch2(), sp); // scratch2 = AccessorInfo::args_
if (heap()->InNewSpace(callback->data())) {
@@ -1429,13 +1439,13 @@
} else {
__ Move(scratch3(), Handle<Object>(callback->data(), isolate()));
}
- __ Push(reg, scratch3());
+ __ push(scratch3());
__ LoadRoot(scratch3(), Heap::kUndefinedValueRootIndex);
__ mov(scratch4(), scratch3());
__ Push(scratch3(), scratch4());
__ mov(scratch4(),
Operand(ExternalReference::isolate_address(isolate())));
- __ Push(scratch4(), name());
+ __ Push(scratch4(), reg, name());
__ mov(r0, sp); // r0 = Handle<Name>
const int kApiStackSpace = 1;
@@ -1465,7 +1475,7 @@
thunk_ref,
r2,
kStackUnwindSpace,
- 5);
+ 6);
}
@@ -1553,7 +1563,7 @@
ExternalReference ref =
ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorForLoad),
isolate());
- __ TailCallExternalReference(ref, 6, 1);
+ __ TailCallExternalReference(ref, StubCache::kInterceptorArgsLength, 1);
}
}
diff --git a/src/assembler.h b/src/assembler.h
index 3ebaee3..6b399f2 100644
--- a/src/assembler.h
+++ b/src/assembler.h
@@ -196,7 +196,6 @@
}
friend class Assembler;
- friend class RegexpAssembler;
friend class Displacement;
friend class RegExpMacroAssemblerIrregexp;
};
diff --git a/src/bootstrapper.cc b/src/bootstrapper.cc
index 58b115d..0756aef 100644
--- a/src/bootstrapper.cc
+++ b/src/bootstrapper.cc
@@ -45,10 +45,6 @@
#include "extensions/statistics-extension.h"
#include "code-stubs.h"
-#if defined(V8_I18N_SUPPORT)
-#include "extensions/i18n/i18n-extension.h"
-#endif
-
namespace v8 {
namespace internal {
@@ -106,9 +102,6 @@
GCExtension::Register();
ExternalizeStringExtension::Register();
StatisticsExtension::Register();
-#if defined(V8_I18N_SUPPORT)
- v8_i18n::Extension::Register();
-#endif
}
@@ -2291,12 +2284,6 @@
InstallExtension(isolate, "v8/statistics", &extension_states);
}
-#if defined(V8_I18N_SUPPORT)
- if (FLAG_enable_i18n) {
- InstallExtension(isolate, "v8/i18n", &extension_states);
- }
-#endif
-
if (extensions == NULL) return true;
// Install required extensions
int count = v8::ImplementationUtilities::GetNameCount(extensions);
diff --git a/src/builtins.h b/src/builtins.h
index cbfa1d7..c712f1e 100644
--- a/src/builtins.h
+++ b/src/builtins.h
@@ -87,8 +87,6 @@
Code::kNoExtraICState) \
V(InRecompileQueue, BUILTIN, UNINITIALIZED, \
Code::kNoExtraICState) \
- V(InstallRecompiledCode, BUILTIN, UNINITIALIZED, \
- Code::kNoExtraICState) \
V(JSConstructStubCountdown, BUILTIN, UNINITIALIZED, \
Code::kNoExtraICState) \
V(JSConstructStubGeneric, BUILTIN, UNINITIALIZED, \
@@ -122,7 +120,7 @@
Code::kNoExtraICState) \
V(KeyedLoadIC_MissForceGeneric, BUILTIN, UNINITIALIZED, \
Code::kNoExtraICState) \
- V(KeyedLoadIC_Slow, BUILTIN, UNINITIALIZED, \
+ V(KeyedLoadIC_Slow, STUB, MONOMORPHIC, \
Code::kNoExtraICState) \
V(StoreIC_Miss, BUILTIN, UNINITIALIZED, \
Code::kNoExtraICState) \
@@ -144,7 +142,7 @@
Code::kNoExtraICState) \
V(LoadIC_Getter_ForDeopt, LOAD_IC, MONOMORPHIC, \
Code::kNoExtraICState) \
- V(LoadIC_Slow, LOAD_IC, GENERIC, \
+ V(LoadIC_Slow, STUB, MONOMORPHIC, \
Code::kNoExtraICState) \
\
V(KeyedLoadIC_Initialize, KEYED_LOAD_IC, UNINITIALIZED, \
@@ -382,7 +380,6 @@
CFunctionId id,
BuiltinExtraArguments extra_args);
static void Generate_InRecompileQueue(MacroAssembler* masm);
- static void Generate_InstallRecompiledCode(MacroAssembler* masm);
static void Generate_ConcurrentRecompile(MacroAssembler* masm);
static void Generate_JSConstructStubCountdown(MacroAssembler* masm);
static void Generate_JSConstructStubGeneric(MacroAssembler* masm);
diff --git a/src/checks.h b/src/checks.h
index 062bdf6..f5c5f23 100644
--- a/src/checks.h
+++ b/src/checks.h
@@ -197,6 +197,20 @@
inline void CheckNonEqualsHelper(const char* file,
+ int line,
+ const char* expected_source,
+ int64_t expected,
+ const char* value_source,
+ int64_t value) {
+ if (expected == value) {
+ V8_Fatal(file, line,
+ "CHECK_EQ(%s, %s) failed\n# Expected: %f\n# Found: %f",
+ expected_source, value_source, expected, value);
+ }
+}
+
+
+inline void CheckNonEqualsHelper(const char* file,
int line,
const char* expected_source,
double expected,
diff --git a/src/code-stubs.h b/src/code-stubs.h
index 81bbb52..946eb76 100644
--- a/src/code-stubs.h
+++ b/src/code-stubs.h
@@ -736,6 +736,13 @@
};
+enum AllocationSiteOverrideMode {
+ DONT_OVERRIDE,
+ DISABLE_ALLOCATION_SITES,
+ LAST_ALLOCATION_SITE_OVERRIDE_MODE = DISABLE_ALLOCATION_SITES
+};
+
+
class ArrayConstructorStub: public PlatformCodeStub {
public:
enum ArgumentCountKey { ANY, NONE, ONE, MORE_THAN_ONE };
@@ -745,6 +752,9 @@
void Generate(MacroAssembler* masm);
private:
+ void GenerateDispatchToArrayStub(MacroAssembler* masm,
+ AllocationSiteOverrideMode mode);
+
virtual CodeStub::Major MajorKey() { return ArrayConstructor; }
virtual int MinorKey() { return argument_count_; }
@@ -1863,13 +1873,6 @@
};
-enum AllocationSiteOverrideMode {
- DONT_OVERRIDE,
- DISABLE_ALLOCATION_SITES,
- LAST_ALLOCATION_SITE_OVERRIDE_MODE = DISABLE_ALLOCATION_SITES
-};
-
-
class ArrayConstructorStubBase : public HydrogenCodeStub {
public:
ArrayConstructorStubBase(ElementsKind kind, ContextCheckMode context_mode,
@@ -1877,7 +1880,8 @@
// It only makes sense to override local allocation site behavior
// if there is a difference between the global allocation site policy
// for an ElementsKind and the desired usage of the stub.
- ASSERT(override_mode != DISABLE_ALLOCATION_SITES ||
+ ASSERT(!(FLAG_track_allocation_sites &&
+ override_mode == DISABLE_ALLOCATION_SITES) ||
AllocationSite::GetMode(kind) == TRACK_ALLOCATION_SITE);
bit_field_ = ElementsKindBits::encode(kind) |
AllocationSiteOverrideModeBits::encode(override_mode) |
diff --git a/src/compiler.cc b/src/compiler.cc
index 50db8e0..47634ec 100644
--- a/src/compiler.cc
+++ b/src/compiler.cc
@@ -1067,7 +1067,7 @@
info->closure()->PrintName();
PrintF(" as it has been disabled.\n");
}
- ASSERT(!info->closure()->IsMarkedForInstallingRecompiledCode());
+ ASSERT(!info->closure()->IsInRecompileQueue());
return Handle<Code>::null();
}
@@ -1114,7 +1114,7 @@
// Optimized code is finally replacing unoptimized code. Reset the latter's
// profiler ticks to prevent too soon re-opt after a deopt.
info->shared_info()->code()->set_profiler_ticks(0);
- ASSERT(!info->closure()->IsMarkedForInstallingRecompiledCode());
+ ASSERT(!info->closure()->IsInRecompileQueue());
return (status == OptimizingCompiler::SUCCEEDED) ? info->code()
: Handle<Code>::null();
}
diff --git a/src/cpu.cc b/src/cpu.cc
index 26eca61..2bf51a7 100644
--- a/src/cpu.cc
+++ b/src/cpu.cc
@@ -54,7 +54,7 @@
// Define __cpuid() for non-MSVC compilers.
#if !V8_CC_MSVC
-static V8_INLINE(void __cpuid(int cpu_info[4], int info_type)) {
+static V8_INLINE void __cpuid(int cpu_info[4], int info_type) {
#if defined(__i386__) && defined(__pic__)
// Make sure to preserve ebx, which contains the pointer
// to the GOT in case we're generating PIC.
diff --git a/src/debug.cc b/src/debug.cc
index 3f2739e..0496b8c 100644
--- a/src/debug.cc
+++ b/src/debug.cc
@@ -2110,8 +2110,7 @@
function->set_code(*lazy_compile);
function->shared()->set_code(*lazy_compile);
} else if (kind == Code::BUILTIN &&
- (function->IsMarkedForInstallingRecompiledCode() ||
- function->IsInRecompileQueue() ||
+ (function->IsInRecompileQueue() ||
function->IsMarkedForLazyRecompilation() ||
function->IsMarkedForConcurrentRecompilation())) {
// Abort in-flight compilation.
diff --git a/src/execution.cc b/src/execution.cc
index c59a737..979641a 100644
--- a/src/execution.cc
+++ b/src/execution.cc
@@ -459,6 +459,22 @@
}
+bool StackGuard::IsInstallCodeRequest() {
+ ExecutionAccess access(isolate_);
+ return (thread_local_.interrupt_flags_ & INSTALL_CODE) != 0;
+}
+
+
+void StackGuard::RequestInstallCode() {
+ ExecutionAccess access(isolate_);
+ thread_local_.interrupt_flags_ |= INSTALL_CODE;
+ if (thread_local_.postpone_interrupts_nesting_ == 0) {
+ thread_local_.jslimit_ = thread_local_.climit_ = kInterruptLimit;
+ isolate_->heap()->SetStackLimits();
+ }
+}
+
+
bool StackGuard::IsFullDeopt() {
ExecutionAccess access(isolate_);
return (thread_local_.interrupt_flags_ & FULL_DEOPT) != 0;
@@ -916,7 +932,6 @@
isolate->counters()->stack_interrupts()->Increment();
isolate->counters()->runtime_profiler_ticks()->Increment();
- isolate->runtime_profiler()->OptimizeNow();
#ifdef ENABLE_DEBUGGER_SUPPORT
if (stack_guard->IsDebugBreak() || stack_guard->IsDebugCommand()) {
DebugBreakHelper(isolate);
@@ -935,6 +950,12 @@
stack_guard->Continue(FULL_DEOPT);
Deoptimizer::DeoptimizeAll(isolate);
}
+ if (stack_guard->IsInstallCodeRequest()) {
+ ASSERT(FLAG_concurrent_recompilation);
+ stack_guard->Continue(INSTALL_CODE);
+ isolate->optimizing_compiler_thread()->InstallOptimizedFunctions();
+ }
+ isolate->runtime_profiler()->OptimizeNow();
return isolate->heap()->undefined_value();
}
diff --git a/src/execution.h b/src/execution.h
index 0c1bf94..371ea30 100644
--- a/src/execution.h
+++ b/src/execution.h
@@ -42,7 +42,8 @@
PREEMPT = 1 << 3,
TERMINATE = 1 << 4,
GC_REQUEST = 1 << 5,
- FULL_DEOPT = 1 << 6
+ FULL_DEOPT = 1 << 6,
+ INSTALL_CODE = 1 << 7
};
@@ -213,6 +214,8 @@
#endif
bool IsGCRequest();
void RequestGC();
+ bool IsInstallCodeRequest();
+ void RequestInstallCode();
bool IsFullDeopt();
void FullDeopt();
void Continue(InterruptFlag after_what);
diff --git a/src/extensions/i18n/break-iterator.js b/src/extensions/i18n/break-iterator.js
deleted file mode 100644
index 898bd5d..0000000
--- a/src/extensions/i18n/break-iterator.js
+++ /dev/null
@@ -1,190 +0,0 @@
-// Copyright 2013 the V8 project authors. All rights reserved.
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following
-// disclaimer in the documentation and/or other materials provided
-// with the distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-// limitations under the License.
-
-// ECMAScript 402 API implementation is broken into separate files for
-// each service. The build system combines them together into one
-// Intl namespace.
-
-/**
- * Initializes the given object so it's a valid BreakIterator instance.
- * Useful for subclassing.
- */
-function initializeBreakIterator(iterator, locales, options) {
- if (iterator.hasOwnProperty('__initializedIntlObject')) {
- throw new TypeError('Trying to re-initialize v8BreakIterator object.');
- }
-
- if (options === undefined) {
- options = {};
- }
-
- var getOption = getGetOption(options, 'breakiterator');
-
- var internalOptions = {};
-
- defineWEProperty(internalOptions, 'type', getOption(
- 'type', 'string', ['character', 'word', 'sentence', 'line'], 'word'));
-
- var locale = resolveLocale('breakiterator', locales, options);
- var resolved = Object.defineProperties({}, {
- requestedLocale: {value: locale.locale, writable: true},
- type: {value: internalOptions.type, writable: true},
- locale: {writable: true}
- });
-
- var internalIterator = %CreateBreakIterator(locale.locale,
- internalOptions,
- resolved);
-
- Object.defineProperty(iterator, 'iterator', {value: internalIterator});
- Object.defineProperty(iterator, 'resolved', {value: resolved});
- Object.defineProperty(iterator, '__initializedIntlObject',
- {value: 'breakiterator'});
-
- return iterator;
-}
-
-
-/**
- * Constructs Intl.v8BreakIterator object given optional locales and options
- * parameters.
- *
- * @constructor
- */
-%SetProperty(Intl, 'v8BreakIterator', function() {
- var locales = arguments[0];
- var options = arguments[1];
-
- if (!this || this === Intl) {
- // Constructor is called as a function.
- return new Intl.v8BreakIterator(locales, options);
- }
-
- return initializeBreakIterator(toObject(this), locales, options);
- },
- ATTRIBUTES.DONT_ENUM
-);
-
-
-/**
- * BreakIterator resolvedOptions method.
- */
-%SetProperty(Intl.v8BreakIterator.prototype, 'resolvedOptions', function() {
- if (%_IsConstructCall()) {
- throw new TypeError(ORDINARY_FUNCTION_CALLED_AS_CONSTRUCTOR);
- }
-
- if (!this || typeof this !== 'object' ||
- this.__initializedIntlObject !== 'breakiterator') {
- throw new TypeError('resolvedOptions method called on a non-object or ' +
- 'on a object that is not Intl.v8BreakIterator.');
- }
-
- var segmenter = this;
- var locale = getOptimalLanguageTag(segmenter.resolved.requestedLocale,
- segmenter.resolved.locale);
-
- return {
- locale: locale,
- type: segmenter.resolved.type
- };
- },
- ATTRIBUTES.DONT_ENUM
-);
-%FunctionSetName(Intl.v8BreakIterator.prototype.resolvedOptions,
- 'resolvedOptions');
-%FunctionRemovePrototype(Intl.v8BreakIterator.prototype.resolvedOptions);
-%SetNativeFlag(Intl.v8BreakIterator.prototype.resolvedOptions);
-
-
-/**
- * Returns the subset of the given locale list for which this locale list
- * has a matching (possibly fallback) locale. Locales appear in the same
- * order in the returned list as in the input list.
- * Options are optional parameter.
- */
-%SetProperty(Intl.v8BreakIterator, 'supportedLocalesOf', function(locales) {
- if (%_IsConstructCall()) {
- throw new TypeError(ORDINARY_FUNCTION_CALLED_AS_CONSTRUCTOR);
- }
-
- return supportedLocalesOf('breakiterator', locales, arguments[1]);
- },
- ATTRIBUTES.DONT_ENUM
-);
-%FunctionSetName(Intl.v8BreakIterator.supportedLocalesOf, 'supportedLocalesOf');
-%FunctionRemovePrototype(Intl.v8BreakIterator.supportedLocalesOf);
-%SetNativeFlag(Intl.v8BreakIterator.supportedLocalesOf);
-
-
-/**
- * Adopts text to segment using the iterator. Old text, if present,
- * gets discarded.
- */
-function adoptText(iterator, text) {
- %BreakIteratorAdoptText(iterator.iterator, String(text));
-}
-
-
-/**
- * Returns index of the first break in the string and moves current pointer.
- */
-function first(iterator) {
- return %BreakIteratorFirst(iterator.iterator);
-}
-
-
-/**
- * Returns the index of the next break and moves the pointer.
- */
-function next(iterator) {
- return %BreakIteratorNext(iterator.iterator);
-}
-
-
-/**
- * Returns index of the current break.
- */
-function current(iterator) {
- return %BreakIteratorCurrent(iterator.iterator);
-}
-
-
-/**
- * Returns type of the current break.
- */
-function breakType(iterator) {
- return %BreakIteratorBreakType(iterator.iterator);
-}
-
-
-addBoundMethod(Intl.v8BreakIterator, 'adoptText', adoptText, 1);
-addBoundMethod(Intl.v8BreakIterator, 'first', first, 0);
-addBoundMethod(Intl.v8BreakIterator, 'next', next, 0);
-addBoundMethod(Intl.v8BreakIterator, 'current', current, 0);
-addBoundMethod(Intl.v8BreakIterator, 'breakType', breakType, 0);
diff --git a/src/extensions/i18n/collator.js b/src/extensions/i18n/collator.js
deleted file mode 100644
index d8d247b..0000000
--- a/src/extensions/i18n/collator.js
+++ /dev/null
@@ -1,209 +0,0 @@
-// Copyright 2013 the V8 project authors. All rights reserved.
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following
-// disclaimer in the documentation and/or other materials provided
-// with the distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-// limitations under the License.
-
-// ECMAScript 402 API implementation is broken into separate files for
-// each service. The build system combines them together into one
-// Intl namespace.
-
-/**
- * Initializes the given object so it's a valid Collator instance.
- * Useful for subclassing.
- */
-function initializeCollator(collator, locales, options) {
- if (collator.hasOwnProperty('__initializedIntlObject')) {
- throw new TypeError('Trying to re-initialize Collator object.');
- }
-
- if (options === undefined) {
- options = {};
- }
-
- var getOption = getGetOption(options, 'collator');
-
- var internalOptions = {};
-
- defineWEProperty(internalOptions, 'usage', getOption(
- 'usage', 'string', ['sort', 'search'], 'sort'));
-
- var sensitivity = getOption('sensitivity', 'string',
- ['base', 'accent', 'case', 'variant']);
- if (sensitivity === undefined && internalOptions.usage === 'sort') {
- sensitivity = 'variant';
- }
- defineWEProperty(internalOptions, 'sensitivity', sensitivity);
-
- defineWEProperty(internalOptions, 'ignorePunctuation', getOption(
- 'ignorePunctuation', 'boolean', undefined, false));
-
- var locale = resolveLocale('collator', locales, options);
-
- // ICU can't take kb, kc... parameters through localeID, so we need to pass
- // them as options.
- // One exception is -co- which has to be part of the extension, but only for
- // usage: sort, and its value can't be 'standard' or 'search'.
- var extensionMap = parseExtension(locale.extension);
- setOptions(
- options, extensionMap, COLLATOR_KEY_MAP, getOption, internalOptions);
-
- var collation = 'default';
- var extension = '';
- if (extensionMap.hasOwnProperty('co') && internalOptions.usage === 'sort') {
- if (ALLOWED_CO_VALUES.indexOf(extensionMap.co) !== -1) {
- extension = '-u-co-' + extensionMap.co;
- // ICU can't tell us what the collation is, so save user's input.
- collation = extensionMap.co;
- }
- } else if (internalOptions.usage === 'search') {
- extension = '-u-co-search';
- }
- defineWEProperty(internalOptions, 'collation', collation);
-
- var requestedLocale = locale.locale + extension;
-
- // We define all properties C++ code may produce, to prevent security
- // problems. If malicious user decides to redefine Object.prototype.locale
- // we can't just use plain x.locale = 'us' or in C++ Set("locale", "us").
- // Object.defineProperties will either succeed defining or throw an error.
- var resolved = Object.defineProperties({}, {
- caseFirst: {writable: true},
- collation: {value: internalOptions.collation, writable: true},
- ignorePunctuation: {writable: true},
- locale: {writable: true},
- numeric: {writable: true},
- requestedLocale: {value: requestedLocale, writable: true},
- sensitivity: {writable: true},
- strength: {writable: true},
- usage: {value: internalOptions.usage, writable: true}
- });
-
- var internalCollator = %CreateCollator(requestedLocale,
- internalOptions,
- resolved);
-
- // Writable, configurable and enumerable are set to false by default.
- Object.defineProperty(collator, 'collator', {value: internalCollator});
- Object.defineProperty(collator, '__initializedIntlObject',
- {value: 'collator'});
- Object.defineProperty(collator, 'resolved', {value: resolved});
-
- return collator;
-}
-
-
-/**
- * Constructs Intl.Collator object given optional locales and options
- * parameters.
- *
- * @constructor
- */
-%SetProperty(Intl, 'Collator', function() {
- var locales = arguments[0];
- var options = arguments[1];
-
- if (!this || this === Intl) {
- // Constructor is called as a function.
- return new Intl.Collator(locales, options);
- }
-
- return initializeCollator(toObject(this), locales, options);
- },
- ATTRIBUTES.DONT_ENUM
-);
-
-
-/**
- * Collator resolvedOptions method.
- */
-%SetProperty(Intl.Collator.prototype, 'resolvedOptions', function() {
- if (%_IsConstructCall()) {
- throw new TypeError(ORDINARY_FUNCTION_CALLED_AS_CONSTRUCTOR);
- }
-
- if (!this || typeof this !== 'object' ||
- this.__initializedIntlObject !== 'collator') {
- throw new TypeError('resolvedOptions method called on a non-object ' +
- 'or on a object that is not Intl.Collator.');
- }
-
- var coll = this;
- var locale = getOptimalLanguageTag(coll.resolved.requestedLocale,
- coll.resolved.locale);
-
- return {
- locale: locale,
- usage: coll.resolved.usage,
- sensitivity: coll.resolved.sensitivity,
- ignorePunctuation: coll.resolved.ignorePunctuation,
- numeric: coll.resolved.numeric,
- caseFirst: coll.resolved.caseFirst,
- collation: coll.resolved.collation
- };
- },
- ATTRIBUTES.DONT_ENUM
-);
-%FunctionSetName(Intl.Collator.prototype.resolvedOptions, 'resolvedOptions');
-%FunctionRemovePrototype(Intl.Collator.prototype.resolvedOptions);
-%SetNativeFlag(Intl.Collator.prototype.resolvedOptions);
-
-
-/**
- * Returns the subset of the given locale list for which this locale list
- * has a matching (possibly fallback) locale. Locales appear in the same
- * order in the returned list as in the input list.
- * Options are optional parameter.
- */
-%SetProperty(Intl.Collator, 'supportedLocalesOf', function(locales) {
- if (%_IsConstructCall()) {
- throw new TypeError(ORDINARY_FUNCTION_CALLED_AS_CONSTRUCTOR);
- }
-
- return supportedLocalesOf('collator', locales, arguments[1]);
- },
- ATTRIBUTES.DONT_ENUM
-);
-%FunctionSetName(Intl.Collator.supportedLocalesOf, 'supportedLocalesOf');
-%FunctionRemovePrototype(Intl.Collator.supportedLocalesOf);
-%SetNativeFlag(Intl.Collator.supportedLocalesOf);
-
-
-/**
- * When the compare method is called with two arguments x and y, it returns a
- * Number other than NaN that represents the result of a locale-sensitive
- * String comparison of x with y.
- * The result is intended to order String values in the sort order specified
- * by the effective locale and collation options computed during construction
- * of this Collator object, and will be negative, zero, or positive, depending
- * on whether x comes before y in the sort order, the Strings are equal under
- * the sort order, or x comes after y in the sort order, respectively.
- */
-function compare(collator, x, y) {
- return %InternalCompare(collator.collator, String(x), String(y));
-};
-
-
-addBoundMethod(Intl.Collator, 'compare', compare, 2);
diff --git a/src/extensions/i18n/date-format.js b/src/extensions/i18n/date-format.js
deleted file mode 100644
index b1d28e5..0000000
--- a/src/extensions/i18n/date-format.js
+++ /dev/null
@@ -1,474 +0,0 @@
-// Copyright 2013 the V8 project authors. All rights reserved.
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following
-// disclaimer in the documentation and/or other materials provided
-// with the distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-// limitations under the License.
-
-// ECMAScript 402 API implementation is broken into separate files for
-// each service. The build system combines them together into one
-// Intl namespace.
-
-/**
- * Returns a string that matches LDML representation of the options object.
- */
-function toLDMLString(options) {
- var getOption = getGetOption(options, 'dateformat');
-
- var ldmlString = '';
-
- var option = getOption('weekday', 'string', ['narrow', 'short', 'long']);
- ldmlString += appendToLDMLString(
- option, {narrow: 'EEEEE', short: 'EEE', long: 'EEEE'});
-
- option = getOption('era', 'string', ['narrow', 'short', 'long']);
- ldmlString += appendToLDMLString(
- option, {narrow: 'GGGGG', short: 'GGG', long: 'GGGG'});
-
- option = getOption('year', 'string', ['2-digit', 'numeric']);
- ldmlString += appendToLDMLString(option, {'2-digit': 'yy', 'numeric': 'y'});
-
- option = getOption('month', 'string',
- ['2-digit', 'numeric', 'narrow', 'short', 'long']);
- ldmlString += appendToLDMLString(option, {'2-digit': 'MM', 'numeric': 'M',
- 'narrow': 'MMMMM', 'short': 'MMM', 'long': 'MMMM'});
-
- option = getOption('day', 'string', ['2-digit', 'numeric']);
- ldmlString += appendToLDMLString(
- option, {'2-digit': 'dd', 'numeric': 'd'});
-
- var hr12 = getOption('hour12', 'boolean');
- option = getOption('hour', 'string', ['2-digit', 'numeric']);
- if (hr12 === undefined) {
- ldmlString += appendToLDMLString(option, {'2-digit': 'jj', 'numeric': 'j'});
- } else if (hr12 === true) {
- ldmlString += appendToLDMLString(option, {'2-digit': 'hh', 'numeric': 'h'});
- } else {
- ldmlString += appendToLDMLString(option, {'2-digit': 'HH', 'numeric': 'H'});
- }
-
- option = getOption('minute', 'string', ['2-digit', 'numeric']);
- ldmlString += appendToLDMLString(option, {'2-digit': 'mm', 'numeric': 'm'});
-
- option = getOption('second', 'string', ['2-digit', 'numeric']);
- ldmlString += appendToLDMLString(option, {'2-digit': 'ss', 'numeric': 's'});
-
- option = getOption('timeZoneName', 'string', ['short', 'long']);
- ldmlString += appendToLDMLString(option, {short: 'v', long: 'vv'});
-
- return ldmlString;
-}
-
-
-/**
- * Returns either LDML equivalent of the current option or empty string.
- */
-function appendToLDMLString(option, pairs) {
- if (option !== undefined) {
- return pairs[option];
- } else {
- return '';
- }
-}
-
-
-/**
- * Returns object that matches LDML representation of the date.
- */
-function fromLDMLString(ldmlString) {
- // First remove '' quoted text, so we lose 'Uhr' strings.
- ldmlString = ldmlString.replace(QUOTED_STRING_RE, '');
-
- var options = {};
- var match = ldmlString.match(/E{3,5}/g);
- options = appendToDateTimeObject(
- options, 'weekday', match, {EEEEE: 'narrow', EEE: 'short', EEEE: 'long'});
-
- match = ldmlString.match(/G{3,5}/g);
- options = appendToDateTimeObject(
- options, 'era', match, {GGGGG: 'narrow', GGG: 'short', GGGG: 'long'});
-
- match = ldmlString.match(/y{1,2}/g);
- options = appendToDateTimeObject(
- options, 'year', match, {y: 'numeric', yy: '2-digit'});
-
- match = ldmlString.match(/M{1,5}/g);
- options = appendToDateTimeObject(options, 'month', match, {MM: '2-digit',
- M: 'numeric', MMMMM: 'narrow', MMM: 'short', MMMM: 'long'});
-
- // Sometimes we get L instead of M for month - standalone name.
- match = ldmlString.match(/L{1,5}/g);
- options = appendToDateTimeObject(options, 'month', match, {LL: '2-digit',
- L: 'numeric', LLLLL: 'narrow', LLL: 'short', LLLL: 'long'});
-
- match = ldmlString.match(/d{1,2}/g);
- options = appendToDateTimeObject(
- options, 'day', match, {d: 'numeric', dd: '2-digit'});
-
- match = ldmlString.match(/h{1,2}/g);
- if (match !== null) {
- options['hour12'] = true;
- }
- options = appendToDateTimeObject(
- options, 'hour', match, {h: 'numeric', hh: '2-digit'});
-
- match = ldmlString.match(/H{1,2}/g);
- if (match !== null) {
- options['hour12'] = false;
- }
- options = appendToDateTimeObject(
- options, 'hour', match, {H: 'numeric', HH: '2-digit'});
-
- match = ldmlString.match(/m{1,2}/g);
- options = appendToDateTimeObject(
- options, 'minute', match, {m: 'numeric', mm: '2-digit'});
-
- match = ldmlString.match(/s{1,2}/g);
- options = appendToDateTimeObject(
- options, 'second', match, {s: 'numeric', ss: '2-digit'});
-
- match = ldmlString.match(/v{1,2}/g);
- options = appendToDateTimeObject(
- options, 'timeZoneName', match, {v: 'short', vv: 'long'});
-
- return options;
-}
-
-
-function appendToDateTimeObject(options, option, match, pairs) {
- if (match === null) {
- if (!options.hasOwnProperty(option)) {
- defineWEProperty(options, option, undefined);
- }
- return options;
- }
-
- var property = match[0];
- defineWEProperty(options, option, pairs[property]);
-
- return options;
-}
-
-
-/**
- * Returns options with at least default values in it.
- */
-function toDateTimeOptions(options, required, defaults) {
- if (options === undefined) {
- options = null;
- } else {
- options = toObject(options);
- }
-
- options = Object.apply(this, [options]);
-
- var needsDefault = true;
- if ((required === 'date' || required === 'any') &&
- (options.weekday !== undefined || options.year !== undefined ||
- options.month !== undefined || options.day !== undefined)) {
- needsDefault = false;
- }
-
- if ((required === 'time' || required === 'any') &&
- (options.hour !== undefined || options.minute !== undefined ||
- options.second !== undefined)) {
- needsDefault = false;
- }
-
- if (needsDefault && (defaults === 'date' || defaults === 'all')) {
- Object.defineProperty(options, 'year', {value: 'numeric',
- writable: true,
- enumerable: true,
- configurable: true});
- Object.defineProperty(options, 'month', {value: 'numeric',
- writable: true,
- enumerable: true,
- configurable: true});
- Object.defineProperty(options, 'day', {value: 'numeric',
- writable: true,
- enumerable: true,
- configurable: true});
- }
-
- if (needsDefault && (defaults === 'time' || defaults === 'all')) {
- Object.defineProperty(options, 'hour', {value: 'numeric',
- writable: true,
- enumerable: true,
- configurable: true});
- Object.defineProperty(options, 'minute', {value: 'numeric',
- writable: true,
- enumerable: true,
- configurable: true});
- Object.defineProperty(options, 'second', {value: 'numeric',
- writable: true,
- enumerable: true,
- configurable: true});
- }
-
- return options;
-}
-
-
-/**
- * Initializes the given object so it's a valid DateTimeFormat instance.
- * Useful for subclassing.
- */
-function initializeDateTimeFormat(dateFormat, locales, options) {
-
- if (dateFormat.hasOwnProperty('__initializedIntlObject')) {
- throw new TypeError('Trying to re-initialize DateTimeFormat object.');
- }
-
- if (options === undefined) {
- options = {};
- }
-
- var locale = resolveLocale('dateformat', locales, options);
-
- options = toDateTimeOptions(options, 'any', 'date');
-
- var getOption = getGetOption(options, 'dateformat');
-
- // We implement only best fit algorithm, but still need to check
- // if the formatMatcher values are in range.
- var matcher = getOption('formatMatcher', 'string',
- ['basic', 'best fit'], 'best fit');
-
- // Build LDML string for the skeleton that we pass to the formatter.
- var ldmlString = toLDMLString(options);
-
- // Filter out supported extension keys so we know what to put in resolved
- // section later on.
- // We need to pass calendar and number system to the method.
- var tz = canonicalizeTimeZoneID(options.timeZone);
-
- // ICU prefers options to be passed using -u- extension key/values, so
- // we need to build that.
- var internalOptions = {};
- var extensionMap = parseExtension(locale.extension);
- var extension = setOptions(options, extensionMap, DATETIME_FORMAT_KEY_MAP,
- getOption, internalOptions);
-
- var requestedLocale = locale.locale + extension;
- var resolved = Object.defineProperties({}, {
- calendar: {writable: true},
- day: {writable: true},
- era: {writable: true},
- hour12: {writable: true},
- hour: {writable: true},
- locale: {writable: true},
- minute: {writable: true},
- month: {writable: true},
- numberingSystem: {writable: true},
- pattern: {writable: true},
- requestedLocale: {value: requestedLocale, writable: true},
- second: {writable: true},
- timeZone: {writable: true},
- timeZoneName: {writable: true},
- tz: {value: tz, writable: true},
- weekday: {writable: true},
- year: {writable: true}
- });
-
- var formatter = %CreateDateTimeFormat(
- requestedLocale, {skeleton: ldmlString, timeZone: tz}, resolved);
-
- if (tz !== undefined && tz !== resolved.timeZone) {
- throw new RangeError('Unsupported time zone specified ' + tz);
- }
-
- Object.defineProperty(dateFormat, 'formatter', {value: formatter});
- Object.defineProperty(dateFormat, 'resolved', {value: resolved});
- Object.defineProperty(dateFormat, '__initializedIntlObject',
- {value: 'dateformat'});
-
- return dateFormat;
-}
-
-
-/**
- * Constructs Intl.DateTimeFormat object given optional locales and options
- * parameters.
- *
- * @constructor
- */
-%SetProperty(Intl, 'DateTimeFormat', function() {
- var locales = arguments[0];
- var options = arguments[1];
-
- if (!this || this === Intl) {
- // Constructor is called as a function.
- return new Intl.DateTimeFormat(locales, options);
- }
-
- return initializeDateTimeFormat(toObject(this), locales, options);
- },
- ATTRIBUTES.DONT_ENUM
-);
-
-
-/**
- * DateTimeFormat resolvedOptions method.
- */
-%SetProperty(Intl.DateTimeFormat.prototype, 'resolvedOptions', function() {
- if (%_IsConstructCall()) {
- throw new TypeError(ORDINARY_FUNCTION_CALLED_AS_CONSTRUCTOR);
- }
-
- if (!this || typeof this !== 'object' ||
- this.__initializedIntlObject !== 'dateformat') {
- throw new TypeError('resolvedOptions method called on a non-object or ' +
- 'on a object that is not Intl.DateTimeFormat.');
- }
-
- var format = this;
- var fromPattern = fromLDMLString(format.resolved.pattern);
- var userCalendar = ICU_CALENDAR_MAP[format.resolved.calendar];
- if (userCalendar === undefined) {
- // Use ICU name if we don't have a match. It shouldn't happen, but
- // it would be too strict to throw for this.
- userCalendar = format.resolved.calendar;
- }
-
- var locale = getOptimalLanguageTag(format.resolved.requestedLocale,
- format.resolved.locale);
-
- var result = {
- locale: locale,
- numberingSystem: format.resolved.numberingSystem,
- calendar: userCalendar,
- timeZone: format.resolved.timeZone
- };
-
- addWECPropertyIfDefined(result, 'timeZoneName', fromPattern.timeZoneName);
- addWECPropertyIfDefined(result, 'era', fromPattern.era);
- addWECPropertyIfDefined(result, 'year', fromPattern.year);
- addWECPropertyIfDefined(result, 'month', fromPattern.month);
- addWECPropertyIfDefined(result, 'day', fromPattern.day);
- addWECPropertyIfDefined(result, 'weekday', fromPattern.weekday);
- addWECPropertyIfDefined(result, 'hour12', fromPattern.hour12);
- addWECPropertyIfDefined(result, 'hour', fromPattern.hour);
- addWECPropertyIfDefined(result, 'minute', fromPattern.minute);
- addWECPropertyIfDefined(result, 'second', fromPattern.second);
-
- return result;
- },
- ATTRIBUTES.DONT_ENUM
-);
-%FunctionSetName(Intl.DateTimeFormat.prototype.resolvedOptions,
- 'resolvedOptions');
-%FunctionRemovePrototype(Intl.DateTimeFormat.prototype.resolvedOptions);
-%SetNativeFlag(Intl.DateTimeFormat.prototype.resolvedOptions);
-
-
-/**
- * Returns the subset of the given locale list for which this locale list
- * has a matching (possibly fallback) locale. Locales appear in the same
- * order in the returned list as in the input list.
- * Options are optional parameter.
- */
-%SetProperty(Intl.DateTimeFormat, 'supportedLocalesOf', function(locales) {
- if (%_IsConstructCall()) {
- throw new TypeError(ORDINARY_FUNCTION_CALLED_AS_CONSTRUCTOR);
- }
-
- return supportedLocalesOf('dateformat', locales, arguments[1]);
- },
- ATTRIBUTES.DONT_ENUM
-);
-%FunctionSetName(Intl.DateTimeFormat.supportedLocalesOf, 'supportedLocalesOf');
-%FunctionRemovePrototype(Intl.DateTimeFormat.supportedLocalesOf);
-%SetNativeFlag(Intl.DateTimeFormat.supportedLocalesOf);
-
-
-/**
- * Returns a String value representing the result of calling ToNumber(date)
- * according to the effective locale and the formatting options of this
- * DateTimeFormat.
- */
-function formatDate(formatter, dateValue) {
- var dateMs;
- if (dateValue === undefined) {
- dateMs = Date.now();
- } else {
- dateMs = Number(dateValue);
- }
-
- if (!isFinite(dateMs)) {
- throw new RangeError('Provided date is not in valid range.');
- }
-
- return %InternalDateFormat(formatter.formatter, new Date(dateMs));
-}
-
-
-/**
- * Returns a Date object representing the result of calling ToString(value)
- * according to the effective locale and the formatting options of this
- * DateTimeFormat.
- * Returns undefined if date string cannot be parsed.
- */
-function parseDate(formatter, value) {
- return %InternalDateParse(formatter.formatter, String(value));
-}
-
-
-// 0 because date is optional argument.
-addBoundMethod(Intl.DateTimeFormat, 'format', formatDate, 0);
-addBoundMethod(Intl.DateTimeFormat, 'v8Parse', parseDate, 1);
-
-
-/**
- * Returns canonical Area/Location name, or throws an exception if the zone
- * name is invalid IANA name.
- */
-function canonicalizeTimeZoneID(tzID) {
- // Skip undefined zones.
- if (tzID === undefined) {
- return tzID;
- }
-
- // Special case handling (UTC, GMT).
- var upperID = tzID.toUpperCase();
- if (upperID === 'UTC' || upperID === 'GMT' ||
- upperID === 'ETC/UTC' || upperID === 'ETC/GMT') {
- return 'UTC';
- }
-
- // We expect only _ and / beside ASCII letters.
- // All inputs should conform to Area/Location from now on.
- var match = TIMEZONE_NAME_CHECK_RE.exec(tzID);
- if (match === null) {
- throw new RangeError('Expected Area/Location for time zone, got ' + tzID);
- }
-
- var result = toTitleCaseWord(match[1]) + '/' + toTitleCaseWord(match[2]);
- var i = 3;
- while (match[i] !== undefined && i < match.length) {
- result = result + '_' + toTitleCaseWord(match[i]);
- i++;
- }
-
- return result;
-}
diff --git a/src/extensions/i18n/footer.js b/src/extensions/i18n/footer.js
deleted file mode 100644
index ac33f1e..0000000
--- a/src/extensions/i18n/footer.js
+++ /dev/null
@@ -1,40 +0,0 @@
-// Copyright 2013 the V8 project authors. All rights reserved.
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following
-// disclaimer in the documentation and/or other materials provided
-// with the distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-// limitations under the License.
-
-// ECMAScript 402 API implementation is broken into separate files for
-// each service. The build system combines them together into one
-// Intl namespace.
-
-// Fix RegExp global state so we don't fail WebKit layout test:
-// fast/js/regexp-caching.html
-// It seems that 'g' or test() operations leave state changed.
-var CLEANUP_RE = new RegExp('');
-CLEANUP_RE.test('');
-
-return Intl;
-}());
diff --git a/src/extensions/i18n/globals.js b/src/extensions/i18n/globals.js
deleted file mode 100644
index 68fabe7..0000000
--- a/src/extensions/i18n/globals.js
+++ /dev/null
@@ -1,168 +0,0 @@
-// Copyright 2013 the V8 project authors. All rights reserved.
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following
-// disclaimer in the documentation and/or other materials provided
-// with the distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-// limitations under the License.
-
-
-/**
- * List of available services.
- */
-var AVAILABLE_SERVICES = ['collator',
- 'numberformat',
- 'dateformat',
- 'breakiterator'];
-
-/**
- * Caches available locales for each service.
- */
-var AVAILABLE_LOCALES = {
- 'collator': undefined,
- 'numberformat': undefined,
- 'dateformat': undefined,
- 'breakiterator': undefined
-};
-
-/**
- * Caches default ICU locale.
- */
-var DEFAULT_ICU_LOCALE = undefined;
-
-/**
- * Unicode extension regular expression.
- */
-var UNICODE_EXTENSION_RE = new RegExp('-u(-[a-z0-9]{2,8})+', 'g');
-
-/**
- * Matches any Unicode extension.
- */
-var ANY_EXTENSION_RE = new RegExp('-[a-z0-9]{1}-.*', 'g');
-
-/**
- * Replace quoted text (single quote, anything but the quote and quote again).
- */
-var QUOTED_STRING_RE = new RegExp("'[^']+'", 'g');
-
-/**
- * Matches valid service name.
- */
-var SERVICE_RE =
- new RegExp('^(collator|numberformat|dateformat|breakiterator)$');
-
-/**
- * Validates a language tag against bcp47 spec.
- * Actual value is assigned on first run.
- */
-var LANGUAGE_TAG_RE = undefined;
-
-/**
- * Helps find duplicate variants in the language tag.
- */
-var LANGUAGE_VARIANT_RE = undefined;
-
-/**
- * Helps find duplicate singletons in the language tag.
- */
-var LANGUAGE_SINGLETON_RE = undefined;
-
-/**
- * Matches valid IANA time zone names.
- */
-var TIMEZONE_NAME_CHECK_RE =
- new RegExp('^([A-Za-z]+)/([A-Za-z]+)(?:_([A-Za-z]+))*$');
-
-/**
- * Maps ICU calendar names into LDML type.
- */
-var ICU_CALENDAR_MAP = {
- 'gregorian': 'gregory',
- 'japanese': 'japanese',
- 'buddhist': 'buddhist',
- 'roc': 'roc',
- 'persian': 'persian',
- 'islamic-civil': 'islamicc',
- 'islamic': 'islamic',
- 'hebrew': 'hebrew',
- 'chinese': 'chinese',
- 'indian': 'indian',
- 'coptic': 'coptic',
- 'ethiopic': 'ethiopic',
- 'ethiopic-amete-alem': 'ethioaa'
-};
-
-/**
- * Map of Unicode extensions to option properties, and their values and types,
- * for a collator.
- */
-var COLLATOR_KEY_MAP = {
- 'kn': {'property': 'numeric', 'type': 'boolean'},
- 'kf': {'property': 'caseFirst', 'type': 'string',
- 'values': ['false', 'lower', 'upper']}
-};
-
-/**
- * Map of Unicode extensions to option properties, and their values and types,
- * for a number format.
- */
-var NUMBER_FORMAT_KEY_MAP = {
- 'nu': {'property': undefined, 'type': 'string'}
-};
-
-/**
- * Map of Unicode extensions to option properties, and their values and types,
- * for a date/time format.
- */
-var DATETIME_FORMAT_KEY_MAP = {
- 'ca': {'property': undefined, 'type': 'string'},
- 'nu': {'property': undefined, 'type': 'string'}
-};
-
-/**
- * Allowed -u-co- values. List taken from:
- * http://unicode.org/repos/cldr/trunk/common/bcp47/collation.xml
- */
-var ALLOWED_CO_VALUES = [
- 'big5han', 'dict', 'direct', 'ducet', 'gb2312', 'phonebk', 'phonetic',
- 'pinyin', 'reformed', 'searchjl', 'stroke', 'trad', 'unihan', 'zhuyin'
-];
-
-/**
- * Object attributes (configurable, writable, enumerable).
- * To combine attributes, OR them.
- * Values/names are copied from v8/include/v8.h:PropertyAttribute
- */
-var ATTRIBUTES = {
- 'NONE': 0,
- 'READ_ONLY': 1,
- 'DONT_ENUM': 2,
- 'DONT_DELETE': 4
-};
-
-/**
- * Error message for when function object is created with new and it's not
- * a constructor.
- */
-var ORDINARY_FUNCTION_CALLED_AS_CONSTRUCTOR =
- 'Function object that\'s not a constructor was created with new';
diff --git a/src/extensions/i18n/header.js b/src/extensions/i18n/header.js
deleted file mode 100644
index 1c0a2d8..0000000
--- a/src/extensions/i18n/header.js
+++ /dev/null
@@ -1,41 +0,0 @@
-// Copyright 2013 the V8 project authors. All rights reserved.
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following
-// disclaimer in the documentation and/or other materials provided
-// with the distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-// limitations under the License.
-
-// ECMAScript 402 API implementation is broken into separate files for
-// each service. The build system combines them together into one
-// Intl namespace.
-
-/**
- * Intl object is a single object that has some named properties,
- * all of which are constructors.
- */
-var Intl = (function() {
-
-'use strict';
-
-var Intl = {};
diff --git a/src/extensions/i18n/i18n-extension.cc b/src/extensions/i18n/i18n-extension.cc
deleted file mode 100644
index b5f2863..0000000
--- a/src/extensions/i18n/i18n-extension.cc
+++ /dev/null
@@ -1,51 +0,0 @@
-// Copyright 2013 the V8 project authors. All rights reserved.
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following
-// disclaimer in the documentation and/or other materials provided
-// with the distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-// limitations under the License.
-
-#include "i18n-extension.h"
-
-#include "natives.h"
-
-using v8::internal::I18NNatives;
-
-namespace v8_i18n {
-
-Extension::Extension()
- : v8::Extension("v8/i18n",
- reinterpret_cast<const char*>(
- I18NNatives::GetScriptsSource().start()),
- 0,
- 0,
- I18NNatives::GetScriptsSource().length()) {}
-
-
-void Extension::Register() {
- static Extension i18n_extension;
- static v8::DeclareExtension extension_declaration(&i18n_extension);
-}
-
-} // namespace v8_i18n
diff --git a/src/extensions/i18n/i18n-extension.h b/src/extensions/i18n/i18n-extension.h
deleted file mode 100644
index 9e538cb..0000000
--- a/src/extensions/i18n/i18n-extension.h
+++ /dev/null
@@ -1,48 +0,0 @@
-// Copyright 2013 the V8 project authors. All rights reserved.
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following
-// disclaimer in the documentation and/or other materials provided
-// with the distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-// limitations under the License.
-
-#ifndef V8_EXTENSIONS_I18N_I18N_EXTENSION_H_
-#define V8_EXTENSIONS_I18N_I18N_EXTENSION_H_
-
-#include "v8.h"
-
-namespace v8_i18n {
-
-class Extension : public v8::Extension {
- public:
- Extension();
-
- static void Register();
-
- private:
- static Extension* extension_;
-};
-
-} // namespace v8_i18n
-
-#endif // V8_EXTENSIONS_I18N_I18N_EXTENSION_H_
diff --git a/src/extensions/i18n/i18n-utils.js b/src/extensions/i18n/i18n-utils.js
deleted file mode 100644
index 545082e..0000000
--- a/src/extensions/i18n/i18n-utils.js
+++ /dev/null
@@ -1,536 +0,0 @@
-// Copyright 2013 the V8 project authors. All rights reserved.
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following
-// disclaimer in the documentation and/or other materials provided
-// with the distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-// limitations under the License.
-
-// ECMAScript 402 API implementation is broken into separate files for
-// each service. The build system combines them together into one
-// Intl namespace.
-
-/**
- * Adds bound method to the prototype of the given object.
- */
-function addBoundMethod(obj, methodName, implementation, length) {
- function getter() {
- if (!this || typeof this !== 'object' ||
- this.__initializedIntlObject === undefined) {
- throw new TypeError('Method ' + methodName + ' called on a ' +
- 'non-object or on a wrong type of object.');
- }
- var internalName = '__bound' + methodName + '__';
- if (this[internalName] === undefined) {
- var that = this;
- var boundMethod;
- if (length === undefined || length === 2) {
- boundMethod = function(x, y) {
- if (%_IsConstructCall()) {
- throw new TypeError(ORDINARY_FUNCTION_CALLED_AS_CONSTRUCTOR);
- }
- return implementation(that, x, y);
- }
- } else if (length === 1) {
- boundMethod = function(x) {
- if (%_IsConstructCall()) {
- throw new TypeError(ORDINARY_FUNCTION_CALLED_AS_CONSTRUCTOR);
- }
- return implementation(that, x);
- }
- } else {
- boundMethod = function() {
- if (%_IsConstructCall()) {
- throw new TypeError(ORDINARY_FUNCTION_CALLED_AS_CONSTRUCTOR);
- }
- // DateTimeFormat.format needs to be 0 arg method, but can stil
- // receive optional dateValue param. If one was provided, pass it
- // along.
- if (arguments.length > 0) {
- return implementation(that, arguments[0]);
- } else {
- return implementation(that);
- }
- }
- }
- %FunctionSetName(boundMethod, internalName);
- %FunctionRemovePrototype(boundMethod);
- %SetNativeFlag(boundMethod);
- this[internalName] = boundMethod;
- }
- return this[internalName];
- }
-
- %FunctionSetName(getter, methodName);
- %FunctionRemovePrototype(getter);
- %SetNativeFlag(getter);
-
- Object.defineProperty(obj.prototype, methodName, {
- get: getter,
- enumerable: false,
- configurable: true
- });
-}
-
-
-/**
- * Returns an intersection of locales and service supported locales.
- * Parameter locales is treated as a priority list.
- */
-function supportedLocalesOf(service, locales, options) {
- if (service.match(SERVICE_RE) === null) {
- throw new Error('Internal error, wrong service type: ' + service);
- }
-
- // Provide defaults if matcher was not specified.
- if (options === undefined) {
- options = {};
- } else {
- options = toObject(options);
- }
-
- var matcher = options.localeMatcher;
- if (matcher !== undefined) {
- matcher = String(matcher);
- if (matcher !== 'lookup' && matcher !== 'best fit') {
- throw new RangeError('Illegal value for localeMatcher:' + matcher);
- }
- } else {
- matcher = 'best fit';
- }
-
- var requestedLocales = initializeLocaleList(locales);
-
- // Cache these, they don't ever change per service.
- if (AVAILABLE_LOCALES[service] === undefined) {
- AVAILABLE_LOCALES[service] = getAvailableLocalesOf(service);
- }
-
- // Use either best fit or lookup algorithm to match locales.
- if (matcher === 'best fit') {
- return initializeLocaleList(bestFitSupportedLocalesOf(
- requestedLocales, AVAILABLE_LOCALES[service]));
- }
-
- return initializeLocaleList(lookupSupportedLocalesOf(
- requestedLocales, AVAILABLE_LOCALES[service]));
-}
-
-
-/**
- * Returns the subset of the provided BCP 47 language priority list for which
- * this service has a matching locale when using the BCP 47 Lookup algorithm.
- * Locales appear in the same order in the returned list as in the input list.
- */
-function lookupSupportedLocalesOf(requestedLocales, availableLocales) {
- var matchedLocales = [];
- for (var i = 0; i < requestedLocales.length; ++i) {
- // Remove -u- extension.
- var locale = requestedLocales[i].replace(UNICODE_EXTENSION_RE, '');
- do {
- if (availableLocales[locale] !== undefined) {
- // Push requested locale not the resolved one.
- matchedLocales.push(requestedLocales[i]);
- break;
- }
- // Truncate locale if possible, if not break.
- var pos = locale.lastIndexOf('-');
- if (pos === -1) {
- break;
- }
- locale = locale.substring(0, pos);
- } while (true);
- }
-
- return matchedLocales;
-}
-
-
-/**
- * Returns the subset of the provided BCP 47 language priority list for which
- * this service has a matching locale when using the implementation
- * dependent algorithm.
- * Locales appear in the same order in the returned list as in the input list.
- */
-function bestFitSupportedLocalesOf(requestedLocales, availableLocales) {
- // TODO(cira): implement better best fit algorithm.
- return lookupSupportedLocalesOf(requestedLocales, availableLocales);
-}
-
-
-/**
- * Returns a getOption function that extracts property value for given
- * options object. If property is missing it returns defaultValue. If value
- * is out of range for that property it throws RangeError.
- */
-function getGetOption(options, caller) {
- if (options === undefined) {
- throw new Error('Internal ' + caller + ' error. ' +
- 'Default options are missing.');
- }
-
- var getOption = function getOption(property, type, values, defaultValue) {
- if (options[property] !== undefined) {
- var value = options[property];
- switch (type) {
- case 'boolean':
- value = Boolean(value);
- break;
- case 'string':
- value = String(value);
- break;
- case 'number':
- value = Number(value);
- break;
- default:
- throw new Error('Internal error. Wrong value type.');
- }
- if (values !== undefined && values.indexOf(value) === -1) {
- throw new RangeError('Value ' + value + ' out of range for ' + caller +
- ' options property ' + property);
- }
-
- return value;
- }
-
- return defaultValue;
- }
-
- return getOption;
-}
-
-
-/**
- * Compares a BCP 47 language priority list requestedLocales against the locales
- * in availableLocales and determines the best available language to meet the
- * request. Two algorithms are available to match the locales: the Lookup
- * algorithm described in RFC 4647 section 3.4, and an implementation dependent
- * best-fit algorithm. Independent of the locale matching algorithm, options
- * specified through Unicode locale extension sequences are negotiated
- * separately, taking the caller's relevant extension keys and locale data as
- * well as client-provided options into consideration. Returns an object with
- * a locale property whose value is the language tag of the selected locale,
- * and properties for each key in relevantExtensionKeys providing the selected
- * value for that key.
- */
-function resolveLocale(service, requestedLocales, options) {
- requestedLocales = initializeLocaleList(requestedLocales);
-
- var getOption = getGetOption(options, service);
- var matcher = getOption('localeMatcher', 'string',
- ['lookup', 'best fit'], 'best fit');
- var resolved;
- if (matcher === 'lookup') {
- resolved = lookupMatcher(service, requestedLocales);
- } else {
- resolved = bestFitMatcher(service, requestedLocales);
- }
-
- return resolved;
-}
-
-
-/**
- * Returns best matched supported locale and extension info using basic
- * lookup algorithm.
- */
-function lookupMatcher(service, requestedLocales) {
- if (service.match(SERVICE_RE) === null) {
- throw new Error('Internal error, wrong service type: ' + service);
- }
-
- // Cache these, they don't ever change per service.
- if (AVAILABLE_LOCALES[service] === undefined) {
- AVAILABLE_LOCALES[service] = getAvailableLocalesOf(service);
- }
-
- for (var i = 0; i < requestedLocales.length; ++i) {
- // Remove all extensions.
- var locale = requestedLocales[i].replace(ANY_EXTENSION_RE, '');
- do {
- if (AVAILABLE_LOCALES[service][locale] !== undefined) {
- // Return the resolved locale and extension.
- var extensionMatch = requestedLocales[i].match(UNICODE_EXTENSION_RE);
- var extension = (extensionMatch === null) ? '' : extensionMatch[0];
- return {'locale': locale, 'extension': extension, 'position': i};
- }
- // Truncate locale if possible.
- var pos = locale.lastIndexOf('-');
- if (pos === -1) {
- break;
- }
- locale = locale.substring(0, pos);
- } while (true);
- }
-
- // Didn't find a match, return default.
- if (DEFAULT_ICU_LOCALE === undefined) {
- DEFAULT_ICU_LOCALE = %GetDefaultICULocale();
- }
-
- return {'locale': DEFAULT_ICU_LOCALE, 'extension': '', 'position': -1};
-}
-
-
-/**
- * Returns best matched supported locale and extension info using
- * implementation dependend algorithm.
- */
-function bestFitMatcher(service, requestedLocales) {
- // TODO(cira): implement better best fit algorithm.
- return lookupMatcher(service, requestedLocales);
-}
-
-
-/**
- * Parses Unicode extension into key - value map.
- * Returns empty object if the extension string is invalid.
- * We are not concerned with the validity of the values at this point.
- */
-function parseExtension(extension) {
- var extensionSplit = extension.split('-');
-
- // Assume ['', 'u', ...] input, but don't throw.
- if (extensionSplit.length <= 2 ||
- (extensionSplit[0] !== '' && extensionSplit[1] !== 'u')) {
- return {};
- }
-
- // Key is {2}alphanum, value is {3,8}alphanum.
- // Some keys may not have explicit values (booleans).
- var extensionMap = {};
- var previousKey = undefined;
- for (var i = 2; i < extensionSplit.length; ++i) {
- var length = extensionSplit[i].length;
- var element = extensionSplit[i];
- if (length === 2) {
- extensionMap[element] = undefined;
- previousKey = element;
- } else if (length >= 3 && length <=8 && previousKey !== undefined) {
- extensionMap[previousKey] = element;
- previousKey = undefined;
- } else {
- // There is a value that's too long, or that doesn't have a key.
- return {};
- }
- }
-
- return extensionMap;
-}
-
-
-/**
- * Converts parameter to an Object if possible.
- */
-function toObject(value) {
- if (value === undefined || value === null) {
- throw new TypeError('Value cannot be converted to an Object.');
- }
-
- return Object(value);
-}
-
-
-/**
- * Populates internalOptions object with boolean key-value pairs
- * from extensionMap and options.
- * Returns filtered extension (number and date format constructors use
- * Unicode extensions for passing parameters to ICU).
- * It's used for extension-option pairs only, e.g. kn-normalization, but not
- * for 'sensitivity' since it doesn't have extension equivalent.
- * Extensions like nu and ca don't have options equivalent, so we place
- * undefined in the map.property to denote that.
- */
-function setOptions(inOptions, extensionMap, keyValues, getOption, outOptions) {
- var extension = '';
-
- var updateExtension = function updateExtension(key, value) {
- return '-' + key + '-' + String(value);
- }
-
- var updateProperty = function updateProperty(property, type, value) {
- if (type === 'boolean' && (typeof value === 'string')) {
- value = (value === 'true') ? true : false;
- }
-
- if (property !== undefined) {
- defineWEProperty(outOptions, property, value);
- }
- }
-
- for (var key in keyValues) {
- if (keyValues.hasOwnProperty(key)) {
- var value = undefined;
- var map = keyValues[key];
- if (map.property !== undefined) {
- // This may return true if user specifies numeric: 'false', since
- // Boolean('nonempty') === true.
- value = getOption(map.property, map.type, map.values);
- }
- if (value !== undefined) {
- updateProperty(map.property, map.type, value);
- extension += updateExtension(key, value);
- continue;
- }
- // User options didn't have it, check Unicode extension.
- // Here we want to convert strings 'true', 'false' into proper Boolean
- // values (not a user error).
- if (extensionMap.hasOwnProperty(key)) {
- value = extensionMap[key];
- if (value !== undefined) {
- updateProperty(map.property, map.type, value);
- extension += updateExtension(key, value);
- } else if (map.type === 'boolean') {
- // Boolean keys are allowed not to have values in Unicode extension.
- // Those default to true.
- updateProperty(map.property, map.type, true);
- extension += updateExtension(key, true);
- }
- }
- }
- }
-
- return extension === ''? '' : '-u' + extension;
-}
-
-
-/**
- * Converts all OwnProperties into
- * configurable: false, writable: false, enumerable: true.
- */
-function freezeArray(array) {
- array.forEach(function(element, index) {
- Object.defineProperty(array, index, {value: element,
- configurable: false,
- writable: false,
- enumerable: true});
- });
-
- Object.defineProperty(array, 'length', {value: array.length,
- writable: false});
-
- return array;
-}
-
-
-/**
- * It's sometimes desireable to leave user requested locale instead of ICU
- * supported one (zh-TW is equivalent to zh-Hant-TW, so we should keep shorter
- * one, if that was what user requested).
- * This function returns user specified tag if its maximized form matches ICU
- * resolved locale. If not we return ICU result.
- */
-function getOptimalLanguageTag(original, resolved) {
- // Returns Array<Object>, where each object has maximized and base properties.
- // Maximized: zh -> zh-Hans-CN
- // Base: zh-CN-u-ca-gregory -> zh-CN
- // Take care of grandfathered or simple cases.
- if (original === resolved) {
- return original;
- }
-
- var locales = %GetLanguageTagVariants([original, resolved]);
- if (locales[0].maximized !== locales[1].maximized) {
- return resolved;
- }
-
- // Preserve extensions of resolved locale, but swap base tags with original.
- var resolvedBase = new RegExp('^' + locales[1].base);
- return resolved.replace(resolvedBase, locales[0].base);
-}
-
-
-/**
- * Returns an Object that contains all of supported locales for a given
- * service.
- * In addition to the supported locales we add xx-ZZ locale for each xx-Yyyy-ZZ
- * that is supported. This is required by the spec.
- */
-function getAvailableLocalesOf(service) {
- var available = %AvailableLocalesOf(service);
-
- for (var i in available) {
- if (available.hasOwnProperty(i)) {
- var parts = i.match(/^([a-z]{2,3})-([A-Z][a-z]{3})-([A-Z]{2})$/);
- if (parts !== null) {
- // Build xx-ZZ. We don't care about the actual value,
- // as long it's not undefined.
- available[parts[1] + '-' + parts[3]] = null;
- }
- }
- }
-
- return available;
-}
-
-
-/**
- * Defines a property and sets writable and enumerable to true.
- * Configurable is false by default.
- */
-function defineWEProperty(object, property, value) {
- Object.defineProperty(object, property,
- {value: value, writable: true, enumerable: true});
-}
-
-
-/**
- * Adds property to an object if the value is not undefined.
- * Sets configurable descriptor to false.
- */
-function addWEPropertyIfDefined(object, property, value) {
- if (value !== undefined) {
- defineWEProperty(object, property, value);
- }
-}
-
-
-/**
- * Defines a property and sets writable, enumerable and configurable to true.
- */
-function defineWECProperty(object, property, value) {
- Object.defineProperty(object, property,
- {value: value,
- writable: true,
- enumerable: true,
- configurable: true});
-}
-
-
-/**
- * Adds property to an object if the value is not undefined.
- * Sets all descriptors to true.
- */
-function addWECPropertyIfDefined(object, property, value) {
- if (value !== undefined) {
- defineWECProperty(object, property, value);
- }
-}
-
-
-/**
- * Returns titlecased word, aMeRricA -> America.
- */
-function toTitleCaseWord(word) {
- return word.substr(0, 1).toUpperCase() + word.substr(1).toLowerCase();
-}
diff --git a/src/extensions/i18n/locale.js b/src/extensions/i18n/locale.js
deleted file mode 100644
index e478327..0000000
--- a/src/extensions/i18n/locale.js
+++ /dev/null
@@ -1,190 +0,0 @@
-// Copyright 2013 the V8 project authors. All rights reserved.
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following
-// disclaimer in the documentation and/or other materials provided
-// with the distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-// limitations under the License.
-
-// ECMAScript 402 API implementation is broken into separate files for
-// each service. The build system combines them together into one
-// Intl namespace.
-
-/**
- * Canonicalizes the language tag, or throws in case the tag is invalid.
- */
-function canonicalizeLanguageTag(localeID) {
- // null is typeof 'object' so we have to do extra check.
- if (typeof localeID !== 'string' && typeof localeID !== 'object' ||
- localeID === null) {
- throw new TypeError('Language ID should be string or object.');
- }
-
- var localeString = String(localeID);
-
- if (isValidLanguageTag(localeString) === false) {
- throw new RangeError('Invalid language tag: ' + localeString);
- }
-
- // This call will strip -kn but not -kn-true extensions.
- // ICU bug filled - http://bugs.icu-project.org/trac/ticket/9265.
- // TODO(cira): check if -u-kn-true-kc-true-kh-true still throws after
- // upgrade to ICU 4.9.
- var tag = %CanonicalizeLanguageTag(localeString);
- if (tag === 'invalid-tag') {
- throw new RangeError('Invalid language tag: ' + localeString);
- }
-
- return tag;
-}
-
-
-/**
- * Returns an array where all locales are canonicalized and duplicates removed.
- * Throws on locales that are not well formed BCP47 tags.
- */
-function initializeLocaleList(locales) {
- var seen = [];
- if (locales === undefined) {
- // Constructor is called without arguments.
- seen = [];
- } else {
- // We allow single string localeID.
- if (typeof locales === 'string') {
- seen.push(canonicalizeLanguageTag(locales));
- return freezeArray(seen);
- }
-
- var o = toObject(locales);
- // Converts it to UInt32 (>>> is shr on 32bit integers).
- var len = o.length >>> 0;
-
- for (var k = 0; k < len; k++) {
- if (k in o) {
- var value = o[k];
-
- var tag = canonicalizeLanguageTag(value);
-
- if (seen.indexOf(tag) === -1) {
- seen.push(tag);
- }
- }
- }
- }
-
- return freezeArray(seen);
-}
-
-
-/**
- * Validates the language tag. Section 2.2.9 of the bcp47 spec
- * defines a valid tag.
- *
- * ICU is too permissible and lets invalid tags, like
- * hant-cmn-cn, through.
- *
- * Returns false if the language tag is invalid.
- */
-function isValidLanguageTag(locale) {
- // Check if it's well-formed, including grandfadered tags.
- if (LANGUAGE_TAG_RE.test(locale) === false) {
- return false;
- }
-
- // Just return if it's a x- form. It's all private.
- if (locale.indexOf('x-') === 0) {
- return true;
- }
-
- // Check if there are any duplicate variants or singletons (extensions).
-
- // Remove private use section.
- locale = locale.split(/-x-/)[0];
-
- // Skip language since it can match variant regex, so we start from 1.
- // We are matching i-klingon here, but that's ok, since i-klingon-klingon
- // is not valid and would fail LANGUAGE_TAG_RE test.
- var variants = [];
- var extensions = [];
- var parts = locale.split(/-/);
- for (var i = 1; i < parts.length; i++) {
- var value = parts[i];
- if (LANGUAGE_VARIANT_RE.test(value) === true && extensions.length === 0) {
- if (variants.indexOf(value) === -1) {
- variants.push(value);
- } else {
- return false;
- }
- }
-
- if (LANGUAGE_SINGLETON_RE.test(value) === true) {
- if (extensions.indexOf(value) === -1) {
- extensions.push(value);
- } else {
- return false;
- }
- }
- }
-
- return true;
- }
-
-
-/**
- * Builds a regular expresion that validates the language tag
- * against bcp47 spec.
- * Uses http://tools.ietf.org/html/bcp47, section 2.1, ABNF.
- * Runs on load and initializes the global REs.
- */
-(function() {
- var alpha = '[a-zA-Z]';
- var digit = '[0-9]';
- var alphanum = '(' + alpha + '|' + digit + ')';
- var regular = '(art-lojban|cel-gaulish|no-bok|no-nyn|zh-guoyu|zh-hakka|' +
- 'zh-min|zh-min-nan|zh-xiang)';
- var irregular = '(en-GB-oed|i-ami|i-bnn|i-default|i-enochian|i-hak|' +
- 'i-klingon|i-lux|i-mingo|i-navajo|i-pwn|i-tao|i-tay|' +
- 'i-tsu|sgn-BE-FR|sgn-BE-NL|sgn-CH-DE)';
- var grandfathered = '(' + irregular + '|' + regular + ')';
- var privateUse = '(x(-' + alphanum + '{1,8})+)';
-
- var singleton = '(' + digit + '|[A-WY-Za-wy-z])';
- LANGUAGE_SINGLETON_RE = new RegExp('^' + singleton + '$', 'i');
-
- var extension = '(' + singleton + '(-' + alphanum + '{2,8})+)';
-
- var variant = '(' + alphanum + '{5,8}|(' + digit + alphanum + '{3}))';
- LANGUAGE_VARIANT_RE = new RegExp('^' + variant + '$', 'i');
-
- var region = '(' + alpha + '{2}|' + digit + '{3})';
- var script = '(' + alpha + '{4})';
- var extLang = '(' + alpha + '{3}(-' + alpha + '{3}){0,2})';
- var language = '(' + alpha + '{2,3}(-' + extLang + ')?|' + alpha + '{4}|' +
- alpha + '{5,8})';
- var langTag = language + '(-' + script + ')?(-' + region + ')?(-' +
- variant + ')*(-' + extension + ')*(-' + privateUse + ')?';
-
- var languageTag =
- '^(' + langTag + '|' + privateUse + '|' + grandfathered + ')$';
- LANGUAGE_TAG_RE = new RegExp(languageTag, 'i');
-})();
diff --git a/src/extensions/i18n/number-format.js b/src/extensions/i18n/number-format.js
deleted file mode 100644
index 5722a5d..0000000
--- a/src/extensions/i18n/number-format.js
+++ /dev/null
@@ -1,289 +0,0 @@
-// Copyright 2013 the V8 project authors. All rights reserved.
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following
-// disclaimer in the documentation and/or other materials provided
-// with the distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-// limitations under the License.
-
-// ECMAScript 402 API implementation is broken into separate files for
-// each service. The build system combines them together into one
-// Intl namespace.
-
-/**
- * Verifies that the input is a well-formed ISO 4217 currency code.
- * Don't uppercase to test. It could convert invalid code into a valid one.
- * For example \u00DFP (Eszett+P) becomes SSP.
- */
-function isWellFormedCurrencyCode(currency) {
- return typeof currency == "string" &&
- currency.length == 3 &&
- currency.match(/[^A-Za-z]/) == null;
-}
-
-
-/**
- * Returns the valid digit count for a property, or throws RangeError on
- * a value out of the range.
- */
-function getNumberOption(options, property, min, max, fallback) {
- var value = options[property];
- if (value !== undefined) {
- value = Number(value);
- if (isNaN(value) || value < min || value > max) {
- throw new RangeError(property + ' value is out of range.');
- }
- return Math.floor(value);
- }
-
- return fallback;
-}
-
-
-/**
- * Initializes the given object so it's a valid NumberFormat instance.
- * Useful for subclassing.
- */
-function initializeNumberFormat(numberFormat, locales, options) {
- if (numberFormat.hasOwnProperty('__initializedIntlObject')) {
- throw new TypeError('Trying to re-initialize NumberFormat object.');
- }
-
- if (options === undefined) {
- options = {};
- }
-
- var getOption = getGetOption(options, 'numberformat');
-
- var locale = resolveLocale('numberformat', locales, options);
-
- var internalOptions = {};
- defineWEProperty(internalOptions, 'style', getOption(
- 'style', 'string', ['decimal', 'percent', 'currency'], 'decimal'));
-
- var currency = getOption('currency', 'string');
- if (currency !== undefined && !isWellFormedCurrencyCode(currency)) {
- throw new RangeError('Invalid currency code: ' + currency);
- }
-
- if (internalOptions.style === 'currency' && currency === undefined) {
- throw new TypeError('Currency code is required with currency style.');
- }
-
- var currencyDisplay = getOption(
- 'currencyDisplay', 'string', ['code', 'symbol', 'name'], 'symbol');
- if (internalOptions.style === 'currency') {
- defineWEProperty(internalOptions, 'currency', currency.toUpperCase());
- defineWEProperty(internalOptions, 'currencyDisplay', currencyDisplay);
- }
-
- // Digit ranges.
- var mnid = getNumberOption(options, 'minimumIntegerDigits', 1, 21, 1);
- defineWEProperty(internalOptions, 'minimumIntegerDigits', mnid);
-
- var mnfd = getNumberOption(options, 'minimumFractionDigits', 0, 20, 0);
- defineWEProperty(internalOptions, 'minimumFractionDigits', mnfd);
-
- var mxfd = getNumberOption(options, 'maximumFractionDigits', mnfd, 20, 3);
- defineWEProperty(internalOptions, 'maximumFractionDigits', mxfd);
-
- var mnsd = options['minimumSignificantDigits'];
- var mxsd = options['maximumSignificantDigits'];
- if (mnsd !== undefined || mxsd !== undefined) {
- mnsd = getNumberOption(options, 'minimumSignificantDigits', 1, 21, 0);
- defineWEProperty(internalOptions, 'minimumSignificantDigits', mnsd);
-
- mxsd = getNumberOption(options, 'maximumSignificantDigits', mnsd, 21, 21);
- defineWEProperty(internalOptions, 'maximumSignificantDigits', mxsd);
- }
-
- // Grouping.
- defineWEProperty(internalOptions, 'useGrouping', getOption(
- 'useGrouping', 'boolean', undefined, true));
-
- // ICU prefers options to be passed using -u- extension key/values for
- // number format, so we need to build that.
- var extensionMap = parseExtension(locale.extension);
- var extension = setOptions(options, extensionMap, NUMBER_FORMAT_KEY_MAP,
- getOption, internalOptions);
-
- var requestedLocale = locale.locale + extension;
- var resolved = Object.defineProperties({}, {
- currency: {writable: true},
- currencyDisplay: {writable: true},
- locale: {writable: true},
- maximumFractionDigits: {writable: true},
- minimumFractionDigits: {writable: true},
- minimumIntegerDigits: {writable: true},
- numberingSystem: {writable: true},
- requestedLocale: {value: requestedLocale, writable: true},
- style: {value: internalOptions.style, writable: true},
- useGrouping: {writable: true}
- });
- if (internalOptions.hasOwnProperty('minimumSignificantDigits')) {
- defineWEProperty(resolved, 'minimumSignificantDigits', undefined);
- }
- if (internalOptions.hasOwnProperty('maximumSignificantDigits')) {
- defineWEProperty(resolved, 'maximumSignificantDigits', undefined);
- }
- var formatter = %CreateNumberFormat(requestedLocale,
- internalOptions,
- resolved);
-
- // We can't get information about number or currency style from ICU, so we
- // assume user request was fulfilled.
- if (internalOptions.style === 'currency') {
- Object.defineProperty(resolved, 'currencyDisplay', {value: currencyDisplay,
- writable: true});
- }
-
- Object.defineProperty(numberFormat, 'formatter', {value: formatter});
- Object.defineProperty(numberFormat, 'resolved', {value: resolved});
- Object.defineProperty(numberFormat, '__initializedIntlObject',
- {value: 'numberformat'});
-
- return numberFormat;
-}
-
-
-/**
- * Constructs Intl.NumberFormat object given optional locales and options
- * parameters.
- *
- * @constructor
- */
-%SetProperty(Intl, 'NumberFormat', function() {
- var locales = arguments[0];
- var options = arguments[1];
-
- if (!this || this === Intl) {
- // Constructor is called as a function.
- return new Intl.NumberFormat(locales, options);
- }
-
- return initializeNumberFormat(toObject(this), locales, options);
- },
- ATTRIBUTES.DONT_ENUM
-);
-
-
-/**
- * NumberFormat resolvedOptions method.
- */
-%SetProperty(Intl.NumberFormat.prototype, 'resolvedOptions', function() {
- if (%_IsConstructCall()) {
- throw new TypeError(ORDINARY_FUNCTION_CALLED_AS_CONSTRUCTOR);
- }
-
- if (!this || typeof this !== 'object' ||
- this.__initializedIntlObject !== 'numberformat') {
- throw new TypeError('resolvedOptions method called on a non-object' +
- ' or on a object that is not Intl.NumberFormat.');
- }
-
- var format = this;
- var locale = getOptimalLanguageTag(format.resolved.requestedLocale,
- format.resolved.locale);
-
- var result = {
- locale: locale,
- numberingSystem: format.resolved.numberingSystem,
- style: format.resolved.style,
- useGrouping: format.resolved.useGrouping,
- minimumIntegerDigits: format.resolved.minimumIntegerDigits,
- minimumFractionDigits: format.resolved.minimumFractionDigits,
- maximumFractionDigits: format.resolved.maximumFractionDigits,
- };
-
- if (result.style === 'currency') {
- defineWECProperty(result, 'currency', format.resolved.currency);
- defineWECProperty(result, 'currencyDisplay',
- format.resolved.currencyDisplay);
- }
-
- if (format.resolved.hasOwnProperty('minimumSignificantDigits')) {
- defineWECProperty(result, 'minimumSignificantDigits',
- format.resolved.minimumSignificantDigits);
- }
-
- if (format.resolved.hasOwnProperty('maximumSignificantDigits')) {
- defineWECProperty(result, 'maximumSignificantDigits',
- format.resolved.maximumSignificantDigits);
- }
-
- return result;
- },
- ATTRIBUTES.DONT_ENUM
-);
-%FunctionSetName(Intl.NumberFormat.prototype.resolvedOptions,
- 'resolvedOptions');
-%FunctionRemovePrototype(Intl.NumberFormat.prototype.resolvedOptions);
-%SetNativeFlag(Intl.NumberFormat.prototype.resolvedOptions);
-
-
-/**
- * Returns the subset of the given locale list for which this locale list
- * has a matching (possibly fallback) locale. Locales appear in the same
- * order in the returned list as in the input list.
- * Options are optional parameter.
- */
-%SetProperty(Intl.NumberFormat, 'supportedLocalesOf', function(locales) {
- if (%_IsConstructCall()) {
- throw new TypeError(ORDINARY_FUNCTION_CALLED_AS_CONSTRUCTOR);
- }
-
- return supportedLocalesOf('numberformat', locales, arguments[1]);
- },
- ATTRIBUTES.DONT_ENUM
-);
-%FunctionSetName(Intl.NumberFormat.supportedLocalesOf, 'supportedLocalesOf');
-%FunctionRemovePrototype(Intl.NumberFormat.supportedLocalesOf);
-%SetNativeFlag(Intl.NumberFormat.supportedLocalesOf);
-
-
-/**
- * Returns a String value representing the result of calling ToNumber(value)
- * according to the effective locale and the formatting options of this
- * NumberFormat.
- */
-function formatNumber(formatter, value) {
- // Spec treats -0 and +0 as 0.
- var number = Number(value);
- if (number === -0) {
- number = 0;
- }
-
- return %InternalNumberFormat(formatter.formatter, number);
-}
-
-
-/**
- * Returns a Number that represents string value that was passed in.
- */
-function parseNumber(formatter, value) {
- return %InternalNumberParse(formatter.formatter, String(value));
-}
-
-
-addBoundMethod(Intl.NumberFormat, 'format', formatNumber, 1);
-addBoundMethod(Intl.NumberFormat, 'v8Parse', parseNumber, 1);
diff --git a/src/extensions/i18n/overrides.js b/src/extensions/i18n/overrides.js
deleted file mode 100644
index b2d60b3..0000000
--- a/src/extensions/i18n/overrides.js
+++ /dev/null
@@ -1,220 +0,0 @@
-// Copyright 2013 the V8 project authors. All rights reserved.
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following
-// disclaimer in the documentation and/or other materials provided
-// with the distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-// limitations under the License.
-
-// ECMAScript 402 API implementation is broken into separate files for
-// each service. The build system combines them together into one
-// Intl namespace.
-
-
-// Save references to Intl objects and methods we use, for added security.
-var savedObjects = {
- 'collator': Intl.Collator,
- 'numberformat': Intl.NumberFormat,
- 'dateformatall': Intl.DateTimeFormat,
- 'dateformatdate': Intl.DateTimeFormat,
- 'dateformattime': Intl.DateTimeFormat
-};
-
-
-// Default (created with undefined locales and options parameters) collator,
-// number and date format instances. They'll be created as needed.
-var defaultObjects = {
- 'collator': undefined,
- 'numberformat': undefined,
- 'dateformatall': undefined,
- 'dateformatdate': undefined,
- 'dateformattime': undefined,
-};
-
-
-/**
- * Returns cached or newly created instance of a given service.
- * We cache only default instances (where no locales or options are provided).
- */
-function cachedOrNewService(service, locales, options, defaults) {
- var useOptions = (defaults === undefined) ? options : defaults;
- if (locales === undefined && options === undefined) {
- if (defaultObjects[service] === undefined) {
- defaultObjects[service] = new savedObjects[service](locales, useOptions);
- }
- return defaultObjects[service];
- }
- return new savedObjects[service](locales, useOptions);
-}
-
-
-/**
- * Compares this and that, and returns less than 0, 0 or greater than 0 value.
- * Overrides the built-in method.
- */
-Object.defineProperty(String.prototype, 'localeCompare', {
- value: function(that) {
- if (%_IsConstructCall()) {
- throw new TypeError(ORDINARY_FUNCTION_CALLED_AS_CONSTRUCTOR);
- }
-
- if (this === undefined || this === null) {
- throw new TypeError('Method invoked on undefined or null value.');
- }
-
- var locales = arguments[1];
- var options = arguments[2];
- var collator = cachedOrNewService('collator', locales, options);
- return compare(collator, this, that);
- },
- writable: true,
- configurable: true,
- enumerable: false
-});
-%FunctionSetName(String.prototype.localeCompare, 'localeCompare');
-%FunctionRemovePrototype(String.prototype.localeCompare);
-%SetNativeFlag(String.prototype.localeCompare);
-
-
-/**
- * Formats a Number object (this) using locale and options values.
- * If locale or options are omitted, defaults are used.
- */
-Object.defineProperty(Number.prototype, 'toLocaleString', {
- value: function() {
- if (%_IsConstructCall()) {
- throw new TypeError(ORDINARY_FUNCTION_CALLED_AS_CONSTRUCTOR);
- }
-
- if (!(this instanceof Number) && typeof(this) !== 'number') {
- throw new TypeError('Method invoked on an object that is not Number.');
- }
-
- var locales = arguments[0];
- var options = arguments[1];
- var numberFormat = cachedOrNewService('numberformat', locales, options);
- return formatNumber(numberFormat, this);
- },
- writable: true,
- configurable: true,
- enumerable: false
-});
-%FunctionSetName(Number.prototype.toLocaleString, 'toLocaleString');
-%FunctionRemovePrototype(Number.prototype.toLocaleString);
-%SetNativeFlag(Number.prototype.toLocaleString);
-
-
-/**
- * Returns actual formatted date or fails if date parameter is invalid.
- */
-function toLocaleDateTime(date, locales, options, required, defaults, service) {
- if (!(date instanceof Date)) {
- throw new TypeError('Method invoked on an object that is not Date.');
- }
-
- if (isNaN(date)) {
- return 'Invalid Date';
- }
-
- var internalOptions = toDateTimeOptions(options, required, defaults);
-
- var dateFormat =
- cachedOrNewService(service, locales, options, internalOptions);
-
- return formatDate(dateFormat, date);
-}
-
-
-/**
- * Formats a Date object (this) using locale and options values.
- * If locale or options are omitted, defaults are used - both date and time are
- * present in the output.
- */
-Object.defineProperty(Date.prototype, 'toLocaleString', {
- value: function() {
- if (%_IsConstructCall()) {
- throw new TypeError(ORDINARY_FUNCTION_CALLED_AS_CONSTRUCTOR);
- }
-
- var locales = arguments[0];
- var options = arguments[1];
- return toLocaleDateTime(
- this, locales, options, 'any', 'all', 'dateformatall');
- },
- writable: true,
- configurable: true,
- enumerable: false
-});
-%FunctionSetName(Date.prototype.toLocaleString, 'toLocaleString');
-%FunctionRemovePrototype(Date.prototype.toLocaleString);
-%SetNativeFlag(Date.prototype.toLocaleString);
-
-
-/**
- * Formats a Date object (this) using locale and options values.
- * If locale or options are omitted, defaults are used - only date is present
- * in the output.
- */
-Object.defineProperty(Date.prototype, 'toLocaleDateString', {
- value: function() {
- if (%_IsConstructCall()) {
- throw new TypeError(ORDINARY_FUNCTION_CALLED_AS_CONSTRUCTOR);
- }
-
- var locales = arguments[0];
- var options = arguments[1];
- return toLocaleDateTime(
- this, locales, options, 'date', 'date', 'dateformatdate');
- },
- writable: true,
- configurable: true,
- enumerable: false
-});
-%FunctionSetName(Date.prototype.toLocaleDateString, 'toLocaleDateString');
-%FunctionRemovePrototype(Date.prototype.toLocaleDateString);
-%SetNativeFlag(Date.prototype.toLocaleDateString);
-
-
-/**
- * Formats a Date object (this) using locale and options values.
- * If locale or options are omitted, defaults are used - only time is present
- * in the output.
- */
-Object.defineProperty(Date.prototype, 'toLocaleTimeString', {
- value: function() {
- if (%_IsConstructCall()) {
- throw new TypeError(ORDINARY_FUNCTION_CALLED_AS_CONSTRUCTOR);
- }
-
- var locales = arguments[0];
- var options = arguments[1];
- return toLocaleDateTime(
- this, locales, options, 'time', 'time', 'dateformattime');
- },
- writable: true,
- configurable: true,
- enumerable: false
-});
-%FunctionSetName(Date.prototype.toLocaleTimeString, 'toLocaleTimeString');
-%FunctionRemovePrototype(Date.prototype.toLocaleTimeString);
-%SetNativeFlag(Date.prototype.toLocaleTimeString);
diff --git a/src/flag-definitions.h b/src/flag-definitions.h
index 7548c01..cc153af 100644
--- a/src/flag-definitions.h
+++ b/src/flag-definitions.h
@@ -401,7 +401,6 @@
"enable use of constant pools for double immediate (ARM only)")
// bootstrapper.cc
-DEFINE_bool(enable_i18n, true, "enable i18n extension")
DEFINE_string(expose_natives_as, NULL, "expose natives in global object")
DEFINE_string(expose_debug_as, NULL, "expose debug in global object")
DEFINE_bool(expose_gc, false, "expose gc extension")
diff --git a/src/globals.h b/src/globals.h
index 992f3a8..1977e68 100644
--- a/src/globals.h
+++ b/src/globals.h
@@ -342,9 +342,9 @@
DISALLOW_COPY_AND_ASSIGN(TypeName)
-// Newly written code should use V8_INLINE() and V8_NOINLINE() directly.
-#define INLINE(declarator) V8_INLINE(declarator)
-#define NO_INLINE(declarator) V8_NOINLINE(declarator)
+// Newly written code should use V8_INLINE and V8_NOINLINE directly.
+#define INLINE(declarator) V8_INLINE declarator
+#define NO_INLINE(declarator) V8_NOINLINE declarator
// Newly written code should use V8_WARN_UNUSED_RESULT.
diff --git a/src/heap.cc b/src/heap.cc
index 0455a84..24e4039 100644
--- a/src/heap.cc
+++ b/src/heap.cc
@@ -4371,7 +4371,7 @@
if (!function->shared()->is_generator()) {
MaybeObject* maybe_failure =
- JSObject::cast(prototype)->SetLocalPropertyIgnoreAttributes(
+ JSObject::cast(prototype)->SetLocalPropertyIgnoreAttributesTrampoline(
constructor_string(), function, DONT_ENUM);
if (maybe_failure->IsFailure()) return maybe_failure;
}
diff --git a/src/hydrogen.cc b/src/hydrogen.cc
index 7b623b5..23c373f 100644
--- a/src/hydrogen.cc
+++ b/src/hydrogen.cc
@@ -4005,7 +4005,9 @@
static bool CanInlinePropertyAccess(Map* type) {
- return !type->is_dictionary_map() && !type->has_named_interceptor();
+ return type->IsJSObjectMap() &&
+ !type->is_dictionary_map() &&
+ !type->has_named_interceptor();
}
@@ -5381,6 +5383,7 @@
map->LookupDescriptor(NULL, *name, &lookup);
if (lookup.IsField()) {
HCheckMaps* checked_object = AddCheckMap(object, map);
+ ASSERT(map->IsJSObjectMap());
return BuildLoadNamedField(
checked_object, HObjectAccess::ForField(map, &lookup, name));
}
@@ -5392,6 +5395,12 @@
return New<HConstant>(constant);
}
+ if (lookup.IsFound()) {
+ // Cannot handle the property, do a generic load instead.
+ HValue* context = environment()->context();
+ return new(zone()) HLoadNamedGeneric(context, object, name);
+ }
+
// Handle a load from a known field somewhere in the prototype chain.
LookupInPrototypes(map, name, &lookup);
if (lookup.IsField()) {
@@ -5484,6 +5493,7 @@
Handle<Map> most_general_consolidated_map;
for (int i = 0; i < maps->length(); ++i) {
Handle<Map> map = maps->at(i);
+ if (!map->IsJSObjectMap()) return NULL;
// Don't allow mixing of JSArrays with JSObjects.
if (map->instance_type() == JS_ARRAY_TYPE) {
if (has_non_js_array_access) return NULL;
@@ -5536,7 +5546,7 @@
HValue* object,
HValue* key,
HValue* val,
- Expression* prop,
+ SmallMapList* maps,
BailoutId ast_id,
int position,
bool is_store,
@@ -5544,7 +5554,6 @@
bool* has_side_effects) {
*has_side_effects = false;
BuildCheckHeapObject(object);
- SmallMapList* maps = prop->GetReceiverTypes();
if (!is_store) {
HInstruction* consolidated_load =
@@ -5600,7 +5609,8 @@
if (untransitionable_maps.length() == 1) {
Handle<Map> untransitionable_map = untransitionable_maps[0];
HInstruction* instr = NULL;
- if (untransitionable_map->has_slow_elements_kind()) {
+ if (untransitionable_map->has_slow_elements_kind() ||
+ !untransitionable_map->IsJSObjectMap()) {
instr = AddInstruction(is_store ? BuildStoreKeyedGeneric(object, key, val)
: BuildLoadKeyedGeneric(object, key));
} else {
@@ -5617,6 +5627,7 @@
for (int i = 0; i < untransitionable_maps.length(); ++i) {
Handle<Map> map = untransitionable_maps[i];
+ if (!map->IsJSObjectMap()) continue;
ElementsKind elements_kind = map->elements_kind();
HBasicBlock* this_map = graph()->CreateBasicBlock();
HBasicBlock* other_map = graph()->CreateBasicBlock();
@@ -5689,10 +5700,9 @@
instr = BuildMonomorphicElementAccess(
obj, key, val, NULL, map, is_store, expr->GetStoreMode());
}
- } else if (expr->GetReceiverTypes() != NULL &&
- !expr->GetReceiverTypes()->is_empty()) {
+ } else if (types != NULL && !types->is_empty()) {
return HandlePolymorphicElementAccess(
- obj, key, val, expr, ast_id, position, is_store,
+ obj, key, val, types, ast_id, position, is_store,
expr->GetStoreMode(), has_side_effects);
} else {
if (is_store) {
diff --git a/src/hydrogen.h b/src/hydrogen.h
index 979a350..c1dafa8 100644
--- a/src/hydrogen.h
+++ b/src/hydrogen.h
@@ -2008,7 +2008,7 @@
HValue* HandlePolymorphicElementAccess(HValue* object,
HValue* key,
HValue* val,
- Expression* prop,
+ SmallMapList* maps,
BailoutId ast_id,
int position,
bool is_store,
diff --git a/src/i18n.js b/src/i18n.js
new file mode 100644
index 0000000..1798bbb
--- /dev/null
+++ b/src/i18n.js
@@ -0,0 +1,2116 @@
+// Copyright 2013 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+// limitations under the License.
+
+// ECMAScript 402 API implementation.
+
+/**
+ * Intl object is a single object that has some named properties,
+ * all of which are constructors.
+ */
+$Object.defineProperty(global, "Intl", { enumerable: false, value: (function() {
+
+'use strict';
+
+var Intl = {};
+
+var undefined = global.undefined;
+
+var AVAILABLE_SERVICES = ['collator',
+ 'numberformat',
+ 'dateformat',
+ 'breakiterator'];
+
+/**
+ * Caches available locales for each service.
+ */
+var AVAILABLE_LOCALES = {
+ 'collator': undefined,
+ 'numberformat': undefined,
+ 'dateformat': undefined,
+ 'breakiterator': undefined
+};
+
+/**
+ * Caches default ICU locale.
+ */
+var DEFAULT_ICU_LOCALE = undefined;
+
+/**
+ * Unicode extension regular expression.
+ */
+var UNICODE_EXTENSION_RE = undefined;
+
+function GetUnicodeExtensionRE() {
+ if (UNICODE_EXTENSION_RE === undefined) {
+ UNICODE_EXTENSION_RE = new $RegExp('-u(-[a-z0-9]{2,8})+', 'g');
+ }
+ return UNICODE_EXTENSION_RE;
+}
+
+/**
+ * Matches any Unicode extension.
+ */
+var ANY_EXTENSION_RE = undefined;
+
+function GetAnyExtensionRE() {
+ if (ANY_EXTENSION_RE === undefined) {
+ ANY_EXTENSION_RE = new $RegExp('-[a-z0-9]{1}-.*', 'g');
+ }
+ return ANY_EXTENSION_RE;
+}
+
+/**
+ * Replace quoted text (single quote, anything but the quote and quote again).
+ */
+var QUOTED_STRING_RE = undefined;
+
+function GetQuotedStringRE() {
+ if (QUOTED_STRING_RE === undefined) {
+ QUOTED_STRING_RE = new $RegExp("'[^']+'", 'g');
+ }
+ return QUOTED_STRING_RE;
+}
+
+/**
+ * Matches valid service name.
+ */
+var SERVICE_RE = undefined;
+
+function GetServiceRE() {
+ if (SERVICE_RE === undefined) {
+ SERVICE_RE =
+ new $RegExp('^(collator|numberformat|dateformat|breakiterator)$');
+ }
+ return SERVICE_RE;
+}
+
+/**
+ * Validates a language tag against bcp47 spec.
+ * Actual value is assigned on first run.
+ */
+var LANGUAGE_TAG_RE = undefined;
+
+function GetLanguageTagRE() {
+ if (LANGUAGE_TAG_RE === undefined) {
+ BuildLanguageTagREs();
+ }
+ return LANGUAGE_TAG_RE;
+}
+
+/**
+ * Helps find duplicate variants in the language tag.
+ */
+var LANGUAGE_VARIANT_RE = undefined;
+
+function GetLanguageVariantRE() {
+ if (LANGUAGE_VARIANT_RE === undefined) {
+ BuildLanguageTagREs();
+ }
+ return LANGUAGE_VARIANT_RE;
+}
+
+/**
+ * Helps find duplicate singletons in the language tag.
+ */
+var LANGUAGE_SINGLETON_RE = undefined;
+
+function GetLanguageSingletonRE() {
+ if (LANGUAGE_SINGLETON_RE === undefined) {
+ BuildLanguageTagREs();
+ }
+ return LANGUAGE_SINGLETON_RE;
+}
+
+/**
+ * Matches valid IANA time zone names.
+ */
+var TIMEZONE_NAME_CHECK_RE = undefined;
+
+function GetTimezoneNameCheckRE() {
+ if (TIMEZONE_NAME_CHECK_RE === undefined) {
+ TIMEZONE_NAME_CHECK_RE =
+ new $RegExp('^([A-Za-z]+)/([A-Za-z]+)(?:_([A-Za-z]+))*$');
+ }
+ return TIMEZONE_NAME_CHECK_RE;
+}
+
+/**
+ * Maps ICU calendar names into LDML type.
+ */
+var ICU_CALENDAR_MAP = {
+ 'gregorian': 'gregory',
+ 'japanese': 'japanese',
+ 'buddhist': 'buddhist',
+ 'roc': 'roc',
+ 'persian': 'persian',
+ 'islamic-civil': 'islamicc',
+ 'islamic': 'islamic',
+ 'hebrew': 'hebrew',
+ 'chinese': 'chinese',
+ 'indian': 'indian',
+ 'coptic': 'coptic',
+ 'ethiopic': 'ethiopic',
+ 'ethiopic-amete-alem': 'ethioaa'
+};
+
+/**
+ * Map of Unicode extensions to option properties, and their values and types,
+ * for a collator.
+ */
+var COLLATOR_KEY_MAP = {
+ 'kn': {'property': 'numeric', 'type': 'boolean'},
+ 'kf': {'property': 'caseFirst', 'type': 'string',
+ 'values': ['false', 'lower', 'upper']}
+};
+
+/**
+ * Map of Unicode extensions to option properties, and their values and types,
+ * for a number format.
+ */
+var NUMBER_FORMAT_KEY_MAP = {
+ 'nu': {'property': undefined, 'type': 'string'}
+};
+
+/**
+ * Map of Unicode extensions to option properties, and their values and types,
+ * for a date/time format.
+ */
+var DATETIME_FORMAT_KEY_MAP = {
+ 'ca': {'property': undefined, 'type': 'string'},
+ 'nu': {'property': undefined, 'type': 'string'}
+};
+
+/**
+ * Allowed -u-co- values. List taken from:
+ * http://unicode.org/repos/cldr/trunk/common/bcp47/collation.xml
+ */
+var ALLOWED_CO_VALUES = [
+ 'big5han', 'dict', 'direct', 'ducet', 'gb2312', 'phonebk', 'phonetic',
+ 'pinyin', 'reformed', 'searchjl', 'stroke', 'trad', 'unihan', 'zhuyin'
+];
+
+/**
+ * Error message for when function object is created with new and it's not
+ * a constructor.
+ */
+var ORDINARY_FUNCTION_CALLED_AS_CONSTRUCTOR =
+ 'Function object that\'s not a constructor was created with new';
+
+
+/**
+ * Adds bound method to the prototype of the given object.
+ */
+function addBoundMethod(obj, methodName, implementation, length) {
+ function getter() {
+ if (!this || typeof this !== 'object' ||
+ this.__initializedIntlObject === undefined) {
+ throw new $TypeError('Method ' + methodName + ' called on a ' +
+ 'non-object or on a wrong type of object.');
+ }
+ var internalName = '__bound' + methodName + '__';
+ if (this[internalName] === undefined) {
+ var that = this;
+ var boundMethod;
+ if (length === undefined || length === 2) {
+ boundMethod = function(x, y) {
+ if (%_IsConstructCall()) {
+ throw new $TypeError(ORDINARY_FUNCTION_CALLED_AS_CONSTRUCTOR);
+ }
+ return implementation(that, x, y);
+ }
+ } else if (length === 1) {
+ boundMethod = function(x) {
+ if (%_IsConstructCall()) {
+ throw new $TypeError(ORDINARY_FUNCTION_CALLED_AS_CONSTRUCTOR);
+ }
+ return implementation(that, x);
+ }
+ } else {
+ boundMethod = function() {
+ if (%_IsConstructCall()) {
+ throw new $TypeError(ORDINARY_FUNCTION_CALLED_AS_CONSTRUCTOR);
+ }
+ // DateTimeFormat.format needs to be 0 arg method, but can stil
+ // receive optional dateValue param. If one was provided, pass it
+ // along.
+ if (arguments.length > 0) {
+ return implementation(that, arguments[0]);
+ } else {
+ return implementation(that);
+ }
+ }
+ }
+ %FunctionSetName(boundMethod, internalName);
+ %FunctionRemovePrototype(boundMethod);
+ %SetNativeFlag(boundMethod);
+ this[internalName] = boundMethod;
+ }
+ return this[internalName];
+ }
+
+ %FunctionSetName(getter, methodName);
+ %FunctionRemovePrototype(getter);
+ %SetNativeFlag(getter);
+
+ $Object.defineProperty(obj.prototype, methodName, {
+ get: getter,
+ enumerable: false,
+ configurable: true
+ });
+}
+
+
+/**
+ * Returns an intersection of locales and service supported locales.
+ * Parameter locales is treated as a priority list.
+ */
+function supportedLocalesOf(service, locales, options) {
+ if (service.match(GetServiceRE()) === null) {
+ throw new $Error('Internal error, wrong service type: ' + service);
+ }
+
+ // Provide defaults if matcher was not specified.
+ if (options === undefined) {
+ options = {};
+ } else {
+ options = toObject(options);
+ }
+
+ var matcher = options.localeMatcher;
+ if (matcher !== undefined) {
+ matcher = $String(matcher);
+ if (matcher !== 'lookup' && matcher !== 'best fit') {
+ throw new $RangeError('Illegal value for localeMatcher:' + matcher);
+ }
+ } else {
+ matcher = 'best fit';
+ }
+
+ var requestedLocales = initializeLocaleList(locales);
+
+ // Cache these, they don't ever change per service.
+ if (AVAILABLE_LOCALES[service] === undefined) {
+ AVAILABLE_LOCALES[service] = getAvailableLocalesOf(service);
+ }
+
+ // Use either best fit or lookup algorithm to match locales.
+ if (matcher === 'best fit') {
+ return initializeLocaleList(bestFitSupportedLocalesOf(
+ requestedLocales, AVAILABLE_LOCALES[service]));
+ }
+
+ return initializeLocaleList(lookupSupportedLocalesOf(
+ requestedLocales, AVAILABLE_LOCALES[service]));
+}
+
+
+/**
+ * Returns the subset of the provided BCP 47 language priority list for which
+ * this service has a matching locale when using the BCP 47 Lookup algorithm.
+ * Locales appear in the same order in the returned list as in the input list.
+ */
+function lookupSupportedLocalesOf(requestedLocales, availableLocales) {
+ var matchedLocales = [];
+ for (var i = 0; i < requestedLocales.length; ++i) {
+ // Remove -u- extension.
+ var locale = requestedLocales[i].replace(GetUnicodeExtensionRE(), '');
+ do {
+ if (availableLocales[locale] !== undefined) {
+ // Push requested locale not the resolved one.
+ matchedLocales.push(requestedLocales[i]);
+ break;
+ }
+ // Truncate locale if possible, if not break.
+ var pos = locale.lastIndexOf('-');
+ if (pos === -1) {
+ break;
+ }
+ locale = locale.substring(0, pos);
+ } while (true);
+ }
+
+ return matchedLocales;
+}
+
+
+/**
+ * Returns the subset of the provided BCP 47 language priority list for which
+ * this service has a matching locale when using the implementation
+ * dependent algorithm.
+ * Locales appear in the same order in the returned list as in the input list.
+ */
+function bestFitSupportedLocalesOf(requestedLocales, availableLocales) {
+ // TODO(cira): implement better best fit algorithm.
+ return lookupSupportedLocalesOf(requestedLocales, availableLocales);
+}
+
+
+/**
+ * Returns a getOption function that extracts property value for given
+ * options object. If property is missing it returns defaultValue. If value
+ * is out of range for that property it throws RangeError.
+ */
+function getGetOption(options, caller) {
+ if (options === undefined) {
+ throw new $Error('Internal ' + caller + ' error. ' +
+ 'Default options are missing.');
+ }
+
+ var getOption = function getOption(property, type, values, defaultValue) {
+ if (options[property] !== undefined) {
+ var value = options[property];
+ switch (type) {
+ case 'boolean':
+ value = $Boolean(value);
+ break;
+ case 'string':
+ value = $String(value);
+ break;
+ case 'number':
+ value = $Number(value);
+ break;
+ default:
+ throw new $Error('Internal error. Wrong value type.');
+ }
+ if (values !== undefined && values.indexOf(value) === -1) {
+ throw new $RangeError('Value ' + value + ' out of range for ' + caller +
+ ' options property ' + property);
+ }
+
+ return value;
+ }
+
+ return defaultValue;
+ }
+
+ return getOption;
+}
+
+
+/**
+ * Compares a BCP 47 language priority list requestedLocales against the locales
+ * in availableLocales and determines the best available language to meet the
+ * request. Two algorithms are available to match the locales: the Lookup
+ * algorithm described in RFC 4647 section 3.4, and an implementation dependent
+ * best-fit algorithm. Independent of the locale matching algorithm, options
+ * specified through Unicode locale extension sequences are negotiated
+ * separately, taking the caller's relevant extension keys and locale data as
+ * well as client-provided options into consideration. Returns an object with
+ * a locale property whose value is the language tag of the selected locale,
+ * and properties for each key in relevantExtensionKeys providing the selected
+ * value for that key.
+ */
+function resolveLocale(service, requestedLocales, options) {
+ requestedLocales = initializeLocaleList(requestedLocales);
+
+ var getOption = getGetOption(options, service);
+ var matcher = getOption('localeMatcher', 'string',
+ ['lookup', 'best fit'], 'best fit');
+ var resolved;
+ if (matcher === 'lookup') {
+ resolved = lookupMatcher(service, requestedLocales);
+ } else {
+ resolved = bestFitMatcher(service, requestedLocales);
+ }
+
+ return resolved;
+}
+
+
+/**
+ * Returns best matched supported locale and extension info using basic
+ * lookup algorithm.
+ */
+function lookupMatcher(service, requestedLocales) {
+ if (service.match(GetServiceRE()) === null) {
+ throw new $Error('Internal error, wrong service type: ' + service);
+ }
+
+ // Cache these, they don't ever change per service.
+ if (AVAILABLE_LOCALES[service] === undefined) {
+ AVAILABLE_LOCALES[service] = getAvailableLocalesOf(service);
+ }
+
+ for (var i = 0; i < requestedLocales.length; ++i) {
+ // Remove all extensions.
+ var locale = requestedLocales[i].replace(GetAnyExtensionRE(), '');
+ do {
+ if (AVAILABLE_LOCALES[service][locale] !== undefined) {
+ // Return the resolved locale and extension.
+ var extensionMatch = requestedLocales[i].match(GetUnicodeExtensionRE());
+ var extension = (extensionMatch === null) ? '' : extensionMatch[0];
+ return {'locale': locale, 'extension': extension, 'position': i};
+ }
+ // Truncate locale if possible.
+ var pos = locale.lastIndexOf('-');
+ if (pos === -1) {
+ break;
+ }
+ locale = locale.substring(0, pos);
+ } while (true);
+ }
+
+ // Didn't find a match, return default.
+ if (DEFAULT_ICU_LOCALE === undefined) {
+ DEFAULT_ICU_LOCALE = %GetDefaultICULocale();
+ }
+
+ return {'locale': DEFAULT_ICU_LOCALE, 'extension': '', 'position': -1};
+}
+
+
+/**
+ * Returns best matched supported locale and extension info using
+ * implementation dependend algorithm.
+ */
+function bestFitMatcher(service, requestedLocales) {
+ // TODO(cira): implement better best fit algorithm.
+ return lookupMatcher(service, requestedLocales);
+}
+
+
+/**
+ * Parses Unicode extension into key - value map.
+ * Returns empty object if the extension string is invalid.
+ * We are not concerned with the validity of the values at this point.
+ */
+function parseExtension(extension) {
+ var extensionSplit = extension.split('-');
+
+ // Assume ['', 'u', ...] input, but don't throw.
+ if (extensionSplit.length <= 2 ||
+ (extensionSplit[0] !== '' && extensionSplit[1] !== 'u')) {
+ return {};
+ }
+
+ // Key is {2}alphanum, value is {3,8}alphanum.
+ // Some keys may not have explicit values (booleans).
+ var extensionMap = {};
+ var previousKey = undefined;
+ for (var i = 2; i < extensionSplit.length; ++i) {
+ var length = extensionSplit[i].length;
+ var element = extensionSplit[i];
+ if (length === 2) {
+ extensionMap[element] = undefined;
+ previousKey = element;
+ } else if (length >= 3 && length <=8 && previousKey !== undefined) {
+ extensionMap[previousKey] = element;
+ previousKey = undefined;
+ } else {
+ // There is a value that's too long, or that doesn't have a key.
+ return {};
+ }
+ }
+
+ return extensionMap;
+}
+
+
+/**
+ * Converts parameter to an Object if possible.
+ */
+function toObject(value) {
+ if (value === undefined || value === null) {
+ throw new $TypeError('Value cannot be converted to an Object.');
+ }
+
+ return $Object(value);
+}
+
+
+/**
+ * Populates internalOptions object with boolean key-value pairs
+ * from extensionMap and options.
+ * Returns filtered extension (number and date format constructors use
+ * Unicode extensions for passing parameters to ICU).
+ * It's used for extension-option pairs only, e.g. kn-normalization, but not
+ * for 'sensitivity' since it doesn't have extension equivalent.
+ * Extensions like nu and ca don't have options equivalent, so we place
+ * undefined in the map.property to denote that.
+ */
+function setOptions(inOptions, extensionMap, keyValues, getOption, outOptions) {
+ var extension = '';
+
+ var updateExtension = function updateExtension(key, value) {
+ return '-' + key + '-' + $String(value);
+ }
+
+ var updateProperty = function updateProperty(property, type, value) {
+ if (type === 'boolean' && (typeof value === 'string')) {
+ value = (value === 'true') ? true : false;
+ }
+
+ if (property !== undefined) {
+ defineWEProperty(outOptions, property, value);
+ }
+ }
+
+ for (var key in keyValues) {
+ if (keyValues.hasOwnProperty(key)) {
+ var value = undefined;
+ var map = keyValues[key];
+ if (map.property !== undefined) {
+ // This may return true if user specifies numeric: 'false', since
+ // Boolean('nonempty') === true.
+ value = getOption(map.property, map.type, map.values);
+ }
+ if (value !== undefined) {
+ updateProperty(map.property, map.type, value);
+ extension += updateExtension(key, value);
+ continue;
+ }
+ // User options didn't have it, check Unicode extension.
+ // Here we want to convert strings 'true', 'false' into proper Boolean
+ // values (not a user error).
+ if (extensionMap.hasOwnProperty(key)) {
+ value = extensionMap[key];
+ if (value !== undefined) {
+ updateProperty(map.property, map.type, value);
+ extension += updateExtension(key, value);
+ } else if (map.type === 'boolean') {
+ // Boolean keys are allowed not to have values in Unicode extension.
+ // Those default to true.
+ updateProperty(map.property, map.type, true);
+ extension += updateExtension(key, true);
+ }
+ }
+ }
+ }
+
+ return extension === ''? '' : '-u' + extension;
+}
+
+
+/**
+ * Converts all OwnProperties into
+ * configurable: false, writable: false, enumerable: true.
+ */
+function freezeArray(array) {
+ array.forEach(function(element, index) {
+ $Object.defineProperty(array, index, {value: element,
+ configurable: false,
+ writable: false,
+ enumerable: true});
+ });
+
+ $Object.defineProperty(array, 'length', {value: array.length,
+ writable: false});
+
+ return array;
+}
+
+
+/**
+ * It's sometimes desireable to leave user requested locale instead of ICU
+ * supported one (zh-TW is equivalent to zh-Hant-TW, so we should keep shorter
+ * one, if that was what user requested).
+ * This function returns user specified tag if its maximized form matches ICU
+ * resolved locale. If not we return ICU result.
+ */
+function getOptimalLanguageTag(original, resolved) {
+ // Returns Array<Object>, where each object has maximized and base properties.
+ // Maximized: zh -> zh-Hans-CN
+ // Base: zh-CN-u-ca-gregory -> zh-CN
+ // Take care of grandfathered or simple cases.
+ if (original === resolved) {
+ return original;
+ }
+
+ var locales = %GetLanguageTagVariants([original, resolved]);
+ if (locales[0].maximized !== locales[1].maximized) {
+ return resolved;
+ }
+
+ // Preserve extensions of resolved locale, but swap base tags with original.
+ var resolvedBase = new $RegExp('^' + locales[1].base);
+ return resolved.replace(resolvedBase, locales[0].base);
+}
+
+
+/**
+ * Returns an Object that contains all of supported locales for a given
+ * service.
+ * In addition to the supported locales we add xx-ZZ locale for each xx-Yyyy-ZZ
+ * that is supported. This is required by the spec.
+ */
+function getAvailableLocalesOf(service) {
+ var available = %AvailableLocalesOf(service);
+
+ for (var i in available) {
+ if (available.hasOwnProperty(i)) {
+ var parts = i.match(/^([a-z]{2,3})-([A-Z][a-z]{3})-([A-Z]{2})$/);
+ if (parts !== null) {
+ // Build xx-ZZ. We don't care about the actual value,
+ // as long it's not undefined.
+ available[parts[1] + '-' + parts[3]] = null;
+ }
+ }
+ }
+
+ return available;
+}
+
+
+/**
+ * Defines a property and sets writable and enumerable to true.
+ * Configurable is false by default.
+ */
+function defineWEProperty(object, property, value) {
+ $Object.defineProperty(object, property,
+ {value: value, writable: true, enumerable: true});
+}
+
+
+/**
+ * Adds property to an object if the value is not undefined.
+ * Sets configurable descriptor to false.
+ */
+function addWEPropertyIfDefined(object, property, value) {
+ if (value !== undefined) {
+ defineWEProperty(object, property, value);
+ }
+}
+
+
+/**
+ * Defines a property and sets writable, enumerable and configurable to true.
+ */
+function defineWECProperty(object, property, value) {
+ $Object.defineProperty(object, property,
+ {value: value,
+ writable: true,
+ enumerable: true,
+ configurable: true});
+}
+
+
+/**
+ * Adds property to an object if the value is not undefined.
+ * Sets all descriptors to true.
+ */
+function addWECPropertyIfDefined(object, property, value) {
+ if (value !== undefined) {
+ defineWECProperty(object, property, value);
+ }
+}
+
+
+/**
+ * Returns titlecased word, aMeRricA -> America.
+ */
+function toTitleCaseWord(word) {
+ return word.substr(0, 1).toUpperCase() + word.substr(1).toLowerCase();
+}
+
+/**
+ * Canonicalizes the language tag, or throws in case the tag is invalid.
+ */
+function canonicalizeLanguageTag(localeID) {
+ // null is typeof 'object' so we have to do extra check.
+ if (typeof localeID !== 'string' && typeof localeID !== 'object' ||
+ localeID === null) {
+ throw new $TypeError('Language ID should be string or object.');
+ }
+
+ var localeString = $String(localeID);
+
+ if (isValidLanguageTag(localeString) === false) {
+ throw new $RangeError('Invalid language tag: ' + localeString);
+ }
+
+ // This call will strip -kn but not -kn-true extensions.
+ // ICU bug filled - http://bugs.icu-project.org/trac/ticket/9265.
+ // TODO(cira): check if -u-kn-true-kc-true-kh-true still throws after
+ // upgrade to ICU 4.9.
+ var tag = %CanonicalizeLanguageTag(localeString);
+ if (tag === 'invalid-tag') {
+ throw new $RangeError('Invalid language tag: ' + localeString);
+ }
+
+ return tag;
+}
+
+
+/**
+ * Returns an array where all locales are canonicalized and duplicates removed.
+ * Throws on locales that are not well formed BCP47 tags.
+ */
+function initializeLocaleList(locales) {
+ var seen = [];
+ if (locales === undefined) {
+ // Constructor is called without arguments.
+ seen = [];
+ } else {
+ // We allow single string localeID.
+ if (typeof locales === 'string') {
+ seen.push(canonicalizeLanguageTag(locales));
+ return freezeArray(seen);
+ }
+
+ var o = toObject(locales);
+ // Converts it to UInt32 (>>> is shr on 32bit integers).
+ var len = o.length >>> 0;
+
+ for (var k = 0; k < len; k++) {
+ if (k in o) {
+ var value = o[k];
+
+ var tag = canonicalizeLanguageTag(value);
+
+ if (seen.indexOf(tag) === -1) {
+ seen.push(tag);
+ }
+ }
+ }
+ }
+
+ return freezeArray(seen);
+}
+
+
+/**
+ * Validates the language tag. Section 2.2.9 of the bcp47 spec
+ * defines a valid tag.
+ *
+ * ICU is too permissible and lets invalid tags, like
+ * hant-cmn-cn, through.
+ *
+ * Returns false if the language tag is invalid.
+ */
+function isValidLanguageTag(locale) {
+ // Check if it's well-formed, including grandfadered tags.
+ if (GetLanguageTagRE().test(locale) === false) {
+ return false;
+ }
+
+ // Just return if it's a x- form. It's all private.
+ if (locale.indexOf('x-') === 0) {
+ return true;
+ }
+
+ // Check if there are any duplicate variants or singletons (extensions).
+
+ // Remove private use section.
+ locale = locale.split(/-x-/)[0];
+
+ // Skip language since it can match variant regex, so we start from 1.
+ // We are matching i-klingon here, but that's ok, since i-klingon-klingon
+ // is not valid and would fail LANGUAGE_TAG_RE test.
+ var variants = [];
+ var extensions = [];
+ var parts = locale.split(/-/);
+ for (var i = 1; i < parts.length; i++) {
+ var value = parts[i];
+ if (GetLanguageVariantRE().test(value) === true && extensions.length === 0) {
+ if (variants.indexOf(value) === -1) {
+ variants.push(value);
+ } else {
+ return false;
+ }
+ }
+
+ if (GetLanguageSingletonRE().test(value) === true) {
+ if (extensions.indexOf(value) === -1) {
+ extensions.push(value);
+ } else {
+ return false;
+ }
+ }
+ }
+
+ return true;
+ }
+
+
+/**
+ * Builds a regular expresion that validates the language tag
+ * against bcp47 spec.
+ * Uses http://tools.ietf.org/html/bcp47, section 2.1, ABNF.
+ * Runs on load and initializes the global REs.
+ */
+function BuildLanguageTagREs() {
+ var alpha = '[a-zA-Z]';
+ var digit = '[0-9]';
+ var alphanum = '(' + alpha + '|' + digit + ')';
+ var regular = '(art-lojban|cel-gaulish|no-bok|no-nyn|zh-guoyu|zh-hakka|' +
+ 'zh-min|zh-min-nan|zh-xiang)';
+ var irregular = '(en-GB-oed|i-ami|i-bnn|i-default|i-enochian|i-hak|' +
+ 'i-klingon|i-lux|i-mingo|i-navajo|i-pwn|i-tao|i-tay|' +
+ 'i-tsu|sgn-BE-FR|sgn-BE-NL|sgn-CH-DE)';
+ var grandfathered = '(' + irregular + '|' + regular + ')';
+ var privateUse = '(x(-' + alphanum + '{1,8})+)';
+
+ var singleton = '(' + digit + '|[A-WY-Za-wy-z])';
+ LANGUAGE_SINGLETON_RE = new $RegExp('^' + singleton + '$', 'i');
+
+ var extension = '(' + singleton + '(-' + alphanum + '{2,8})+)';
+
+ var variant = '(' + alphanum + '{5,8}|(' + digit + alphanum + '{3}))';
+ LANGUAGE_VARIANT_RE = new $RegExp('^' + variant + '$', 'i');
+
+ var region = '(' + alpha + '{2}|' + digit + '{3})';
+ var script = '(' + alpha + '{4})';
+ var extLang = '(' + alpha + '{3}(-' + alpha + '{3}){0,2})';
+ var language = '(' + alpha + '{2,3}(-' + extLang + ')?|' + alpha + '{4}|' +
+ alpha + '{5,8})';
+ var langTag = language + '(-' + script + ')?(-' + region + ')?(-' +
+ variant + ')*(-' + extension + ')*(-' + privateUse + ')?';
+
+ var languageTag =
+ '^(' + langTag + '|' + privateUse + '|' + grandfathered + ')$';
+ LANGUAGE_TAG_RE = new $RegExp(languageTag, 'i');
+}
+
+/**
+ * Initializes the given object so it's a valid Collator instance.
+ * Useful for subclassing.
+ */
+function initializeCollator(collator, locales, options) {
+ if (collator.hasOwnProperty('__initializedIntlObject')) {
+ throw new $TypeError('Trying to re-initialize Collator object.');
+ }
+
+ if (options === undefined) {
+ options = {};
+ }
+
+ var getOption = getGetOption(options, 'collator');
+
+ var internalOptions = {};
+
+ defineWEProperty(internalOptions, 'usage', getOption(
+ 'usage', 'string', ['sort', 'search'], 'sort'));
+
+ var sensitivity = getOption('sensitivity', 'string',
+ ['base', 'accent', 'case', 'variant']);
+ if (sensitivity === undefined && internalOptions.usage === 'sort') {
+ sensitivity = 'variant';
+ }
+ defineWEProperty(internalOptions, 'sensitivity', sensitivity);
+
+ defineWEProperty(internalOptions, 'ignorePunctuation', getOption(
+ 'ignorePunctuation', 'boolean', undefined, false));
+
+ var locale = resolveLocale('collator', locales, options);
+
+ // ICU can't take kb, kc... parameters through localeID, so we need to pass
+ // them as options.
+ // One exception is -co- which has to be part of the extension, but only for
+ // usage: sort, and its value can't be 'standard' or 'search'.
+ var extensionMap = parseExtension(locale.extension);
+ setOptions(
+ options, extensionMap, COLLATOR_KEY_MAP, getOption, internalOptions);
+
+ var collation = 'default';
+ var extension = '';
+ if (extensionMap.hasOwnProperty('co') && internalOptions.usage === 'sort') {
+ if (ALLOWED_CO_VALUES.indexOf(extensionMap.co) !== -1) {
+ extension = '-u-co-' + extensionMap.co;
+ // ICU can't tell us what the collation is, so save user's input.
+ collation = extensionMap.co;
+ }
+ } else if (internalOptions.usage === 'search') {
+ extension = '-u-co-search';
+ }
+ defineWEProperty(internalOptions, 'collation', collation);
+
+ var requestedLocale = locale.locale + extension;
+
+ // We define all properties C++ code may produce, to prevent security
+ // problems. If malicious user decides to redefine Object.prototype.locale
+ // we can't just use plain x.locale = 'us' or in C++ Set("locale", "us").
+ // Object.defineProperties will either succeed defining or throw an error.
+ var resolved = $Object.defineProperties({}, {
+ caseFirst: {writable: true},
+ collation: {value: internalOptions.collation, writable: true},
+ ignorePunctuation: {writable: true},
+ locale: {writable: true},
+ numeric: {writable: true},
+ requestedLocale: {value: requestedLocale, writable: true},
+ sensitivity: {writable: true},
+ strength: {writable: true},
+ usage: {value: internalOptions.usage, writable: true}
+ });
+
+ var internalCollator = %CreateCollator(requestedLocale,
+ internalOptions,
+ resolved);
+
+ // Writable, configurable and enumerable are set to false by default.
+ $Object.defineProperty(collator, 'collator', {value: internalCollator});
+ $Object.defineProperty(collator, '__initializedIntlObject',
+ {value: 'collator'});
+ $Object.defineProperty(collator, 'resolved', {value: resolved});
+
+ return collator;
+}
+
+
+/**
+ * Constructs Intl.Collator object given optional locales and options
+ * parameters.
+ *
+ * @constructor
+ */
+%SetProperty(Intl, 'Collator', function() {
+ var locales = arguments[0];
+ var options = arguments[1];
+
+ if (!this || this === Intl) {
+ // Constructor is called as a function.
+ return new Intl.Collator(locales, options);
+ }
+
+ return initializeCollator(toObject(this), locales, options);
+ },
+ DONT_ENUM
+);
+
+
+/**
+ * Collator resolvedOptions method.
+ */
+%SetProperty(Intl.Collator.prototype, 'resolvedOptions', function() {
+ if (%_IsConstructCall()) {
+ throw new $TypeError(ORDINARY_FUNCTION_CALLED_AS_CONSTRUCTOR);
+ }
+
+ if (!this || typeof this !== 'object' ||
+ this.__initializedIntlObject !== 'collator') {
+ throw new $TypeError('resolvedOptions method called on a non-object ' +
+ 'or on a object that is not Intl.Collator.');
+ }
+
+ var coll = this;
+ var locale = getOptimalLanguageTag(coll.resolved.requestedLocale,
+ coll.resolved.locale);
+
+ return {
+ locale: locale,
+ usage: coll.resolved.usage,
+ sensitivity: coll.resolved.sensitivity,
+ ignorePunctuation: coll.resolved.ignorePunctuation,
+ numeric: coll.resolved.numeric,
+ caseFirst: coll.resolved.caseFirst,
+ collation: coll.resolved.collation
+ };
+ },
+ DONT_ENUM
+);
+%FunctionSetName(Intl.Collator.prototype.resolvedOptions, 'resolvedOptions');
+%FunctionRemovePrototype(Intl.Collator.prototype.resolvedOptions);
+%SetNativeFlag(Intl.Collator.prototype.resolvedOptions);
+
+
+/**
+ * Returns the subset of the given locale list for which this locale list
+ * has a matching (possibly fallback) locale. Locales appear in the same
+ * order in the returned list as in the input list.
+ * Options are optional parameter.
+ */
+%SetProperty(Intl.Collator, 'supportedLocalesOf', function(locales) {
+ if (%_IsConstructCall()) {
+ throw new $TypeError(ORDINARY_FUNCTION_CALLED_AS_CONSTRUCTOR);
+ }
+
+ return supportedLocalesOf('collator', locales, arguments[1]);
+ },
+ DONT_ENUM
+);
+%FunctionSetName(Intl.Collator.supportedLocalesOf, 'supportedLocalesOf');
+%FunctionRemovePrototype(Intl.Collator.supportedLocalesOf);
+%SetNativeFlag(Intl.Collator.supportedLocalesOf);
+
+
+/**
+ * When the compare method is called with two arguments x and y, it returns a
+ * Number other than NaN that represents the result of a locale-sensitive
+ * String comparison of x with y.
+ * The result is intended to order String values in the sort order specified
+ * by the effective locale and collation options computed during construction
+ * of this Collator object, and will be negative, zero, or positive, depending
+ * on whether x comes before y in the sort order, the Strings are equal under
+ * the sort order, or x comes after y in the sort order, respectively.
+ */
+function compare(collator, x, y) {
+ return %InternalCompare(collator.collator, $String(x), $String(y));
+};
+
+
+addBoundMethod(Intl.Collator, 'compare', compare, 2);
+
+/**
+ * Verifies that the input is a well-formed ISO 4217 currency code.
+ * Don't uppercase to test. It could convert invalid code into a valid one.
+ * For example \u00DFP (Eszett+P) becomes SSP.
+ */
+function isWellFormedCurrencyCode(currency) {
+ return typeof currency == "string" &&
+ currency.length == 3 &&
+ currency.match(/[^A-Za-z]/) == null;
+}
+
+
+/**
+ * Returns the valid digit count for a property, or throws RangeError on
+ * a value out of the range.
+ */
+function getNumberOption(options, property, min, max, fallback) {
+ var value = options[property];
+ if (value !== undefined) {
+ value = $Number(value);
+ if ($isNaN(value) || value < min || value > max) {
+ throw new $RangeError(property + ' value is out of range.');
+ }
+ return $floor(value);
+ }
+
+ return fallback;
+}
+
+
+/**
+ * Initializes the given object so it's a valid NumberFormat instance.
+ * Useful for subclassing.
+ */
+function initializeNumberFormat(numberFormat, locales, options) {
+ if (numberFormat.hasOwnProperty('__initializedIntlObject')) {
+ throw new $TypeError('Trying to re-initialize NumberFormat object.');
+ }
+
+ if (options === undefined) {
+ options = {};
+ }
+
+ var getOption = getGetOption(options, 'numberformat');
+
+ var locale = resolveLocale('numberformat', locales, options);
+
+ var internalOptions = {};
+ defineWEProperty(internalOptions, 'style', getOption(
+ 'style', 'string', ['decimal', 'percent', 'currency'], 'decimal'));
+
+ var currency = getOption('currency', 'string');
+ if (currency !== undefined && !isWellFormedCurrencyCode(currency)) {
+ throw new $RangeError('Invalid currency code: ' + currency);
+ }
+
+ if (internalOptions.style === 'currency' && currency === undefined) {
+ throw new $TypeError('Currency code is required with currency style.');
+ }
+
+ var currencyDisplay = getOption(
+ 'currencyDisplay', 'string', ['code', 'symbol', 'name'], 'symbol');
+ if (internalOptions.style === 'currency') {
+ defineWEProperty(internalOptions, 'currency', currency.toUpperCase());
+ defineWEProperty(internalOptions, 'currencyDisplay', currencyDisplay);
+ }
+
+ // Digit ranges.
+ var mnid = getNumberOption(options, 'minimumIntegerDigits', 1, 21, 1);
+ defineWEProperty(internalOptions, 'minimumIntegerDigits', mnid);
+
+ var mnfd = getNumberOption(options, 'minimumFractionDigits', 0, 20, 0);
+ defineWEProperty(internalOptions, 'minimumFractionDigits', mnfd);
+
+ var mxfd = getNumberOption(options, 'maximumFractionDigits', mnfd, 20, 3);
+ defineWEProperty(internalOptions, 'maximumFractionDigits', mxfd);
+
+ var mnsd = options['minimumSignificantDigits'];
+ var mxsd = options['maximumSignificantDigits'];
+ if (mnsd !== undefined || mxsd !== undefined) {
+ mnsd = getNumberOption(options, 'minimumSignificantDigits', 1, 21, 0);
+ defineWEProperty(internalOptions, 'minimumSignificantDigits', mnsd);
+
+ mxsd = getNumberOption(options, 'maximumSignificantDigits', mnsd, 21, 21);
+ defineWEProperty(internalOptions, 'maximumSignificantDigits', mxsd);
+ }
+
+ // Grouping.
+ defineWEProperty(internalOptions, 'useGrouping', getOption(
+ 'useGrouping', 'boolean', undefined, true));
+
+ // ICU prefers options to be passed using -u- extension key/values for
+ // number format, so we need to build that.
+ var extensionMap = parseExtension(locale.extension);
+ var extension = setOptions(options, extensionMap, NUMBER_FORMAT_KEY_MAP,
+ getOption, internalOptions);
+
+ var requestedLocale = locale.locale + extension;
+ var resolved = $Object.defineProperties({}, {
+ currency: {writable: true},
+ currencyDisplay: {writable: true},
+ locale: {writable: true},
+ maximumFractionDigits: {writable: true},
+ minimumFractionDigits: {writable: true},
+ minimumIntegerDigits: {writable: true},
+ numberingSystem: {writable: true},
+ requestedLocale: {value: requestedLocale, writable: true},
+ style: {value: internalOptions.style, writable: true},
+ useGrouping: {writable: true}
+ });
+ if (internalOptions.hasOwnProperty('minimumSignificantDigits')) {
+ defineWEProperty(resolved, 'minimumSignificantDigits', undefined);
+ }
+ if (internalOptions.hasOwnProperty('maximumSignificantDigits')) {
+ defineWEProperty(resolved, 'maximumSignificantDigits', undefined);
+ }
+ var formatter = %CreateNumberFormat(requestedLocale,
+ internalOptions,
+ resolved);
+
+ // We can't get information about number or currency style from ICU, so we
+ // assume user request was fulfilled.
+ if (internalOptions.style === 'currency') {
+ $Object.defineProperty(resolved, 'currencyDisplay', {value: currencyDisplay,
+ writable: true});
+ }
+
+ $Object.defineProperty(numberFormat, 'formatter', {value: formatter});
+ $Object.defineProperty(numberFormat, 'resolved', {value: resolved});
+ $Object.defineProperty(numberFormat, '__initializedIntlObject',
+ {value: 'numberformat'});
+
+ return numberFormat;
+}
+
+
+/**
+ * Constructs Intl.NumberFormat object given optional locales and options
+ * parameters.
+ *
+ * @constructor
+ */
+%SetProperty(Intl, 'NumberFormat', function() {
+ var locales = arguments[0];
+ var options = arguments[1];
+
+ if (!this || this === Intl) {
+ // Constructor is called as a function.
+ return new Intl.NumberFormat(locales, options);
+ }
+
+ return initializeNumberFormat(toObject(this), locales, options);
+ },
+ DONT_ENUM
+);
+
+
+/**
+ * NumberFormat resolvedOptions method.
+ */
+%SetProperty(Intl.NumberFormat.prototype, 'resolvedOptions', function() {
+ if (%_IsConstructCall()) {
+ throw new $TypeError(ORDINARY_FUNCTION_CALLED_AS_CONSTRUCTOR);
+ }
+
+ if (!this || typeof this !== 'object' ||
+ this.__initializedIntlObject !== 'numberformat') {
+ throw new $TypeError('resolvedOptions method called on a non-object' +
+ ' or on a object that is not Intl.NumberFormat.');
+ }
+
+ var format = this;
+ var locale = getOptimalLanguageTag(format.resolved.requestedLocale,
+ format.resolved.locale);
+
+ var result = {
+ locale: locale,
+ numberingSystem: format.resolved.numberingSystem,
+ style: format.resolved.style,
+ useGrouping: format.resolved.useGrouping,
+ minimumIntegerDigits: format.resolved.minimumIntegerDigits,
+ minimumFractionDigits: format.resolved.minimumFractionDigits,
+ maximumFractionDigits: format.resolved.maximumFractionDigits,
+ };
+
+ if (result.style === 'currency') {
+ defineWECProperty(result, 'currency', format.resolved.currency);
+ defineWECProperty(result, 'currencyDisplay',
+ format.resolved.currencyDisplay);
+ }
+
+ if (format.resolved.hasOwnProperty('minimumSignificantDigits')) {
+ defineWECProperty(result, 'minimumSignificantDigits',
+ format.resolved.minimumSignificantDigits);
+ }
+
+ if (format.resolved.hasOwnProperty('maximumSignificantDigits')) {
+ defineWECProperty(result, 'maximumSignificantDigits',
+ format.resolved.maximumSignificantDigits);
+ }
+
+ return result;
+ },
+ DONT_ENUM
+);
+%FunctionSetName(Intl.NumberFormat.prototype.resolvedOptions,
+ 'resolvedOptions');
+%FunctionRemovePrototype(Intl.NumberFormat.prototype.resolvedOptions);
+%SetNativeFlag(Intl.NumberFormat.prototype.resolvedOptions);
+
+
+/**
+ * Returns the subset of the given locale list for which this locale list
+ * has a matching (possibly fallback) locale. Locales appear in the same
+ * order in the returned list as in the input list.
+ * Options are optional parameter.
+ */
+%SetProperty(Intl.NumberFormat, 'supportedLocalesOf', function(locales) {
+ if (%_IsConstructCall()) {
+ throw new $TypeError(ORDINARY_FUNCTION_CALLED_AS_CONSTRUCTOR);
+ }
+
+ return supportedLocalesOf('numberformat', locales, arguments[1]);
+ },
+ DONT_ENUM
+);
+%FunctionSetName(Intl.NumberFormat.supportedLocalesOf, 'supportedLocalesOf');
+%FunctionRemovePrototype(Intl.NumberFormat.supportedLocalesOf);
+%SetNativeFlag(Intl.NumberFormat.supportedLocalesOf);
+
+
+/**
+ * Returns a String value representing the result of calling ToNumber(value)
+ * according to the effective locale and the formatting options of this
+ * NumberFormat.
+ */
+function formatNumber(formatter, value) {
+ // Spec treats -0 and +0 as 0.
+ var number = $Number(value);
+ if (number === -0) {
+ number = 0;
+ }
+
+ return %InternalNumberFormat(formatter.formatter, number);
+}
+
+
+/**
+ * Returns a Number that represents string value that was passed in.
+ */
+function parseNumber(formatter, value) {
+ return %InternalNumberParse(formatter.formatter, $String(value));
+}
+
+
+addBoundMethod(Intl.NumberFormat, 'format', formatNumber, 1);
+addBoundMethod(Intl.NumberFormat, 'v8Parse', parseNumber, 1);
+
+/**
+ * Returns a string that matches LDML representation of the options object.
+ */
+function toLDMLString(options) {
+ var getOption = getGetOption(options, 'dateformat');
+
+ var ldmlString = '';
+
+ var option = getOption('weekday', 'string', ['narrow', 'short', 'long']);
+ ldmlString += appendToLDMLString(
+ option, {narrow: 'EEEEE', short: 'EEE', long: 'EEEE'});
+
+ option = getOption('era', 'string', ['narrow', 'short', 'long']);
+ ldmlString += appendToLDMLString(
+ option, {narrow: 'GGGGG', short: 'GGG', long: 'GGGG'});
+
+ option = getOption('year', 'string', ['2-digit', 'numeric']);
+ ldmlString += appendToLDMLString(option, {'2-digit': 'yy', 'numeric': 'y'});
+
+ option = getOption('month', 'string',
+ ['2-digit', 'numeric', 'narrow', 'short', 'long']);
+ ldmlString += appendToLDMLString(option, {'2-digit': 'MM', 'numeric': 'M',
+ 'narrow': 'MMMMM', 'short': 'MMM', 'long': 'MMMM'});
+
+ option = getOption('day', 'string', ['2-digit', 'numeric']);
+ ldmlString += appendToLDMLString(
+ option, {'2-digit': 'dd', 'numeric': 'd'});
+
+ var hr12 = getOption('hour12', 'boolean');
+ option = getOption('hour', 'string', ['2-digit', 'numeric']);
+ if (hr12 === undefined) {
+ ldmlString += appendToLDMLString(option, {'2-digit': 'jj', 'numeric': 'j'});
+ } else if (hr12 === true) {
+ ldmlString += appendToLDMLString(option, {'2-digit': 'hh', 'numeric': 'h'});
+ } else {
+ ldmlString += appendToLDMLString(option, {'2-digit': 'HH', 'numeric': 'H'});
+ }
+
+ option = getOption('minute', 'string', ['2-digit', 'numeric']);
+ ldmlString += appendToLDMLString(option, {'2-digit': 'mm', 'numeric': 'm'});
+
+ option = getOption('second', 'string', ['2-digit', 'numeric']);
+ ldmlString += appendToLDMLString(option, {'2-digit': 'ss', 'numeric': 's'});
+
+ option = getOption('timeZoneName', 'string', ['short', 'long']);
+ ldmlString += appendToLDMLString(option, {short: 'v', long: 'vv'});
+
+ return ldmlString;
+}
+
+
+/**
+ * Returns either LDML equivalent of the current option or empty string.
+ */
+function appendToLDMLString(option, pairs) {
+ if (option !== undefined) {
+ return pairs[option];
+ } else {
+ return '';
+ }
+}
+
+
+/**
+ * Returns object that matches LDML representation of the date.
+ */
+function fromLDMLString(ldmlString) {
+ // First remove '' quoted text, so we lose 'Uhr' strings.
+ ldmlString = ldmlString.replace(GetQuotedStringRE(), '');
+
+ var options = {};
+ var match = ldmlString.match(/E{3,5}/g);
+ options = appendToDateTimeObject(
+ options, 'weekday', match, {EEEEE: 'narrow', EEE: 'short', EEEE: 'long'});
+
+ match = ldmlString.match(/G{3,5}/g);
+ options = appendToDateTimeObject(
+ options, 'era', match, {GGGGG: 'narrow', GGG: 'short', GGGG: 'long'});
+
+ match = ldmlString.match(/y{1,2}/g);
+ options = appendToDateTimeObject(
+ options, 'year', match, {y: 'numeric', yy: '2-digit'});
+
+ match = ldmlString.match(/M{1,5}/g);
+ options = appendToDateTimeObject(options, 'month', match, {MM: '2-digit',
+ M: 'numeric', MMMMM: 'narrow', MMM: 'short', MMMM: 'long'});
+
+ // Sometimes we get L instead of M for month - standalone name.
+ match = ldmlString.match(/L{1,5}/g);
+ options = appendToDateTimeObject(options, 'month', match, {LL: '2-digit',
+ L: 'numeric', LLLLL: 'narrow', LLL: 'short', LLLL: 'long'});
+
+ match = ldmlString.match(/d{1,2}/g);
+ options = appendToDateTimeObject(
+ options, 'day', match, {d: 'numeric', dd: '2-digit'});
+
+ match = ldmlString.match(/h{1,2}/g);
+ if (match !== null) {
+ options['hour12'] = true;
+ }
+ options = appendToDateTimeObject(
+ options, 'hour', match, {h: 'numeric', hh: '2-digit'});
+
+ match = ldmlString.match(/H{1,2}/g);
+ if (match !== null) {
+ options['hour12'] = false;
+ }
+ options = appendToDateTimeObject(
+ options, 'hour', match, {H: 'numeric', HH: '2-digit'});
+
+ match = ldmlString.match(/m{1,2}/g);
+ options = appendToDateTimeObject(
+ options, 'minute', match, {m: 'numeric', mm: '2-digit'});
+
+ match = ldmlString.match(/s{1,2}/g);
+ options = appendToDateTimeObject(
+ options, 'second', match, {s: 'numeric', ss: '2-digit'});
+
+ match = ldmlString.match(/v{1,2}/g);
+ options = appendToDateTimeObject(
+ options, 'timeZoneName', match, {v: 'short', vv: 'long'});
+
+ return options;
+}
+
+
+function appendToDateTimeObject(options, option, match, pairs) {
+ if (match === null) {
+ if (!options.hasOwnProperty(option)) {
+ defineWEProperty(options, option, undefined);
+ }
+ return options;
+ }
+
+ var property = match[0];
+ defineWEProperty(options, option, pairs[property]);
+
+ return options;
+}
+
+
+/**
+ * Returns options with at least default values in it.
+ */
+function toDateTimeOptions(options, required, defaults) {
+ if (options === undefined) {
+ options = null;
+ } else {
+ options = toObject(options);
+ }
+
+ options = $Object.apply(this, [options]);
+
+ var needsDefault = true;
+ if ((required === 'date' || required === 'any') &&
+ (options.weekday !== undefined || options.year !== undefined ||
+ options.month !== undefined || options.day !== undefined)) {
+ needsDefault = false;
+ }
+
+ if ((required === 'time' || required === 'any') &&
+ (options.hour !== undefined || options.minute !== undefined ||
+ options.second !== undefined)) {
+ needsDefault = false;
+ }
+
+ if (needsDefault && (defaults === 'date' || defaults === 'all')) {
+ $Object.defineProperty(options, 'year', {value: 'numeric',
+ writable: true,
+ enumerable: true,
+ configurable: true});
+ $Object.defineProperty(options, 'month', {value: 'numeric',
+ writable: true,
+ enumerable: true,
+ configurable: true});
+ $Object.defineProperty(options, 'day', {value: 'numeric',
+ writable: true,
+ enumerable: true,
+ configurable: true});
+ }
+
+ if (needsDefault && (defaults === 'time' || defaults === 'all')) {
+ $Object.defineProperty(options, 'hour', {value: 'numeric',
+ writable: true,
+ enumerable: true,
+ configurable: true});
+ $Object.defineProperty(options, 'minute', {value: 'numeric',
+ writable: true,
+ enumerable: true,
+ configurable: true});
+ $Object.defineProperty(options, 'second', {value: 'numeric',
+ writable: true,
+ enumerable: true,
+ configurable: true});
+ }
+
+ return options;
+}
+
+
+/**
+ * Initializes the given object so it's a valid DateTimeFormat instance.
+ * Useful for subclassing.
+ */
+function initializeDateTimeFormat(dateFormat, locales, options) {
+
+ if (dateFormat.hasOwnProperty('__initializedIntlObject')) {
+ throw new $TypeError('Trying to re-initialize DateTimeFormat object.');
+ }
+
+ if (options === undefined) {
+ options = {};
+ }
+
+ var locale = resolveLocale('dateformat', locales, options);
+
+ options = toDateTimeOptions(options, 'any', 'date');
+
+ var getOption = getGetOption(options, 'dateformat');
+
+ // We implement only best fit algorithm, but still need to check
+ // if the formatMatcher values are in range.
+ var matcher = getOption('formatMatcher', 'string',
+ ['basic', 'best fit'], 'best fit');
+
+ // Build LDML string for the skeleton that we pass to the formatter.
+ var ldmlString = toLDMLString(options);
+
+ // Filter out supported extension keys so we know what to put in resolved
+ // section later on.
+ // We need to pass calendar and number system to the method.
+ var tz = canonicalizeTimeZoneID(options.timeZone);
+
+ // ICU prefers options to be passed using -u- extension key/values, so
+ // we need to build that.
+ var internalOptions = {};
+ var extensionMap = parseExtension(locale.extension);
+ var extension = setOptions(options, extensionMap, DATETIME_FORMAT_KEY_MAP,
+ getOption, internalOptions);
+
+ var requestedLocale = locale.locale + extension;
+ var resolved = $Object.defineProperties({}, {
+ calendar: {writable: true},
+ day: {writable: true},
+ era: {writable: true},
+ hour12: {writable: true},
+ hour: {writable: true},
+ locale: {writable: true},
+ minute: {writable: true},
+ month: {writable: true},
+ numberingSystem: {writable: true},
+ pattern: {writable: true},
+ requestedLocale: {value: requestedLocale, writable: true},
+ second: {writable: true},
+ timeZone: {writable: true},
+ timeZoneName: {writable: true},
+ tz: {value: tz, writable: true},
+ weekday: {writable: true},
+ year: {writable: true}
+ });
+
+ var formatter = %CreateDateTimeFormat(
+ requestedLocale, {skeleton: ldmlString, timeZone: tz}, resolved);
+
+ if (tz !== undefined && tz !== resolved.timeZone) {
+ throw new $RangeError('Unsupported time zone specified ' + tz);
+ }
+
+ $Object.defineProperty(dateFormat, 'formatter', {value: formatter});
+ $Object.defineProperty(dateFormat, 'resolved', {value: resolved});
+ $Object.defineProperty(dateFormat, '__initializedIntlObject',
+ {value: 'dateformat'});
+
+ return dateFormat;
+}
+
+
+/**
+ * Constructs Intl.DateTimeFormat object given optional locales and options
+ * parameters.
+ *
+ * @constructor
+ */
+%SetProperty(Intl, 'DateTimeFormat', function() {
+ var locales = arguments[0];
+ var options = arguments[1];
+
+ if (!this || this === Intl) {
+ // Constructor is called as a function.
+ return new Intl.DateTimeFormat(locales, options);
+ }
+
+ return initializeDateTimeFormat(toObject(this), locales, options);
+ },
+ DONT_ENUM
+);
+
+
+/**
+ * DateTimeFormat resolvedOptions method.
+ */
+%SetProperty(Intl.DateTimeFormat.prototype, 'resolvedOptions', function() {
+ if (%_IsConstructCall()) {
+ throw new $TypeError(ORDINARY_FUNCTION_CALLED_AS_CONSTRUCTOR);
+ }
+
+ if (!this || typeof this !== 'object' ||
+ this.__initializedIntlObject !== 'dateformat') {
+ throw new $TypeError('resolvedOptions method called on a non-object or ' +
+ 'on a object that is not Intl.DateTimeFormat.');
+ }
+
+ var format = this;
+ var fromPattern = fromLDMLString(format.resolved.pattern);
+ var userCalendar = ICU_CALENDAR_MAP[format.resolved.calendar];
+ if (userCalendar === undefined) {
+ // Use ICU name if we don't have a match. It shouldn't happen, but
+ // it would be too strict to throw for this.
+ userCalendar = format.resolved.calendar;
+ }
+
+ var locale = getOptimalLanguageTag(format.resolved.requestedLocale,
+ format.resolved.locale);
+
+ var result = {
+ locale: locale,
+ numberingSystem: format.resolved.numberingSystem,
+ calendar: userCalendar,
+ timeZone: format.resolved.timeZone
+ };
+
+ addWECPropertyIfDefined(result, 'timeZoneName', fromPattern.timeZoneName);
+ addWECPropertyIfDefined(result, 'era', fromPattern.era);
+ addWECPropertyIfDefined(result, 'year', fromPattern.year);
+ addWECPropertyIfDefined(result, 'month', fromPattern.month);
+ addWECPropertyIfDefined(result, 'day', fromPattern.day);
+ addWECPropertyIfDefined(result, 'weekday', fromPattern.weekday);
+ addWECPropertyIfDefined(result, 'hour12', fromPattern.hour12);
+ addWECPropertyIfDefined(result, 'hour', fromPattern.hour);
+ addWECPropertyIfDefined(result, 'minute', fromPattern.minute);
+ addWECPropertyIfDefined(result, 'second', fromPattern.second);
+
+ return result;
+ },
+ DONT_ENUM
+);
+%FunctionSetName(Intl.DateTimeFormat.prototype.resolvedOptions,
+ 'resolvedOptions');
+%FunctionRemovePrototype(Intl.DateTimeFormat.prototype.resolvedOptions);
+%SetNativeFlag(Intl.DateTimeFormat.prototype.resolvedOptions);
+
+
+/**
+ * Returns the subset of the given locale list for which this locale list
+ * has a matching (possibly fallback) locale. Locales appear in the same
+ * order in the returned list as in the input list.
+ * Options are optional parameter.
+ */
+%SetProperty(Intl.DateTimeFormat, 'supportedLocalesOf', function(locales) {
+ if (%_IsConstructCall()) {
+ throw new $TypeError(ORDINARY_FUNCTION_CALLED_AS_CONSTRUCTOR);
+ }
+
+ return supportedLocalesOf('dateformat', locales, arguments[1]);
+ },
+ DONT_ENUM
+);
+%FunctionSetName(Intl.DateTimeFormat.supportedLocalesOf, 'supportedLocalesOf');
+%FunctionRemovePrototype(Intl.DateTimeFormat.supportedLocalesOf);
+%SetNativeFlag(Intl.DateTimeFormat.supportedLocalesOf);
+
+
+/**
+ * Returns a String value representing the result of calling ToNumber(date)
+ * according to the effective locale and the formatting options of this
+ * DateTimeFormat.
+ */
+function formatDate(formatter, dateValue) {
+ var dateMs;
+ if (dateValue === undefined) {
+ dateMs = $Date.now();
+ } else {
+ dateMs = $Number(dateValue);
+ }
+
+ if (!$isFinite(dateMs)) {
+ throw new $RangeError('Provided date is not in valid range.');
+ }
+
+ return %InternalDateFormat(formatter.formatter, new $Date(dateMs));
+}
+
+
+/**
+ * Returns a Date object representing the result of calling ToString(value)
+ * according to the effective locale and the formatting options of this
+ * DateTimeFormat.
+ * Returns undefined if date string cannot be parsed.
+ */
+function parseDate(formatter, value) {
+ return %InternalDateParse(formatter.formatter, $String(value));
+}
+
+
+// 0 because date is optional argument.
+addBoundMethod(Intl.DateTimeFormat, 'format', formatDate, 0);
+addBoundMethod(Intl.DateTimeFormat, 'v8Parse', parseDate, 1);
+
+
+/**
+ * Returns canonical Area/Location name, or throws an exception if the zone
+ * name is invalid IANA name.
+ */
+function canonicalizeTimeZoneID(tzID) {
+ // Skip undefined zones.
+ if (tzID === undefined) {
+ return tzID;
+ }
+
+ // Special case handling (UTC, GMT).
+ var upperID = tzID.toUpperCase();
+ if (upperID === 'UTC' || upperID === 'GMT' ||
+ upperID === 'ETC/UTC' || upperID === 'ETC/GMT') {
+ return 'UTC';
+ }
+
+ // We expect only _ and / beside ASCII letters.
+ // All inputs should conform to Area/Location from now on.
+ var match = GetTimezoneNameCheckRE().exec(tzID);
+ if (match === null) {
+ throw new $RangeError('Expected Area/Location for time zone, got ' + tzID);
+ }
+
+ var result = toTitleCaseWord(match[1]) + '/' + toTitleCaseWord(match[2]);
+ var i = 3;
+ while (match[i] !== undefined && i < match.length) {
+ result = result + '_' + toTitleCaseWord(match[i]);
+ i++;
+ }
+
+ return result;
+}
+
+/**
+ * Initializes the given object so it's a valid BreakIterator instance.
+ * Useful for subclassing.
+ */
+function initializeBreakIterator(iterator, locales, options) {
+ if (iterator.hasOwnProperty('__initializedIntlObject')) {
+ throw new $TypeError('Trying to re-initialize v8BreakIterator object.');
+ }
+
+ if (options === undefined) {
+ options = {};
+ }
+
+ var getOption = getGetOption(options, 'breakiterator');
+
+ var internalOptions = {};
+
+ defineWEProperty(internalOptions, 'type', getOption(
+ 'type', 'string', ['character', 'word', 'sentence', 'line'], 'word'));
+
+ var locale = resolveLocale('breakiterator', locales, options);
+ var resolved = $Object.defineProperties({}, {
+ requestedLocale: {value: locale.locale, writable: true},
+ type: {value: internalOptions.type, writable: true},
+ locale: {writable: true}
+ });
+
+ var internalIterator = %CreateBreakIterator(locale.locale,
+ internalOptions,
+ resolved);
+
+ $Object.defineProperty(iterator, 'iterator', {value: internalIterator});
+ $Object.defineProperty(iterator, 'resolved', {value: resolved});
+ $Object.defineProperty(iterator, '__initializedIntlObject',
+ {value: 'breakiterator'});
+
+ return iterator;
+}
+
+
+/**
+ * Constructs Intl.v8BreakIterator object given optional locales and options
+ * parameters.
+ *
+ * @constructor
+ */
+%SetProperty(Intl, 'v8BreakIterator', function() {
+ var locales = arguments[0];
+ var options = arguments[1];
+
+ if (!this || this === Intl) {
+ // Constructor is called as a function.
+ return new Intl.v8BreakIterator(locales, options);
+ }
+
+ return initializeBreakIterator(toObject(this), locales, options);
+ },
+ DONT_ENUM
+);
+
+
+/**
+ * BreakIterator resolvedOptions method.
+ */
+%SetProperty(Intl.v8BreakIterator.prototype, 'resolvedOptions', function() {
+ if (%_IsConstructCall()) {
+ throw new $TypeError(ORDINARY_FUNCTION_CALLED_AS_CONSTRUCTOR);
+ }
+
+ if (!this || typeof this !== 'object' ||
+ this.__initializedIntlObject !== 'breakiterator') {
+ throw new $TypeError('resolvedOptions method called on a non-object or ' +
+ 'on a object that is not Intl.v8BreakIterator.');
+ }
+
+ var segmenter = this;
+ var locale = getOptimalLanguageTag(segmenter.resolved.requestedLocale,
+ segmenter.resolved.locale);
+
+ return {
+ locale: locale,
+ type: segmenter.resolved.type
+ };
+ },
+ DONT_ENUM
+);
+%FunctionSetName(Intl.v8BreakIterator.prototype.resolvedOptions,
+ 'resolvedOptions');
+%FunctionRemovePrototype(Intl.v8BreakIterator.prototype.resolvedOptions);
+%SetNativeFlag(Intl.v8BreakIterator.prototype.resolvedOptions);
+
+
+/**
+ * Returns the subset of the given locale list for which this locale list
+ * has a matching (possibly fallback) locale. Locales appear in the same
+ * order in the returned list as in the input list.
+ * Options are optional parameter.
+ */
+%SetProperty(Intl.v8BreakIterator, 'supportedLocalesOf', function(locales) {
+ if (%_IsConstructCall()) {
+ throw new $TypeError(ORDINARY_FUNCTION_CALLED_AS_CONSTRUCTOR);
+ }
+
+ return supportedLocalesOf('breakiterator', locales, arguments[1]);
+ },
+ DONT_ENUM
+);
+%FunctionSetName(Intl.v8BreakIterator.supportedLocalesOf, 'supportedLocalesOf');
+%FunctionRemovePrototype(Intl.v8BreakIterator.supportedLocalesOf);
+%SetNativeFlag(Intl.v8BreakIterator.supportedLocalesOf);
+
+
+/**
+ * Adopts text to segment using the iterator. Old text, if present,
+ * gets discarded.
+ */
+function adoptText(iterator, text) {
+ %BreakIteratorAdoptText(iterator.iterator, $String(text));
+}
+
+
+/**
+ * Returns index of the first break in the string and moves current pointer.
+ */
+function first(iterator) {
+ return %BreakIteratorFirst(iterator.iterator);
+}
+
+
+/**
+ * Returns the index of the next break and moves the pointer.
+ */
+function next(iterator) {
+ return %BreakIteratorNext(iterator.iterator);
+}
+
+
+/**
+ * Returns index of the current break.
+ */
+function current(iterator) {
+ return %BreakIteratorCurrent(iterator.iterator);
+}
+
+
+/**
+ * Returns type of the current break.
+ */
+function breakType(iterator) {
+ return %BreakIteratorBreakType(iterator.iterator);
+}
+
+
+addBoundMethod(Intl.v8BreakIterator, 'adoptText', adoptText, 1);
+addBoundMethod(Intl.v8BreakIterator, 'first', first, 0);
+addBoundMethod(Intl.v8BreakIterator, 'next', next, 0);
+addBoundMethod(Intl.v8BreakIterator, 'current', current, 0);
+addBoundMethod(Intl.v8BreakIterator, 'breakType', breakType, 0);
+
+// Save references to Intl objects and methods we use, for added security.
+var savedObjects = {
+ 'collator': Intl.Collator,
+ 'numberformat': Intl.NumberFormat,
+ 'dateformatall': Intl.DateTimeFormat,
+ 'dateformatdate': Intl.DateTimeFormat,
+ 'dateformattime': Intl.DateTimeFormat
+};
+
+
+// Default (created with undefined locales and options parameters) collator,
+// number and date format instances. They'll be created as needed.
+var defaultObjects = {
+ 'collator': undefined,
+ 'numberformat': undefined,
+ 'dateformatall': undefined,
+ 'dateformatdate': undefined,
+ 'dateformattime': undefined,
+};
+
+
+/**
+ * Returns cached or newly created instance of a given service.
+ * We cache only default instances (where no locales or options are provided).
+ */
+function cachedOrNewService(service, locales, options, defaults) {
+ var useOptions = (defaults === undefined) ? options : defaults;
+ if (locales === undefined && options === undefined) {
+ if (defaultObjects[service] === undefined) {
+ defaultObjects[service] = new savedObjects[service](locales, useOptions);
+ }
+ return defaultObjects[service];
+ }
+ return new savedObjects[service](locales, useOptions);
+}
+
+
+/**
+ * Compares this and that, and returns less than 0, 0 or greater than 0 value.
+ * Overrides the built-in method.
+ */
+$Object.defineProperty($String.prototype, 'localeCompare', {
+ value: function(that) {
+ if (%_IsConstructCall()) {
+ throw new $TypeError(ORDINARY_FUNCTION_CALLED_AS_CONSTRUCTOR);
+ }
+
+ if (this === undefined || this === null) {
+ throw new $TypeError('Method invoked on undefined or null value.');
+ }
+
+ var locales = arguments[1];
+ var options = arguments[2];
+ var collator = cachedOrNewService('collator', locales, options);
+ return compare(collator, this, that);
+ },
+ writable: true,
+ configurable: true,
+ enumerable: false
+});
+%FunctionSetName($String.prototype.localeCompare, 'localeCompare');
+%FunctionRemovePrototype($String.prototype.localeCompare);
+%SetNativeFlag($String.prototype.localeCompare);
+
+
+/**
+ * Formats a Number object (this) using locale and options values.
+ * If locale or options are omitted, defaults are used.
+ */
+$Object.defineProperty($Number.prototype, 'toLocaleString', {
+ value: function() {
+ if (%_IsConstructCall()) {
+ throw new $TypeError(ORDINARY_FUNCTION_CALLED_AS_CONSTRUCTOR);
+ }
+
+ if (!(this instanceof $Number) && typeof(this) !== 'number') {
+ throw new $TypeError('Method invoked on an object that is not Number.');
+ }
+
+ var locales = arguments[0];
+ var options = arguments[1];
+ var numberFormat = cachedOrNewService('numberformat', locales, options);
+ return formatNumber(numberFormat, this);
+ },
+ writable: true,
+ configurable: true,
+ enumerable: false
+});
+%FunctionSetName($Number.prototype.toLocaleString, 'toLocaleString');
+%FunctionRemovePrototype($Number.prototype.toLocaleString);
+%SetNativeFlag($Number.prototype.toLocaleString);
+
+
+/**
+ * Returns actual formatted date or fails if date parameter is invalid.
+ */
+function toLocaleDateTime(date, locales, options, required, defaults, service) {
+ if (!(date instanceof $Date)) {
+ throw new $TypeError('Method invoked on an object that is not Date.');
+ }
+
+ if ($isNaN(date)) {
+ return 'Invalid Date';
+ }
+
+ var internalOptions = toDateTimeOptions(options, required, defaults);
+
+ var dateFormat =
+ cachedOrNewService(service, locales, options, internalOptions);
+
+ return formatDate(dateFormat, date);
+}
+
+
+/**
+ * Formats a Date object (this) using locale and options values.
+ * If locale or options are omitted, defaults are used - both date and time are
+ * present in the output.
+ */
+$Object.defineProperty($Date.prototype, 'toLocaleString', {
+ value: function() {
+ if (%_IsConstructCall()) {
+ throw new $TypeError(ORDINARY_FUNCTION_CALLED_AS_CONSTRUCTOR);
+ }
+
+ var locales = arguments[0];
+ var options = arguments[1];
+ return toLocaleDateTime(
+ this, locales, options, 'any', 'all', 'dateformatall');
+ },
+ writable: true,
+ configurable: true,
+ enumerable: false
+});
+%FunctionSetName($Date.prototype.toLocaleString, 'toLocaleString');
+%FunctionRemovePrototype($Date.prototype.toLocaleString);
+%SetNativeFlag($Date.prototype.toLocaleString);
+
+
+/**
+ * Formats a Date object (this) using locale and options values.
+ * If locale or options are omitted, defaults are used - only date is present
+ * in the output.
+ */
+$Object.defineProperty($Date.prototype, 'toLocaleDateString', {
+ value: function() {
+ if (%_IsConstructCall()) {
+ throw new $TypeError(ORDINARY_FUNCTION_CALLED_AS_CONSTRUCTOR);
+ }
+
+ var locales = arguments[0];
+ var options = arguments[1];
+ return toLocaleDateTime(
+ this, locales, options, 'date', 'date', 'dateformatdate');
+ },
+ writable: true,
+ configurable: true,
+ enumerable: false
+});
+%FunctionSetName($Date.prototype.toLocaleDateString, 'toLocaleDateString');
+%FunctionRemovePrototype($Date.prototype.toLocaleDateString);
+%SetNativeFlag($Date.prototype.toLocaleDateString);
+
+
+/**
+ * Formats a Date object (this) using locale and options values.
+ * If locale or options are omitted, defaults are used - only time is present
+ * in the output.
+ */
+$Object.defineProperty($Date.prototype, 'toLocaleTimeString', {
+ value: function() {
+ if (%_IsConstructCall()) {
+ throw new $TypeError(ORDINARY_FUNCTION_CALLED_AS_CONSTRUCTOR);
+ }
+
+ var locales = arguments[0];
+ var options = arguments[1];
+ return toLocaleDateTime(
+ this, locales, options, 'time', 'time', 'dateformattime');
+ },
+ writable: true,
+ configurable: true,
+ enumerable: false
+});
+%FunctionSetName($Date.prototype.toLocaleTimeString, 'toLocaleTimeString');
+%FunctionRemovePrototype($Date.prototype.toLocaleTimeString);
+%SetNativeFlag($Date.prototype.toLocaleTimeString);
+
+return Intl;
+}())});
diff --git a/src/ia32/builtins-ia32.cc b/src/ia32/builtins-ia32.cc
index 5f5d397..a159748 100644
--- a/src/ia32/builtins-ia32.cc
+++ b/src/ia32/builtins-ia32.cc
@@ -74,6 +74,24 @@
}
+static void CallRuntimePassFunction(MacroAssembler* masm,
+ Runtime::FunctionId function_id) {
+ FrameScope scope(masm, StackFrame::INTERNAL);
+ // Push a copy of the function.
+ __ push(edi);
+ // Push call kind information.
+ __ push(ecx);
+ // Function is also the parameter to the runtime call.
+ __ push(edi);
+
+ __ CallRuntime(function_id, 1);
+ // Restore call kind information.
+ __ pop(ecx);
+ // Restore receiver.
+ __ pop(edi);
+}
+
+
static void GenerateTailCallToSharedCode(MacroAssembler* masm) {
__ mov(eax, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
__ mov(eax, FieldOperand(eax, SharedFunctionInfo::kCodeOffset));
@@ -83,56 +101,29 @@
void Builtins::Generate_InRecompileQueue(MacroAssembler* masm) {
+ // Checking whether the queued function is ready for install is optional,
+ // since we come across interrupts and stack checks elsewhere. However,
+ // not checking may delay installing ready functions, and always checking
+ // would be quite expensive. A good compromise is to first check against
+ // stack limit as a cue for an interrupt signal.
+ Label ok;
+ ExternalReference stack_limit =
+ ExternalReference::address_of_stack_limit(masm->isolate());
+ __ cmp(esp, Operand::StaticVariable(stack_limit));
+ __ j(above_equal, &ok, Label::kNear);
+
+ CallRuntimePassFunction(masm, Runtime::kTryInstallRecompiledCode);
+ // Tail call to returned code.
+ __ lea(eax, FieldOperand(eax, Code::kHeaderSize));
+ __ jmp(eax);
+
+ __ bind(&ok);
GenerateTailCallToSharedCode(masm);
}
-void Builtins::Generate_InstallRecompiledCode(MacroAssembler* masm) {
- {
- FrameScope scope(masm, StackFrame::INTERNAL);
-
- // Push a copy of the function.
- __ push(edi);
- // Push call kind information.
- __ push(ecx);
-
- __ push(edi); // Function is also the parameter to the runtime call.
- __ CallRuntime(Runtime::kInstallRecompiledCode, 1);
-
- // Restore call kind information.
- __ pop(ecx);
- // Restore receiver.
- __ pop(edi);
-
- // Tear down internal frame.
- }
-
- // Do a tail-call of the compiled function.
- __ lea(eax, FieldOperand(eax, Code::kHeaderSize));
- __ jmp(eax);
-}
-
-
void Builtins::Generate_ConcurrentRecompile(MacroAssembler* masm) {
- {
- FrameScope scope(masm, StackFrame::INTERNAL);
-
- // Push a copy of the function onto the stack.
- __ push(edi);
- // Push call kind information.
- __ push(ecx);
-
- __ push(edi); // Function is also the parameter to the runtime call.
- __ CallRuntime(Runtime::kConcurrentRecompile, 1);
-
- // Restore call kind information.
- __ pop(ecx);
- // Restore receiver.
- __ pop(edi);
-
- // Tear down internal frame.
- }
-
+ CallRuntimePassFunction(masm, Runtime::kConcurrentRecompile);
GenerateTailCallToSharedCode(masm);
}
@@ -519,25 +510,7 @@
void Builtins::Generate_LazyCompile(MacroAssembler* masm) {
- {
- FrameScope scope(masm, StackFrame::INTERNAL);
-
- // Push a copy of the function.
- __ push(edi);
- // Push call kind information.
- __ push(ecx);
-
- __ push(edi); // Function is also the parameter to the runtime call.
- __ CallRuntime(Runtime::kLazyCompile, 1);
-
- // Restore call kind information.
- __ pop(ecx);
- // Restore receiver.
- __ pop(edi);
-
- // Tear down internal frame.
- }
-
+ CallRuntimePassFunction(masm, Runtime::kLazyCompile);
// Do a tail-call of the compiled function.
__ lea(eax, FieldOperand(eax, Code::kHeaderSize));
__ jmp(eax);
@@ -545,25 +518,7 @@
void Builtins::Generate_LazyRecompile(MacroAssembler* masm) {
- {
- FrameScope scope(masm, StackFrame::INTERNAL);
-
- // Push a copy of the function onto the stack.
- __ push(edi);
- // Push call kind information.
- __ push(ecx);
-
- __ push(edi); // Function is also the parameter to the runtime call.
- __ CallRuntime(Runtime::kLazyRecompile, 1);
-
- // Restore call kind information.
- __ pop(ecx);
- // Restore receiver.
- __ pop(edi);
-
- // Tear down internal frame.
- }
-
+ CallRuntimePassFunction(masm, Runtime::kLazyRecompile);
// Do a tail-call of the compiled function.
__ lea(eax, FieldOperand(eax, Code::kHeaderSize));
__ jmp(eax);
diff --git a/src/ia32/code-stubs-ia32.cc b/src/ia32/code-stubs-ia32.cc
index ee9e535..a83c1ae 100644
--- a/src/ia32/code-stubs-ia32.cc
+++ b/src/ia32/code-stubs-ia32.cc
@@ -5515,7 +5515,6 @@
__ j(below, &done);
// Check the number to string cache.
- Label not_cached;
__ bind(¬_string);
// Puts the cached result into scratch1.
NumberToStringStub::GenerateLookupNumberStringCache(masm,
@@ -5523,22 +5522,9 @@
scratch1,
scratch2,
scratch3,
- ¬_cached);
+ slow);
__ mov(arg, scratch1);
__ mov(Operand(esp, stack_offset), arg);
- __ jmp(&done);
-
- // Check if the argument is a safe string wrapper.
- __ bind(¬_cached);
- __ JumpIfSmi(arg, slow);
- __ CmpObjectType(arg, JS_VALUE_TYPE, scratch1); // map -> scratch1.
- __ j(not_equal, slow);
- __ test_b(FieldOperand(scratch1, Map::kBitField2Offset),
- 1 << Map::kStringWrapperSafeForDefaultValueOf);
- __ j(zero, slow);
- __ mov(arg, FieldOperand(arg, JSValue::kValueOffset));
- __ mov(Operand(esp, stack_offset), arg);
-
__ bind(&done);
}
@@ -7239,96 +7225,128 @@
template<class T>
-static void CreateArrayDispatch(MacroAssembler* masm) {
- int last_index = GetSequenceIndexFromFastElementsKind(
- TERMINAL_FAST_ELEMENTS_KIND);
- for (int i = 0; i <= last_index; ++i) {
- Label next;
- ElementsKind kind = GetFastElementsKindFromSequenceIndex(i);
- __ cmp(edx, kind);
- __ j(not_equal, &next);
- T stub(kind);
+static void CreateArrayDispatch(MacroAssembler* masm,
+ AllocationSiteOverrideMode mode) {
+ if (mode == DISABLE_ALLOCATION_SITES) {
+ T stub(GetInitialFastElementsKind(),
+ CONTEXT_CHECK_REQUIRED,
+ mode);
__ TailCallStub(&stub);
- __ bind(&next);
- }
+ } else if (mode == DONT_OVERRIDE) {
+ int last_index = GetSequenceIndexFromFastElementsKind(
+ TERMINAL_FAST_ELEMENTS_KIND);
+ for (int i = 0; i <= last_index; ++i) {
+ Label next;
+ ElementsKind kind = GetFastElementsKindFromSequenceIndex(i);
+ __ cmp(edx, kind);
+ __ j(not_equal, &next);
+ T stub(kind);
+ __ TailCallStub(&stub);
+ __ bind(&next);
+ }
- // If we reached this point there is a problem.
- __ Abort(kUnexpectedElementsKindInArrayConstructor);
+ // If we reached this point there is a problem.
+ __ Abort(kUnexpectedElementsKindInArrayConstructor);
+ } else {
+ UNREACHABLE();
+ }
}
-static void CreateArrayDispatchOneArgument(MacroAssembler* masm) {
- // ebx - type info cell
- // edx - kind
+static void CreateArrayDispatchOneArgument(MacroAssembler* masm,
+ AllocationSiteOverrideMode mode) {
+ // ebx - type info cell (if mode != DISABLE_ALLOCATION_SITES)
+ // edx - kind (if mode != DISABLE_ALLOCATION_SITES)
// eax - number of arguments
// edi - constructor?
// esp[0] - return address
// esp[4] - last argument
- ASSERT(FAST_SMI_ELEMENTS == 0);
- ASSERT(FAST_HOLEY_SMI_ELEMENTS == 1);
- ASSERT(FAST_ELEMENTS == 2);
- ASSERT(FAST_HOLEY_ELEMENTS == 3);
- ASSERT(FAST_DOUBLE_ELEMENTS == 4);
- ASSERT(FAST_HOLEY_DOUBLE_ELEMENTS == 5);
-
- Handle<Object> undefined_sentinel(
- masm->isolate()->heap()->undefined_value(),
- masm->isolate());
-
- // is the low bit set? If so, we are holey and that is good.
- __ test_b(edx, 1);
Label normal_sequence;
- __ j(not_zero, &normal_sequence);
+ if (mode == DONT_OVERRIDE) {
+ ASSERT(FAST_SMI_ELEMENTS == 0);
+ ASSERT(FAST_HOLEY_SMI_ELEMENTS == 1);
+ ASSERT(FAST_ELEMENTS == 2);
+ ASSERT(FAST_HOLEY_ELEMENTS == 3);
+ ASSERT(FAST_DOUBLE_ELEMENTS == 4);
+ ASSERT(FAST_HOLEY_DOUBLE_ELEMENTS == 5);
+
+ // is the low bit set? If so, we are holey and that is good.
+ __ test_b(edx, 1);
+ __ j(not_zero, &normal_sequence);
+ }
// look at the first argument
__ mov(ecx, Operand(esp, kPointerSize));
__ test(ecx, ecx);
__ j(zero, &normal_sequence);
- // We are going to create a holey array, but our kind is non-holey.
- // Fix kind and retry (only if we have an allocation site in the cell).
- __ inc(edx);
- __ cmp(ebx, Immediate(undefined_sentinel));
- __ j(equal, &normal_sequence);
- __ mov(ecx, FieldOperand(ebx, Cell::kValueOffset));
- Handle<Map> allocation_site_map(
- masm->isolate()->heap()->allocation_site_map(),
- masm->isolate());
- __ cmp(FieldOperand(ecx, 0), Immediate(allocation_site_map));
- __ j(not_equal, &normal_sequence);
+ if (mode == DISABLE_ALLOCATION_SITES) {
+ ElementsKind initial = GetInitialFastElementsKind();
+ ElementsKind holey_initial = GetHoleyElementsKind(initial);
- // Save the resulting elements kind in type info
- __ SmiTag(edx);
- __ mov(FieldOperand(ecx, AllocationSite::kTransitionInfoOffset), edx);
- __ SmiUntag(edx);
+ ArraySingleArgumentConstructorStub stub_holey(holey_initial,
+ CONTEXT_CHECK_REQUIRED,
+ DISABLE_ALLOCATION_SITES);
+ __ TailCallStub(&stub_holey);
- __ bind(&normal_sequence);
- int last_index = GetSequenceIndexFromFastElementsKind(
- TERMINAL_FAST_ELEMENTS_KIND);
- for (int i = 0; i <= last_index; ++i) {
- Label next;
- ElementsKind kind = GetFastElementsKindFromSequenceIndex(i);
- __ cmp(edx, kind);
- __ j(not_equal, &next);
- ArraySingleArgumentConstructorStub stub(kind);
+ __ bind(&normal_sequence);
+ ArraySingleArgumentConstructorStub stub(initial,
+ CONTEXT_CHECK_REQUIRED,
+ DISABLE_ALLOCATION_SITES);
__ TailCallStub(&stub);
- __ bind(&next);
- }
+ } else if (mode == DONT_OVERRIDE) {
+ // We are going to create a holey array, but our kind is non-holey.
+ // Fix kind and retry.
+ __ inc(edx);
+ __ mov(ecx, FieldOperand(ebx, Cell::kValueOffset));
+ if (FLAG_debug_code) {
+ Handle<Map> allocation_site_map(
+ masm->isolate()->heap()->allocation_site_map(),
+ masm->isolate());
+ __ cmp(FieldOperand(ecx, 0), Immediate(allocation_site_map));
+ __ Assert(equal, kExpectedAllocationSiteInCell);
+ }
- // If we reached this point there is a problem.
- __ Abort(kUnexpectedElementsKindInArrayConstructor);
+ // Save the resulting elements kind in type info
+ __ SmiTag(edx);
+ __ mov(FieldOperand(ecx, AllocationSite::kTransitionInfoOffset), edx);
+ __ SmiUntag(edx);
+
+ __ bind(&normal_sequence);
+ int last_index = GetSequenceIndexFromFastElementsKind(
+ TERMINAL_FAST_ELEMENTS_KIND);
+ for (int i = 0; i <= last_index; ++i) {
+ Label next;
+ ElementsKind kind = GetFastElementsKindFromSequenceIndex(i);
+ __ cmp(edx, kind);
+ __ j(not_equal, &next);
+ ArraySingleArgumentConstructorStub stub(kind);
+ __ TailCallStub(&stub);
+ __ bind(&next);
+ }
+
+ // If we reached this point there is a problem.
+ __ Abort(kUnexpectedElementsKindInArrayConstructor);
+ } else {
+ UNREACHABLE();
+ }
}
template<class T>
static void ArrayConstructorStubAheadOfTimeHelper(Isolate* isolate) {
+ ElementsKind initial_kind = GetInitialFastElementsKind();
+ ElementsKind initial_holey_kind = GetHoleyElementsKind(initial_kind);
+
int to_index = GetSequenceIndexFromFastElementsKind(
TERMINAL_FAST_ELEMENTS_KIND);
for (int i = 0; i <= to_index; ++i) {
ElementsKind kind = GetFastElementsKindFromSequenceIndex(i);
T stub(kind);
stub.GetCode(isolate)->set_is_pregenerated(true);
- if (AllocationSite::GetMode(kind) != DONT_TRACK_ALLOCATION_SITE) {
+ if (AllocationSite::GetMode(kind) != DONT_TRACK_ALLOCATION_SITE ||
+ (!FLAG_track_allocation_sites &&
+ (kind == initial_kind || kind == initial_holey_kind))) {
T stub1(kind, CONTEXT_CHECK_REQUIRED, DISABLE_ALLOCATION_SITES);
stub1.GetCode(isolate)->set_is_pregenerated(true);
}
@@ -7361,6 +7379,34 @@
}
+void ArrayConstructorStub::GenerateDispatchToArrayStub(
+ MacroAssembler* masm,
+ AllocationSiteOverrideMode mode) {
+ if (argument_count_ == ANY) {
+ Label not_zero_case, not_one_case;
+ __ test(eax, eax);
+ __ j(not_zero, ¬_zero_case);
+ CreateArrayDispatch<ArrayNoArgumentConstructorStub>(masm, mode);
+
+ __ bind(¬_zero_case);
+ __ cmp(eax, 1);
+ __ j(greater, ¬_one_case);
+ CreateArrayDispatchOneArgument(masm, mode);
+
+ __ bind(¬_one_case);
+ CreateArrayDispatch<ArrayNArgumentsConstructorStub>(masm, mode);
+ } else if (argument_count_ == NONE) {
+ CreateArrayDispatch<ArrayNoArgumentConstructorStub>(masm, mode);
+ } else if (argument_count_ == ONE) {
+ CreateArrayDispatchOneArgument(masm, mode);
+ } else if (argument_count_ == MORE_THAN_ONE) {
+ CreateArrayDispatch<ArrayNArgumentsConstructorStub>(masm, mode);
+ } else {
+ UNREACHABLE();
+ }
+}
+
+
void ArrayConstructorStub::Generate(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- eax : argc (only if argument_count_ == ANY)
@@ -7395,50 +7441,22 @@
__ bind(&okay_here);
}
- Label no_info, switch_ready;
- // Get the elements kind and case on that.
+ Label no_info;
+ // If the type cell is undefined, or contains anything other than an
+ // AllocationSite, call an array constructor that doesn't use AllocationSites.
__ cmp(ebx, Immediate(undefined_sentinel));
__ j(equal, &no_info);
__ mov(edx, FieldOperand(ebx, Cell::kValueOffset));
-
- // The type cell may have undefined in its value.
- __ cmp(edx, Immediate(undefined_sentinel));
- __ j(equal, &no_info);
-
- // The type cell has either an AllocationSite or a JSFunction
__ cmp(FieldOperand(edx, 0), Immediate(Handle<Map>(
masm->isolate()->heap()->allocation_site_map())));
__ j(not_equal, &no_info);
__ mov(edx, FieldOperand(edx, AllocationSite::kTransitionInfoOffset));
__ SmiUntag(edx);
- __ jmp(&switch_ready);
+ GenerateDispatchToArrayStub(masm, DONT_OVERRIDE);
+
__ bind(&no_info);
- __ mov(edx, Immediate(GetInitialFastElementsKind()));
- __ bind(&switch_ready);
-
- if (argument_count_ == ANY) {
- Label not_zero_case, not_one_case;
- __ test(eax, eax);
- __ j(not_zero, ¬_zero_case);
- CreateArrayDispatch<ArrayNoArgumentConstructorStub>(masm);
-
- __ bind(¬_zero_case);
- __ cmp(eax, 1);
- __ j(greater, ¬_one_case);
- CreateArrayDispatchOneArgument(masm);
-
- __ bind(¬_one_case);
- CreateArrayDispatch<ArrayNArgumentsConstructorStub>(masm);
- } else if (argument_count_ == NONE) {
- CreateArrayDispatch<ArrayNoArgumentConstructorStub>(masm);
- } else if (argument_count_ == ONE) {
- CreateArrayDispatchOneArgument(masm);
- } else if (argument_count_ == MORE_THAN_ONE) {
- CreateArrayDispatch<ArrayNArgumentsConstructorStub>(masm);
- } else {
- UNREACHABLE();
- }
+ GenerateDispatchToArrayStub(masm, DISABLE_ALLOCATION_SITES);
}
diff --git a/src/ia32/full-codegen-ia32.cc b/src/ia32/full-codegen-ia32.cc
index db82b39..6d39cc1 100644
--- a/src/ia32/full-codegen-ia32.cc
+++ b/src/ia32/full-codegen-ia32.cc
@@ -2956,7 +2956,7 @@
VisitForAccumulatorValue(args->at(0));
- Label materialize_true, materialize_false;
+ Label materialize_true, materialize_false, skip_lookup;
Label* if_true = NULL;
Label* if_false = NULL;
Label* fall_through = NULL;
@@ -2970,7 +2970,7 @@
__ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset));
__ test_b(FieldOperand(ebx, Map::kBitField2Offset),
1 << Map::kStringWrapperSafeForDefaultValueOf);
- __ j(not_zero, if_true);
+ __ j(not_zero, &skip_lookup);
// Check for fast case object. Return false for slow case objects.
__ mov(ecx, FieldOperand(eax, JSObject::kPropertiesOffset));
@@ -3016,6 +3016,12 @@
// Reload map as register ebx was used as temporary above.
__ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset));
+ // Set the bit in the map to indicate that there is no local valueOf field.
+ __ or_(FieldOperand(ebx, Map::kBitField2Offset),
+ Immediate(1 << Map::kStringWrapperSafeForDefaultValueOf));
+
+ __ bind(&skip_lookup);
+
// If a valueOf property is not found on the object check that its
// prototype is the un-modified String prototype. If not result is false.
__ mov(ecx, FieldOperand(ebx, Map::kPrototypeOffset));
@@ -3027,10 +3033,9 @@
__ cmp(ecx,
ContextOperand(edx,
Context::STRING_FUNCTION_PROTOTYPE_MAP_INDEX));
- __ j(not_equal, if_false);
- __ jmp(if_true);
-
PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
+ Split(equal, if_true, if_false, fall_through);
+
context()->Plug(if_true, if_false);
}
diff --git a/src/ia32/lithium-codegen-ia32.cc b/src/ia32/lithium-codegen-ia32.cc
index 860646c..d50b780 100644
--- a/src/ia32/lithium-codegen-ia32.cc
+++ b/src/ia32/lithium-codegen-ia32.cc
@@ -382,9 +382,13 @@
instr->CompileToNative(this);
- if (!CpuFeatures::IsSupported(SSE2) &&
- FLAG_debug_code && FLAG_enable_slow_asserts) {
+ if (!CpuFeatures::IsSupported(SSE2)) {
+ if (instr->IsGoto()) {
+ x87_stack_.LeavingBlock(current_block_, LGoto::cast(instr));
+ } else if (FLAG_debug_code && FLAG_enable_slow_asserts &&
+ !instr->IsGap() && !instr->IsReturn()) {
__ VerifyX87StackDepth(x87_stack_.depth());
+ }
}
}
EnsureSpaceForLazyDeopt();
@@ -682,6 +686,21 @@
__ fstp(0);
stack_depth_--;
}
+ if (FLAG_debug_code && FLAG_enable_slow_asserts) __ VerifyX87StackDepth(0);
+ }
+}
+
+
+void LCodeGen::X87Stack::LeavingBlock(int current_block_id, LGoto* goto_instr) {
+ ASSERT(stack_depth_ <= 1);
+ // If ever used for new stubs producing two pairs of doubles joined into two
+ // phis this assert hits. That situation is not handled, since the two stacks
+ // might have st0 and st1 swapped.
+ if (current_block_id + 1 != goto_instr->block_id()) {
+ // If we have a value on the x87 stack on leaving a block, it must be a
+ // phi input. If the next block we compile is not the join block, we have
+ // to discard the stack state.
+ stack_depth_ = 0;
}
}
@@ -2486,6 +2505,10 @@
}
+void LCodeGen::DoClobberDoubles(LClobberDoubles* instr) {
+}
+
+
void LCodeGen::DoGoto(LGoto* instr) {
EmitGoto(instr->block_id());
}
@@ -4103,85 +4126,66 @@
void LCodeGen::DoRandom(LRandom* instr) {
- class DeferredDoRandom V8_FINAL : public LDeferredCode {
- public:
- DeferredDoRandom(LCodeGen* codegen,
- LRandom* instr,
- const X87Stack& x87_stack)
- : LDeferredCode(codegen, x87_stack), instr_(instr) { }
- virtual void Generate() V8_OVERRIDE { codegen()->DoDeferredRandom(instr_); }
- virtual LInstruction* instr() V8_OVERRIDE { return instr_; }
- private:
- LRandom* instr_;
- };
-
- DeferredDoRandom* deferred =
- new(zone()) DeferredDoRandom(this, instr, x87_stack_);
-
CpuFeatureScope scope(masm(), SSE2);
- // Having marked this instruction as a call we can use any
- // registers.
- ASSERT(ToDoubleRegister(instr->result()).is(xmm1));
- ASSERT(ToRegister(instr->global_object()).is(eax));
+
// Assert that the register size is indeed the size of each seed.
static const int kSeedSize = sizeof(uint32_t);
STATIC_ASSERT(kPointerSize == kSeedSize);
- __ mov(eax, FieldOperand(eax, GlobalObject::kNativeContextOffset));
+ // Load native context
+ Register global_object = ToRegister(instr->global_object());
+ Register native_context = global_object;
+ __ mov(native_context, FieldOperand(
+ global_object, GlobalObject::kNativeContextOffset));
+
+ // Load state (FixedArray of the native context's random seeds)
static const int kRandomSeedOffset =
FixedArray::kHeaderSize + Context::RANDOM_SEED_INDEX * kPointerSize;
- __ mov(ebx, FieldOperand(eax, kRandomSeedOffset));
- // ebx: FixedArray of the native context's random seeds
+ Register state = native_context;
+ __ mov(state, FieldOperand(native_context, kRandomSeedOffset));
// Load state[0].
- __ mov(ecx, FieldOperand(ebx, ByteArray::kHeaderSize));
- // If state[0] == 0, call runtime to initialize seeds.
- __ test(ecx, ecx);
- __ j(zero, deferred->entry());
+ Register state0 = ToRegister(instr->scratch());
+ __ mov(state0, FieldOperand(state, ByteArray::kHeaderSize));
// Load state[1].
- __ mov(eax, FieldOperand(ebx, ByteArray::kHeaderSize + kSeedSize));
- // ecx: state[0]
- // eax: state[1]
+ Register state1 = ToRegister(instr->scratch2());
+ __ mov(state1, FieldOperand(state, ByteArray::kHeaderSize + kSeedSize));
// state[0] = 18273 * (state[0] & 0xFFFF) + (state[0] >> 16)
- __ movzx_w(edx, ecx);
- __ imul(edx, edx, 18273);
- __ shr(ecx, 16);
- __ add(ecx, edx);
+ Register scratch3 = ToRegister(instr->scratch3());
+ __ movzx_w(scratch3, state0);
+ __ imul(scratch3, scratch3, 18273);
+ __ shr(state0, 16);
+ __ add(state0, scratch3);
// Save state[0].
- __ mov(FieldOperand(ebx, ByteArray::kHeaderSize), ecx);
+ __ mov(FieldOperand(state, ByteArray::kHeaderSize), state0);
// state[1] = 36969 * (state[1] & 0xFFFF) + (state[1] >> 16)
- __ movzx_w(edx, eax);
- __ imul(edx, edx, 36969);
- __ shr(eax, 16);
- __ add(eax, edx);
+ __ movzx_w(scratch3, state1);
+ __ imul(scratch3, scratch3, 36969);
+ __ shr(state1, 16);
+ __ add(state1, scratch3);
// Save state[1].
- __ mov(FieldOperand(ebx, ByteArray::kHeaderSize + kSeedSize), eax);
+ __ mov(FieldOperand(state, ByteArray::kHeaderSize + kSeedSize), state1);
// Random bit pattern = (state[0] << 14) + (state[1] & 0x3FFFF)
- __ shl(ecx, 14);
- __ and_(eax, Immediate(0x3FFFF));
- __ add(eax, ecx);
+ Register random = state0;
+ __ shl(random, 14);
+ __ and_(state1, Immediate(0x3FFFF));
+ __ add(random, state1);
- __ bind(deferred->exit());
- // Convert 32 random bits in eax to 0.(32 random bits) in a double
+ // Convert 32 random bits in random to 0.(32 random bits) in a double
// by computing:
// ( 1.(20 0s)(32 random bits) x 2^20 ) - (1.0 x 2^20)).
- __ mov(ebx, Immediate(0x49800000)); // 1.0 x 2^20 as single.
- __ movd(xmm2, ebx);
- __ movd(xmm1, eax);
- __ cvtss2sd(xmm2, xmm2);
- __ xorps(xmm1, xmm2);
- __ subsd(xmm1, xmm2);
-}
-
-
-void LCodeGen::DoDeferredRandom(LRandom* instr) {
- __ PrepareCallCFunction(1, ebx);
- __ mov(Operand(esp, 0), eax);
- __ CallCFunction(ExternalReference::random_uint32_function(isolate()), 1);
- // Return value is in eax.
+ XMMRegister result = ToDoubleRegister(instr->result());
+ // We use xmm0 as fixed scratch register here.
+ XMMRegister scratch4 = xmm0;
+ __ mov(scratch3, Immediate(0x49800000)); // 1.0 x 2^20 as single.
+ __ movd(scratch4, scratch3);
+ __ movd(result, random);
+ __ cvtss2sd(scratch4, scratch4);
+ __ xorps(result, scratch4);
+ __ subsd(result, scratch4);
}
@@ -5285,11 +5289,13 @@
}
__ bind(&load_smi);
- __ SmiUntag(input_reg); // Untag smi before converting to float.
- __ push(input_reg);
+ // Clobbering a temp is faster than re-tagging the
+ // input register since we avoid dependencies.
+ __ mov(temp_reg, input_reg);
+ __ SmiUntag(temp_reg); // Untag smi before converting to float.
+ __ push(temp_reg);
__ fild_s(Operand(esp, 0));
- __ pop(input_reg);
- __ SmiTag(input_reg); // Retag smi.
+ __ add(esp, Immediate(kPointerSize));
__ bind(&done);
X87CommitWrite(res_reg);
}
@@ -5345,11 +5351,12 @@
ASSERT(mode == NUMBER_CANDIDATE_IS_SMI);
}
- // Smi to XMM conversion
__ bind(&load_smi);
- __ SmiUntag(input_reg); // Untag smi before converting to float.
- __ cvtsi2sd(result_reg, Operand(input_reg));
- __ SmiTag(input_reg); // Retag smi.
+ // Smi to XMM conversion. Clobbering a temp is faster than re-tagging the
+ // input register since we avoid dependencies.
+ __ mov(temp_reg, input_reg);
+ __ SmiUntag(temp_reg); // Untag smi before converting to float.
+ __ cvtsi2sd(result_reg, Operand(temp_reg));
__ bind(&done);
}
@@ -5423,14 +5430,14 @@
LOperand* input = instr->value();
ASSERT(input->IsRegister());
LOperand* temp = instr->temp();
- ASSERT(temp == NULL || temp->IsRegister());
+ ASSERT(temp->IsRegister());
LOperand* result = instr->result();
ASSERT(result->IsDoubleRegister());
Register input_reg = ToRegister(input);
bool deoptimize_on_minus_zero =
instr->hydrogen()->deoptimize_on_minus_zero();
- Register temp_reg = deoptimize_on_minus_zero ? ToRegister(temp) : no_reg;
+ Register temp_reg = ToRegister(temp);
HValue* value = instr->hydrogen()->value();
NumberUntagDMode mode = value->representation().IsSmi()
diff --git a/src/ia32/lithium-codegen-ia32.h b/src/ia32/lithium-codegen-ia32.h
index cc1747d..769917f 100644
--- a/src/ia32/lithium-codegen-ia32.h
+++ b/src/ia32/lithium-codegen-ia32.h
@@ -166,7 +166,6 @@
void DoDeferredTaggedToI(LTaggedToI* instr, Label* done);
void DoDeferredMathAbsTaggedHeapNumber(LMathAbs* instr);
void DoDeferredStackCheck(LStackCheck* instr);
- void DoDeferredRandom(LRandom* instr);
void DoDeferredStringCharCodeAt(LStringCharCodeAt* instr);
void DoDeferredStringCharFromCode(LStringCharFromCode* instr);
void DoDeferredAllocate(LAllocate* instr);
@@ -471,6 +470,7 @@
void PrepareToWrite(X87Register reg);
void CommitWrite(X87Register reg);
void FlushIfNecessary(LInstruction* instr, LCodeGen* cgen);
+ void LeavingBlock(int current_block_id, LGoto* goto_instr);
int depth() const { return stack_depth_; }
void pop() {
ASSERT(is_mutable_);
diff --git a/src/ia32/lithium-ia32.cc b/src/ia32/lithium-ia32.cc
index 07dbf13..ca1e60d 100644
--- a/src/ia32/lithium-ia32.cc
+++ b/src/ia32/lithium-ia32.cc
@@ -954,6 +954,16 @@
if (FLAG_stress_environments && !instr->HasEnvironment()) {
instr = AssignEnvironment(instr);
}
+ if (!CpuFeatures::IsSafeForSnapshot(SSE2) && instr->IsGoto() &&
+ LGoto::cast(instr)->jumps_to_join()) {
+ // TODO(olivf) Since phis of spilled values are joined as registers
+ // (not in the stack slot), we need to allow the goto gaps to keep one
+ // x87 register alive. To ensure all other values are still spilled, we
+ // insert a fpu register barrier right before.
+ LClobberDoubles* clobber = new(zone()) LClobberDoubles();
+ clobber->set_hydrogen_value(current);
+ chunk_->AddInstruction(clobber, current_block_);
+ }
instr->set_hydrogen_value(current);
chunk_->AddInstruction(instr, current_block_);
}
@@ -1046,7 +1056,7 @@
LInstruction* LChunkBuilder::DoGoto(HGoto* instr) {
- return new(zone()) LGoto(instr->FirstSuccessor()->block_id());
+ return new(zone()) LGoto(instr->FirstSuccessor());
}
@@ -1058,7 +1068,7 @@
HBasicBlock* successor = HConstant::cast(value)->BooleanValue()
? instr->FirstSuccessor()
: instr->SecondSuccessor();
- return new(zone()) LGoto(successor->block_id());
+ return new(zone()) LGoto(successor);
}
ToBooleanStub::Types expected = instr->expected_input_types();
@@ -1705,10 +1715,14 @@
LInstruction* LChunkBuilder::DoRandom(HRandom* instr) {
ASSERT(instr->representation().IsDouble());
- ASSERT(instr->global_object()->representation().IsSmiOrTagged());
- LOperand* global_object = UseFixed(instr->global_object(), eax);
- LRandom* result = new(zone()) LRandom(global_object);
- return MarkAsCall(DefineFixedDouble(result, xmm1), instr);
+ ASSERT(instr->global_object()->representation().IsTagged());
+ LOperand* global_object = UseTempRegister(instr->global_object());
+ LOperand* scratch = TempRegister();
+ LOperand* scratch2 = TempRegister();
+ LOperand* scratch3 = TempRegister();
+ LRandom* result = new(zone()) LRandom(
+ global_object, scratch, scratch2, scratch3);
+ return DefineFixedDouble(result, xmm1);
}
@@ -1933,9 +1947,7 @@
info()->MarkAsDeferredCalling();
LOperand* value = UseRegister(instr->value());
// Temp register only necessary for minus zero check.
- LOperand* temp = instr->deoptimize_on_minus_zero()
- ? TempRegister()
- : NULL;
+ LOperand* temp = TempRegister();
LNumberUntagD* res = new(zone()) LNumberUntagD(value, temp);
return AssignEnvironment(DefineAsRegister(res));
} else if (to.IsSmi()) {
diff --git a/src/ia32/lithium-ia32.h b/src/ia32/lithium-ia32.h
index ab964af..3a609c9 100644
--- a/src/ia32/lithium-ia32.h
+++ b/src/ia32/lithium-ia32.h
@@ -73,6 +73,7 @@
V(ClampTToUint8) \
V(ClampTToUint8NoSSE2) \
V(ClassOfTestAndBranch) \
+ V(ClobberDoubles) \
V(CompareNumericAndBranch) \
V(CmpObjectEqAndBranch) \
V(CmpHoleAndBranch) \
@@ -406,19 +407,32 @@
};
+class LClobberDoubles V8_FINAL : public LTemplateInstruction<0, 0, 0> {
+ public:
+ LClobberDoubles() { ASSERT(!CpuFeatures::IsSafeForSnapshot(SSE2)); }
+
+ virtual bool ClobbersDoubleRegisters() const { return true; }
+
+ DECLARE_CONCRETE_INSTRUCTION(ClobberDoubles, "clobber-d")
+};
+
+
class LGoto V8_FINAL : public LTemplateInstruction<0, 0, 0> {
public:
- explicit LGoto(int block_id) : block_id_(block_id) { }
+ explicit LGoto(HBasicBlock* block) : block_(block) { }
virtual bool HasInterestingComment(LCodeGen* gen) const V8_OVERRIDE;
DECLARE_CONCRETE_INSTRUCTION(Goto, "goto")
virtual void PrintDataTo(StringStream* stream) V8_OVERRIDE;
virtual bool IsControl() const V8_OVERRIDE { return true; }
- int block_id() const { return block_id_; }
+ int block_id() const { return block_->block_id(); }
+ virtual bool ClobbersDoubleRegisters() const { return false; }
+
+ bool jumps_to_join() const { return block_->predecessors()->length() > 1; }
private:
- int block_id_;
+ HBasicBlock* block_;
};
@@ -1448,13 +1462,22 @@
};
-class LRandom V8_FINAL : public LTemplateInstruction<1, 1, 0> {
+class LRandom V8_FINAL : public LTemplateInstruction<1, 1, 3> {
public:
- explicit LRandom(LOperand* global_object) {
+ LRandom(LOperand* global_object,
+ LOperand* scratch,
+ LOperand* scratch2,
+ LOperand* scratch3) {
inputs_[0] = global_object;
+ temps_[0] = scratch;
+ temps_[1] = scratch2;
+ temps_[2] = scratch3;
}
- LOperand* global_object() { return inputs_[0]; }
+ LOperand* global_object() const { return inputs_[0]; }
+ LOperand* scratch() const { return temps_[0]; }
+ LOperand* scratch2() const { return temps_[1]; }
+ LOperand* scratch3() const { return temps_[2]; }
DECLARE_CONCRETE_INSTRUCTION(Random, "random")
DECLARE_HYDROGEN_ACCESSOR(Random)
diff --git a/src/ia32/macro-assembler-ia32.cc b/src/ia32/macro-assembler-ia32.cc
index fbfe9dd..b65d328 100644
--- a/src/ia32/macro-assembler-ia32.cc
+++ b/src/ia32/macro-assembler-ia32.cc
@@ -2798,6 +2798,8 @@
void MacroAssembler::VerifyX87StackDepth(uint32_t depth) {
// Make sure the floating point stack is either empty or has depth items.
ASSERT(depth <= 7);
+ // This is very expensive.
+ ASSERT(FLAG_debug_code && FLAG_enable_slow_asserts);
// The top-of-stack (tos) is 7 if there is one item pushed.
int tos = (8 - depth) % 8;
diff --git a/src/ia32/stub-cache-ia32.cc b/src/ia32/stub-cache-ia32.cc
index d2da43e..354c2fd 100644
--- a/src/ia32/stub-cache-ia32.cc
+++ b/src/ia32/stub-cache-ia32.cc
@@ -392,6 +392,11 @@
Register holder,
Register name,
Handle<JSObject> holder_obj) {
+ STATIC_ASSERT(StubCache::kInterceptorArgsNameIndex == 0);
+ STATIC_ASSERT(StubCache::kInterceptorArgsInfoIndex == 1);
+ STATIC_ASSERT(StubCache::kInterceptorArgsThisIndex == 2);
+ STATIC_ASSERT(StubCache::kInterceptorArgsHolderIndex == 3);
+ STATIC_ASSERT(StubCache::kInterceptorArgsLength == 4);
__ push(name);
Handle<InterceptorInfo> interceptor(holder_obj->GetNamedInterceptor());
ASSERT(!masm->isolate()->heap()->InNewSpace(*interceptor));
@@ -400,8 +405,6 @@
__ push(scratch);
__ push(receiver);
__ push(holder);
- __ push(FieldOperand(scratch, InterceptorInfo::kDataOffset));
- __ push(Immediate(reinterpret_cast<int>(masm->isolate())));
}
@@ -415,7 +418,7 @@
__ CallExternalReference(
ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorOnly),
masm->isolate()),
- 6);
+ StubCache::kInterceptorArgsLength);
}
@@ -733,7 +736,7 @@
__ CallExternalReference(
ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorForCall),
masm->isolate()),
- 6);
+ StubCache::kInterceptorArgsLength);
// Restore the name_ register.
__ pop(name_);
@@ -1401,14 +1404,20 @@
ASSERT(!scratch3().is(reg));
__ pop(scratch3()); // Get return address to place it below.
+ STATIC_ASSERT(PropertyCallbackArguments::kThisIndex == 0);
+ STATIC_ASSERT(PropertyCallbackArguments::kDataIndex == -1);
+ STATIC_ASSERT(PropertyCallbackArguments::kReturnValueOffset == -2);
+ STATIC_ASSERT(PropertyCallbackArguments::kReturnValueDefaultValueIndex == -3);
+ STATIC_ASSERT(PropertyCallbackArguments::kIsolateIndex == -4);
+ STATIC_ASSERT(PropertyCallbackArguments::kHolderIndex == -5);
__ push(receiver()); // receiver
__ mov(scratch2(), esp);
ASSERT(!scratch2().is(reg));
- __ push(reg); // holder
// Push data from ExecutableAccessorInfo.
if (isolate()->heap()->InNewSpace(callback->data())) {
- __ mov(scratch1(), Immediate(callback));
- __ push(FieldOperand(scratch1(), ExecutableAccessorInfo::kDataOffset));
+ Register scratch = reg.is(scratch1()) ? receiver() : scratch1();
+ __ mov(scratch, Immediate(callback));
+ __ push(FieldOperand(scratch, ExecutableAccessorInfo::kDataOffset));
} else {
__ push(Immediate(Handle<Object>(callback->data(), isolate())));
}
@@ -1416,6 +1425,7 @@
// ReturnValue default value
__ push(Immediate(isolate()->factory()->undefined_value()));
__ push(Immediate(reinterpret_cast<int>(isolate())));
+ __ push(reg); // holder
// Save a pointer to where we pushed the arguments pointer. This will be
// passed as the const ExecutableAccessorInfo& to the C++ callback.
@@ -1450,7 +1460,7 @@
thunk_address,
ApiParameterOperand(2),
kStackSpace,
- 6);
+ 7);
}
@@ -1557,7 +1567,7 @@
ExternalReference ref =
ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorForLoad),
isolate());
- __ TailCallExternalReference(ref, 6, 1);
+ __ TailCallExternalReference(ref, StubCache::kInterceptorArgsLength, 1);
}
}
diff --git a/src/ic.cc b/src/ic.cc
index 7211ad9..5518751 100644
--- a/src/ic.cc
+++ b/src/ic.cc
@@ -996,7 +996,7 @@
bool IC::UpdatePolymorphicIC(State state,
- Handle<JSObject> receiver,
+ Handle<HeapObject> receiver,
Handle<String> name,
Handle<Code> code,
StrictModeFlag strict_mode) {
@@ -1077,44 +1077,44 @@
}
-void LoadIC::UpdateMonomorphicIC(Handle<JSObject> receiver,
+void LoadIC::UpdateMonomorphicIC(Handle<HeapObject> receiver,
Handle<Code> handler,
Handle<String> name,
StrictModeFlag strict_mode) {
- if (handler->type() == Code::NORMAL) return set_target(*handler);
+ if (handler->is_load_stub()) return set_target(*handler);
Handle<Code> ic = isolate()->stub_cache()->ComputeMonomorphicLoadIC(
receiver, handler, name);
set_target(*ic);
}
-void KeyedLoadIC::UpdateMonomorphicIC(Handle<JSObject> receiver,
+void KeyedLoadIC::UpdateMonomorphicIC(Handle<HeapObject> receiver,
Handle<Code> handler,
Handle<String> name,
StrictModeFlag strict_mode) {
- if (handler->type() == Code::NORMAL) return set_target(*handler);
+ if (handler->is_keyed_load_stub()) return set_target(*handler);
Handle<Code> ic = isolate()->stub_cache()->ComputeMonomorphicKeyedLoadIC(
receiver, handler, name);
set_target(*ic);
}
-void StoreIC::UpdateMonomorphicIC(Handle<JSObject> receiver,
+void StoreIC::UpdateMonomorphicIC(Handle<HeapObject> receiver,
Handle<Code> handler,
Handle<String> name,
StrictModeFlag strict_mode) {
- if (handler->type() == Code::NORMAL) return set_target(*handler);
+ if (handler->is_store_stub()) return set_target(*handler);
Handle<Code> ic = isolate()->stub_cache()->ComputeMonomorphicStoreIC(
receiver, handler, name, strict_mode);
set_target(*ic);
}
-void KeyedStoreIC::UpdateMonomorphicIC(Handle<JSObject> receiver,
+void KeyedStoreIC::UpdateMonomorphicIC(Handle<HeapObject> receiver,
Handle<Code> handler,
Handle<String> name,
StrictModeFlag strict_mode) {
- if (handler->type() == Code::NORMAL) return set_target(*handler);
+ if (handler->is_keyed_store_stub()) return set_target(*handler);
Handle<Code> ic = isolate()->stub_cache()->ComputeMonomorphicKeyedStoreIC(
receiver, handler, name, strict_mode);
set_target(*ic);
@@ -1155,7 +1155,7 @@
// not necessarily equal to target()->state().
void IC::PatchCache(State state,
StrictModeFlag strict_mode,
- Handle<JSObject> receiver,
+ Handle<HeapObject> receiver,
Handle<String> name,
Handle<Code> code) {
switch (state) {
@@ -1265,32 +1265,26 @@
State state,
Handle<Object> object,
Handle<String> name) {
- // Bail out if the result is not cacheable.
- if (!lookup->IsCacheable()) {
- set_target(*generic_stub());
- return;
- }
+ if (!object->IsHeapObject()) return;
- // TODO(jkummerow): It would be nice to support non-JSObjects in
- // UpdateCaches, then we wouldn't need to go generic here.
- if (!object->IsJSObject()) {
- set_target(*generic_stub());
- return;
- }
+ Handle<HeapObject> receiver = Handle<HeapObject>::cast(object);
- Handle<JSObject> receiver = Handle<JSObject>::cast(object);
Handle<Code> code;
if (state == UNINITIALIZED) {
// This is the first time we execute this inline cache.
// Set the target to the pre monomorphic stub to delay
// setting the monomorphic state.
code = pre_monomorphic_stub();
+ } else if (!lookup->IsCacheable()) {
+ // Bail out if the result is not cacheable.
+ code = slow_stub();
+ } else if (!object->IsJSObject()) {
+ // TODO(jkummerow): It would be nice to support non-JSObjects in
+ // ComputeLoadHandler, then we wouldn't need to go generic here.
+ code = slow_stub();
} else {
- code = ComputeLoadHandler(lookup, receiver, name);
- if (code.is_null()) {
- set_target(*generic_stub());
- return;
- }
+ code = ComputeLoadHandler(lookup, Handle<JSObject>::cast(receiver), name);
+ if (code.is_null()) code = slow_stub();
}
PatchCache(state, kNonStrictMode, receiver, name, code);
diff --git a/src/ic.h b/src/ic.h
index 5c883cd..8f09e1d 100644
--- a/src/ic.h
+++ b/src/ic.h
@@ -167,14 +167,14 @@
static inline void SetTargetAtAddress(Address address, Code* target);
static void PostPatching(Address address, Code* target, Code* old_target);
- virtual void UpdateMonomorphicIC(Handle<JSObject> receiver,
+ virtual void UpdateMonomorphicIC(Handle<HeapObject> receiver,
Handle<Code> handler,
Handle<String> name,
StrictModeFlag strict_mode) {
set_target(*handler);
}
bool UpdatePolymorphicIC(State state,
- Handle<JSObject> receiver,
+ Handle<HeapObject> receiver,
Handle<String> name,
Handle<Code> code,
StrictModeFlag strict_mode);
@@ -192,7 +192,7 @@
bool IsTransitionedMapOfMonomorphicTarget(Map* receiver_map);
void PatchCache(State state,
StrictModeFlag strict_mode,
- Handle<JSObject> receiver,
+ Handle<HeapObject> receiver,
Handle<String> name,
Handle<Code> code);
virtual void UpdateMegamorphicCache(Map* map, Name* name, Code* code);
@@ -388,7 +388,7 @@
protected:
virtual Code::Kind kind() const { return Code::LOAD_IC; }
- virtual Handle<Code> generic_stub() const {
+ virtual Handle<Code> slow_stub() const {
return isolate()->builtins()->LoadIC_Slow();
}
@@ -403,7 +403,7 @@
Handle<Object> object,
Handle<String> name);
- virtual void UpdateMonomorphicIC(Handle<JSObject> receiver,
+ virtual void UpdateMonomorphicIC(Handle<HeapObject> receiver,
Handle<Code> handler,
Handle<String> name,
StrictModeFlag strict_mode);
@@ -483,9 +483,12 @@
virtual Handle<Code> generic_stub() const {
return isolate()->builtins()->KeyedLoadIC_Generic();
}
+ virtual Handle<Code> slow_stub() const {
+ return isolate()->builtins()->KeyedLoadIC_Slow();
+ }
// Update the inline cache.
- virtual void UpdateMonomorphicIC(Handle<JSObject> receiver,
+ virtual void UpdateMonomorphicIC(Handle<HeapObject> receiver,
Handle<Code> handler,
Handle<String> name,
StrictModeFlag strict_mode);
@@ -574,7 +577,7 @@
return isolate()->builtins()->StoreIC_GlobalProxy_Strict();
}
- virtual void UpdateMonomorphicIC(Handle<JSObject> receiver,
+ virtual void UpdateMonomorphicIC(Handle<HeapObject> receiver,
Handle<Code> handler,
Handle<String> name,
StrictModeFlag strict_mode);
@@ -689,7 +692,7 @@
KeyedAccessStoreMode store_mode,
StrictModeFlag strict_mode);
- virtual void UpdateMonomorphicIC(Handle<JSObject> receiver,
+ virtual void UpdateMonomorphicIC(Handle<HeapObject> receiver,
Handle<Code> handler,
Handle<String> name,
StrictModeFlag strict_mode);
diff --git a/src/mips/builtins-mips.cc b/src/mips/builtins-mips.cc
index f27ded7..3aabd97 100644
--- a/src/mips/builtins-mips.cc
+++ b/src/mips/builtins-mips.cc
@@ -299,6 +299,24 @@
}
+static void CallRuntimePassFunction(MacroAssembler* masm,
+ Runtime::FunctionId function_id) {
+ FrameScope scope(masm, StackFrame::INTERNAL);
+ // Push a copy of the function onto the stack.
+ __ push(a1);
+ // Push call kind information.
+ __ push(t1);
+ // Function is also the parameter to the runtime call.
+ __ push(a1);
+
+ __ CallRuntime(function_id, 1);
+ // Restore call kind information.
+ __ pop(t1);
+ // Restore receiver.
+ __ pop(a1);
+}
+
+
static void GenerateTailCallToSharedCode(MacroAssembler* masm) {
__ lw(a2, FieldMemOperand(a1, JSFunction::kSharedFunctionInfoOffset));
__ lw(a2, FieldMemOperand(a2, SharedFunctionInfo::kCodeOffset));
@@ -308,59 +326,27 @@
void Builtins::Generate_InRecompileQueue(MacroAssembler* masm) {
+ // Checking whether the queued function is ready for install is optional,
+ // since we come across interrupts and stack checks elsewhere. However,
+ // not checking may delay installing ready functions, and always checking
+ // would be quite expensive. A good compromise is to first check against
+ // stack limit as a cue for an interrupt signal.
+ Label ok;
+ __ LoadRoot(t0, Heap::kStackLimitRootIndex);
+ __ Branch(&ok, hs, sp, Operand(t0));
+
+ CallRuntimePassFunction(masm, Runtime::kTryInstallRecompiledCode);
+ // Tail call to returned code.
+ __ Addu(at, v0, Operand(Code::kHeaderSize - kHeapObjectTag));
+ __ Jump(at);
+
+ __ bind(&ok);
GenerateTailCallToSharedCode(masm);
}
-void Builtins::Generate_InstallRecompiledCode(MacroAssembler* masm) {
- // Enter an internal frame.
- {
- FrameScope scope(masm, StackFrame::INTERNAL);
-
- // Preserve the function.
- __ push(a1);
- // Push call kind information.
- __ push(t1);
-
- // Push the function on the stack as the argument to the runtime function.
- __ push(a1);
- __ CallRuntime(Runtime::kInstallRecompiledCode, 1);
- // Calculate the entry point.
- __ Addu(t9, v0, Operand(Code::kHeaderSize - kHeapObjectTag));
-
- // Restore call kind information.
- __ pop(t1);
- // Restore saved function.
- __ pop(a1);
-
- // Tear down temporary frame.
- }
-
- // Do a tail-call of the compiled function.
- __ Jump(t9);
-}
-
-
void Builtins::Generate_ConcurrentRecompile(MacroAssembler* masm) {
- {
- FrameScope scope(masm, StackFrame::INTERNAL);
-
- // Push a copy of the function onto the stack.
- __ push(a1);
- // Push call kind information.
- __ push(t1);
-
- __ push(a1); // Function is also the parameter to the runtime call.
- __ CallRuntime(Runtime::kConcurrentRecompile, 1);
-
- // Restore call kind information.
- __ pop(t1);
- // Restore receiver.
- __ pop(a1);
-
- // Tear down internal frame.
- }
-
+ CallRuntimePassFunction(masm, Runtime::kConcurrentRecompile);
GenerateTailCallToSharedCode(masm);
}
@@ -815,60 +801,17 @@
void Builtins::Generate_LazyCompile(MacroAssembler* masm) {
- // Enter an internal frame.
- {
- FrameScope scope(masm, StackFrame::INTERNAL);
-
- // Preserve the function.
- __ push(a1);
- // Push call kind information.
- __ push(t1);
-
- // Push the function on the stack as the argument to the runtime function.
- __ push(a1);
- // Call the runtime function.
- __ CallRuntime(Runtime::kLazyCompile, 1);
- // Calculate the entry point.
- __ addiu(t9, v0, Code::kHeaderSize - kHeapObjectTag);
-
- // Restore call kind information.
- __ pop(t1);
- // Restore saved function.
- __ pop(a1);
-
- // Tear down temporary frame.
- }
-
+ CallRuntimePassFunction(masm, Runtime::kLazyCompile);
// Do a tail-call of the compiled function.
+ __ Addu(t9, v0, Operand(Code::kHeaderSize - kHeapObjectTag));
__ Jump(t9);
}
void Builtins::Generate_LazyRecompile(MacroAssembler* masm) {
- // Enter an internal frame.
- {
- FrameScope scope(masm, StackFrame::INTERNAL);
-
- // Preserve the function.
- __ push(a1);
- // Push call kind information.
- __ push(t1);
-
- // Push the function on the stack as the argument to the runtime function.
- __ push(a1);
- __ CallRuntime(Runtime::kLazyRecompile, 1);
- // Calculate the entry point.
- __ Addu(t9, v0, Operand(Code::kHeaderSize - kHeapObjectTag));
-
- // Restore call kind information.
- __ pop(t1);
- // Restore saved function.
- __ pop(a1);
-
- // Tear down temporary frame.
- }
-
+ CallRuntimePassFunction(masm, Runtime::kLazyRecompile);
// Do a tail-call of the compiled function.
+ __ Addu(t9, v0, Operand(Code::kHeaderSize - kHeapObjectTag));
__ Jump(t9);
}
diff --git a/src/mips/code-stubs-mips.cc b/src/mips/code-stubs-mips.cc
index b536209..0589bf0 100644
--- a/src/mips/code-stubs-mips.cc
+++ b/src/mips/code-stubs-mips.cc
@@ -5861,7 +5861,6 @@
__ Branch(&done, lt, scratch1, Operand(FIRST_NONSTRING_TYPE));
// Check the number to string cache.
- Label not_cached;
__ bind(¬_string);
// Puts the cached result into scratch1.
NumberToStringStub::GenerateLookupNumberStringCache(masm,
@@ -5870,23 +5869,9 @@
scratch2,
scratch3,
scratch4,
- ¬_cached);
+ slow);
__ mov(arg, scratch1);
__ sw(arg, MemOperand(sp, stack_offset));
- __ jmp(&done);
-
- // Check if the argument is a safe string wrapper.
- __ bind(¬_cached);
- __ JumpIfSmi(arg, slow);
- __ GetObjectType(arg, scratch1, scratch2); // map -> scratch1.
- __ Branch(slow, ne, scratch2, Operand(JS_VALUE_TYPE));
- __ lbu(scratch2, FieldMemOperand(scratch1, Map::kBitField2Offset));
- __ li(scratch4, 1 << Map::kStringWrapperSafeForDefaultValueOf);
- __ And(scratch2, scratch2, scratch4);
- __ Branch(slow, ne, scratch2, Operand(scratch4));
- __ lw(arg, FieldMemOperand(arg, JSValue::kValueOffset));
- __ sw(arg, MemOperand(sp, stack_offset));
-
__ bind(&done);
}
@@ -6983,87 +6968,125 @@
template<class T>
-static void CreateArrayDispatch(MacroAssembler* masm) {
- int last_index = GetSequenceIndexFromFastElementsKind(
- TERMINAL_FAST_ELEMENTS_KIND);
- for (int i = 0; i <= last_index; ++i) {
- Label next;
- ElementsKind kind = GetFastElementsKindFromSequenceIndex(i);
- __ Branch(&next, ne, a3, Operand(kind));
- T stub(kind);
+static void CreateArrayDispatch(MacroAssembler* masm,
+ AllocationSiteOverrideMode mode) {
+ if (mode == DISABLE_ALLOCATION_SITES) {
+ T stub(GetInitialFastElementsKind(),
+ CONTEXT_CHECK_REQUIRED,
+ mode);
__ TailCallStub(&stub);
- __ bind(&next);
- }
+ } else if (mode == DONT_OVERRIDE) {
+ int last_index = GetSequenceIndexFromFastElementsKind(
+ TERMINAL_FAST_ELEMENTS_KIND);
+ for (int i = 0; i <= last_index; ++i) {
+ Label next;
+ ElementsKind kind = GetFastElementsKindFromSequenceIndex(i);
+ __ Branch(&next, ne, a3, Operand(kind));
+ T stub(kind);
+ __ TailCallStub(&stub);
+ __ bind(&next);
+ }
- // If we reached this point there is a problem.
- __ Abort(kUnexpectedElementsKindInArrayConstructor);
+ // If we reached this point there is a problem.
+ __ Abort(kUnexpectedElementsKindInArrayConstructor);
+ } else {
+ UNREACHABLE();
+ }
}
-static void CreateArrayDispatchOneArgument(MacroAssembler* masm) {
- // a2 - type info cell
- // a3 - kind
+static void CreateArrayDispatchOneArgument(MacroAssembler* masm,
+ AllocationSiteOverrideMode mode) {
+ // a2 - type info cell (if mode != DISABLE_ALLOCATION_SITES)
+ // a3 - kind (if mode != DISABLE_ALLOCATION_SITES)
// a0 - number of arguments
// a1 - constructor?
// sp[0] - last argument
- ASSERT(FAST_SMI_ELEMENTS == 0);
- ASSERT(FAST_HOLEY_SMI_ELEMENTS == 1);
- ASSERT(FAST_ELEMENTS == 2);
- ASSERT(FAST_HOLEY_ELEMENTS == 3);
- ASSERT(FAST_DOUBLE_ELEMENTS == 4);
- ASSERT(FAST_HOLEY_DOUBLE_ELEMENTS == 5);
-
- // is the low bit set? If so, we are holey and that is good.
Label normal_sequence;
- __ And(at, a3, Operand(1));
- __ Branch(&normal_sequence, ne, at, Operand(zero_reg));
+ if (mode == DONT_OVERRIDE) {
+ ASSERT(FAST_SMI_ELEMENTS == 0);
+ ASSERT(FAST_HOLEY_SMI_ELEMENTS == 1);
+ ASSERT(FAST_ELEMENTS == 2);
+ ASSERT(FAST_HOLEY_ELEMENTS == 3);
+ ASSERT(FAST_DOUBLE_ELEMENTS == 4);
+ ASSERT(FAST_HOLEY_DOUBLE_ELEMENTS == 5);
+
+ // is the low bit set? If so, we are holey and that is good.
+ __ And(at, a3, Operand(1));
+ __ Branch(&normal_sequence, ne, at, Operand(zero_reg));
+ }
// look at the first argument
__ lw(t1, MemOperand(sp, 0));
__ Branch(&normal_sequence, eq, t1, Operand(zero_reg));
- // We are going to create a holey array, but our kind is non-holey.
- // Fix kind and retry (only if we have an allocation site in the cell).
- __ Addu(a3, a3, Operand(1));
- __ LoadRoot(at, Heap::kUndefinedValueRootIndex);
- __ Branch(&normal_sequence, eq, a2, Operand(at));
- __ lw(t1, FieldMemOperand(a2, Cell::kValueOffset));
- __ lw(t1, FieldMemOperand(t1, 0));
- __ LoadRoot(at, Heap::kAllocationSiteMapRootIndex);
- __ Branch(&normal_sequence, ne, t1, Operand(at));
+ if (mode == DISABLE_ALLOCATION_SITES) {
+ ElementsKind initial = GetInitialFastElementsKind();
+ ElementsKind holey_initial = GetHoleyElementsKind(initial);
- // Save the resulting elements kind in type info
- __ SmiTag(a3);
- __ lw(t1, FieldMemOperand(a2, Cell::kValueOffset));
- __ sw(a3, FieldMemOperand(t1, AllocationSite::kTransitionInfoOffset));
- __ SmiUntag(a3);
+ ArraySingleArgumentConstructorStub stub_holey(holey_initial,
+ CONTEXT_CHECK_REQUIRED,
+ DISABLE_ALLOCATION_SITES);
+ __ TailCallStub(&stub_holey);
- __ bind(&normal_sequence);
- int last_index = GetSequenceIndexFromFastElementsKind(
- TERMINAL_FAST_ELEMENTS_KIND);
- for (int i = 0; i <= last_index; ++i) {
- Label next;
- ElementsKind kind = GetFastElementsKindFromSequenceIndex(i);
- __ Branch(&next, ne, a3, Operand(kind));
- ArraySingleArgumentConstructorStub stub(kind);
+ __ bind(&normal_sequence);
+ ArraySingleArgumentConstructorStub stub(initial,
+ CONTEXT_CHECK_REQUIRED,
+ DISABLE_ALLOCATION_SITES);
__ TailCallStub(&stub);
- __ bind(&next);
- }
+ } else if (mode == DONT_OVERRIDE) {
+ // We are going to create a holey array, but our kind is non-holey.
+ // Fix kind and retry (only if we have an allocation site in the cell).
+ __ Addu(a3, a3, Operand(1));
+ __ lw(t1, FieldMemOperand(a2, Cell::kValueOffset));
- // If we reached this point there is a problem.
- __ Abort(kUnexpectedElementsKindInArrayConstructor);
+ if (FLAG_debug_code) {
+ __ lw(t1, FieldMemOperand(t1, 0));
+ __ LoadRoot(at, Heap::kAllocationSiteMapRootIndex);
+ __ Assert(eq, kExpectedAllocationSiteInCell, t1, Operand(at));
+ __ lw(t1, FieldMemOperand(a2, Cell::kValueOffset));
+ }
+
+ // Save the resulting elements kind in type info
+ __ SmiTag(a3);
+ __ lw(t1, FieldMemOperand(a2, Cell::kValueOffset));
+ __ sw(a3, FieldMemOperand(t1, AllocationSite::kTransitionInfoOffset));
+ __ SmiUntag(a3);
+
+ __ bind(&normal_sequence);
+ int last_index = GetSequenceIndexFromFastElementsKind(
+ TERMINAL_FAST_ELEMENTS_KIND);
+ for (int i = 0; i <= last_index; ++i) {
+ Label next;
+ ElementsKind kind = GetFastElementsKindFromSequenceIndex(i);
+ __ Branch(&next, ne, a3, Operand(kind));
+ ArraySingleArgumentConstructorStub stub(kind);
+ __ TailCallStub(&stub);
+ __ bind(&next);
+ }
+
+ // If we reached this point there is a problem.
+ __ Abort(kUnexpectedElementsKindInArrayConstructor);
+ } else {
+ UNREACHABLE();
+ }
}
template<class T>
static void ArrayConstructorStubAheadOfTimeHelper(Isolate* isolate) {
+ ElementsKind initial_kind = GetInitialFastElementsKind();
+ ElementsKind initial_holey_kind = GetHoleyElementsKind(initial_kind);
+
int to_index = GetSequenceIndexFromFastElementsKind(
TERMINAL_FAST_ELEMENTS_KIND);
for (int i = 0; i <= to_index; ++i) {
ElementsKind kind = GetFastElementsKindFromSequenceIndex(i);
T stub(kind);
stub.GetCode(isolate)->set_is_pregenerated(true);
- if (AllocationSite::GetMode(kind) != DONT_TRACK_ALLOCATION_SITE) {
+ if (AllocationSite::GetMode(kind) != DONT_TRACK_ALLOCATION_SITE ||
+ (!FLAG_track_allocation_sites &&
+ (kind == initial_kind || kind == initial_holey_kind))) {
T stub1(kind, CONTEXT_CHECK_REQUIRED, DISABLE_ALLOCATION_SITES);
stub1.GetCode(isolate)->set_is_pregenerated(true);
}
@@ -7096,6 +7119,33 @@
}
+void ArrayConstructorStub::GenerateDispatchToArrayStub(
+ MacroAssembler* masm,
+ AllocationSiteOverrideMode mode) {
+ if (argument_count_ == ANY) {
+ Label not_zero_case, not_one_case;
+ __ And(at, a0, a0);
+ __ Branch(¬_zero_case, ne, at, Operand(zero_reg));
+ CreateArrayDispatch<ArrayNoArgumentConstructorStub>(masm, mode);
+
+ __ bind(¬_zero_case);
+ __ Branch(¬_one_case, gt, a0, Operand(1));
+ CreateArrayDispatchOneArgument(masm, mode);
+
+ __ bind(¬_one_case);
+ CreateArrayDispatch<ArrayNArgumentsConstructorStub>(masm, mode);
+ } else if (argument_count_ == NONE) {
+ CreateArrayDispatch<ArrayNoArgumentConstructorStub>(masm, mode);
+ } else if (argument_count_ == ONE) {
+ CreateArrayDispatchOneArgument(masm, mode);
+ } else if (argument_count_ == MORE_THAN_ONE) {
+ CreateArrayDispatch<ArrayNArgumentsConstructorStub>(masm, mode);
+ } else {
+ UNREACHABLE();
+ }
+}
+
+
void ArrayConstructorStub::Generate(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- a0 : argc (only if argument_count_ == ANY)
@@ -7129,49 +7179,24 @@
__ bind(&okay_here);
}
- Label no_info, switch_ready;
+ Label no_info;
// Get the elements kind and case on that.
__ LoadRoot(at, Heap::kUndefinedValueRootIndex);
__ Branch(&no_info, eq, a2, Operand(at));
__ lw(a3, FieldMemOperand(a2, Cell::kValueOffset));
- // The type cell may have undefined in its value.
- __ LoadRoot(at, Heap::kUndefinedValueRootIndex);
- __ Branch(&no_info, eq, a3, Operand(at));
-
- // The type cell has either an AllocationSite or a JSFunction.
+ // If the type cell is undefined, or contains anything other than an
+ // AllocationSite, call an array constructor that doesn't use AllocationSites.
__ lw(t0, FieldMemOperand(a3, 0));
__ LoadRoot(at, Heap::kAllocationSiteMapRootIndex);
__ Branch(&no_info, ne, t0, Operand(at));
__ lw(a3, FieldMemOperand(a3, AllocationSite::kTransitionInfoOffset));
__ SmiUntag(a3);
- __ jmp(&switch_ready);
+ GenerateDispatchToArrayStub(masm, DONT_OVERRIDE);
+
__ bind(&no_info);
- __ li(a3, Operand(GetInitialFastElementsKind()));
- __ bind(&switch_ready);
-
- if (argument_count_ == ANY) {
- Label not_zero_case, not_one_case;
- __ And(at, a0, a0);
- __ Branch(¬_zero_case, ne, at, Operand(zero_reg));
- CreateArrayDispatch<ArrayNoArgumentConstructorStub>(masm);
-
- __ bind(¬_zero_case);
- __ Branch(¬_one_case, gt, a0, Operand(1));
- CreateArrayDispatchOneArgument(masm);
-
- __ bind(¬_one_case);
- CreateArrayDispatch<ArrayNArgumentsConstructorStub>(masm);
- } else if (argument_count_ == NONE) {
- CreateArrayDispatch<ArrayNoArgumentConstructorStub>(masm);
- } else if (argument_count_ == ONE) {
- CreateArrayDispatchOneArgument(masm);
- } else if (argument_count_ == MORE_THAN_ONE) {
- CreateArrayDispatch<ArrayNArgumentsConstructorStub>(masm);
- } else {
- UNREACHABLE();
- }
+ GenerateDispatchToArrayStub(masm, DISABLE_ALLOCATION_SITES);
}
diff --git a/src/mips/full-codegen-mips.cc b/src/mips/full-codegen-mips.cc
index bf6f1c8..df3f417 100644
--- a/src/mips/full-codegen-mips.cc
+++ b/src/mips/full-codegen-mips.cc
@@ -3028,7 +3028,7 @@
VisitForAccumulatorValue(args->at(0));
- Label materialize_true, materialize_false;
+ Label materialize_true, materialize_false, skip_lookup;
Label* if_true = NULL;
Label* if_false = NULL;
Label* fall_through = NULL;
@@ -3040,7 +3040,7 @@
__ lw(a1, FieldMemOperand(v0, HeapObject::kMapOffset));
__ lbu(t0, FieldMemOperand(a1, Map::kBitField2Offset));
__ And(t0, t0, 1 << Map::kStringWrapperSafeForDefaultValueOf);
- __ Branch(if_true, ne, t0, Operand(zero_reg));
+ __ Branch(&skip_lookup, ne, t0, Operand(zero_reg));
// Check for fast case object. Generate false result for slow case object.
__ lw(a2, FieldMemOperand(v0, JSObject::kPropertiesOffset));
@@ -3086,6 +3086,14 @@
__ Branch(&loop, ne, t0, Operand(a2));
__ bind(&done);
+
+ // Set the bit in the map to indicate that there is no local valueOf field.
+ __ lbu(a2, FieldMemOperand(a1, Map::kBitField2Offset));
+ __ Or(a2, a2, Operand(1 << Map::kStringWrapperSafeForDefaultValueOf));
+ __ sb(a2, FieldMemOperand(a1, Map::kBitField2Offset));
+
+ __ bind(&skip_lookup);
+
// If a valueOf property is not found on the object check that its
// prototype is the un-modified String prototype. If not result is false.
__ lw(a2, FieldMemOperand(a1, Map::kPrototypeOffset));
@@ -3094,11 +3102,9 @@
__ lw(a3, ContextOperand(cp, Context::GLOBAL_OBJECT_INDEX));
__ lw(a3, FieldMemOperand(a3, GlobalObject::kNativeContextOffset));
__ lw(a3, ContextOperand(a3, Context::STRING_FUNCTION_PROTOTYPE_MAP_INDEX));
- __ Branch(if_false, ne, a2, Operand(a3));
-
- __ jmp(if_true);
-
PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
+ Split(eq, a2, Operand(a3), if_true, if_false, fall_through);
+
context()->Plug(if_true, if_false);
}
diff --git a/src/mips/lithium-codegen-mips.cc b/src/mips/lithium-codegen-mips.cc
index ab713a3..b37c7e0 100644
--- a/src/mips/lithium-codegen-mips.cc
+++ b/src/mips/lithium-codegen-mips.cc
@@ -3813,79 +3813,64 @@
void LCodeGen::DoRandom(LRandom* instr) {
- class DeferredDoRandom V8_FINAL : public LDeferredCode {
- public:
- DeferredDoRandom(LCodeGen* codegen, LRandom* instr)
- : LDeferredCode(codegen), instr_(instr) { }
- virtual void Generate() V8_OVERRIDE { codegen()->DoDeferredRandom(instr_); }
- virtual LInstruction* instr() V8_OVERRIDE { return instr_; }
- private:
- LRandom* instr_;
- };
-
- DeferredDoRandom* deferred = new(zone()) DeferredDoRandom(this, instr);
- // Having marked this instruction as a call we can use any
- // registers.
- ASSERT(ToDoubleRegister(instr->result()).is(f0));
- ASSERT(ToRegister(instr->global_object()).is(a0));
-
+ // Assert that the register size is indeed the size of each seed.
static const int kSeedSize = sizeof(uint32_t);
STATIC_ASSERT(kPointerSize == kSeedSize);
- __ lw(a0, FieldMemOperand(a0, GlobalObject::kNativeContextOffset));
+ // Load native context.
+ Register global_object = ToRegister(instr->global_object());
+ Register native_context = global_object;
+ __ lw(native_context, FieldMemOperand(
+ global_object, GlobalObject::kNativeContextOffset));
+
+ // Load state (FixedArray of the native context's random seeds).
static const int kRandomSeedOffset =
FixedArray::kHeaderSize + Context::RANDOM_SEED_INDEX * kPointerSize;
- __ lw(a2, FieldMemOperand(a0, kRandomSeedOffset));
- // a2: FixedArray of the native context's random seeds
+ Register state = native_context;
+ __ lw(state, FieldMemOperand(native_context, kRandomSeedOffset));
// Load state[0].
- __ lw(a1, FieldMemOperand(a2, ByteArray::kHeaderSize));
- __ Branch(deferred->entry(), eq, a1, Operand(zero_reg));
+ Register state0 = ToRegister(instr->scratch());
+ __ lw(state0, FieldMemOperand(state, ByteArray::kHeaderSize));
// Load state[1].
- __ lw(a0, FieldMemOperand(a2, ByteArray::kHeaderSize + kSeedSize));
- // a1: state[0].
- // a0: state[1].
+ Register state1 = ToRegister(instr->scratch2());
+ __ lw(state1, FieldMemOperand(state, ByteArray::kHeaderSize + kSeedSize));
// state[0] = 18273 * (state[0] & 0xFFFF) + (state[0] >> 16)
- __ And(a3, a1, Operand(0xFFFF));
- __ li(t0, Operand(18273));
- __ Mul(a3, a3, t0);
- __ srl(a1, a1, 16);
- __ Addu(a1, a3, a1);
+ Register scratch3 = ToRegister(instr->scratch3());
+ Register scratch4 = scratch0();
+ __ And(scratch3, state0, Operand(0xFFFF));
+ __ li(scratch4, Operand(18273));
+ __ Mul(scratch3, scratch3, scratch4);
+ __ srl(state0, state0, 16);
+ __ Addu(state0, scratch3, state0);
// Save state[0].
- __ sw(a1, FieldMemOperand(a2, ByteArray::kHeaderSize));
+ __ sw(state0, FieldMemOperand(state, ByteArray::kHeaderSize));
// state[1] = 36969 * (state[1] & 0xFFFF) + (state[1] >> 16)
- __ And(a3, a0, Operand(0xFFFF));
- __ li(t0, Operand(36969));
- __ Mul(a3, a3, t0);
- __ srl(a0, a0, 16),
- __ Addu(a0, a3, a0);
+ __ And(scratch3, state1, Operand(0xFFFF));
+ __ li(scratch4, Operand(36969));
+ __ Mul(scratch3, scratch3, scratch4);
+ __ srl(state1, state1, 16),
+ __ Addu(state1, scratch3, state1);
// Save state[1].
- __ sw(a0, FieldMemOperand(a2, ByteArray::kHeaderSize + kSeedSize));
+ __ sw(state1, FieldMemOperand(state, ByteArray::kHeaderSize + kSeedSize));
// Random bit pattern = (state[0] << 14) + (state[1] & 0x3FFFF)
- __ And(a0, a0, Operand(0x3FFFF));
- __ sll(a1, a1, 14);
- __ Addu(v0, a0, a1);
-
- __ bind(deferred->exit());
+ Register random = scratch4;
+ __ And(random, state1, Operand(0x3FFFF));
+ __ sll(state0, state0, 14);
+ __ Addu(random, random, state0);
// 0x41300000 is the top half of 1.0 x 2^20 as a double.
- __ li(a2, Operand(0x41300000));
+ __ li(scratch3, Operand(0x41300000));
// Move 0x41300000xxxxxxxx (x = random bits in v0) to FPU.
- __ Move(f12, v0, a2);
+ DoubleRegister result = ToDoubleRegister(instr->result());
+ __ Move(result, random, scratch3);
// Move 0x4130000000000000 to FPU.
- __ Move(f14, zero_reg, a2);
- // Subtract to get the result.
- __ sub_d(f0, f12, f14);
-}
-
-
-void LCodeGen::DoDeferredRandom(LRandom* instr) {
- __ PrepareCallCFunction(1, scratch0());
- __ CallCFunction(ExternalReference::random_uint32_function(isolate()), 1);
- // Return value is in v0.
+ DoubleRegister scratch5 = double_scratch0();
+ __ Move(scratch5, zero_reg, scratch3);
+ __ sub_d(result, result, scratch5);
}
diff --git a/src/mips/lithium-codegen-mips.h b/src/mips/lithium-codegen-mips.h
index 8437435..84105ca 100644
--- a/src/mips/lithium-codegen-mips.h
+++ b/src/mips/lithium-codegen-mips.h
@@ -147,7 +147,6 @@
void DoDeferredTaggedToI(LTaggedToI* instr);
void DoDeferredMathAbsTaggedHeapNumber(LMathAbs* instr);
void DoDeferredStackCheck(LStackCheck* instr);
- void DoDeferredRandom(LRandom* instr);
void DoDeferredStringCharCodeAt(LStringCharCodeAt* instr);
void DoDeferredStringCharFromCode(LStringCharFromCode* instr);
void DoDeferredAllocate(LAllocate* instr);
diff --git a/src/mips/lithium-mips.cc b/src/mips/lithium-mips.cc
index 9476f4d..4dc8022 100644
--- a/src/mips/lithium-mips.cc
+++ b/src/mips/lithium-mips.cc
@@ -1624,9 +1624,13 @@
LInstruction* LChunkBuilder::DoRandom(HRandom* instr) {
ASSERT(instr->representation().IsDouble());
ASSERT(instr->global_object()->representation().IsTagged());
- LOperand* global_object = UseFixed(instr->global_object(), a0);
- LRandom* result = new(zone()) LRandom(global_object);
- return MarkAsCall(DefineFixedDouble(result, f0), instr);
+ LOperand* global_object = UseTempRegister(instr->global_object());
+ LOperand* scratch = TempRegister();
+ LOperand* scratch2 = TempRegister();
+ LOperand* scratch3 = TempRegister();
+ LRandom* result = new(zone()) LRandom(
+ global_object, scratch, scratch2, scratch3);
+ return DefineFixedDouble(result, f0);
}
diff --git a/src/mips/lithium-mips.h b/src/mips/lithium-mips.h
index fa2aed5..29a8eac 100644
--- a/src/mips/lithium-mips.h
+++ b/src/mips/lithium-mips.h
@@ -1444,13 +1444,22 @@
};
-class LRandom V8_FINAL : public LTemplateInstruction<1, 1, 0> {
+class LRandom V8_FINAL : public LTemplateInstruction<1, 1, 3> {
public:
- explicit LRandom(LOperand* global_object) {
+ LRandom(LOperand* global_object,
+ LOperand* scratch,
+ LOperand* scratch2,
+ LOperand* scratch3) {
inputs_[0] = global_object;
+ temps_[0] = scratch;
+ temps_[1] = scratch2;
+ temps_[2] = scratch3;
}
- LOperand* global_object() { return inputs_[0]; }
+ LOperand* global_object() const { return inputs_[0]; }
+ LOperand* scratch() const { return temps_[0]; }
+ LOperand* scratch2() const { return temps_[1]; }
+ LOperand* scratch3() const { return temps_[2]; }
DECLARE_CONCRETE_INSTRUCTION(Random, "random")
DECLARE_HYDROGEN_ACCESSOR(Random)
diff --git a/src/mips/stub-cache-mips.cc b/src/mips/stub-cache-mips.cc
index a8004d9..58452ca 100644
--- a/src/mips/stub-cache-mips.cc
+++ b/src/mips/stub-cache-mips.cc
@@ -777,16 +777,17 @@
Register holder,
Register name,
Handle<JSObject> holder_obj) {
+ STATIC_ASSERT(StubCache::kInterceptorArgsNameIndex == 0);
+ STATIC_ASSERT(StubCache::kInterceptorArgsInfoIndex == 1);
+ STATIC_ASSERT(StubCache::kInterceptorArgsThisIndex == 2);
+ STATIC_ASSERT(StubCache::kInterceptorArgsHolderIndex == 3);
+ STATIC_ASSERT(StubCache::kInterceptorArgsLength == 4);
__ push(name);
Handle<InterceptorInfo> interceptor(holder_obj->GetNamedInterceptor());
ASSERT(!masm->isolate()->heap()->InNewSpace(*interceptor));
Register scratch = name;
__ li(scratch, Operand(interceptor));
__ Push(scratch, receiver, holder);
- __ lw(scratch, FieldMemOperand(scratch, InterceptorInfo::kDataOffset));
- __ push(scratch);
- __ li(scratch, Operand(ExternalReference::isolate_address(masm->isolate())));
- __ push(scratch);
}
@@ -801,7 +802,7 @@
ExternalReference ref =
ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorOnly),
masm->isolate());
- __ PrepareCEntryArgs(6);
+ __ PrepareCEntryArgs(StubCache::kInterceptorArgsLength);
__ PrepareCEntryFunction(ref);
CEntryStub stub(1);
@@ -1107,7 +1108,7 @@
ExternalReference(
IC_Utility(IC::kLoadPropertyWithInterceptorForCall),
masm->isolate()),
- 6);
+ StubCache::kInterceptorArgsLength);
// Restore the name_ register.
__ pop(name_);
// Leave the internal frame.
@@ -1415,6 +1416,15 @@
Handle<ExecutableAccessorInfo> callback) {
// Build AccessorInfo::args_ list on the stack and push property name below
// the exit frame to make GC aware of them and store pointers to them.
+ STATIC_ASSERT(PropertyCallbackArguments::kThisIndex == 0);
+ STATIC_ASSERT(PropertyCallbackArguments::kDataIndex == -1);
+ STATIC_ASSERT(PropertyCallbackArguments::kReturnValueOffset == -2);
+ STATIC_ASSERT(PropertyCallbackArguments::kReturnValueDefaultValueIndex == -3);
+ STATIC_ASSERT(PropertyCallbackArguments::kIsolateIndex == -4);
+ STATIC_ASSERT(PropertyCallbackArguments::kHolderIndex == -5);
+ ASSERT(!scratch2().is(reg));
+ ASSERT(!scratch3().is(reg));
+ ASSERT(!scratch4().is(reg));
__ push(receiver());
__ mov(scratch2(), sp); // scratch2 = AccessorInfo::args_
if (heap()->InNewSpace(callback->data())) {
@@ -1425,14 +1435,14 @@
__ li(scratch3(), Handle<Object>(callback->data(), isolate()));
}
__ Subu(sp, sp, 6 * kPointerSize);
- __ sw(reg, MemOperand(sp, 5 * kPointerSize));
- __ sw(scratch3(), MemOperand(sp, 4 * kPointerSize));
+ __ sw(scratch3(), MemOperand(sp, 5 * kPointerSize));
__ LoadRoot(scratch3(), Heap::kUndefinedValueRootIndex);
+ __ sw(scratch3(), MemOperand(sp, 4 * kPointerSize));
__ sw(scratch3(), MemOperand(sp, 3 * kPointerSize));
- __ sw(scratch3(), MemOperand(sp, 2 * kPointerSize));
__ li(scratch4(),
Operand(ExternalReference::isolate_address(isolate())));
- __ sw(scratch4(), MemOperand(sp, 1 * kPointerSize));
+ __ sw(scratch4(), MemOperand(sp, 2 * kPointerSize));
+ __ sw(reg, MemOperand(sp, 1 * kPointerSize));
__ sw(name(), MemOperand(sp, 0 * kPointerSize));
__ mov(a2, scratch2()); // Saved in case scratch2 == a1.
@@ -1465,7 +1475,7 @@
thunk_ref,
a2,
kStackUnwindSpace,
- 5);
+ 6);
}
@@ -1550,7 +1560,7 @@
ExternalReference ref = ExternalReference(
IC_Utility(IC::kLoadPropertyWithInterceptorForLoad), isolate());
- __ TailCallExternalReference(ref, 6, 1);
+ __ TailCallExternalReference(ref, StubCache::kInterceptorArgsLength, 1);
}
}
diff --git a/src/mksnapshot.cc b/src/mksnapshot.cc
index efd6e79..9cf9e2e 100644
--- a/src/mksnapshot.cc
+++ b/src/mksnapshot.cc
@@ -314,9 +314,6 @@
// By default, log code create information in the snapshot.
i::FLAG_log_code = true;
- // Disable the i18n extension, as it doesn't support being snapshotted yet.
- i::FLAG_enable_i18n = false;
-
// Print the usage if an error occurs when parsing the command line
// flags or if the help flag is set.
int result = i::FlagList::SetFlagsFromCommandLine(&argc, argv, true);
diff --git a/src/natives.h b/src/natives.h
index e3f69d1..5f34420 100644
--- a/src/natives.h
+++ b/src/natives.h
@@ -36,7 +36,7 @@
int index);
enum NativeType {
- CORE, EXPERIMENTAL, D8, TEST, I18N
+ CORE, EXPERIMENTAL, D8, TEST
};
template <NativeType type>
@@ -61,7 +61,6 @@
typedef NativesCollection<CORE> Natives;
typedef NativesCollection<EXPERIMENTAL> ExperimentalNatives;
-typedef NativesCollection<I18N> I18NNatives;
} } // namespace v8::internal
diff --git a/src/objects-inl.h b/src/objects-inl.h
index c2dc750..89abe50 100644
--- a/src/objects-inl.h
+++ b/src/objects-inl.h
@@ -4970,12 +4970,6 @@
}
-bool JSFunction::IsMarkedForInstallingRecompiledCode() {
- return code() == GetIsolate()->builtins()->builtin(
- Builtins::kInstallRecompiledCode);
-}
-
-
bool JSFunction::IsMarkedForConcurrentRecompilation() {
return code() == GetIsolate()->builtins()->builtin(
Builtins::kConcurrentRecompile);
diff --git a/src/objects.cc b/src/objects.cc
index 43e3f53..e37f6d1 100644
--- a/src/objects.cc
+++ b/src/objects.cc
@@ -4479,18 +4479,19 @@
}
-void JSObject::UpdateMapCodeCache(Handle<JSObject> object,
- Handle<Name> name,
- Handle<Code> code) {
+void HeapObject::UpdateMapCodeCache(Handle<HeapObject> object,
+ Handle<Name> name,
+ Handle<Code> code) {
Handle<Map> map(object->map());
if (map->is_shared()) {
+ Handle<JSObject> receiver = Handle<JSObject>::cast(object);
// Fast case maps are never marked as shared.
- ASSERT(!object->HasFastProperties());
+ ASSERT(!receiver->HasFastProperties());
// Replace the map with an identical copy that can be safely modified.
map = Map::CopyNormalized(map, KEEP_INOBJECT_PROPERTIES,
UNIQUE_NORMALIZED_MAP);
- object->GetIsolate()->counters()->normalized_maps()->Increment();
- object->set_map(*map);
+ receiver->GetIsolate()->counters()->normalized_maps()->Increment();
+ receiver->set_map(*map);
}
Map::UpdateCodeCache(map, name, code);
}
@@ -9321,18 +9322,6 @@
}
-void JSFunction::MarkForInstallingRecompiledCode() {
- // The debugger could have switched the builtin to lazy compile.
- // In that case, simply carry on. It will be dealt with later.
- ASSERT(!IsOptimized());
- ASSERT(shared()->allows_lazy_compilation() || code()->optimizable());
- ASSERT(FLAG_concurrent_recompilation);
- set_code_no_write_barrier(
- GetIsolate()->builtins()->builtin(Builtins::kInstallRecompiledCode));
- // No write barrier required, since the builtin is part of the root set.
-}
-
-
void JSFunction::MarkInRecompileQueue() {
// We can only arrive here via the concurrent-recompilation builtin. If
// break points were set, the code would point to the lazy-compile builtin.
@@ -13806,6 +13795,74 @@
template<typename Shape, typename Key>
+uint32_t HashTable<Shape, Key>::EntryForProbe(Key key,
+ Object* k,
+ int probe,
+ uint32_t expected) {
+ uint32_t hash = HashTable<Shape, Key>::HashForObject(key, k);
+ uint32_t capacity = Capacity();
+ uint32_t entry = FirstProbe(hash, capacity);
+ for (int i = 1; i < probe; i++) {
+ if (entry == expected) return expected;
+ entry = NextProbe(entry, i, capacity);
+ }
+ return entry;
+}
+
+
+template<typename Shape, typename Key>
+void HashTable<Shape, Key>::Swap(uint32_t entry1,
+ uint32_t entry2,
+ WriteBarrierMode mode) {
+ int index1 = EntryToIndex(entry1);
+ int index2 = EntryToIndex(entry2);
+ Object* temp[Shape::kEntrySize];
+ for (int j = 0; j < Shape::kEntrySize; j++) {
+ temp[j] = get(index1 + j);
+ }
+ for (int j = 0; j < Shape::kEntrySize; j++) {
+ set(index1 + j, get(index2 + j), mode);
+ }
+ for (int j = 0; j < Shape::kEntrySize; j++) {
+ set(index2 + j, temp[j], mode);
+ }
+}
+
+
+template<typename Shape, typename Key>
+void HashTable<Shape, Key>::Rehash(Key key) {
+ DisallowHeapAllocation no_gc;
+ WriteBarrierMode mode = GetWriteBarrierMode(no_gc);
+ uint32_t capacity = Capacity();
+ bool done = false;
+ for (int probe = 1; !done; probe++) {
+ // All elements at entries given by one of the first _probe_ probes
+ // are placed correctly. Other elements might need to be moved.
+ done = true;
+ for (uint32_t current = 0; current < capacity; current++) {
+ Object* current_key = get(EntryToIndex(current));
+ if (IsKey(current_key)) {
+ uint32_t target = EntryForProbe(key, current_key, probe, current);
+ if (current == target) continue;
+ Object* target_key = get(EntryToIndex(target));
+ if (!IsKey(target_key) ||
+ EntryForProbe(key, target_key, probe, target) != target) {
+ // Put the current element into the correct position.
+ Swap(current, target, mode);
+ // The other element will be processed on the next iteration.
+ current--;
+ } else {
+ // The place for the current element is occupied. Leave the element
+ // for the next probe.
+ done = false;
+ }
+ }
+ }
+ }
+}
+
+
+template<typename Shape, typename Key>
MaybeObject* HashTable<Shape, Key>::EnsureCapacity(int n, Key key) {
int capacity = Capacity();
int nof = NumberOfElements() + n;
diff --git a/src/objects.h b/src/objects.h
index af0a891..d3593b6 100644
--- a/src/objects.h
+++ b/src/objects.h
@@ -1113,6 +1113,8 @@
V(kEval, "eval") \
V(kExpected0AsASmiSentinel, "Expected 0 as a Smi sentinel") \
V(kExpectedAlignmentMarker, "expected alignment marker") \
+ V(kExpectedAllocationSiteInCell, \
+ "Expected AllocationSite in property cell") \
V(kExpectedPropertyCellInRegisterA2, \
"Expected property cell in register a2") \
V(kExpectedPropertyCellInRegisterEbx, \
@@ -1756,6 +1758,13 @@
// during marking GC.
static inline Object** RawField(HeapObject* obj, int offset);
+ // Adds the |code| object related to |name| to the code cache of this map. If
+ // this map is a dictionary map that is shared, the map copied and installed
+ // onto the object.
+ static void UpdateMapCodeCache(Handle<HeapObject> object,
+ Handle<Name> name,
+ Handle<Code> code);
+
// Casting.
static inline HeapObject* cast(Object* obj);
@@ -2188,13 +2197,6 @@
inline MUST_USE_RESULT MaybeObject* TryMigrateInstance();
// Can cause GC.
- MUST_USE_RESULT MaybeObject* SetLocalPropertyIgnoreAttributes(
- Name* key,
- Object* value,
- PropertyAttributes attributes,
- ValueType value_type = OPTIMAL_REPRESENTATION,
- StoreMode mode = ALLOW_AS_CONSTANT,
- ExtensibilityCheck extensibility_check = PERFORM_EXTENSIBILITY_CHECK);
MUST_USE_RESULT MaybeObject* SetLocalPropertyIgnoreAttributesTrampoline(
Name* key,
Object* value,
@@ -2574,10 +2576,6 @@
MUST_USE_RESULT MaybeObject* NormalizeElements();
- static void UpdateMapCodeCache(Handle<JSObject> object,
- Handle<Name> name,
- Handle<Code> code);
-
// Transform slow named properties to fast variants.
// Returns failure if allocation failed.
static void TransformToFastProperties(Handle<JSObject> object,
@@ -2736,6 +2734,15 @@
friend class DictionaryElementsAccessor;
friend class JSReceiver;
+ // TODO(mstarzinger): Soon to be handlified.
+ MUST_USE_RESULT MaybeObject* SetLocalPropertyIgnoreAttributes(
+ Name* key,
+ Object* value,
+ PropertyAttributes attributes,
+ ValueType value_type = OPTIMAL_REPRESENTATION,
+ StoreMode mode = ALLOW_AS_CONSTANT,
+ ExtensibilityCheck extensibility_check = PERFORM_EXTENSIBILITY_CHECK);
+
MUST_USE_RESULT MaybeObject* GetElementWithCallback(Object* receiver,
Object* structure,
uint32_t index,
@@ -3473,6 +3480,9 @@
inline int FindEntry(Key key);
int FindEntry(Isolate* isolate, Key key);
+ // Rehashes the table in-place.
+ void Rehash(Key key);
+
protected:
// Find the entry at which to insert element with the given key that
// has the given hash value.
@@ -3519,6 +3529,13 @@
return (last + number) & (size - 1);
}
+ // Returns _expected_ if one of entries given by the first _probe_ probes is
+ // equal to _expected_. Otherwise, returns the entry given by the probe
+ // number _probe_.
+ uint32_t EntryForProbe(Key key, Object* k, int probe, uint32_t expected);
+
+ void Swap(uint32_t entry1, uint32_t entry2, WriteBarrierMode mode);
+
// Rehashes this hash-table into the new table.
MUST_USE_RESULT MaybeObject* Rehash(HashTable* new_table, Key key);
@@ -5909,6 +5926,10 @@
return instance_type() >= FIRST_JS_OBJECT_TYPE;
}
+ bool IsJSObjectMap() {
+ return instance_type() >= FIRST_JS_OBJECT_TYPE;
+ }
+
// Fires when the layout of an object with a leaf map changes.
// This includes adding transitions to the leaf map or changing
// the descriptor array.
@@ -6979,7 +7000,6 @@
// recompiled the next time it is executed.
void MarkForLazyRecompilation();
void MarkForConcurrentRecompilation();
- void MarkForInstallingRecompiledCode();
void MarkInRecompileQueue();
// Helpers to compile this function. Returns true on success, false on
@@ -6998,7 +7018,6 @@
// recompilation.
inline bool IsMarkedForLazyRecompilation();
inline bool IsMarkedForConcurrentRecompilation();
- inline bool IsMarkedForInstallingRecompiledCode();
// Tells whether or not the function is on the concurrent recompilation queue.
inline bool IsInRecompileQueue();
diff --git a/src/optimizing-compiler-thread.cc b/src/optimizing-compiler-thread.cc
index a040453..085143d 100644
--- a/src/optimizing-compiler-thread.cc
+++ b/src/optimizing-compiler-thread.cc
@@ -114,11 +114,8 @@
osr_candidates_.RemoveElement(optimizing_compiler);
ready_for_osr_.Add(optimizing_compiler);
} else {
- LockGuard<Mutex> mark_and_queue(&install_mutex_);
- Heap::RelocationLock relocation_lock(isolate_->heap());
- AllowHandleDereference ahd;
- optimizing_compiler->info()->closure()->MarkForInstallingRecompiledCode();
output_queue_.Enqueue(optimizing_compiler);
+ isolate_->stack_guard()->RequestInstallCode();
}
}
@@ -201,10 +198,7 @@
HandleScope handle_scope(isolate_);
OptimizingCompiler* compiler;
while (true) {
- { // Memory barrier to ensure marked functions are queued.
- LockGuard<Mutex> marked_and_queued(&install_mutex_);
- if (!output_queue_.Dequeue(&compiler)) return;
- }
+ if (!output_queue_.Dequeue(&compiler)) return;
Compiler::InstallOptimizedCode(compiler);
}
diff --git a/src/optimizing-compiler-thread.h b/src/optimizing-compiler-thread.h
index f45665b..d1ed6a2 100644
--- a/src/optimizing-compiler-thread.h
+++ b/src/optimizing-compiler-thread.h
@@ -120,7 +120,6 @@
// List of recompilation tasks ready for OSR.
List<OptimizingCompiler*> ready_for_osr_;
- Mutex install_mutex_;
volatile AtomicWord stop_thread_;
volatile Atomic32 queue_length_;
TimeDelta time_spent_compiling_;
diff --git a/src/platform/elapsed-timer.h b/src/platform/elapsed-timer.h
index 8044bd0..2311db2 100644
--- a/src/platform/elapsed-timer.h
+++ b/src/platform/elapsed-timer.h
@@ -103,7 +103,7 @@
}
private:
- V8_INLINE(static TimeTicks Now()) {
+ static V8_INLINE TimeTicks Now() {
TimeTicks now = TimeTicks::HighResNow();
ASSERT(!now.IsNull());
return now;
diff --git a/src/platform/mutex.cc b/src/platform/mutex.cc
index 1a7c69a..ad97740 100644
--- a/src/platform/mutex.cc
+++ b/src/platform/mutex.cc
@@ -34,7 +34,7 @@
#if V8_OS_POSIX
-static V8_INLINE(void InitializeNativeHandle(pthread_mutex_t* mutex)) {
+static V8_INLINE void InitializeNativeHandle(pthread_mutex_t* mutex) {
int result;
#if defined(DEBUG)
// Use an error checking mutex in debug mode.
@@ -55,7 +55,7 @@
}
-static V8_INLINE(void InitializeRecursiveNativeHandle(pthread_mutex_t* mutex)) {
+static V8_INLINE void InitializeRecursiveNativeHandle(pthread_mutex_t* mutex) {
pthread_mutexattr_t attr;
int result = pthread_mutexattr_init(&attr);
ASSERT_EQ(0, result);
@@ -69,28 +69,28 @@
}
-static V8_INLINE(void DestroyNativeHandle(pthread_mutex_t* mutex)) {
+static V8_INLINE void DestroyNativeHandle(pthread_mutex_t* mutex) {
int result = pthread_mutex_destroy(mutex);
ASSERT_EQ(0, result);
USE(result);
}
-static V8_INLINE(void LockNativeHandle(pthread_mutex_t* mutex)) {
+static V8_INLINE void LockNativeHandle(pthread_mutex_t* mutex) {
int result = pthread_mutex_lock(mutex);
ASSERT_EQ(0, result);
USE(result);
}
-static V8_INLINE(void UnlockNativeHandle(pthread_mutex_t* mutex)) {
+static V8_INLINE void UnlockNativeHandle(pthread_mutex_t* mutex) {
int result = pthread_mutex_unlock(mutex);
ASSERT_EQ(0, result);
USE(result);
}
-static V8_INLINE(bool TryLockNativeHandle(pthread_mutex_t* mutex)) {
+static V8_INLINE bool TryLockNativeHandle(pthread_mutex_t* mutex) {
int result = pthread_mutex_trylock(mutex);
if (result == EBUSY) {
return false;
@@ -101,32 +101,32 @@
#elif V8_OS_WIN
-static V8_INLINE(void InitializeNativeHandle(PCRITICAL_SECTION cs)) {
+static V8_INLINE void InitializeNativeHandle(PCRITICAL_SECTION cs) {
InitializeCriticalSection(cs);
}
-static V8_INLINE(void InitializeRecursiveNativeHandle(PCRITICAL_SECTION cs)) {
+static V8_INLINE void InitializeRecursiveNativeHandle(PCRITICAL_SECTION cs) {
InitializeCriticalSection(cs);
}
-static V8_INLINE(void DestroyNativeHandle(PCRITICAL_SECTION cs)) {
+static V8_INLINE void DestroyNativeHandle(PCRITICAL_SECTION cs) {
DeleteCriticalSection(cs);
}
-static V8_INLINE(void LockNativeHandle(PCRITICAL_SECTION cs)) {
+static V8_INLINE void LockNativeHandle(PCRITICAL_SECTION cs) {
EnterCriticalSection(cs);
}
-static V8_INLINE(void UnlockNativeHandle(PCRITICAL_SECTION cs)) {
+static V8_INLINE void UnlockNativeHandle(PCRITICAL_SECTION cs) {
LeaveCriticalSection(cs);
}
-static V8_INLINE(bool TryLockNativeHandle(PCRITICAL_SECTION cs)) {
+static V8_INLINE bool TryLockNativeHandle(PCRITICAL_SECTION cs) {
return TryEnterCriticalSection(cs);
}
diff --git a/src/platform/mutex.h b/src/platform/mutex.h
index f08de4f..0f899ca 100644
--- a/src/platform/mutex.h
+++ b/src/platform/mutex.h
@@ -94,14 +94,14 @@
int level_;
#endif
- V8_INLINE(void AssertHeldAndUnmark()) {
+ V8_INLINE void AssertHeldAndUnmark() {
#ifdef DEBUG
ASSERT_EQ(1, level_);
level_--;
#endif
}
- V8_INLINE(void AssertUnheldAndMark()) {
+ V8_INLINE void AssertUnheldAndMark() {
#ifdef DEBUG
ASSERT_EQ(0, level_);
level_++;
diff --git a/src/platform/socket.h b/src/platform/socket.h
index e9e2fa2..ff8c1de 100644
--- a/src/platform/socket.h
+++ b/src/platform/socket.h
@@ -66,7 +66,7 @@
// Set the value of the SO_REUSEADDR socket option.
bool SetReuseAddress(bool reuse_address);
- V8_INLINE(bool IsValid()) const {
+ V8_INLINE bool IsValid() const {
return native_handle_ != kInvalidNativeHandle;
}
diff --git a/src/runtime-profiler.cc b/src/runtime-profiler.cc
index 8676d81..95dcc4f 100644
--- a/src/runtime-profiler.cc
+++ b/src/runtime-profiler.cc
@@ -149,7 +149,6 @@
// recompilation race. This goes away as soon as OSR becomes one-shot.
return;
}
- ASSERT(!function->IsMarkedForInstallingRecompiledCode());
ASSERT(!function->IsInRecompileQueue());
function->MarkForConcurrentRecompilation();
} else {
@@ -227,12 +226,6 @@
if (isolate_->DebuggerHasBreakPoints()) return;
- if (FLAG_concurrent_recompilation) {
- // Take this as opportunity to process the optimizing compiler thread's
- // output queue so that it does not unnecessarily keep objects alive.
- isolate_->optimizing_compiler_thread()->InstallOptimizedFunctions();
- }
-
DisallowHeapAllocation no_gc;
// Run through the JavaScript frames and collect them. If we already
diff --git a/src/runtime.cc b/src/runtime.cc
index 00efa51..c09fb1d 100644
--- a/src/runtime.cc
+++ b/src/runtime.cc
@@ -2276,9 +2276,13 @@
LookupResult lookup(isolate);
global->LocalLookup(*name, &lookup);
if (!lookup.IsFound()) {
- return global->SetLocalPropertyIgnoreAttributes(*name,
- *value,
- attributes);
+ HandleScope handle_scope(isolate);
+ Handle<GlobalObject> global(isolate->context()->global_object());
+ RETURN_IF_EMPTY_HANDLE(
+ isolate,
+ JSObject::SetLocalPropertyIgnoreAttributes(global, name, value,
+ attributes));
+ return *value;
}
if (!lookup.IsReadOnly()) {
@@ -2495,41 +2499,41 @@
RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpInitializeObject) {
- SealHandleScope shs(isolate);
+ HandleScope scope(isolate);
DisallowHeapAllocation no_allocation;
ASSERT(args.length() == 5);
- CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
- CONVERT_ARG_CHECKED(String, source, 1);
+ CONVERT_ARG_HANDLE_CHECKED(JSRegExp, regexp, 0);
+ CONVERT_ARG_HANDLE_CHECKED(String, source, 1);
// If source is the empty string we set it to "(?:)" instead as
// suggested by ECMA-262, 5th, section 15.10.4.1.
- if (source->length() == 0) source = isolate->heap()->query_colon_string();
+ if (source->length() == 0) source = isolate->factory()->query_colon_string();
- Object* global = args[2];
- if (!global->IsTrue()) global = isolate->heap()->false_value();
+ CONVERT_ARG_HANDLE_CHECKED(Object, global, 2);
+ if (!global->IsTrue()) global = isolate->factory()->false_value();
- Object* ignoreCase = args[3];
- if (!ignoreCase->IsTrue()) ignoreCase = isolate->heap()->false_value();
+ CONVERT_ARG_HANDLE_CHECKED(Object, ignoreCase, 3);
+ if (!ignoreCase->IsTrue()) ignoreCase = isolate->factory()->false_value();
- Object* multiline = args[4];
- if (!multiline->IsTrue()) multiline = isolate->heap()->false_value();
+ CONVERT_ARG_HANDLE_CHECKED(Object, multiline, 4);
+ if (!multiline->IsTrue()) multiline = isolate->factory()->false_value();
Map* map = regexp->map();
Object* constructor = map->constructor();
if (constructor->IsJSFunction() &&
JSFunction::cast(constructor)->initial_map() == map) {
// If we still have the original map, set in-object properties directly.
- regexp->InObjectPropertyAtPut(JSRegExp::kSourceFieldIndex, source);
+ regexp->InObjectPropertyAtPut(JSRegExp::kSourceFieldIndex, *source);
// Both true and false are immovable immortal objects so no need for write
// barrier.
regexp->InObjectPropertyAtPut(
- JSRegExp::kGlobalFieldIndex, global, SKIP_WRITE_BARRIER);
+ JSRegExp::kGlobalFieldIndex, *global, SKIP_WRITE_BARRIER);
regexp->InObjectPropertyAtPut(
- JSRegExp::kIgnoreCaseFieldIndex, ignoreCase, SKIP_WRITE_BARRIER);
+ JSRegExp::kIgnoreCaseFieldIndex, *ignoreCase, SKIP_WRITE_BARRIER);
regexp->InObjectPropertyAtPut(
- JSRegExp::kMultilineFieldIndex, multiline, SKIP_WRITE_BARRIER);
+ JSRegExp::kMultilineFieldIndex, *multiline, SKIP_WRITE_BARRIER);
regexp->InObjectPropertyAtPut(
JSRegExp::kLastIndexFieldIndex, Smi::FromInt(0), SKIP_WRITE_BARRIER);
- return regexp;
+ return *regexp;
}
// Map has changed, so use generic, but slower, method.
@@ -2537,34 +2541,19 @@
static_cast<PropertyAttributes>(READ_ONLY | DONT_ENUM | DONT_DELETE);
PropertyAttributes writable =
static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE);
- Heap* heap = isolate->heap();
- MaybeObject* result;
- result = regexp->SetLocalPropertyIgnoreAttributes(heap->source_string(),
- source,
- final);
- // TODO(jkummerow): Turn these back into ASSERTs when we can be certain
- // that it never fires in Release mode in the wild.
- CHECK(!result->IsFailure());
- result = regexp->SetLocalPropertyIgnoreAttributes(heap->global_string(),
- global,
- final);
- CHECK(!result->IsFailure());
- result =
- regexp->SetLocalPropertyIgnoreAttributes(heap->ignore_case_string(),
- ignoreCase,
- final);
- CHECK(!result->IsFailure());
- result = regexp->SetLocalPropertyIgnoreAttributes(heap->multiline_string(),
- multiline,
- final);
- CHECK(!result->IsFailure());
- result =
- regexp->SetLocalPropertyIgnoreAttributes(heap->last_index_string(),
- Smi::FromInt(0),
- writable);
- CHECK(!result->IsFailure());
- USE(result);
- return regexp;
+ Handle<Object> zero(Smi::FromInt(0), isolate);
+ Factory* factory = isolate->factory();
+ CHECK_NOT_EMPTY_HANDLE(isolate, JSObject::SetLocalPropertyIgnoreAttributes(
+ regexp, factory->source_string(), source, final));
+ CHECK_NOT_EMPTY_HANDLE(isolate, JSObject::SetLocalPropertyIgnoreAttributes(
+ regexp, factory->global_string(), global, final));
+ CHECK_NOT_EMPTY_HANDLE(isolate, JSObject::SetLocalPropertyIgnoreAttributes(
+ regexp, factory->ignore_case_string(), ignoreCase, final));
+ CHECK_NOT_EMPTY_HANDLE(isolate, JSObject::SetLocalPropertyIgnoreAttributes(
+ regexp, factory->multiline_string(), multiline, final));
+ CHECK_NOT_EMPTY_HANDLE(isolate, JSObject::SetLocalPropertyIgnoreAttributes(
+ regexp, factory->last_index_string(), zero, writable));
+ return *regexp;
}
@@ -5064,9 +5053,10 @@
JSObject::NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0);
// Use IgnoreAttributes version since a readonly property may be
// overridden and SetProperty does not allow this.
- return js_object->SetLocalPropertyIgnoreAttributes(*name,
- *obj_value,
- attr);
+ Handle<Object> result = JSObject::SetLocalPropertyIgnoreAttributes(
+ js_object, name, obj_value, attr);
+ RETURN_IF_EMPTY_HANDLE(isolate, result);
+ return *result;
}
return Runtime::ForceSetObjectProperty(isolate,
@@ -5252,7 +5242,10 @@
index, *value, attr, kNonStrictMode, false, DEFINE_PROPERTY);
} else {
if (name->IsString()) Handle<String>::cast(name)->TryFlatten();
- return js_object->SetLocalPropertyIgnoreAttributes(*name, *value, attr);
+ Handle<Object> result = JSObject::SetLocalPropertyIgnoreAttributes(
+ js_object, name, value, attr);
+ RETURN_IF_EMPTY_HANDLE(isolate, result);
+ return *result;
}
}
@@ -5267,7 +5260,10 @@
return js_object->SetElement(
index, *value, attr, kNonStrictMode, false, DEFINE_PROPERTY);
} else {
- return js_object->SetLocalPropertyIgnoreAttributes(*name, *value, attr);
+ Handle<Object> result = JSObject::SetLocalPropertyIgnoreAttributes(
+ js_object, name, value, attr);
+ RETURN_IF_EMPTY_HANDLE(isolate, result);
+ return *result;
}
}
@@ -5470,10 +5466,11 @@
// Set a local property, even if it is READ_ONLY. If the property does not
// exist, it will be added with attributes NONE.
RUNTIME_FUNCTION(MaybeObject*, Runtime_IgnoreAttributesAndSetProperty) {
- SealHandleScope shs(isolate);
+ HandleScope scope(isolate);
RUNTIME_ASSERT(args.length() == 3 || args.length() == 4);
- CONVERT_ARG_CHECKED(JSObject, object, 0);
- CONVERT_ARG_CHECKED(Name, name, 1);
+ CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
+ CONVERT_ARG_HANDLE_CHECKED(Name, name, 1);
+ CONVERT_ARG_HANDLE_CHECKED(Object, value, 2);
// Compute attributes.
PropertyAttributes attributes = NONE;
if (args.length() == 4) {
@@ -5483,9 +5480,10 @@
(unchecked_value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
attributes = static_cast<PropertyAttributes>(unchecked_value);
}
-
- return object->
- SetLocalPropertyIgnoreAttributes(name, args[2], attributes);
+ Handle<Object> result = JSObject::SetLocalPropertyIgnoreAttributes(
+ object, name, value, attributes);
+ RETURN_IF_EMPTY_HANDLE(isolate, result);
+ return *result;
}
@@ -8346,16 +8344,6 @@
}
-RUNTIME_FUNCTION(MaybeObject*, Runtime_InstallRecompiledCode) {
- HandleScope handle_scope(isolate);
- ASSERT(args.length() == 1);
- CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
- ASSERT(isolate->use_crankshaft() && FLAG_concurrent_recompilation);
- isolate->optimizing_compiler_thread()->InstallOptimizedFunctions();
- return function->code();
-}
-
-
class ActivationsFinder : public ThreadVisitor {
public:
Code* code_;
@@ -8553,8 +8541,7 @@
}
CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
if (FLAG_concurrent_recompilation && sync_with_compiler_thread) {
- while (function->IsInRecompileQueue() ||
- function->IsMarkedForInstallingRecompiledCode()) {
+ while (function->IsInRecompileQueue()) {
isolate->optimizing_compiler_thread()->InstallOptimizedFunctions();
OS::Sleep(50);
}
@@ -9382,7 +9369,6 @@
// First check if this is a real stack overflow.
if (isolate->stack_guard()->IsStackOverflow()) {
- SealHandleScope shs(isolate);
return isolate->StackOverflow();
}
@@ -9390,6 +9376,23 @@
}
+RUNTIME_FUNCTION(MaybeObject*, Runtime_TryInstallRecompiledCode) {
+ HandleScope scope(isolate);
+ ASSERT(args.length() == 1);
+ CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
+
+ // First check if this is a real stack overflow.
+ if (isolate->stack_guard()->IsStackOverflow()) {
+ SealHandleScope shs(isolate);
+ return isolate->StackOverflow();
+ }
+
+ isolate->optimizing_compiler_thread()->InstallOptimizedFunctions();
+ return (function->IsOptimized()) ? function->code()
+ : function->shared()->code();
+}
+
+
RUNTIME_FUNCTION(MaybeObject*, Runtime_Interrupt) {
SealHandleScope shs(isolate);
ASSERT(args.length() == 0);
diff --git a/src/runtime.h b/src/runtime.h
index bce09a4..60c6677 100644
--- a/src/runtime.h
+++ b/src/runtime.h
@@ -88,7 +88,7 @@
F(LazyCompile, 1, 1) \
F(LazyRecompile, 1, 1) \
F(ConcurrentRecompile, 1, 1) \
- F(InstallRecompiledCode, 1, 1) \
+ F(TryInstallRecompiledCode, 1, 1) \
F(NotifyDeoptimized, 1, 1) \
F(NotifyStubFailure, 0, 1) \
F(NotifyOSR, 0, 1) \
diff --git a/src/spaces.h b/src/spaces.h
index 1ccdacb..43f44a5 100644
--- a/src/spaces.h
+++ b/src/spaces.h
@@ -1085,7 +1085,7 @@
// Returns an indication of whether a pointer is in a space that has
// been allocated by this MemoryAllocator.
- V8_INLINE(bool IsOutsideAllocatedSpace(const void* address)) const {
+ V8_INLINE bool IsOutsideAllocatedSpace(const void* address) const {
return address < lowest_ever_allocated_ ||
address >= highest_ever_allocated_;
}
diff --git a/src/stub-cache.cc b/src/stub-cache.cc
index bdfb32f..7b23d0c 100644
--- a/src/stub-cache.cc
+++ b/src/stub-cache.cc
@@ -166,68 +166,68 @@
}
-Handle<Code> StubCache::ComputeMonomorphicLoadIC(Handle<JSObject> receiver,
+Handle<Code> StubCache::ComputeMonomorphicLoadIC(Handle<HeapObject> receiver,
Handle<Code> handler,
Handle<Name> name) {
- Handle<Code> ic = FindIC(name, receiver, Code::LOAD_IC, handler->type());
+ Handle<Map> map(receiver->map());
+ Handle<Code> ic = FindIC(name, map, Code::LOAD_IC, handler->type());
if (!ic.is_null()) return ic;
LoadStubCompiler ic_compiler(isolate());
- ic = ic_compiler.CompileMonomorphicIC(
- Handle<Map>(receiver->map()), handler, name);
+ ic = ic_compiler.CompileMonomorphicIC(map, handler, name);
- JSObject::UpdateMapCodeCache(receiver, name, ic);
+ HeapObject::UpdateMapCodeCache(receiver, name, ic);
return ic;
}
-Handle<Code> StubCache::ComputeMonomorphicKeyedLoadIC(Handle<JSObject> receiver,
- Handle<Code> handler,
- Handle<Name> name) {
- Handle<Code> ic = FindIC(
- name, receiver, Code::KEYED_LOAD_IC, handler->type());
+Handle<Code> StubCache::ComputeMonomorphicKeyedLoadIC(
+ Handle<HeapObject> receiver,
+ Handle<Code> handler,
+ Handle<Name> name) {
+ Handle<Map> map(receiver->map());
+ Handle<Code> ic = FindIC(name, map, Code::KEYED_LOAD_IC, handler->type());
if (!ic.is_null()) return ic;
KeyedLoadStubCompiler ic_compiler(isolate());
- ic = ic_compiler.CompileMonomorphicIC(
- Handle<Map>(receiver->map()), handler, name);
+ ic = ic_compiler.CompileMonomorphicIC(map, handler, name);
- JSObject::UpdateMapCodeCache(receiver, name, ic);
+ HeapObject::UpdateMapCodeCache(receiver, name, ic);
return ic;
}
-Handle<Code> StubCache::ComputeMonomorphicStoreIC(Handle<JSObject> receiver,
+Handle<Code> StubCache::ComputeMonomorphicStoreIC(Handle<HeapObject> receiver,
Handle<Code> handler,
Handle<Name> name,
StrictModeFlag strict_mode) {
+ Handle<Map> map(receiver->map());
Handle<Code> ic = FindIC(
- name, receiver, Code::STORE_IC, handler->type(), strict_mode);
+ name, map, Code::STORE_IC, handler->type(), strict_mode);
if (!ic.is_null()) return ic;
StoreStubCompiler ic_compiler(isolate(), strict_mode);
- ic = ic_compiler.CompileMonomorphicIC(
- Handle<Map>(receiver->map()), handler, name);
+ ic = ic_compiler.CompileMonomorphicIC(map, handler, name);
- JSObject::UpdateMapCodeCache(receiver, name, ic);
+ HeapObject::UpdateMapCodeCache(receiver, name, ic);
return ic;
}
Handle<Code> StubCache::ComputeMonomorphicKeyedStoreIC(
- Handle<JSObject> receiver,
+ Handle<HeapObject> receiver,
Handle<Code> handler,
Handle<Name> name,
StrictModeFlag strict_mode) {
+ Handle<Map> map(receiver->map());
Handle<Code> ic = FindIC(
- name, receiver, Code::KEYED_STORE_IC, handler->type(), strict_mode);
+ name, map, Code::KEYED_STORE_IC, handler->type(), strict_mode);
if (!ic.is_null()) return ic;
KeyedStoreStubCompiler ic_compiler(isolate(), strict_mode, STANDARD_STORE);
- ic = ic_compiler.CompileMonomorphicIC(
- Handle<Map>(receiver->map()), handler, name);
+ ic = ic_compiler.CompileMonomorphicIC(map, handler, name);
- JSObject::UpdateMapCodeCache(receiver, name, ic);
+ HeapObject::UpdateMapCodeCache(receiver, name, ic);
return ic;
}
@@ -264,7 +264,7 @@
LoadStubCompiler compiler(isolate_);
handler =
compiler.CompileLoadNonexistent(receiver, current, cache_name, global);
- JSObject::UpdateMapCodeCache(receiver, cache_name, handler);
+ HeapObject::UpdateMapCodeCache(receiver, cache_name, handler);
return handler;
}
@@ -289,7 +289,7 @@
LoadStubCompiler compiler(isolate_);
Handle<Code> handler =
compiler.CompileLoadField(receiver, holder, name, field, representation);
- JSObject::UpdateMapCodeCache(stub_holder, name, handler);
+ HeapObject::UpdateMapCodeCache(stub_holder, name, handler);
return handler;
}
@@ -308,7 +308,7 @@
LoadStubCompiler compiler(isolate_);
Handle<Code> handler =
compiler.CompileLoadCallback(receiver, holder, name, callback);
- JSObject::UpdateMapCodeCache(stub_holder, name, handler);
+ HeapObject::UpdateMapCodeCache(stub_holder, name, handler);
return handler;
}
@@ -326,7 +326,7 @@
LoadStubCompiler compiler(isolate_);
Handle<Code> handler =
compiler.CompileLoadCallback(receiver, holder, name, call_optimization);
- JSObject::UpdateMapCodeCache(stub_holder, name, handler);
+ HeapObject::UpdateMapCodeCache(stub_holder, name, handler);
return handler;
}
@@ -343,7 +343,7 @@
LoadStubCompiler compiler(isolate_);
Handle<Code> handler =
compiler.CompileLoadViaGetter(receiver, holder, name, getter);
- JSObject::UpdateMapCodeCache(stub_holder, name, handler);
+ HeapObject::UpdateMapCodeCache(stub_holder, name, handler);
return handler;
}
@@ -359,7 +359,7 @@
LoadStubCompiler compiler(isolate_);
handler = compiler.CompileLoadConstant(receiver, holder, name, value);
- JSObject::UpdateMapCodeCache(stub_holder, name, handler);
+ HeapObject::UpdateMapCodeCache(stub_holder, name, handler);
return handler;
}
@@ -376,7 +376,7 @@
LoadStubCompiler compiler(isolate_);
Handle<Code> handler =
compiler.CompileLoadInterceptor(receiver, holder, name);
- JSObject::UpdateMapCodeCache(stub_holder, name, handler);
+ HeapObject::UpdateMapCodeCache(stub_holder, name, handler);
return handler;
}
@@ -399,7 +399,7 @@
LoadStubCompiler compiler(isolate_);
Handle<Code> ic =
compiler.CompileLoadGlobal(receiver, holder, cell, name, is_dont_delete);
- JSObject::UpdateMapCodeCache(stub_holder, name, ic);
+ HeapObject::UpdateMapCodeCache(stub_holder, name, ic);
return ic;
}
@@ -425,7 +425,7 @@
KeyedLoadStubCompiler compiler(isolate_);
Handle<Code> handler =
compiler.CompileLoadField(receiver, holder, name, field, representation);
- JSObject::UpdateMapCodeCache(stub_holder, name, handler);
+ HeapObject::UpdateMapCodeCache(stub_holder, name, handler);
return handler;
}
@@ -442,7 +442,7 @@
KeyedLoadStubCompiler compiler(isolate_);
handler = compiler.CompileLoadConstant(receiver, holder, name, value);
- JSObject::UpdateMapCodeCache(stub_holder, name, handler);
+ HeapObject::UpdateMapCodeCache(stub_holder, name, handler);
return handler;
}
@@ -458,7 +458,7 @@
KeyedLoadStubCompiler compiler(isolate_);
Handle<Code> handler =
compiler.CompileLoadInterceptor(receiver, holder, name);
- JSObject::UpdateMapCodeCache(stub_holder, name, handler);
+ HeapObject::UpdateMapCodeCache(stub_holder, name, handler);
return handler;
}
@@ -476,7 +476,7 @@
KeyedLoadStubCompiler compiler(isolate_);
Handle<Code> handler =
compiler.CompileLoadCallback(receiver, holder, name, callback);
- JSObject::UpdateMapCodeCache(stub_holder, name, handler);
+ HeapObject::UpdateMapCodeCache(stub_holder, name, handler);
return handler;
}
@@ -494,7 +494,7 @@
KeyedLoadStubCompiler compiler(isolate_);
Handle<Code> handler =
compiler.CompileLoadCallback(receiver, holder, name, call_optimization);
- JSObject::UpdateMapCodeCache(stub_holder, name, handler);
+ HeapObject::UpdateMapCodeCache(stub_holder, name, handler);
return handler;
}
@@ -509,7 +509,7 @@
StoreStubCompiler compiler(isolate_, strict_mode);
Handle<Code> handler = compiler.CompileStoreField(receiver, lookup, name);
- JSObject::UpdateMapCodeCache(receiver, name, handler);
+ HeapObject::UpdateMapCodeCache(receiver, name, handler);
return handler;
}
@@ -526,7 +526,7 @@
StoreStubCompiler compiler(isolate_, strict_mode);
Handle<Code> handler =
compiler.CompileStoreTransition(receiver, lookup, transition, name);
- JSObject::UpdateMapCodeCache(receiver, name, handler);
+ HeapObject::UpdateMapCodeCache(receiver, name, handler);
return handler;
}
@@ -606,7 +606,7 @@
Handle<Map> cell_map(isolate_->heap()->global_property_cell_map());
code->ReplaceNthObject(1, *cell_map, *cell);
- JSObject::UpdateMapCodeCache(receiver, name, code);
+ HeapObject::UpdateMapCodeCache(receiver, name, code);
return code;
}
@@ -626,7 +626,7 @@
StoreStubCompiler compiler(isolate_, strict_mode);
Handle<Code> handler = compiler.CompileStoreCallback(
receiver, holder, name, callback);
- JSObject::UpdateMapCodeCache(receiver, name, handler);
+ HeapObject::UpdateMapCodeCache(receiver, name, handler);
return handler;
}
@@ -644,7 +644,7 @@
StoreStubCompiler compiler(isolate_, strict_mode);
Handle<Code> handler = compiler.CompileStoreCallback(
receiver, holder, name, call_optimization);
- JSObject::UpdateMapCodeCache(receiver, name, handler);
+ HeapObject::UpdateMapCodeCache(receiver, name, handler);
return handler;
}
@@ -661,7 +661,7 @@
StoreStubCompiler compiler(isolate_, strict_mode);
Handle<Code> handler = compiler.CompileStoreViaSetter(
receiver, holder, name, setter);
- JSObject::UpdateMapCodeCache(receiver, name, handler);
+ HeapObject::UpdateMapCodeCache(receiver, name, handler);
return handler;
}
@@ -675,7 +675,7 @@
StoreStubCompiler compiler(isolate_, strict_mode);
Handle<Code> handler = compiler.CompileStoreInterceptor(receiver, name);
- JSObject::UpdateMapCodeCache(receiver, name, handler);
+ HeapObject::UpdateMapCodeCache(receiver, name, handler);
return handler;
}
@@ -690,7 +690,7 @@
KeyedStoreStubCompiler compiler(isolate(), strict_mode, STANDARD_STORE);
Handle<Code> handler = compiler.CompileStoreField(receiver, lookup, name);
- JSObject::UpdateMapCodeCache(receiver, name, handler);
+ HeapObject::UpdateMapCodeCache(receiver, name, handler);
return handler;
}
@@ -708,7 +708,7 @@
KeyedStoreStubCompiler compiler(isolate(), strict_mode, STANDARD_STORE);
Handle<Code> handler =
compiler.CompileStoreTransition(receiver, lookup, transition, name);
- JSObject::UpdateMapCodeCache(receiver, name, handler);
+ HeapObject::UpdateMapCodeCache(receiver, name, handler);
return handler;
}
@@ -765,7 +765,7 @@
GDBJIT(AddCode(GDBJITInterface::CALL_IC, *name, *code));
if (CallStubCompiler::CanBeCached(function)) {
- JSObject::UpdateMapCodeCache(stub_holder, name, code);
+ HeapObject::UpdateMapCodeCache(stub_holder, name, code);
}
return code;
}
@@ -806,7 +806,7 @@
PROFILE(isolate_,
CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_IC_TAG), *code, *name));
GDBJIT(AddCode(GDBJITInterface::CALL_IC, *name, *code));
- JSObject::UpdateMapCodeCache(stub_holder, name, code);
+ HeapObject::UpdateMapCodeCache(stub_holder, name, code);
return code;
}
@@ -845,7 +845,7 @@
PROFILE(isolate(),
CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_IC_TAG), *code, *name));
GDBJIT(AddCode(GDBJITInterface::CALL_IC, *name, *code));
- JSObject::UpdateMapCodeCache(stub_holder, name, code);
+ HeapObject::UpdateMapCodeCache(stub_holder, name, code);
return code;
}
@@ -876,7 +876,7 @@
CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_IC_TAG), *code, *name));
GDBJIT(AddCode(GDBJITInterface::CALL_IC, *name, *code));
if (CallStubCompiler::CanBeCached(function)) {
- JSObject::UpdateMapCodeCache(stub_holder, name, code);
+ HeapObject::UpdateMapCodeCache(stub_holder, name, code);
}
return code;
}
@@ -1249,9 +1249,6 @@
}
-static const int kAccessorInfoOffsetInInterceptorArgs = 2;
-
-
/**
* Attempts to load a property with an interceptor (which must be present),
* but doesn't search the prototype chain.
@@ -1260,13 +1257,11 @@
* provide any value for the given name.
*/
RUNTIME_FUNCTION(MaybeObject*, LoadPropertyWithInterceptorOnly) {
- typedef PropertyCallbackArguments PCA;
- static const int kArgsOffset = kAccessorInfoOffsetInInterceptorArgs;
- Handle<Name> name_handle = args.at<Name>(0);
- Handle<InterceptorInfo> interceptor_info = args.at<InterceptorInfo>(1);
- ASSERT(kArgsOffset == 2);
- // No ReturnValue in interceptors.
- ASSERT_EQ(kArgsOffset + PCA::kArgsLength - 2, args.length());
+ ASSERT(args.length() == StubCache::kInterceptorArgsLength);
+ Handle<Name> name_handle =
+ args.at<Name>(StubCache::kInterceptorArgsNameIndex);
+ Handle<InterceptorInfo> interceptor_info =
+ args.at<InterceptorInfo>(StubCache::kInterceptorArgsInfoIndex);
// TODO(rossberg): Support symbols in the API.
if (name_handle->IsSymbol())
@@ -1279,13 +1274,11 @@
ASSERT(getter != NULL);
Handle<JSObject> receiver =
- args.at<JSObject>(kArgsOffset - PCA::kThisIndex);
+ args.at<JSObject>(StubCache::kInterceptorArgsThisIndex);
Handle<JSObject> holder =
- args.at<JSObject>(kArgsOffset - PCA::kHolderIndex);
- PropertyCallbackArguments callback_args(isolate,
- interceptor_info->data(),
- *receiver,
- *holder);
+ args.at<JSObject>(StubCache::kInterceptorArgsHolderIndex);
+ PropertyCallbackArguments callback_args(
+ isolate, interceptor_info->data(), *receiver, *holder);
{
// Use the interceptor getter.
HandleScope scope(isolate);
@@ -1323,17 +1316,15 @@
static MaybeObject* LoadWithInterceptor(Arguments* args,
PropertyAttributes* attrs) {
- typedef PropertyCallbackArguments PCA;
- static const int kArgsOffset = kAccessorInfoOffsetInInterceptorArgs;
- Handle<Name> name_handle = args->at<Name>(0);
- Handle<InterceptorInfo> interceptor_info = args->at<InterceptorInfo>(1);
- ASSERT(kArgsOffset == 2);
- // No ReturnValue in interceptors.
- ASSERT_EQ(kArgsOffset + PCA::kArgsLength - 2, args->length());
+ ASSERT(args->length() == StubCache::kInterceptorArgsLength);
+ Handle<Name> name_handle =
+ args->at<Name>(StubCache::kInterceptorArgsNameIndex);
+ Handle<InterceptorInfo> interceptor_info =
+ args->at<InterceptorInfo>(StubCache::kInterceptorArgsInfoIndex);
Handle<JSObject> receiver_handle =
- args->at<JSObject>(kArgsOffset - PCA::kThisIndex);
+ args->at<JSObject>(StubCache::kInterceptorArgsThisIndex);
Handle<JSObject> holder_handle =
- args->at<JSObject>(kArgsOffset - PCA::kHolderIndex);
+ args->at<JSObject>(StubCache::kInterceptorArgsHolderIndex);
Isolate* isolate = receiver_handle->GetIsolate();
diff --git a/src/stub-cache.h b/src/stub-cache.h
index 141e567..63cb42b 100644
--- a/src/stub-cache.h
+++ b/src/stub-cache.h
@@ -104,20 +104,20 @@
Code::StubType type,
StrictModeFlag strict_mode);
- Handle<Code> ComputeMonomorphicLoadIC(Handle<JSObject> receiver,
+ Handle<Code> ComputeMonomorphicLoadIC(Handle<HeapObject> receiver,
Handle<Code> handler,
Handle<Name> name);
- Handle<Code> ComputeMonomorphicKeyedLoadIC(Handle<JSObject> receiver,
+ Handle<Code> ComputeMonomorphicKeyedLoadIC(Handle<HeapObject> receiver,
Handle<Code> handler,
Handle<Name> name);
- Handle<Code> ComputeMonomorphicStoreIC(Handle<JSObject> receiver,
+ Handle<Code> ComputeMonomorphicStoreIC(Handle<HeapObject> receiver,
Handle<Code> handler,
Handle<Name> name,
StrictModeFlag strict_mode);
- Handle<Code> ComputeMonomorphicKeyedStoreIC(Handle<JSObject> receiver,
+ Handle<Code> ComputeMonomorphicKeyedStoreIC(Handle<HeapObject> receiver,
Handle<Code> handler,
Handle<Name> name,
StrictModeFlag strict_mode);
@@ -408,6 +408,16 @@
Heap* heap() { return isolate()->heap(); }
Factory* factory() { return isolate()->factory(); }
+ // These constants describe the structure of the interceptor arguments on the
+ // stack. The arguments are pushed by the (platform-specific)
+ // PushInterceptorArguments and read by LoadPropertyWithInterceptorOnly and
+ // LoadWithInterceptor.
+ static const int kInterceptorArgsNameIndex = 0;
+ static const int kInterceptorArgsInfoIndex = 1;
+ static const int kInterceptorArgsThisIndex = 2;
+ static const int kInterceptorArgsHolderIndex = 3;
+ static const int kInterceptorArgsLength = 4;
+
private:
explicit StubCache(Isolate* isolate);
diff --git a/src/unique.h b/src/unique.h
new file mode 100644
index 0000000..7ae704a
--- /dev/null
+++ b/src/unique.h
@@ -0,0 +1,266 @@
+// Copyright 2013 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef V8_HYDROGEN_UNIQUE_H_
+#define V8_HYDROGEN_UNIQUE_H_
+
+#include "handles.h"
+#include "utils.h"
+#include "zone.h"
+
+namespace v8 {
+namespace internal {
+
+
+template <typename T>
+class UniqueSet;
+
+
+// Represents a handle to an object on the heap, but with the additional
+// ability of checking for equality and hashing without accessing the heap.
+//
+// Creating a Unique<T> requires first dereferencing the handle to obtain
+// the address of the object, which is used as the hashcode and the basis for
+// comparison. The object can be moved later by the GC, but comparison
+// and hashing use the old address of the object, without dereferencing it.
+//
+// Careful! Comparison of two Uniques is only correct if both were created
+// in the same "era" of GC or if at least one is a non-movable object.
+template <typename T>
+class Unique V8_FINAL {
+ public:
+ // TODO(titzer): make private and introduce some builder/owner class.
+ explicit Unique(Handle<T> handle) {
+ if (handle.is_null()) {
+ raw_address_ = NULL;
+ } else {
+ raw_address_ = reinterpret_cast<Address>(*handle);
+ ASSERT_NE(raw_address_, NULL);
+ }
+ handle_ = handle;
+ }
+
+ // Constructor for handling automatic up casting.
+ // Ex. Unique<JSFunction> can be passed when Unique<Object> is expected.
+ template <class S> Unique(Unique<S> uniq) {
+#ifdef DEBUG
+ T* a = NULL;
+ S* b = NULL;
+ a = b; // Fake assignment to enforce type checks.
+ USE(a);
+#endif
+ raw_address_ = uniq.raw_address_;
+ handle_ = uniq.handle_; // Creates a new handle sharing the same location.
+ }
+
+ template <typename U>
+ bool operator==(const Unique<U>& other) const {
+ return raw_address_ == other.raw_address_;
+ }
+
+ template <typename U>
+ bool operator!=(const Unique<U>& other) const {
+ return raw_address_ != other.raw_address_;
+ }
+
+ intptr_t Hashcode() const {
+ return reinterpret_cast<intptr_t>(raw_address_);
+ }
+
+ bool IsNull() {
+ return raw_address_ == NULL;
+ }
+
+ // Don't do this unless you have access to the heap!
+ // No, seriously! You can compare and hash and set-ify uniques that were
+ // all created at the same time; please don't dereference.
+ Handle<T> handle() {
+ return handle_;
+ }
+
+ friend class UniqueSet<T>; // Uses internal details for speed.
+ template <class U>
+ friend class Unique; // For comparing raw_address values.
+
+ private:
+ Address raw_address_;
+ Handle<T> handle_;
+};
+
+
+template <typename T>
+class UniqueSet V8_FINAL : public ZoneObject {
+ public:
+ // Constructor. A new set will be empty.
+ UniqueSet() : size_(0), capacity_(0), array_(NULL) { }
+
+ // Add a new element to this unique set. Mutates this set. O(|this|).
+ void Add(Unique<T> uniq, Zone* zone) {
+ // Keep the set sorted by the {raw_address} of the unique elements.
+ for (int i = 0; i < size_; i++) {
+ if (array_[i] == uniq) return;
+ if (array_[i].raw_address_ > uniq.raw_address_) {
+ // Insert in the middle.
+ Grow(size_ + 1, zone);
+ for (int j = size_ - 1; j >= i; j--) array_[j + 1] = array_[j];
+ array_[i] = uniq;
+ size_++;
+ return;
+ }
+ }
+ // Append the element to the the end.
+ Grow(size_ + 1, zone);
+ array_[size_++] = uniq;
+ }
+
+ // Compare this set against another set. O(|this|).
+ bool Equals(UniqueSet<T>* that) {
+ if (that->size_ != this->size_) return false;
+ for (int i = 0; i < this->size_; i++) {
+ if (this->array_[i] != that->array_[i]) return false;
+ }
+ return true;
+ }
+
+ // Check if this set is a subset of the given set. O(|this| + |that|).
+ bool IsSubset(UniqueSet<T>* that) {
+ if (that->size_ < this->size_) return false;
+ int j = 0;
+ for (int i = 0; i < this->size_; i++) {
+ Unique<T> sought = this->array_[i];
+ while (true) {
+ if (sought == that->array_[j++]) break;
+ // Fail whenever there are more elements in {this} than {that}.
+ if ((this->size_ - i) > (that->size_ - j)) return false;
+ }
+ }
+ return true;
+ }
+
+ // Returns a new set representing the intersection of this set and the other.
+ // O(|this| + |that|).
+ UniqueSet<T>* Intersect(UniqueSet<T>* that, Zone* zone) {
+ if (that->size_ == 0 || this->size_ == 0) return new(zone) UniqueSet<T>();
+
+ UniqueSet<T>* out = new(zone) UniqueSet<T>();
+ out->Grow(Min(this->size_, that->size_), zone);
+
+ int i = 0, j = 0, k = 0;
+ while (i < this->size_ && j < that->size_) {
+ Unique<T> a = this->array_[i];
+ Unique<T> b = that->array_[j];
+ if (a == b) {
+ out->array_[k++] = a;
+ i++;
+ j++;
+ } else if (a.raw_address_ < b.raw_address_) {
+ i++;
+ } else {
+ j++;
+ }
+ }
+
+ out->size_ = k;
+ return out;
+ }
+
+ // Returns a new set representing the union of this set and the other.
+ // O(|this| + |that|).
+ UniqueSet<T>* Union(UniqueSet<T>* that, Zone* zone) {
+ if (that->size_ == 0) return this->Copy(zone);
+ if (this->size_ == 0) return that->Copy(zone);
+
+ UniqueSet<T>* out = new(zone) UniqueSet<T>();
+ out->Grow(this->size_ + that->size_, zone);
+
+ int i = 0, j = 0, k = 0;
+ while (i < this->size_ && j < that->size_) {
+ Unique<T> a = this->array_[i];
+ Unique<T> b = that->array_[j];
+ if (a == b) {
+ out->array_[k++] = a;
+ i++;
+ j++;
+ } else if (a.raw_address_ < b.raw_address_) {
+ out->array_[k++] = a;
+ i++;
+ } else {
+ out->array_[k++] = b;
+ j++;
+ }
+ }
+
+ while (i < this->size_) out->array_[k++] = this->array_[i++];
+ while (j < that->size_) out->array_[k++] = that->array_[j++];
+
+ out->size_ = k;
+ return out;
+ }
+
+ // Makes an exact copy of this set. O(|this| + |that|).
+ UniqueSet<T>* Copy(Zone* zone) {
+ UniqueSet<T>* copy = new(zone) UniqueSet<T>();
+ copy->size_ = this->size_;
+ copy->capacity_ = this->size_;
+ copy->array_ = zone->NewArray<Unique<T> >(this->size_);
+ memcpy(copy->array_, this->array_, this->size_ * sizeof(Unique<T>));
+ return copy;
+ }
+
+ inline int size() {
+ return size_;
+ }
+
+ private:
+ // These sets should be small, since operations are implemented with simple
+ // linear algorithms. Enforce a maximum size.
+ static const int kMaxCapacity = 65535;
+
+ uint16_t size_;
+ uint16_t capacity_;
+ Unique<T>* array_;
+
+ // Grow the size of internal storage to be at least {size} elements.
+ void Grow(int size, Zone* zone) {
+ CHECK(size < kMaxCapacity); // Enforce maximum size.
+ if (capacity_ < size) {
+ int new_capacity = 2 * capacity_ + size;
+ if (new_capacity > kMaxCapacity) new_capacity = kMaxCapacity;
+ Unique<T>* new_array = zone->NewArray<Unique<T> >(new_capacity);
+ if (size_ > 0) {
+ memcpy(new_array, array_, size_ * sizeof(Unique<T>));
+ }
+ capacity_ = new_capacity;
+ array_ = new_array;
+ }
+ }
+};
+
+
+} } // namespace v8::internal
+
+#endif // V8_HYDROGEN_UNIQUE_H_
diff --git a/src/utils/random-number-generator.h b/src/utils/random-number-generator.h
index fc14ef4..bd7dca7 100644
--- a/src/utils/random-number-generator.h
+++ b/src/utils/random-number-generator.h
@@ -59,7 +59,7 @@
// that one int value is pseudorandomly generated and returned.
// All 2^32 possible integer values are produced with (approximately) equal
// probability.
- V8_INLINE(int NextInt()) V8_WARN_UNUSED_RESULT {
+ V8_INLINE int NextInt() V8_WARN_UNUSED_RESULT {
return Next(32);
}
@@ -76,7 +76,7 @@
// |NextBoolean()| is that one boolean value is pseudorandomly generated and
// returned. The values true and false are produced with (approximately) equal
// probability.
- V8_INLINE(bool NextBool()) V8_WARN_UNUSED_RESULT {
+ V8_INLINE bool NextBool() V8_WARN_UNUSED_RESULT {
return Next(1) != 0;
}
diff --git a/src/version.cc b/src/version.cc
index a491a4f..da82885 100644
--- a/src/version.cc
+++ b/src/version.cc
@@ -34,7 +34,7 @@
// system so their names cannot be changed without changing the scripts.
#define MAJOR_VERSION 3
#define MINOR_VERSION 21
-#define BUILD_NUMBER 14
+#define BUILD_NUMBER 15
#define PATCH_LEVEL 0
// Use 1 for candidates and 0 otherwise.
// (Boolean macro values are not supported by all preprocessors.)
diff --git a/src/x64/builtins-x64.cc b/src/x64/builtins-x64.cc
index 1960c3c..81721c2 100644
--- a/src/x64/builtins-x64.cc
+++ b/src/x64/builtins-x64.cc
@@ -73,6 +73,24 @@
}
+static void CallRuntimePassFunction(MacroAssembler* masm,
+ Runtime::FunctionId function_id) {
+ FrameScope scope(masm, StackFrame::INTERNAL);
+ // Push a copy of the function onto the stack.
+ __ push(rdi);
+ // Push call kind information.
+ __ push(rcx);
+ // Function is also the parameter to the runtime call.
+ __ push(rdi);
+
+ __ CallRuntime(function_id, 1);
+ // Restore call kind information.
+ __ pop(rcx);
+ // Restore receiver.
+ __ pop(rdi);
+}
+
+
static void GenerateTailCallToSharedCode(MacroAssembler* masm) {
__ movq(kScratchRegister,
FieldOperand(rdi, JSFunction::kSharedFunctionInfoOffset));
@@ -84,57 +102,27 @@
void Builtins::Generate_InRecompileQueue(MacroAssembler* masm) {
+ // Checking whether the queued function is ready for install is optional,
+ // since we come across interrupts and stack checks elsewhere. However,
+ // not checking may delay installing ready functions, and always checking
+ // would be quite expensive. A good compromise is to first check against
+ // stack limit as a cue for an interrupt signal.
+ Label ok;
+ __ CompareRoot(rsp, Heap::kStackLimitRootIndex);
+ __ j(above_equal, &ok);
+
+ CallRuntimePassFunction(masm, Runtime::kTryInstallRecompiledCode);
+ // Tail call to returned code.
+ __ lea(rax, FieldOperand(rax, Code::kHeaderSize));
+ __ jmp(rax);
+
+ __ bind(&ok);
GenerateTailCallToSharedCode(masm);
}
-void Builtins::Generate_InstallRecompiledCode(MacroAssembler* masm) {
- // Enter an internal frame.
- {
- FrameScope scope(masm, StackFrame::INTERNAL);
-
- // Push a copy of the function onto the stack.
- __ push(rdi);
- // Push call kind information.
- __ push(rcx);
-
- __ push(rdi); // Function is also the parameter to the runtime call.
- __ CallRuntime(Runtime::kInstallRecompiledCode, 1);
-
- // Restore call kind information.
- __ pop(rcx);
- // Restore function.
- __ pop(rdi);
-
- // Tear down internal frame.
- }
-
- // Do a tail-call of the compiled function.
- __ lea(rax, FieldOperand(rax, Code::kHeaderSize));
- __ jmp(rax);
-}
-
-
void Builtins::Generate_ConcurrentRecompile(MacroAssembler* masm) {
- {
- FrameScope scope(masm, StackFrame::INTERNAL);
-
- // Push a copy of the function onto the stack.
- __ push(rdi);
- // Push call kind information.
- __ push(rcx);
-
- __ push(rdi); // Function is also the parameter to the runtime call.
- __ CallRuntime(Runtime::kConcurrentRecompile, 1);
-
- // Restore call kind information.
- __ pop(rcx);
- // Restore receiver.
- __ pop(rdi);
-
- // Tear down internal frame.
- }
-
+ CallRuntimePassFunction(masm, Runtime::kConcurrentRecompile);
GenerateTailCallToSharedCode(masm);
}
@@ -586,26 +574,7 @@
void Builtins::Generate_LazyCompile(MacroAssembler* masm) {
- // Enter an internal frame.
- {
- FrameScope scope(masm, StackFrame::INTERNAL);
-
- // Push a copy of the function onto the stack.
- __ push(rdi);
- // Push call kind information.
- __ push(rcx);
-
- __ push(rdi); // Function is also the parameter to the runtime call.
- __ CallRuntime(Runtime::kLazyCompile, 1);
-
- // Restore call kind information.
- __ pop(rcx);
- // Restore receiver.
- __ pop(rdi);
-
- // Tear down internal frame.
- }
-
+ CallRuntimePassFunction(masm, Runtime::kLazyCompile);
// Do a tail-call of the compiled function.
__ lea(rax, FieldOperand(rax, Code::kHeaderSize));
__ jmp(rax);
@@ -613,26 +582,7 @@
void Builtins::Generate_LazyRecompile(MacroAssembler* masm) {
- // Enter an internal frame.
- {
- FrameScope scope(masm, StackFrame::INTERNAL);
-
- // Push a copy of the function onto the stack.
- __ push(rdi);
- // Push call kind information.
- __ push(rcx);
-
- __ push(rdi); // Function is also the parameter to the runtime call.
- __ CallRuntime(Runtime::kLazyRecompile, 1);
-
- // Restore call kind information.
- __ pop(rcx);
- // Restore function.
- __ pop(rdi);
-
- // Tear down internal frame.
- }
-
+ CallRuntimePassFunction(masm, Runtime::kLazyRecompile);
// Do a tail-call of the compiled function.
__ lea(rax, FieldOperand(rax, Code::kHeaderSize));
__ jmp(rax);
diff --git a/src/x64/code-stubs-x64.cc b/src/x64/code-stubs-x64.cc
index f6cfb4f..51e1a53 100644
--- a/src/x64/code-stubs-x64.cc
+++ b/src/x64/code-stubs-x64.cc
@@ -4644,7 +4644,6 @@
__ j(below, &done);
// Check the number to string cache.
- Label not_cached;
__ bind(¬_string);
// Puts the cached result into scratch1.
NumberToStringStub::GenerateLookupNumberStringCache(masm,
@@ -4652,22 +4651,9 @@
scratch1,
scratch2,
scratch3,
- ¬_cached);
+ slow);
__ movq(arg, scratch1);
__ movq(Operand(rsp, stack_offset), arg);
- __ jmp(&done);
-
- // Check if the argument is a safe string wrapper.
- __ bind(¬_cached);
- __ JumpIfSmi(arg, slow);
- __ CmpObjectType(arg, JS_VALUE_TYPE, scratch1); // map -> scratch1.
- __ j(not_equal, slow);
- __ testb(FieldOperand(scratch1, Map::kBitField2Offset),
- Immediate(1 << Map::kStringWrapperSafeForDefaultValueOf));
- __ j(zero, slow);
- __ movq(arg, FieldOperand(arg, JSValue::kValueOffset));
- __ movq(Operand(rsp, stack_offset), arg);
-
__ bind(&done);
}
@@ -6326,46 +6312,59 @@
template<class T>
-static void CreateArrayDispatch(MacroAssembler* masm) {
- int last_index = GetSequenceIndexFromFastElementsKind(
- TERMINAL_FAST_ELEMENTS_KIND);
- for (int i = 0; i <= last_index; ++i) {
- Label next;
- ElementsKind kind = GetFastElementsKindFromSequenceIndex(i);
- __ cmpl(rdx, Immediate(kind));
- __ j(not_equal, &next);
- T stub(kind);
+static void CreateArrayDispatch(MacroAssembler* masm,
+ AllocationSiteOverrideMode mode) {
+ if (mode == DISABLE_ALLOCATION_SITES) {
+ T stub(GetInitialFastElementsKind(),
+ CONTEXT_CHECK_REQUIRED,
+ mode);
__ TailCallStub(&stub);
- __ bind(&next);
- }
+ } else if (mode == DONT_OVERRIDE) {
+ int last_index = GetSequenceIndexFromFastElementsKind(
+ TERMINAL_FAST_ELEMENTS_KIND);
+ for (int i = 0; i <= last_index; ++i) {
+ Label next;
+ ElementsKind kind = GetFastElementsKindFromSequenceIndex(i);
+ __ cmpl(rdx, Immediate(kind));
+ __ j(not_equal, &next);
+ T stub(kind);
+ __ TailCallStub(&stub);
+ __ bind(&next);
+ }
- // If we reached this point there is a problem.
- __ Abort(kUnexpectedElementsKindInArrayConstructor);
+ // If we reached this point there is a problem.
+ __ Abort(kUnexpectedElementsKindInArrayConstructor);
+ } else {
+ UNREACHABLE();
+ }
}
-static void CreateArrayDispatchOneArgument(MacroAssembler* masm) {
- // rbx - type info cell
- // rdx - kind
+static void CreateArrayDispatchOneArgument(MacroAssembler* masm,
+ AllocationSiteOverrideMode mode) {
+ // rbx - type info cell (if mode != DISABLE_ALLOCATION_SITES)
+ // rdx - kind (if mode != DISABLE_ALLOCATION_SITES)
// rax - number of arguments
// rdi - constructor?
// rsp[0] - return address
// rsp[8] - last argument
- ASSERT(FAST_SMI_ELEMENTS == 0);
- ASSERT(FAST_HOLEY_SMI_ELEMENTS == 1);
- ASSERT(FAST_ELEMENTS == 2);
- ASSERT(FAST_HOLEY_ELEMENTS == 3);
- ASSERT(FAST_DOUBLE_ELEMENTS == 4);
- ASSERT(FAST_HOLEY_DOUBLE_ELEMENTS == 5);
-
Handle<Object> undefined_sentinel(
masm->isolate()->heap()->undefined_value(),
masm->isolate());
- // is the low bit set? If so, we are holey and that is good.
- __ testb(rdx, Immediate(1));
Label normal_sequence;
- __ j(not_zero, &normal_sequence);
+ if (mode == DONT_OVERRIDE) {
+ ASSERT(FAST_SMI_ELEMENTS == 0);
+ ASSERT(FAST_HOLEY_SMI_ELEMENTS == 1);
+ ASSERT(FAST_ELEMENTS == 2);
+ ASSERT(FAST_HOLEY_ELEMENTS == 3);
+ ASSERT(FAST_DOUBLE_ELEMENTS == 4);
+ ASSERT(FAST_HOLEY_DOUBLE_ELEMENTS == 5);
+
+ // is the low bit set? If so, we are holey and that is good.
+ __ testb(rdx, Immediate(1));
+ __ j(not_zero, &normal_sequence);
+ }
// look at the first argument
StackArgumentsAccessor args(rsp, 1, ARGUMENTS_DONT_CONTAIN_RECEIVER);
@@ -6373,50 +6372,73 @@
__ testq(rcx, rcx);
__ j(zero, &normal_sequence);
- // We are going to create a holey array, but our kind is non-holey.
- // Fix kind and retry (only if we have an allocation site in the cell).
- __ incl(rdx);
- __ Cmp(rbx, undefined_sentinel);
- __ j(equal, &normal_sequence);
- __ movq(rcx, FieldOperand(rbx, Cell::kValueOffset));
- Handle<Map> allocation_site_map(
- masm->isolate()->heap()->allocation_site_map(),
- masm->isolate());
- __ Cmp(FieldOperand(rcx, 0), allocation_site_map);
- __ j(not_equal, &normal_sequence);
+ if (mode == DISABLE_ALLOCATION_SITES) {
+ ElementsKind initial = GetInitialFastElementsKind();
+ ElementsKind holey_initial = GetHoleyElementsKind(initial);
- // Save the resulting elements kind in type info
- __ Integer32ToSmi(rdx, rdx);
- __ movq(FieldOperand(rcx, AllocationSite::kTransitionInfoOffset), rdx);
- __ SmiToInteger32(rdx, rdx);
+ ArraySingleArgumentConstructorStub stub_holey(holey_initial,
+ CONTEXT_CHECK_REQUIRED,
+ DISABLE_ALLOCATION_SITES);
+ __ TailCallStub(&stub_holey);
- __ bind(&normal_sequence);
- int last_index = GetSequenceIndexFromFastElementsKind(
- TERMINAL_FAST_ELEMENTS_KIND);
- for (int i = 0; i <= last_index; ++i) {
- Label next;
- ElementsKind kind = GetFastElementsKindFromSequenceIndex(i);
- __ cmpl(rdx, Immediate(kind));
- __ j(not_equal, &next);
- ArraySingleArgumentConstructorStub stub(kind);
+ __ bind(&normal_sequence);
+ ArraySingleArgumentConstructorStub stub(initial,
+ CONTEXT_CHECK_REQUIRED,
+ DISABLE_ALLOCATION_SITES);
__ TailCallStub(&stub);
- __ bind(&next);
- }
+ } else if (mode == DONT_OVERRIDE) {
+ // We are going to create a holey array, but our kind is non-holey.
+ // Fix kind and retry (only if we have an allocation site in the cell).
+ __ incl(rdx);
+ __ movq(rcx, FieldOperand(rbx, Cell::kValueOffset));
+ if (FLAG_debug_code) {
+ Handle<Map> allocation_site_map(
+ masm->isolate()->heap()->allocation_site_map(),
+ masm->isolate());
+ __ Cmp(FieldOperand(rcx, 0), allocation_site_map);
+ __ Assert(equal, kExpectedAllocationSiteInCell);
+ }
- // If we reached this point there is a problem.
- __ Abort(kUnexpectedElementsKindInArrayConstructor);
+ // Save the resulting elements kind in type info
+ __ Integer32ToSmi(rdx, rdx);
+ __ movq(FieldOperand(rcx, AllocationSite::kTransitionInfoOffset), rdx);
+ __ SmiToInteger32(rdx, rdx);
+
+ __ bind(&normal_sequence);
+ int last_index = GetSequenceIndexFromFastElementsKind(
+ TERMINAL_FAST_ELEMENTS_KIND);
+ for (int i = 0; i <= last_index; ++i) {
+ Label next;
+ ElementsKind kind = GetFastElementsKindFromSequenceIndex(i);
+ __ cmpl(rdx, Immediate(kind));
+ __ j(not_equal, &next);
+ ArraySingleArgumentConstructorStub stub(kind);
+ __ TailCallStub(&stub);
+ __ bind(&next);
+ }
+
+ // If we reached this point there is a problem.
+ __ Abort(kUnexpectedElementsKindInArrayConstructor);
+ } else {
+ UNREACHABLE();
+ }
}
template<class T>
static void ArrayConstructorStubAheadOfTimeHelper(Isolate* isolate) {
+ ElementsKind initial_kind = GetInitialFastElementsKind();
+ ElementsKind initial_holey_kind = GetHoleyElementsKind(initial_kind);
+
int to_index = GetSequenceIndexFromFastElementsKind(
TERMINAL_FAST_ELEMENTS_KIND);
for (int i = 0; i <= to_index; ++i) {
ElementsKind kind = GetFastElementsKindFromSequenceIndex(i);
T stub(kind);
stub.GetCode(isolate)->set_is_pregenerated(true);
- if (AllocationSite::GetMode(kind) != DONT_TRACK_ALLOCATION_SITE) {
+ if (AllocationSite::GetMode(kind) != DONT_TRACK_ALLOCATION_SITE ||
+ (!FLAG_track_allocation_sites &&
+ (kind == initial_kind || kind == initial_holey_kind))) {
T stub1(kind, CONTEXT_CHECK_REQUIRED, DISABLE_ALLOCATION_SITES);
stub1.GetCode(isolate)->set_is_pregenerated(true);
}
@@ -6449,6 +6471,34 @@
}
+void ArrayConstructorStub::GenerateDispatchToArrayStub(
+ MacroAssembler* masm,
+ AllocationSiteOverrideMode mode) {
+ if (argument_count_ == ANY) {
+ Label not_zero_case, not_one_case;
+ __ testq(rax, rax);
+ __ j(not_zero, ¬_zero_case);
+ CreateArrayDispatch<ArrayNoArgumentConstructorStub>(masm, mode);
+
+ __ bind(¬_zero_case);
+ __ cmpl(rax, Immediate(1));
+ __ j(greater, ¬_one_case);
+ CreateArrayDispatchOneArgument(masm, mode);
+
+ __ bind(¬_one_case);
+ CreateArrayDispatch<ArrayNArgumentsConstructorStub>(masm, mode);
+ } else if (argument_count_ == NONE) {
+ CreateArrayDispatch<ArrayNoArgumentConstructorStub>(masm, mode);
+ } else if (argument_count_ == ONE) {
+ CreateArrayDispatchOneArgument(masm, mode);
+ } else if (argument_count_ == MORE_THAN_ONE) {
+ CreateArrayDispatch<ArrayNArgumentsConstructorStub>(masm, mode);
+ } else {
+ UNREACHABLE();
+ }
+}
+
+
void ArrayConstructorStub::Generate(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- rax : argc
@@ -6484,50 +6534,22 @@
__ bind(&okay_here);
}
- Label no_info, switch_ready;
- // Get the elements kind and case on that.
+ Label no_info;
+ // If the type cell is undefined, or contains anything other than an
+ // AllocationSite, call an array constructor that doesn't use AllocationSites.
__ Cmp(rbx, undefined_sentinel);
__ j(equal, &no_info);
__ movq(rdx, FieldOperand(rbx, Cell::kValueOffset));
-
- // The type cell may have undefined in its value.
- __ Cmp(rdx, undefined_sentinel);
- __ j(equal, &no_info);
-
- // The type cell has either an AllocationSite or a JSFunction
__ Cmp(FieldOperand(rdx, 0),
Handle<Map>(masm->isolate()->heap()->allocation_site_map()));
__ j(not_equal, &no_info);
__ movq(rdx, FieldOperand(rdx, AllocationSite::kTransitionInfoOffset));
__ SmiToInteger32(rdx, rdx);
- __ jmp(&switch_ready);
+ GenerateDispatchToArrayStub(masm, DONT_OVERRIDE);
+
__ bind(&no_info);
- __ movq(rdx, Immediate(GetInitialFastElementsKind()));
- __ bind(&switch_ready);
-
- if (argument_count_ == ANY) {
- Label not_zero_case, not_one_case;
- __ testq(rax, rax);
- __ j(not_zero, ¬_zero_case);
- CreateArrayDispatch<ArrayNoArgumentConstructorStub>(masm);
-
- __ bind(¬_zero_case);
- __ cmpl(rax, Immediate(1));
- __ j(greater, ¬_one_case);
- CreateArrayDispatchOneArgument(masm);
-
- __ bind(¬_one_case);
- CreateArrayDispatch<ArrayNArgumentsConstructorStub>(masm);
- } else if (argument_count_ == NONE) {
- CreateArrayDispatch<ArrayNoArgumentConstructorStub>(masm);
- } else if (argument_count_ == ONE) {
- CreateArrayDispatchOneArgument(masm);
- } else if (argument_count_ == MORE_THAN_ONE) {
- CreateArrayDispatch<ArrayNArgumentsConstructorStub>(masm);
- } else {
- UNREACHABLE();
- }
+ GenerateDispatchToArrayStub(masm, DISABLE_ALLOCATION_SITES);
}
diff --git a/src/x64/full-codegen-x64.cc b/src/x64/full-codegen-x64.cc
index c182dd0..c24512e 100644
--- a/src/x64/full-codegen-x64.cc
+++ b/src/x64/full-codegen-x64.cc
@@ -2935,7 +2935,7 @@
VisitForAccumulatorValue(args->at(0));
- Label materialize_true, materialize_false;
+ Label materialize_true, materialize_false, skip_lookup;
Label* if_true = NULL;
Label* if_false = NULL;
Label* fall_through = NULL;
@@ -2949,7 +2949,7 @@
__ movq(rbx, FieldOperand(rax, HeapObject::kMapOffset));
__ testb(FieldOperand(rbx, Map::kBitField2Offset),
Immediate(1 << Map::kStringWrapperSafeForDefaultValueOf));
- __ j(not_zero, if_true);
+ __ j(not_zero, &skip_lookup);
// Check for fast case object. Generate false result for slow case object.
__ movq(rcx, FieldOperand(rax, JSObject::kPropertiesOffset));
@@ -2967,7 +2967,7 @@
__ cmpq(rcx, Immediate(0));
__ j(equal, &done);
- __ LoadInstanceDescriptors(rbx, rbx);
+ __ LoadInstanceDescriptors(rbx, r8);
// rbx: descriptor array.
// rcx: valid entries in the descriptor array.
// Calculate the end of the descriptor array.
@@ -2975,24 +2975,28 @@
SmiIndex index = masm_->SmiToIndex(rdx, rcx, kPointerSizeLog2);
__ lea(rcx,
Operand(
- rbx, index.reg, index.scale, DescriptorArray::kFirstOffset));
+ r8, index.reg, index.scale, DescriptorArray::kFirstOffset));
// Calculate location of the first key name.
- __ addq(rbx, Immediate(DescriptorArray::kFirstOffset));
+ __ addq(r8, Immediate(DescriptorArray::kFirstOffset));
// Loop through all the keys in the descriptor array. If one of these is the
// internalized string "valueOf" the result is false.
__ jmp(&entry);
__ bind(&loop);
- __ movq(rdx, FieldOperand(rbx, 0));
+ __ movq(rdx, FieldOperand(r8, 0));
__ Cmp(rdx, isolate()->factory()->value_of_string());
__ j(equal, if_false);
- __ addq(rbx, Immediate(DescriptorArray::kDescriptorSize * kPointerSize));
+ __ addq(r8, Immediate(DescriptorArray::kDescriptorSize * kPointerSize));
__ bind(&entry);
- __ cmpq(rbx, rcx);
+ __ cmpq(r8, rcx);
__ j(not_equal, &loop);
__ bind(&done);
- // Reload map as register rbx was used as temporary above.
- __ movq(rbx, FieldOperand(rax, HeapObject::kMapOffset));
+
+ // Set the bit in the map to indicate that there is no local valueOf field.
+ __ or_(FieldOperand(rbx, Map::kBitField2Offset),
+ Immediate(1 << Map::kStringWrapperSafeForDefaultValueOf));
+
+ __ bind(&skip_lookup);
// If a valueOf property is not found on the object check that its
// prototype is the un-modified String prototype. If not result is false.
@@ -3004,10 +3008,9 @@
__ movq(rdx, FieldOperand(rdx, GlobalObject::kNativeContextOffset));
__ cmpq(rcx,
ContextOperand(rdx, Context::STRING_FUNCTION_PROTOTYPE_MAP_INDEX));
- __ j(not_equal, if_false);
- __ jmp(if_true);
-
PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
+ Split(equal, if_true, if_false, fall_through);
+
context()->Plug(if_true, if_false);
}
diff --git a/src/x64/lithium-codegen-x64.cc b/src/x64/lithium-codegen-x64.cc
index 836abe8..9dca6b3 100644
--- a/src/x64/lithium-codegen-x64.cc
+++ b/src/x64/lithium-codegen-x64.cc
@@ -3667,90 +3667,64 @@
void LCodeGen::DoRandom(LRandom* instr) {
- class DeferredDoRandom V8_FINAL : public LDeferredCode {
- public:
- DeferredDoRandom(LCodeGen* codegen, LRandom* instr)
- : LDeferredCode(codegen), instr_(instr) { }
- virtual void Generate() V8_OVERRIDE { codegen()->DoDeferredRandom(instr_); }
- virtual LInstruction* instr() V8_OVERRIDE { return instr_; }
- private:
- LRandom* instr_;
- };
-
- DeferredDoRandom* deferred = new(zone()) DeferredDoRandom(this, instr);
-
- // Having marked this instruction as a call we can use any
- // registers.
- ASSERT(ToDoubleRegister(instr->result()).is(xmm1));
-
- // Choose the right register for the first argument depending on
- // calling convention.
-#ifdef _WIN64
- ASSERT(ToRegister(instr->global_object()).is(rcx));
- Register global_object = rcx;
-#else
- ASSERT(ToRegister(instr->global_object()).is(rdi));
- Register global_object = rdi;
-#endif
-
+ // Assert that register size is twice the size of each seed.
static const int kSeedSize = sizeof(uint32_t);
STATIC_ASSERT(kPointerSize == 2 * kSeedSize);
- __ movq(global_object,
- FieldOperand(global_object, GlobalObject::kNativeContextOffset));
+ // Load native context
+ Register global_object = ToRegister(instr->global_object());
+ Register native_context = global_object;
+ __ movq(native_context, FieldOperand(
+ global_object, GlobalObject::kNativeContextOffset));
+
+ // Load state (FixedArray of the native context's random seeds)
static const int kRandomSeedOffset =
FixedArray::kHeaderSize + Context::RANDOM_SEED_INDEX * kPointerSize;
- __ movq(rbx, FieldOperand(global_object, kRandomSeedOffset));
- // rbx: FixedArray of the native context's random seeds
+ Register state = native_context;
+ __ movq(state, FieldOperand(native_context, kRandomSeedOffset));
// Load state[0].
- __ movl(rax, FieldOperand(rbx, ByteArray::kHeaderSize));
- // If state[0] == 0, call runtime to initialize seeds.
- __ testl(rax, rax);
- __ j(zero, deferred->entry());
+ Register state0 = ToRegister(instr->scratch());
+ __ movl(state0, FieldOperand(state, ByteArray::kHeaderSize));
// Load state[1].
- __ movl(rcx, FieldOperand(rbx, ByteArray::kHeaderSize + kSeedSize));
+ Register state1 = ToRegister(instr->scratch2());
+ __ movl(state1, FieldOperand(state, ByteArray::kHeaderSize + kSeedSize));
// state[0] = 18273 * (state[0] & 0xFFFF) + (state[0] >> 16)
- // Only operate on the lower 32 bit of rax.
- __ movzxwl(rdx, rax);
- __ imull(rdx, rdx, Immediate(18273));
- __ shrl(rax, Immediate(16));
- __ addl(rax, rdx);
+ Register scratch3 = ToRegister(instr->scratch3());
+ __ movzxwl(scratch3, state0);
+ __ imull(scratch3, scratch3, Immediate(18273));
+ __ shrl(state0, Immediate(16));
+ __ addl(state0, scratch3);
// Save state[0].
- __ movl(FieldOperand(rbx, ByteArray::kHeaderSize), rax);
+ __ movl(FieldOperand(state, ByteArray::kHeaderSize), state0);
// state[1] = 36969 * (state[1] & 0xFFFF) + (state[1] >> 16)
- __ movzxwl(rdx, rcx);
- __ imull(rdx, rdx, Immediate(36969));
- __ shrl(rcx, Immediate(16));
- __ addl(rcx, rdx);
+ __ movzxwl(scratch3, state1);
+ __ imull(scratch3, scratch3, Immediate(36969));
+ __ shrl(state1, Immediate(16));
+ __ addl(state1, scratch3);
// Save state[1].
- __ movl(FieldOperand(rbx, ByteArray::kHeaderSize + kSeedSize), rcx);
+ __ movl(FieldOperand(state, ByteArray::kHeaderSize + kSeedSize), state1);
// Random bit pattern = (state[0] << 14) + (state[1] & 0x3FFFF)
- __ shll(rax, Immediate(14));
- __ andl(rcx, Immediate(0x3FFFF));
- __ addl(rax, rcx);
+ Register random = state0;
+ __ shll(random, Immediate(14));
+ __ andl(state1, Immediate(0x3FFFF));
+ __ addl(random, state1);
- __ bind(deferred->exit());
// Convert 32 random bits in rax to 0.(32 random bits) in a double
// by computing:
// ( 1.(20 0s)(32 random bits) x 2^20 ) - (1.0 x 2^20)).
- __ movq(rcx, V8_INT64_C(0x4130000000000000),
+ XMMRegister result = ToDoubleRegister(instr->result());
+ // We use xmm0 as fixed scratch register here.
+ XMMRegister scratch4 = xmm0;
+ __ movq(scratch3, V8_INT64_C(0x4130000000000000),
RelocInfo::NONE64); // 1.0 x 2^20 as double
- __ movq(xmm2, rcx);
- __ movd(xmm1, rax);
- __ xorps(xmm1, xmm2);
- __ subsd(xmm1, xmm2);
-}
-
-
-void LCodeGen::DoDeferredRandom(LRandom* instr) {
- __ PrepareCallCFunction(1);
- __ CallCFunction(ExternalReference::random_uint32_function(isolate()), 1);
- __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
- // Return value is in rax.
+ __ movq(scratch4, scratch3);
+ __ movd(result, random);
+ __ xorps(result, scratch4);
+ __ subsd(result, scratch4);
}
diff --git a/src/x64/lithium-codegen-x64.h b/src/x64/lithium-codegen-x64.h
index 222a419..f994645 100644
--- a/src/x64/lithium-codegen-x64.h
+++ b/src/x64/lithium-codegen-x64.h
@@ -126,7 +126,6 @@
void DoDeferredTaggedToI(LTaggedToI* instr, Label* done);
void DoDeferredMathAbsTaggedHeapNumber(LMathAbs* instr);
void DoDeferredStackCheck(LStackCheck* instr);
- void DoDeferredRandom(LRandom* instr);
void DoDeferredStringCharCodeAt(LStringCharCodeAt* instr);
void DoDeferredStringCharFromCode(LStringCharFromCode* instr);
void DoDeferredAllocate(LAllocate* instr);
diff --git a/src/x64/lithium-x64.cc b/src/x64/lithium-x64.cc
index ac48b09..d9daaac 100644
--- a/src/x64/lithium-x64.cc
+++ b/src/x64/lithium-x64.cc
@@ -1613,9 +1613,13 @@
LInstruction* LChunkBuilder::DoRandom(HRandom* instr) {
ASSERT(instr->representation().IsDouble());
ASSERT(instr->global_object()->representation().IsTagged());
- LOperand* global_object = UseFixed(instr->global_object(), arg_reg_1);
- LRandom* result = new(zone()) LRandom(global_object);
- return MarkAsCall(DefineFixedDouble(result, xmm1), instr);
+ LOperand* global_object = UseTempRegister(instr->global_object());
+ LOperand* scratch = TempRegister();
+ LOperand* scratch2 = TempRegister();
+ LOperand* scratch3 = TempRegister();
+ LRandom* result = new(zone()) LRandom(
+ global_object, scratch, scratch2, scratch3);
+ return DefineFixedDouble(result, xmm1);
}
diff --git a/src/x64/lithium-x64.h b/src/x64/lithium-x64.h
index ff0c61b..b3d08c8 100644
--- a/src/x64/lithium-x64.h
+++ b/src/x64/lithium-x64.h
@@ -1404,13 +1404,22 @@
};
-class LRandom V8_FINAL : public LTemplateInstruction<1, 1, 0> {
+class LRandom V8_FINAL : public LTemplateInstruction<1, 1, 3> {
public:
- explicit LRandom(LOperand* global_object) {
+ LRandom(LOperand* global_object,
+ LOperand* scratch,
+ LOperand* scratch2,
+ LOperand* scratch3) {
inputs_[0] = global_object;
+ temps_[0] = scratch;
+ temps_[1] = scratch2;
+ temps_[2] = scratch3;
}
LOperand* global_object() { return inputs_[0]; }
+ LOperand* scratch() const { return temps_[0]; }
+ LOperand* scratch2() const { return temps_[1]; }
+ LOperand* scratch3() const { return temps_[2]; }
DECLARE_CONCRETE_INSTRUCTION(Random, "random")
DECLARE_HYDROGEN_ACCESSOR(Random)
diff --git a/src/x64/stub-cache-x64.cc b/src/x64/stub-cache-x64.cc
index b2cfa86..95276d5 100644
--- a/src/x64/stub-cache-x64.cc
+++ b/src/x64/stub-cache-x64.cc
@@ -29,6 +29,7 @@
#if V8_TARGET_ARCH_X64
+#include "arguments.h"
#include "ic-inl.h"
#include "codegen.h"
#include "stub-cache.h"
@@ -366,6 +367,11 @@
Register holder,
Register name,
Handle<JSObject> holder_obj) {
+ STATIC_ASSERT(StubCache::kInterceptorArgsNameIndex == 0);
+ STATIC_ASSERT(StubCache::kInterceptorArgsInfoIndex == 1);
+ STATIC_ASSERT(StubCache::kInterceptorArgsThisIndex == 2);
+ STATIC_ASSERT(StubCache::kInterceptorArgsHolderIndex == 3);
+ STATIC_ASSERT(StubCache::kInterceptorArgsLength == 4);
__ push(name);
Handle<InterceptorInfo> interceptor(holder_obj->GetNamedInterceptor());
ASSERT(!masm->isolate()->heap()->InNewSpace(*interceptor));
@@ -373,8 +379,6 @@
__ push(kScratchRegister);
__ push(receiver);
__ push(holder);
- __ push(FieldOperand(kScratchRegister, InterceptorInfo::kDataOffset));
- __ PushAddress(ExternalReference::isolate_address(masm->isolate()));
}
@@ -389,7 +393,7 @@
ExternalReference ref =
ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorOnly),
masm->isolate());
- __ Set(rax, 6);
+ __ Set(rax, StubCache::kInterceptorArgsLength);
__ LoadAddress(rbx, ref);
CEntryStub stub(1);
@@ -719,7 +723,7 @@
__ CallExternalReference(
ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorForCall),
masm->isolate()),
- 6);
+ StubCache::kInterceptorArgsLength);
// Restore the name_ register.
__ pop(name_);
@@ -1322,19 +1326,27 @@
ASSERT(!scratch4().is(reg));
__ PopReturnAddressTo(scratch4());
+ STATIC_ASSERT(PropertyCallbackArguments::kThisIndex == 0);
+ STATIC_ASSERT(PropertyCallbackArguments::kDataIndex == -1);
+ STATIC_ASSERT(PropertyCallbackArguments::kReturnValueOffset == -2);
+ STATIC_ASSERT(PropertyCallbackArguments::kReturnValueDefaultValueIndex == -3);
+ STATIC_ASSERT(PropertyCallbackArguments::kIsolateIndex == -4);
+ STATIC_ASSERT(PropertyCallbackArguments::kHolderIndex == -5);
__ push(receiver()); // receiver
- __ push(reg); // holder
if (heap()->InNewSpace(callback->data())) {
- __ Move(scratch1(), callback);
- __ push(FieldOperand(scratch1(),
+ ASSERT(!scratch2().is(reg));
+ __ Move(scratch2(), callback);
+ __ push(FieldOperand(scratch2(),
ExecutableAccessorInfo::kDataOffset)); // data
} else {
__ Push(Handle<Object>(callback->data(), isolate()));
}
+ ASSERT(!kScratchRegister.is(reg));
__ LoadRoot(kScratchRegister, Heap::kUndefinedValueRootIndex);
__ push(kScratchRegister); // return value
__ push(kScratchRegister); // return value default
__ PushAddress(ExternalReference::isolate_address(isolate()));
+ __ push(reg); // holder
__ push(name()); // name
// Save a pointer to where we pushed the arguments pointer. This will be
// passed as the const ExecutableAccessorInfo& to the C++ callback.
@@ -1378,7 +1390,7 @@
thunk_address,
getter_arg,
kStackSpace,
- 5);
+ 6);
}
@@ -1477,7 +1489,7 @@
ExternalReference ref = ExternalReference(
IC_Utility(IC::kLoadPropertyWithInterceptorForLoad), isolate());
- __ TailCallExternalReference(ref, 6, 1);
+ __ TailCallExternalReference(ref, StubCache::kInterceptorArgsLength, 1);
}
}
@@ -2233,13 +2245,6 @@
// -- ...
// -- rsp[(argc + 1) * 4] : receiver
// -----------------------------------
-
- if (!CpuFeatures::IsSupported(SSE2)) {
- return Handle<Code>::null();
- }
-
- CpuFeatureScope use_sse2(masm(), SSE2);
-
const int argc = arguments().immediate();
// If the object is not a JSObject or we got an unexpected number of
diff --git a/test/cctest/cctest.gyp b/test/cctest/cctest.gyp
index 0775cc5..ee7ffad 100644
--- a/test/cctest/cctest.gyp
+++ b/test/cctest/cctest.gyp
@@ -106,6 +106,7 @@
'test-time.cc',
'test-types.cc',
'test-unbound-queue.cc',
+ 'test-unique.cc',
'test-utils.cc',
'test-version.cc',
'test-weakmaps.cc',
diff --git a/test/cctest/test-api.cc b/test/cctest/test-api.cc
index 6e47cd6..f4e40cd 100644
--- a/test/cctest/test-api.cc
+++ b/test/cctest/test-api.cc
@@ -12670,8 +12670,8 @@
typedef Persistent<T, CopyablePersistentTraits<T> > CopyablePersistent;
static const bool kResetInDestructor = true;
template<class S, class M>
- V8_INLINE(static void Copy(const Persistent<S, M>& source,
- CopyablePersistent* dest)) {
+ static V8_INLINE void Copy(const Persistent<S, M>& source,
+ CopyablePersistent* dest) {
// do nothing, just allow copy
}
};
diff --git a/test/cctest/test-assembler-arm.cc b/test/cctest/test-assembler-arm.cc
index cac162e..1a4c1ae 100644
--- a/test/cctest/test-assembler-arm.cc
+++ b/test/cctest/test-assembler-arm.cc
@@ -1439,4 +1439,75 @@
}
+TEST(code_relative_offset) {
+ // Test extracting the offset of a label from the beginning of the code
+ // in a register.
+ CcTest::InitializeVM();
+ Isolate* isolate = Isolate::Current();
+ HandleScope scope(isolate);
+ // Initialize a code object that will contain the code.
+ Handle<Object> code_object(isolate->heap()->undefined_value(), isolate);
+
+ Assembler assm(isolate, NULL, 0);
+
+ Label start, target_away, target_faraway;
+
+ __ stm(db_w, sp, r4.bit() | r5.bit() | lr.bit());
+
+ // r3 is used as the address zero, the test will crash when we load it.
+ __ mov(r3, Operand::Zero());
+
+ // r5 will be a pointer to the start of the code.
+ __ mov(r5, Operand(code_object));
+ __ mov_label_offset(r4, &start);
+
+ __ mov_label_offset(r1, &target_faraway);
+ __ str(r1, MemOperand(sp, kPointerSize, NegPreIndex));
+
+ __ mov_label_offset(r1, &target_away);
+
+ // Jump straight to 'target_away' the first time and use the relative
+ // position the second time. This covers the case when extracting the
+ // position of a label which is linked.
+ __ mov(r2, Operand::Zero());
+ __ bind(&start);
+ __ cmp(r2, Operand::Zero());
+ __ b(eq, &target_away);
+ __ add(pc, r5, r1);
+ // Emit invalid instructions to push the label between 2^8 and 2^16
+ // instructions away. The test will crash if they are reached.
+ for (int i = 0; i < (1 << 10); i++) {
+ __ ldr(r3, MemOperand(r3));
+ }
+ __ bind(&target_away);
+ // This will be hit twice: r0 = r0 + 5 + 5.
+ __ add(r0, r0, Operand(5));
+
+ __ ldr(r1, MemOperand(sp, kPointerSize, PostIndex), ne);
+ __ add(pc, r5, r4, LeaveCC, ne);
+
+ __ mov(r2, Operand(1));
+ __ b(&start);
+ // Emit invalid instructions to push the label between 2^16 and 2^24
+ // instructions away. The test will crash if they are reached.
+ for (int i = 0; i < (1 << 21); i++) {
+ __ ldr(r3, MemOperand(r3));
+ }
+ __ bind(&target_faraway);
+ // r0 = r0 + 5 + 5 + 11
+ __ add(r0, r0, Operand(11));
+
+ __ ldm(ia_w, sp, r4.bit() | r5.bit() | pc.bit());
+
+ CodeDesc desc;
+ assm.GetCode(&desc);
+ Handle<Code> code = isolate->factory()->NewCode(desc,
+ Code::ComputeFlags(Code::STUB), code_object);
+ CHECK(code->IsCode());
+ F1 f = FUNCTION_CAST<F1>(code->entry());
+ int res = reinterpret_cast<int>(CALL_GENERATED_CODE(f, 21, 0, 0, 0, 0));
+ ::printf("f() = %d\n", res);
+ CHECK_EQ(42, res);
+}
+
#undef __
diff --git a/test/cctest/test-dictionary.cc b/test/cctest/test-dictionary.cc
index 21c20bd..b9e8b1e 100644
--- a/test/cctest/test-dictionary.cc
+++ b/test/cctest/test-dictionary.cc
@@ -101,6 +101,57 @@
}
+class ObjectHashTableTest: public ObjectHashTable {
+ public:
+ void insert(int entry, int key, int value) {
+ set(EntryToIndex(entry), Smi::FromInt(key));
+ set(EntryToIndex(entry) + 1, Smi::FromInt(value));
+ }
+
+ int lookup(int key) {
+ return Smi::cast(Lookup(Smi::FromInt(key)))->value();
+ }
+
+ int capacity() {
+ return Capacity();
+ }
+};
+
+
+TEST(HashTableRehash) {
+ LocalContext context;
+ Isolate* isolate = Isolate::Current();
+ Factory* factory = isolate->factory();
+ v8::HandleScope scope(context->GetIsolate());
+ // Test almost filled table.
+ {
+ Handle<ObjectHashTable> table = factory->NewObjectHashTable(100);
+ ObjectHashTableTest* t = reinterpret_cast<ObjectHashTableTest*>(*table);
+ int capacity = t->capacity();
+ for (int i = 0; i < capacity - 1; i++) {
+ t->insert(i, i * i, i);
+ }
+ t->Rehash(Smi::FromInt(0));
+ for (int i = 0; i < capacity - 1; i++) {
+ CHECK_EQ(i, t->lookup(i * i));
+ }
+ }
+ // Test half-filled table.
+ {
+ Handle<ObjectHashTable> table = factory->NewObjectHashTable(100);
+ ObjectHashTableTest* t = reinterpret_cast<ObjectHashTableTest*>(*table);
+ int capacity = t->capacity();
+ for (int i = 0; i < capacity / 2; i++) {
+ t->insert(i, i * i, i);
+ }
+ t->Rehash(Smi::FromInt(0));
+ for (int i = 0; i < capacity / 2; i++) {
+ CHECK_EQ(i, t->lookup(i * i));
+ }
+ }
+}
+
+
#ifdef DEBUG
TEST(ObjectHashSetCausesGC) {
i::FLAG_stress_compaction = false;
diff --git a/test/cctest/test-heap.cc b/test/cctest/test-heap.cc
index 64075d2..9d74011 100644
--- a/test/cctest/test-heap.cc
+++ b/test/cctest/test-heap.cc
@@ -3141,10 +3141,6 @@
i::FLAG_allow_natives_syntax = true;
i::FLAG_flush_code_incrementally = true;
- // Disable loading the i18n extension which breaks the assumptions of this
- // test about the heap layout.
- i::FLAG_enable_i18n = false;
-
CcTest::InitializeVM();
Isolate* isolate = Isolate::Current();
Heap* heap = isolate->heap();
diff --git a/test/cctest/test-unique.cc b/test/cctest/test-unique.cc
new file mode 100644
index 0000000..1d26858
--- /dev/null
+++ b/test/cctest/test-unique.cc
@@ -0,0 +1,488 @@
+// Copyright 2013 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <stdlib.h>
+
+#include "v8.h"
+
+#include "factory.h"
+#include "global-handles.h"
+#include "unique.h"
+#include "cctest.h"
+
+using namespace v8::internal;
+
+template <class T, class U>
+void CheckHashCodeEqual(Unique<T> a, Unique<U> b) {
+ int64_t hasha = static_cast<int64_t>(a.Hashcode());
+ int64_t hashb = static_cast<int64_t>(b.Hashcode());
+ CHECK_NE(static_cast<int64_t>(0), hasha);
+ CHECK_NE(static_cast<int64_t>(0), hashb);
+ CHECK_EQ(hasha, hashb);
+}
+
+
+template <class T, class U>
+void CheckHashCodeNotEqual(Unique<T> a, Unique<U> b) {
+ int64_t hasha = static_cast<int64_t>(a.Hashcode());
+ int64_t hashb = static_cast<int64_t>(b.Hashcode());
+ CHECK_NE(static_cast<int64_t>(0), hasha);
+ CHECK_NE(static_cast<int64_t>(0), hashb);
+ CHECK_NE(hasha, hashb);
+}
+
+
+TEST(UniqueCreate) {
+ CcTest::InitializeVM();
+ Isolate* isolate = Isolate::Current();
+ Factory* factory = isolate->factory();
+ HandleScope sc(isolate);
+
+ Handle<String> A = factory->InternalizeUtf8String("A");
+ Unique<String> HA(A);
+
+ CHECK(*HA.handle() == *A);
+ CHECK_EQ(*A, *HA.handle());
+
+ Unique<String> HA2(A);
+
+ CheckHashCodeEqual(HA, HA2);
+ CHECK(HA == HA2);
+ CHECK_EQ(*HA.handle(), *HA2.handle());
+
+ CHECK(HA2 == HA);
+ CHECK_EQ(*HA2.handle(), *HA.handle());
+
+ Handle<String> B = factory->InternalizeUtf8String("B");
+ Unique<String> HB(B);
+
+ CheckHashCodeNotEqual(HA, HB);
+ CHECK(HA != HB);
+ CHECK_NE(*HA.handle(), *HB.handle());
+
+ CHECK(HB != HA);
+ CHECK_NE(*HB.handle(), *HA.handle());
+
+ // TODO(titzer): check that Unique properly survives a GC.
+}
+
+
+TEST(UniqueSubsume) {
+ CcTest::InitializeVM();
+ Isolate* isolate = Isolate::Current();
+ Factory* factory = isolate->factory();
+ HandleScope sc(isolate);
+
+ Handle<String> A = factory->InternalizeUtf8String("A");
+ Unique<String> HA(A);
+
+ CHECK(*HA.handle() == *A);
+ CHECK_EQ(*A, *HA.handle());
+
+ Unique<Object> HO = HA; // Here comes the subsumption, boys.
+
+ CheckHashCodeEqual(HA, HO);
+ CHECK(HA == HO);
+ CHECK_EQ(*HA.handle(), *HO.handle());
+
+ CHECK(HO == HA);
+ CHECK_EQ(*HO.handle(), *HA.handle());
+}
+
+
+TEST(UniqueSet_Add) {
+ CcTest::InitializeVM();
+ Isolate* isolate = Isolate::Current();
+ Factory* factory = isolate->factory();
+ HandleScope sc(isolate);
+
+ Unique<String> A(factory->InternalizeUtf8String("A"));
+ Unique<String> B(factory->InternalizeUtf8String("B"));
+ Unique<String> C(factory->InternalizeUtf8String("C"));
+
+ Zone zone(isolate);
+
+ UniqueSet<String>* set = new(&zone) UniqueSet<String>();
+
+ CHECK_EQ(0, set->size());
+ set->Add(A, &zone);
+ CHECK_EQ(1, set->size());
+ set->Add(A, &zone);
+ CHECK_EQ(1, set->size());
+ set->Add(B, &zone);
+ CHECK_EQ(2, set->size());
+ set->Add(C, &zone);
+ CHECK_EQ(3, set->size());
+ set->Add(C, &zone);
+ CHECK_EQ(3, set->size());
+ set->Add(B, &zone);
+ CHECK_EQ(3, set->size());
+ set->Add(A, &zone);
+ CHECK_EQ(3, set->size());
+}
+
+
+template <class T>
+static void CHECK_SETS(
+ UniqueSet<T>* set1, UniqueSet<T>* set2, bool expected) {
+ CHECK(set1->Equals(set1));
+ CHECK(set2->Equals(set2));
+ CHECK(expected == set1->Equals(set2));
+ CHECK(expected == set2->Equals(set1));
+}
+
+
+TEST(UniqueSet_Equals) {
+ CcTest::InitializeVM();
+ Isolate* isolate = Isolate::Current();
+ Factory* factory = isolate->factory();
+ HandleScope sc(isolate);
+
+ Unique<String> A(factory->InternalizeUtf8String("A"));
+ Unique<String> B(factory->InternalizeUtf8String("B"));
+ Unique<String> C(factory->InternalizeUtf8String("C"));
+
+ Zone zone(isolate);
+
+ UniqueSet<String>* set1 = new(&zone) UniqueSet<String>();
+ UniqueSet<String>* set2 = new(&zone) UniqueSet<String>();
+
+ CHECK_SETS(set1, set2, true);
+
+ set1->Add(A, &zone);
+
+ CHECK_SETS(set1, set2, false);
+
+ set2->Add(A, &zone);
+
+ CHECK_SETS(set1, set2, true);
+
+ set1->Add(B, &zone);
+
+ CHECK_SETS(set1, set2, false);
+
+ set2->Add(C, &zone);
+
+ CHECK_SETS(set1, set2, false);
+
+ set1->Add(C, &zone);
+
+ CHECK_SETS(set1, set2, false);
+
+ set2->Add(B, &zone);
+
+ CHECK_SETS(set1, set2, true);
+}
+
+
+TEST(UniqueSet_IsSubset1) {
+ CcTest::InitializeVM();
+ Isolate* isolate = Isolate::Current();
+ Factory* factory = isolate->factory();
+ HandleScope sc(isolate);
+
+ Unique<String> A(factory->InternalizeUtf8String("A"));
+ Unique<String> B(factory->InternalizeUtf8String("B"));
+ Unique<String> C(factory->InternalizeUtf8String("C"));
+
+ Zone zone(isolate);
+
+ UniqueSet<String>* set1 = new(&zone) UniqueSet<String>();
+ UniqueSet<String>* set2 = new(&zone) UniqueSet<String>();
+
+ CHECK(set1->IsSubset(set2));
+ CHECK(set2->IsSubset(set1));
+
+ set1->Add(A, &zone);
+
+ CHECK(!set1->IsSubset(set2));
+ CHECK(set2->IsSubset(set1));
+
+ set2->Add(B, &zone);
+
+ CHECK(!set1->IsSubset(set2));
+ CHECK(!set2->IsSubset(set1));
+
+ set2->Add(A, &zone);
+
+ CHECK(set1->IsSubset(set2));
+ CHECK(!set2->IsSubset(set1));
+
+ set1->Add(B, &zone);
+
+ CHECK(set1->IsSubset(set2));
+ CHECK(set2->IsSubset(set1));
+}
+
+
+TEST(UniqueSet_IsSubset2) {
+ CcTest::InitializeVM();
+ Isolate* isolate = Isolate::Current();
+ Factory* factory = isolate->factory();
+ HandleScope sc(isolate);
+
+ Unique<String> A(factory->InternalizeUtf8String("A"));
+ Unique<String> B(factory->InternalizeUtf8String("B"));
+ Unique<String> C(factory->InternalizeUtf8String("C"));
+ Unique<String> D(factory->InternalizeUtf8String("D"));
+ Unique<String> E(factory->InternalizeUtf8String("E"));
+ Unique<String> F(factory->InternalizeUtf8String("F"));
+ Unique<String> G(factory->InternalizeUtf8String("G"));
+
+ Zone zone(isolate);
+
+ UniqueSet<String>* set1 = new(&zone) UniqueSet<String>();
+ UniqueSet<String>* set2 = new(&zone) UniqueSet<String>();
+
+ set1->Add(A, &zone);
+ set1->Add(C, &zone);
+ set1->Add(E, &zone);
+
+ set2->Add(A, &zone);
+ set2->Add(B, &zone);
+ set2->Add(C, &zone);
+ set2->Add(D, &zone);
+ set2->Add(E, &zone);
+ set2->Add(F, &zone);
+
+ CHECK(set1->IsSubset(set2));
+ CHECK(!set2->IsSubset(set1));
+
+ set1->Add(G, &zone);
+
+ CHECK(!set1->IsSubset(set2));
+ CHECK(!set2->IsSubset(set1));
+}
+
+
+template <class T>
+static UniqueSet<T>* MakeSet(Zone* zone, int which, Unique<T>* elements) {
+ UniqueSet<T>* set = new(zone) UniqueSet<T>();
+ for (int i = 0; i < 32; i++) {
+ if ((which & (1 << i)) != 0) set->Add(elements[i], zone);
+ }
+ return set;
+}
+
+
+TEST(UniqueSet_IsSubsetExhaustive) {
+ const int kSetSize = 6;
+
+ CcTest::InitializeVM();
+ Isolate* isolate = Isolate::Current();
+ Factory* factory = isolate->factory();
+ HandleScope sc(isolate);
+
+ Zone zone(isolate);
+
+ Unique<String> A(factory->InternalizeUtf8String("A"));
+ Unique<String> B(factory->InternalizeUtf8String("B"));
+ Unique<String> C(factory->InternalizeUtf8String("C"));
+ Unique<String> D(factory->InternalizeUtf8String("D"));
+ Unique<String> E(factory->InternalizeUtf8String("E"));
+ Unique<String> F(factory->InternalizeUtf8String("F"));
+ Unique<String> G(factory->InternalizeUtf8String("G"));
+
+ Unique<String> elements[] = {
+ A, B, C, D, E, F, G
+ };
+
+ // Exhaustively test all sets with <= 6 elements.
+ for (int i = 0; i < (1 << kSetSize); i++) {
+ for (int j = 0; j < (1 << kSetSize); j++) {
+ UniqueSet<String>* set1 = MakeSet(&zone, i, elements);
+ UniqueSet<String>* set2 = MakeSet(&zone, j, elements);
+
+ CHECK(((i & j) == i) == set1->IsSubset(set2));
+ }
+ }
+}
+
+
+TEST(UniqueSet_Intersect1) {
+ CcTest::InitializeVM();
+ Isolate* isolate = Isolate::Current();
+ Factory* factory = isolate->factory();
+ HandleScope sc(isolate);
+
+ Unique<String> A(factory->InternalizeUtf8String("A"));
+ Unique<String> B(factory->InternalizeUtf8String("B"));
+ Unique<String> C(factory->InternalizeUtf8String("C"));
+
+ Zone zone(isolate);
+
+ UniqueSet<String>* set1 = new(&zone) UniqueSet<String>();
+ UniqueSet<String>* set2 = new(&zone) UniqueSet<String>();
+ UniqueSet<String>* result;
+
+ CHECK(set1->IsSubset(set2));
+ CHECK(set2->IsSubset(set1));
+
+ set1->Add(A, &zone);
+
+ result = set1->Intersect(set2, &zone);
+
+ CHECK_EQ(0, result->size());
+ CHECK(set2->Equals(result));
+
+ set2->Add(A, &zone);
+
+ result = set1->Intersect(set2, &zone);
+
+ CHECK_EQ(1, result->size());
+ CHECK(set1->Equals(result));
+ CHECK(set2->Equals(result));
+
+ set2->Add(B, &zone);
+ set2->Add(C, &zone);
+
+ result = set1->Intersect(set2, &zone);
+
+ CHECK_EQ(1, result->size());
+ CHECK(set1->Equals(result));
+}
+
+
+TEST(UniqueSet_IntersectExhaustive) {
+ const int kSetSize = 6;
+
+ CcTest::InitializeVM();
+ Isolate* isolate = Isolate::Current();
+ Factory* factory = isolate->factory();
+ HandleScope sc(isolate);
+
+ Zone zone(isolate);
+
+ Unique<String> A(factory->InternalizeUtf8String("A"));
+ Unique<String> B(factory->InternalizeUtf8String("B"));
+ Unique<String> C(factory->InternalizeUtf8String("C"));
+ Unique<String> D(factory->InternalizeUtf8String("D"));
+ Unique<String> E(factory->InternalizeUtf8String("E"));
+ Unique<String> F(factory->InternalizeUtf8String("F"));
+ Unique<String> G(factory->InternalizeUtf8String("G"));
+
+ Unique<String> elements[] = {
+ A, B, C, D, E, F, G
+ };
+
+ // Exhaustively test all sets with <= 6 elements.
+ for (int i = 0; i < (1 << kSetSize); i++) {
+ for (int j = 0; j < (1 << kSetSize); j++) {
+ UniqueSet<String>* set1 = MakeSet(&zone, i, elements);
+ UniqueSet<String>* set2 = MakeSet(&zone, j, elements);
+
+ UniqueSet<String>* result = set1->Intersect(set2, &zone);
+ UniqueSet<String>* expected = MakeSet(&zone, i & j, elements);
+
+ CHECK(result->Equals(expected));
+ CHECK(expected->Equals(result));
+ }
+ }
+}
+
+
+TEST(UniqueSet_Union1) {
+ CcTest::InitializeVM();
+ Isolate* isolate = Isolate::Current();
+ Factory* factory = isolate->factory();
+ HandleScope sc(isolate);
+
+ Unique<String> A(factory->InternalizeUtf8String("A"));
+ Unique<String> B(factory->InternalizeUtf8String("B"));
+ Unique<String> C(factory->InternalizeUtf8String("C"));
+
+ Zone zone(isolate);
+
+ UniqueSet<String>* set1 = new(&zone) UniqueSet<String>();
+ UniqueSet<String>* set2 = new(&zone) UniqueSet<String>();
+ UniqueSet<String>* result;
+
+ CHECK(set1->IsSubset(set2));
+ CHECK(set2->IsSubset(set1));
+
+ set1->Add(A, &zone);
+
+ result = set1->Union(set2, &zone);
+
+ CHECK_EQ(1, result->size());
+ CHECK(set1->Equals(result));
+
+ set2->Add(A, &zone);
+
+ result = set1->Union(set2, &zone);
+
+ CHECK_EQ(1, result->size());
+ CHECK(set1->Equals(result));
+ CHECK(set2->Equals(result));
+
+ set2->Add(B, &zone);
+ set2->Add(C, &zone);
+
+ result = set1->Union(set2, &zone);
+
+ CHECK_EQ(3, result->size());
+ CHECK(set2->Equals(result));
+}
+
+
+TEST(UniqueSet_UnionExhaustive) {
+ const int kSetSize = 6;
+
+ CcTest::InitializeVM();
+ Isolate* isolate = Isolate::Current();
+ Factory* factory = isolate->factory();
+ HandleScope sc(isolate);
+
+ Zone zone(isolate);
+
+ Unique<String> A(factory->InternalizeUtf8String("A"));
+ Unique<String> B(factory->InternalizeUtf8String("B"));
+ Unique<String> C(factory->InternalizeUtf8String("C"));
+ Unique<String> D(factory->InternalizeUtf8String("D"));
+ Unique<String> E(factory->InternalizeUtf8String("E"));
+ Unique<String> F(factory->InternalizeUtf8String("F"));
+ Unique<String> G(factory->InternalizeUtf8String("G"));
+
+ Unique<String> elements[] = {
+ A, B, C, D, E, F, G
+ };
+
+ // Exhaustively test all sets with <= 6 elements.
+ for (int i = 0; i < (1 << kSetSize); i++) {
+ for (int j = 0; j < (1 << kSetSize); j++) {
+ UniqueSet<String>* set1 = MakeSet(&zone, i, elements);
+ UniqueSet<String>* set2 = MakeSet(&zone, j, elements);
+
+ UniqueSet<String>* result = set1->Union(set2, &zone);
+ UniqueSet<String>* expected = MakeSet(&zone, i | j, elements);
+
+ CHECK(result->Equals(expected));
+ CHECK(expected->Equals(result));
+ }
+ }
+}
+
diff --git a/test/mjsunit/debug-script.js b/test/mjsunit/debug-script.js
index 6e673f7..1cbdb37 100644
--- a/test/mjsunit/debug-script.js
+++ b/test/mjsunit/debug-script.js
@@ -59,9 +59,9 @@
}
// This has to be updated if the number of native scripts change.
-assertEquals(16, named_native_count);
-// Only the 'gc' and (depending on flags) the 'i18n' extensions are loaded.
-assertTrue(extension_count == 1 || extension_count == 2);
+assertTrue(named_native_count == 16 || named_native_count == 17);
+// Only the 'gc' extension is loaded.
+assertEquals(1, extension_count);
// This script and mjsunit.js has been loaded. If using d8, d8 loads
// a normal script during startup too.
assertTrue(normal_count == 2 || normal_count == 3);
diff --git a/test/mjsunit/fuzz-natives-part1.js b/test/mjsunit/fuzz-natives-part1.js
index 08b7258..e76b9be 100644
--- a/test/mjsunit/fuzz-natives-part1.js
+++ b/test/mjsunit/fuzz-natives-part1.js
@@ -151,7 +151,6 @@
"LazyCompile": true,
"LazyRecompile": true,
"ConcurrentRecompile": true,
- "InstallRecompiledCode": true,
"NotifyDeoptimized": true,
"NotifyStubFailure": true,
"NotifyOSR": true,
diff --git a/test/mjsunit/fuzz-natives-part2.js b/test/mjsunit/fuzz-natives-part2.js
index 1cebf41..0797deb 100644
--- a/test/mjsunit/fuzz-natives-part2.js
+++ b/test/mjsunit/fuzz-natives-part2.js
@@ -151,7 +151,6 @@
"LazyCompile": true,
"LazyRecompile": true,
"ConcurrentRecompile": true,
- "InstallRecompiledCode": true,
"NotifyDeoptimized": true,
"NotifyStubFailure": true,
"NotifyOSR": true,
diff --git a/test/mjsunit/fuzz-natives-part3.js b/test/mjsunit/fuzz-natives-part3.js
index f2efee4..9a3a883 100644
--- a/test/mjsunit/fuzz-natives-part3.js
+++ b/test/mjsunit/fuzz-natives-part3.js
@@ -151,7 +151,6 @@
"LazyCompile": true,
"LazyRecompile": true,
"ConcurrentRecompile": true,
- "InstallRecompiledCode": true,
"NotifyDeoptimized": true,
"NotifyStubFailure": true,
"NotifyOSR": true,
diff --git a/test/mjsunit/fuzz-natives-part4.js b/test/mjsunit/fuzz-natives-part4.js
index fa53480..83e00d2 100644
--- a/test/mjsunit/fuzz-natives-part4.js
+++ b/test/mjsunit/fuzz-natives-part4.js
@@ -151,7 +151,6 @@
"LazyCompile": true,
"LazyRecompile": true,
"ConcurrentRecompile": true,
- "InstallRecompiledCode": true,
"NotifyDeoptimized": true,
"NotifyStubFailure": true,
"NotifyOSR": true,
diff --git a/test/mjsunit/regress/regress-2855.js b/test/mjsunit/regress/regress-2855.js
index ac721af..24ec452 100644
--- a/test/mjsunit/regress/regress-2855.js
+++ b/test/mjsunit/regress/regress-2855.js
@@ -39,3 +39,19 @@
}
assertEquals(expected, "" + foo("hello"));
}
+
+// Make sure we look up "valueOf" only once.
+var count = 0;
+var x = new String("foo");
+Object.defineProperty(x, "valueOf",
+ { get: function() {
+ count++;
+ return function() {
+ return 11;
+ }
+ }
+ });
+for (var i = 0; i < 3; i++) {
+ assertEquals("11", "" + x);
+ assertEquals(i + 1, count);
+}
diff --git a/tools/gyp/v8.gyp b/tools/gyp/v8.gyp
index 4f629ff..aa01a84 100644
--- a/tools/gyp/v8.gyp
+++ b/tools/gyp/v8.gyp
@@ -129,11 +129,6 @@
],
},
}],
- ['v8_enable_i18n_support==1', {
- 'sources': [
- '<(SHARED_INTERMEDIATE_DIR)/i18n-libraries.cc',
- ],
- }],
],
'dependencies': [
'v8_base.<(v8_target_arch)',
@@ -197,11 +192,6 @@
'V8_SHARED',
],
}],
- ['v8_enable_i18n_support==1', {
- 'sources': [
- '<(SHARED_INTERMEDIATE_DIR)/i18n-libraries.cc',
- ],
- }],
]
},
{
@@ -367,6 +357,8 @@
'../../src/hydrogen-mark-deoptimize.h',
'../../src/hydrogen-minus-zero.cc',
'../../src/hydrogen-minus-zero.h',
+ '../../src/hydrogen-osr.cc',
+ '../../src/hydrogen-osr.h',
'../../src/hydrogen-range-analysis.cc',
'../../src/hydrogen-range-analysis.h',
'../../src/hydrogen-redundant-phi.cc',
@@ -379,8 +371,6 @@
'../../src/hydrogen-sce.h',
'../../src/hydrogen-uint32-analysis.cc',
'../../src/hydrogen-uint32-analysis.h',
- '../../src/hydrogen-osr.cc',
- '../../src/hydrogen-osr.h',
'../../src/i18n.cc',
'../../src/i18n.h',
'../../src/icu_util.cc',
@@ -528,6 +518,7 @@
'../../src/unicode-inl.h',
'../../src/unicode.cc',
'../../src/unicode.h',
+ '../../src/unique.h',
'../../src/uri.h',
'../../src/utils-inl.h',
'../../src/utils.cc',
@@ -863,10 +854,6 @@
]
}],
['v8_enable_i18n_support==1', {
- 'sources': [
- '../../src/extensions/i18n/i18n-extension.cc',
- '../../src/extensions/i18n/i18n-extension.h',
- ],
'dependencies': [
'<(DEPTH)/third_party/icu/icu.gyp:icui18n',
'<(DEPTH)/third_party/icu/icu.gyp:icuuc',
@@ -894,24 +881,15 @@
'toolsets': ['target'],
}],
['v8_enable_i18n_support==1', {
- 'actions': [{
- 'action_name': 'js2c_i18n',
- 'inputs': [
- '../../tools/js2c.py',
- '<@(i18n_library_files)',
+ 'variables': {
+ 'i18n_library_files': [
+ '../../src/i18n.js',
],
- 'outputs': [
- '<(SHARED_INTERMEDIATE_DIR)/i18n-libraries.cc',
- ],
- 'action': [
- 'python',
- '../../tools/js2c.py',
- '<@(_outputs)',
- 'I18N',
- '<(v8_compress_startup_data)',
- '<@(i18n_library_files)'
- ],
- }],
+ },
+ }, {
+ 'variables': {
+ 'i18n_library_files': [],
+ },
}],
],
'variables': {
@@ -945,18 +923,6 @@
'../../src/harmony-string.js',
'../../src/harmony-array.js',
],
- 'i18n_library_files': [
- '../../src/extensions/i18n/header.js',
- '../../src/extensions/i18n/globals.js',
- '../../src/extensions/i18n/locale.js',
- '../../src/extensions/i18n/collator.js',
- '../../src/extensions/i18n/number-format.js',
- '../../src/extensions/i18n/date-format.js',
- '../../src/extensions/i18n/break-iterator.js',
- '../../src/extensions/i18n/i18n-utils.js',
- '../../src/extensions/i18n/overrides.js',
- '../../src/extensions/i18n/footer.js',
- ],
},
'actions': [
{
@@ -964,6 +930,7 @@
'inputs': [
'../../tools/js2c.py',
'<@(library_files)',
+ '<@(i18n_library_files)',
],
'outputs': [
'<(SHARED_INTERMEDIATE_DIR)/libraries.cc',
@@ -974,7 +941,8 @@
'<@(_outputs)',
'CORE',
'<(v8_compress_startup_data)',
- '<@(library_files)'
+ '<@(library_files)',
+ '<@(i18n_library_files)',
],
},
{