Version 3.22.4
Function::Call and Object::CallAsFunction APIs should allow v8::Value as a receiver (issue 2915).
Removed unnecessary mutex (Chromium issue 291236).
Removed ArrayBufferView::BaseAddress method.
Performance and stability improvements on all platforms.
git-svn-id: http://v8.googlecode.com/svn/trunk@17010 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
diff --git a/ChangeLog b/ChangeLog
index 153f45c..6a90e29 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,15 @@
+2013-09-30: Version 3.22.4
+
+ Function::Call and Object::CallAsFunction APIs should allow v8::Value as
+ a receiver (issue 2915).
+
+ Removed unnecessary mutex (Chromium issue 291236).
+
+ Removed ArrayBufferView::BaseAddress method.
+
+ Performance and stability improvements on all platforms.
+
+
2013-09-27: Version 3.22.3
Added methods to enable configuration of ResourceConstraints based on
diff --git a/Makefile b/Makefile
index bcf3bcc..6f1de5c 100644
--- a/Makefile
+++ b/Makefile
@@ -76,10 +76,10 @@
endif
# extrachecks=on/off
ifeq ($(extrachecks), on)
- GYPFLAGS += -Dv8_enable_extra_checks=1
+ GYPFLAGS += -Dv8_enable_extra_checks=1 -Dv8_enable_handle_zapping=1
endif
ifeq ($(extrachecks), off)
- GYPFLAGS += -Dv8_enable_extra_checks=0
+ GYPFLAGS += -Dv8_enable_extra_checks=0 -Dv8_enable_handle_zapping=0
endif
# gdbjit=on/off
ifeq ($(gdbjit), on)
@@ -129,6 +129,10 @@
GYPFLAGS += -Dv8_enable_i18n_support=0
TESTFLAGS += --noi18n
endif
+# deprecation_warnings=on
+ifeq ($(deprecationwarnings), on)
+ GYPFLAGS += -Dv8_deprecation_warnings=1
+endif
# arm specific flags.
# armv7=false/true
ifeq ($(armv7), false)
diff --git a/OWNERS b/OWNERS
index 6fe40e2..e69a7d5 100644
--- a/OWNERS
+++ b/OWNERS
@@ -3,11 +3,12 @@
dslomov@chromium.org
hpayer@chromium.org
jkummerow@chromium.org
-mmassi@chromium.org
+machenbach@chromium.org
mstarzinger@chromium.org
mvstanton@chromium.org
rossberg@chromium.org
svenpanne@chromium.org
+titzer@chromium.org
ulan@chromium.org
vegorov@chromium.org
verwaest@chromium.org
diff --git a/build/features.gypi b/build/features.gypi
index 5343284..7863b1c 100644
--- a/build/features.gypi
+++ b/build/features.gypi
@@ -55,6 +55,9 @@
# Enable ECMAScript Internationalization API. Enabling this feature will
# add a dependency on the ICU library.
'v8_enable_i18n_support%': 1,
+
+ # Enable compiler warnings when using V8_DEPRECATED apis.
+ 'v8_deprecation_warnings%': 0,
},
'target_defaults': {
'conditions': [
@@ -76,6 +79,9 @@
['v8_interpreted_regexp==1', {
'defines': ['V8_INTERPRETED_REGEXP',],
}],
+ ['v8_deprecation_warnings==1', {
+ 'defines': ['V8_DEPRECATION_WARNINGS',],
+ }],
['v8_enable_i18n_support==1', {
'defines': ['V8_I18N_SUPPORT',],
}],
@@ -89,21 +95,29 @@
'Debug': {
'variables': {
'v8_enable_extra_checks%': 1,
+ 'v8_enable_handle_zapping%': 1,
},
'conditions': [
['v8_enable_extra_checks==1', {
'defines': ['ENABLE_EXTRA_CHECKS',],
}],
+ ['v8_enable_handle_zapping==1', {
+ 'defines': ['ENABLE_HANDLE_ZAPPING',],
+ }],
],
}, # Debug
'Release': {
'variables': {
'v8_enable_extra_checks%': 0,
+ 'v8_enable_handle_zapping%': 0,
},
'conditions': [
['v8_enable_extra_checks==1', {
'defines': ['ENABLE_EXTRA_CHECKS',],
}],
+ ['v8_enable_handle_zapping==1', {
+ 'defines': ['ENABLE_HANDLE_ZAPPING',],
+ }],
], # conditions
}, # Release
}, # configurations
diff --git a/include/v8-profiler.h b/include/v8-profiler.h
index 217a938..c393039 100644
--- a/include/v8-profiler.h
+++ b/include/v8-profiler.h
@@ -62,11 +62,6 @@
*/
const char* GetBailoutReason() const;
- /** DEPRECATED. Please use GetHitCount instead.
- * Returns the count of samples where function was currently executing.
- */
- V8_DEPRECATED(double GetSelfSamplesCount() const);
-
/**
* Returns the count of samples where the function was currently executing.
*/
diff --git a/include/v8.h b/include/v8.h
index 19abf0f..8e3fed6 100644
--- a/include/v8.h
+++ b/include/v8.h
@@ -586,7 +586,6 @@
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 bool IsEmpty() const { return val_ == 0; }
@@ -656,8 +655,6 @@
V8_INLINE void ClearWeak();
- V8_DEPRECATED(V8_INLINE void ClearWeak(Isolate* isolate)) { ClearWeak(); }
-
/**
* Marks the reference to this object independent. Garbage collector is free
* to ignore any object groups containing this object. Weak callback for an
@@ -666,10 +663,6 @@
*/
V8_INLINE void MarkIndependent();
- V8_DEPRECATED(V8_INLINE void MarkIndependent(Isolate* isolate)) {
- MarkIndependent();
- }
-
/**
* Marks the reference to this object partially dependent. Partially dependent
* handles only depend on other partially dependent handles and these
@@ -680,51 +673,26 @@
*/
V8_INLINE void MarkPartiallyDependent();
- V8_DEPRECATED(V8_INLINE void MarkPartiallyDependent(Isolate* isolate)) {
- MarkPartiallyDependent();
- }
-
V8_INLINE bool IsIndependent() 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_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_DEPRECATED(V8_INLINE bool IsWeak(Isolate* isolate) const) {
- return IsWeak();
- }
-
/**
* 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_DEPRECATED(
- V8_INLINE void SetWrapperClassId(Isolate * isolate, uint16_t class_id)) {
- SetWrapperClassId(class_id);
- }
-
/**
* 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_DEPRECATED(V8_INLINE uint16_t WrapperClassId(Isolate* isolate) const) {
- return WrapperClassId();
- }
-
// TODO(dcarney): remove
V8_INLINE T* ClearAndLeak();
@@ -1573,11 +1541,6 @@
int Utf8Length() const;
/**
- * This function is no longer useful.
- */
- V8_DEPRECATED(V8_INLINE bool MayContainNonAscii() const) { return true; }
-
- /**
* Returns whether this string is known to contain only one byte data.
* Does not read the string.
* False negatives are possible.
@@ -1627,11 +1590,6 @@
int start = 0,
int length = -1,
int options = NO_OPTIONS) const;
- // ASCII characters.
- V8_DEPRECATED(int WriteAscii(char* buffer,
- int start = 0,
- int length = -1,
- int options = NO_OPTIONS) const);
// One byte characters.
int WriteOneByte(uint8_t* buffer,
int start = 0,
@@ -1762,24 +1720,29 @@
V8_INLINE static String* Cast(v8::Value* obj);
- // TODO(dcarney): deprecate
/**
* Allocates a new string from either UTF-8 encoded or ASCII data.
* 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_DEPRECATED(
+ "Use NewFromOneByte instead",
+ 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_DEPRECATED(
+ "Use NewFromTwoByte instead",
+ 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_DEPRECATED(
+ "Use NewFromUtf8 instead",
+ V8_INLINE static Local<String> NewSymbol(
+ const char* data, int length = -1));
enum NewStringType {
kNormalString, kInternalizedString, kUndetectableString
@@ -2322,7 +2285,7 @@
* Call an Object as a function if a callback is set by the
* ObjectTemplate::SetCallAsFunctionHandler method.
*/
- Local<Value> CallAsFunction(Handle<Object> recv,
+ Local<Value> CallAsFunction(Handle<Value> recv,
int argc,
Handle<Value> argv[]);
@@ -2495,7 +2458,7 @@
Local<Object> NewInstance() const;
Local<Object> NewInstance(int argc, Handle<Value> argv[]) const;
- Local<Value> Call(Handle<Object> recv, int argc, Handle<Value> argv[]);
+ Local<Value> Call(Handle<Value> recv, int argc, Handle<Value> argv[]);
void SetName(Handle<String> name);
Handle<Value> GetName() const;
@@ -2685,10 +2648,6 @@
* Size of a view in bytes.
*/
size_t ByteLength();
- /**
- * Base address of a view.
- */
- void* BaseAddress();
V8_INLINE static ArrayBufferView* Cast(Value* obj);
@@ -4590,11 +4549,6 @@
ReturnAddressLocationResolver return_address_resolver);
/**
- * Deprecated, use the variant with the Isolate parameter below instead.
- */
- V8_DEPRECATED(static bool SetFunctionEntryHook(FunctionEntryHook entry_hook));
-
- /**
* Allows the host application to provide the address of a function that's
* invoked on entry to every V8-generated function.
* Note that \p entry_hook is invoked at the very start of each
@@ -4691,9 +4645,6 @@
*/
static bool Dispose();
- /** Deprecated. Use Isolate::GetHeapStatistics instead. */
- V8_DEPRECATED(static void GetHeapStatistics(HeapStatistics* heap_statistics));
-
/**
* Iterates through all external resources referenced from current isolate
* heap. GC is not invoked prior to iterating, therefore there is no
@@ -4991,17 +4942,14 @@
Handle<ObjectTemplate> global_template = Handle<ObjectTemplate>(),
Handle<Value> global_object = Handle<Value>());
- // TODO(dcarney): Remove this function.
- /** Deprecated. Use Isolate::GetEnteredContext */
- static Local<Context> GetEntered();
+ V8_DEPRECATED("Use Isolate::GetEnteredContext instead",
+ static Local<Context> GetEntered());
- // TODO(dcarney) Remove this function.
- /** Deprecated. Use Isolate::GetCurrentContext instead. */
- static Local<Context> GetCurrent();
+ V8_DEPRECATED("Use Isolate::GetCurrentContext instead",
+ static Local<Context> GetCurrent());
- // TODO(dcarney) Remove this function.
- /** Deprecated. Use Isolate::GetCallingContext instead. */
- static Local<Context> GetCalling();
+ V8_DEPRECATED("Use Isolate::GetCallingContext instead",
+ static Local<Context> GetCalling());
/**
* Sets the security token for the context. To access an object in
@@ -5210,9 +5158,6 @@
*/
V8_INLINE explicit Unlocker(Isolate* isolate) { Initialize(isolate); }
- /** Deprecated. Use Isolate version instead. */
- V8_DEPRECATED(Unlocker());
-
~Unlocker();
private:
void Initialize(Isolate* isolate);
@@ -5228,9 +5173,6 @@
*/
V8_INLINE explicit Locker(Isolate* isolate) { Initialize(isolate); }
- /** Deprecated. Use Isolate version instead. */
- V8_DEPRECATED(Locker());
-
~Locker();
/**
@@ -5240,12 +5182,12 @@
* that will switch between multiple threads that are in contention
* for the V8 lock.
*/
- static void StartPreemption(int every_n_ms);
+ static void StartPreemption(Isolate* isolate, int every_n_ms);
/**
* Stop preemption.
*/
- static void StopPreemption();
+ static void StopPreemption(Isolate* isolate);
/**
* Returns whether or not the locker for a given isolate, is locked by the
diff --git a/include/v8config.h b/include/v8config.h
index 6fe5c5a..834f9c5 100644
--- a/include/v8config.h
+++ b/include/v8config.h
@@ -245,6 +245,7 @@
// older compilers.
# define V8_HAS_ATTRIBUTE_ALWAYS_INLINE (V8_GNUC_PREREQ(4, 4, 0))
# define V8_HAS_ATTRIBUTE_DEPRECATED (V8_GNUC_PREREQ(3, 4, 0))
+# define V8_HAS_ATTRIBUTE_DEPRECATED_MESSAGE (V8_GNUC_PREREQ(4, 5, 0))
# define V8_HAS_ATTRIBUTE_NOINLINE (V8_GNUC_PREREQ(3, 4, 0))
# define V8_HAS_ATTRIBUTE_VISIBILITY (V8_GNUC_PREREQ(4, 3, 0))
# define V8_HAS_ATTRIBUTE_WARN_UNUSED_RESULT \
@@ -320,12 +321,16 @@
// A macro to mark classes or functions as deprecated.
-#if !V8_DISABLE_DEPRECATIONS && V8_HAS_ATTRIBUTE_DEPRECATED
-# define V8_DEPRECATED(declarator) declarator __attribute__((deprecated))
-#elif !V8_DISABLE_DEPRECATIONS && V8_HAS_DECLSPEC_DEPRECATED
-# define V8_DEPRECATED(declarator) __declspec(deprecated) declarator
+#if defined(V8_DEPRECATION_WARNINGS) && V8_HAS_ATTRIBUTE_DEPRECATED_MESSAGE
+# define V8_DEPRECATED(message, declarator) \
+declarator __attribute__((deprecated(message)))
+#elif defined(V8_DEPRECATION_WARNINGS) && V8_HAS_ATTRIBUTE_DEPRECATED
+# define V8_DEPRECATED(message, declarator) \
+declarator __attribute__((deprecated))
+#elif defined(V8_DEPRECATION_WARNINGS) && V8_HAS_DECLSPEC_DEPRECATED
+# define V8_DEPRECATED(message, declarator) __declspec(deprecated) declarator
#else
-# define V8_DEPRECATED(declarator) declarator
+# define V8_DEPRECATED(message, declarator) declarator
#endif
diff --git a/src/api.cc b/src/api.cc
index 6d62749..f5daba4 100644
--- a/src/api.cc
+++ b/src/api.cc
@@ -3936,7 +3936,7 @@
}
-Local<v8::Value> Object::CallAsFunction(v8::Handle<v8::Object> recv,
+Local<v8::Value> Object::CallAsFunction(v8::Handle<v8::Value> recv,
int argc,
v8::Handle<v8::Value> argv[]) {
i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
@@ -3964,7 +3964,7 @@
}
EXCEPTION_PREAMBLE(isolate);
i::Handle<i::Object> returned = i::Execution::Call(
- isolate, fun, recv_obj, argc, args, &has_pending_exception);
+ isolate, fun, recv_obj, argc, args, &has_pending_exception, true);
EXCEPTION_BAILOUT_CHECK_DO_CALLBACK(isolate, Local<Value>());
return Utils::ToLocal(scope.CloseAndEscape(returned));
}
@@ -4048,7 +4048,7 @@
}
-Local<v8::Value> Function::Call(v8::Handle<v8::Object> recv, int argc,
+Local<v8::Value> Function::Call(v8::Handle<v8::Value> recv, int argc,
v8::Handle<v8::Value> argv[]) {
i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
ON_BAILOUT(isolate, "v8::Function::Call()", return Local<v8::Value>());
@@ -4065,7 +4065,7 @@
i::Handle<i::Object>* args = reinterpret_cast<i::Handle<i::Object>*>(argv);
EXCEPTION_PREAMBLE(isolate);
i::Handle<i::Object> returned = i::Execution::Call(
- isolate, fun, recv_obj, argc, args, &has_pending_exception);
+ isolate, fun, recv_obj, argc, args, &has_pending_exception, true);
EXCEPTION_BAILOUT_CHECK_DO_CALLBACK(isolate, Local<Object>());
raw_result = *returned;
}
@@ -4709,39 +4709,6 @@
}
-int String::WriteAscii(char* buffer,
- int start,
- int length,
- int options) const {
- i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
- LOG_API(isolate, "String::WriteAscii");
- ENTER_V8(isolate);
- ASSERT(start >= 0 && length >= -1);
- i::Handle<i::String> str = Utils::OpenHandle(this);
- isolate->string_tracker()->RecordWrite(str);
- if (options & HINT_MANY_WRITES_EXPECTED) {
- FlattenString(str); // Flatten the string for efficiency.
- }
-
- int end = length;
- if ((length == -1) || (length > str->length() - start)) {
- end = str->length() - start;
- }
- if (end < 0) return 0;
- i::StringCharacterStream write_stream(*str, isolate->write_iterator(), start);
- int i;
- for (i = 0; i < end; i++) {
- char c = static_cast<char>(write_stream.GetNext());
- if (c == '\0' && !(options & PRESERVE_ASCII_NULL)) c = ' ';
- buffer[i] = c;
- }
- if (!(options & NO_NULL_TERMINATION) && (length == -1 || i < length)) {
- buffer[i] = '\0';
- }
- return i;
-}
-
-
template<typename CharType>
static inline int WriteHelper(const String* string,
CharType* buffer,
@@ -4983,11 +4950,6 @@
}
-bool v8::V8::SetFunctionEntryHook(FunctionEntryHook entry_hook) {
- return SetFunctionEntryHook(Isolate::GetCurrent(), entry_hook);
-}
-
-
bool v8::V8::SetFunctionEntryHook(Isolate* ext_isolate,
FunctionEntryHook entry_hook) {
ASSERT(ext_isolate != NULL);
@@ -5048,22 +5010,6 @@
heap_size_limit_(0) { }
-void v8::V8::GetHeapStatistics(HeapStatistics* heap_statistics) {
- i::Isolate* isolate = i::Isolate::UncheckedCurrent();
- if (isolate == NULL || !isolate->IsInitialized()) {
- // Isolate is unitialized thus heap is not configured yet.
- heap_statistics->total_heap_size_ = 0;
- heap_statistics->total_heap_size_executable_ = 0;
- heap_statistics->total_physical_size_ = 0;
- heap_statistics->used_heap_size_ = 0;
- heap_statistics->heap_size_limit_ = 0;
- return;
- }
- Isolate* ext_isolate = reinterpret_cast<Isolate*>(isolate);
- return ext_isolate->GetHeapStatistics(heap_statistics);
-}
-
-
void v8::V8::VisitExternalResources(ExternalResourceVisitor* visitor) {
i::Isolate* isolate = i::Isolate::Current();
isolate->heap()->VisitExternalResources(visitor);
@@ -6022,15 +5968,6 @@
}
-void* v8::ArrayBufferView::BaseAddress() {
- i::Handle<i::JSArrayBufferView> obj = Utils::OpenHandle(this);
- i::Handle<i::JSArrayBuffer> buffer(i::JSArrayBuffer::cast(obj->buffer()));
- void* buffer_data = buffer->backing_store();
- size_t byte_offset = static_cast<size_t>(obj->byte_offset()->Number());
- return static_cast<uint8_t*>(buffer_data) + byte_offset;
-}
-
-
size_t v8::TypedArray::Length() {
i::Handle<i::JSTypedArray> obj = Utils::OpenHandle(this);
return static_cast<size_t>(obj->length()->Number());
@@ -6976,11 +6913,6 @@
}
-double CpuProfileNode::GetSelfSamplesCount() const {
- return reinterpret_cast<const i::ProfileNode*>(this)->self_ticks();
-}
-
-
unsigned CpuProfileNode::GetHitCount() const {
return reinterpret_cast<const i::ProfileNode*>(this)->self_ticks();
}
@@ -7534,7 +7466,7 @@
isolate_->UnlinkDeferredHandles(this);
for (int i = 0; i < blocks_.length(); i++) {
-#ifdef ENABLE_EXTRA_CHECKS
+#ifdef ENABLE_HANDLE_ZAPPING
HandleScope::ZapRange(blocks_[i], &blocks_[i][kHandleBlockSize]);
#endif
isolate_->handle_scope_implementer()->ReturnBlock(blocks_[i]);
diff --git a/src/api.h b/src/api.h
index 8fb17a0..9197baf 100644
--- a/src/api.h
+++ b/src/api.h
@@ -667,7 +667,7 @@
#ifdef DEBUG
// SealHandleScope may make the prev_limit to point inside the block.
if (block_start <= prev_limit && prev_limit <= block_limit) {
-#ifdef ENABLE_EXTRA_CHECKS
+#ifdef ENABLE_HANDLE_ZAPPING
internal::HandleScope::ZapRange(prev_limit, block_limit);
#endif
break;
@@ -677,7 +677,7 @@
#endif
blocks_.RemoveLast();
-#ifdef ENABLE_EXTRA_CHECKS
+#ifdef ENABLE_HANDLE_ZAPPING
internal::HandleScope::ZapRange(block_start, block_limit);
#endif
if (spare_ != NULL) {
diff --git a/src/arm/assembler-arm.h b/src/arm/assembler-arm.h
index d7b8f02..47dda2a 100644
--- a/src/arm/assembler-arm.h
+++ b/src/arm/assembler-arm.h
@@ -115,22 +115,47 @@
// mode. This way we get the compile-time error checking in debug mode
// and best performance in optimized code.
+// These constants are used in several locations, including static initializers
+const int kRegister_no_reg_Code = -1;
+const int kRegister_r0_Code = 0;
+const int kRegister_r1_Code = 1;
+const int kRegister_r2_Code = 2;
+const int kRegister_r3_Code = 3;
+const int kRegister_r4_Code = 4;
+const int kRegister_r5_Code = 5;
+const int kRegister_r6_Code = 6;
+const int kRegister_r7_Code = 7;
+const int kRegister_r8_Code = 8;
+const int kRegister_r9_Code = 9;
+const int kRegister_r10_Code = 10;
+const int kRegister_fp_Code = 11;
+const int kRegister_ip_Code = 12;
+const int kRegister_sp_Code = 13;
+const int kRegister_lr_Code = 14;
+const int kRegister_pc_Code = 15;
+
// Core register
struct Register {
static const int kNumRegisters = 16;
static const int kMaxNumAllocatableRegisters =
- FLAG_enable_ool_constant_pool ? 7 : 8;
+ FLAG_enable_ool_constant_pool ? 8 : 9;
static const int kSizeInBytes = 4;
inline static int NumAllocatableRegisters();
static int ToAllocationIndex(Register reg) {
+ if (FLAG_enable_ool_constant_pool && (reg.code() >= kRegister_r8_Code)) {
+ return reg.code() - 1;
+ }
ASSERT(reg.code() < kMaxNumAllocatableRegisters);
return reg.code();
}
static Register FromAllocationIndex(int index) {
ASSERT(index >= 0 && index < kMaxNumAllocatableRegisters);
+ if (FLAG_enable_ool_constant_pool && (index >= 7)) {
+ return from_code(index + 1);
+ }
return from_code(index);
}
@@ -145,7 +170,11 @@
"r5",
"r6",
"r7",
+ "r8",
};
+ if (FLAG_enable_ool_constant_pool && (index >= 7)) {
+ return names[index + 1];
+ }
return names[index];
}
@@ -174,25 +203,6 @@
int code_;
};
-// These constants are used in several locations, including static initializers
-const int kRegister_no_reg_Code = -1;
-const int kRegister_r0_Code = 0;
-const int kRegister_r1_Code = 1;
-const int kRegister_r2_Code = 2;
-const int kRegister_r3_Code = 3;
-const int kRegister_r4_Code = 4;
-const int kRegister_r5_Code = 5;
-const int kRegister_r6_Code = 6;
-const int kRegister_r7_Code = 7;
-const int kRegister_r8_Code = 8;
-const int kRegister_r9_Code = 9;
-const int kRegister_r10_Code = 10;
-const int kRegister_fp_Code = 11;
-const int kRegister_ip_Code = 12;
-const int kRegister_sp_Code = 13;
-const int kRegister_lr_Code = 14;
-const int kRegister_pc_Code = 15;
-
const Register no_reg = { kRegister_no_reg_Code };
const Register r0 = { kRegister_r0_Code };
@@ -202,7 +212,7 @@
const Register r4 = { kRegister_r4_Code };
const Register r5 = { kRegister_r5_Code };
const Register r6 = { kRegister_r6_Code };
-// Used as constant pool pointer register if FLAGS_enable_ool_constant_pool.
+// Used as constant pool pointer register if FLAG_enable_ool_constant_pool.
const Register r7 = { kRegister_r7_Code };
// Used as context register.
const Register r8 = { kRegister_r8_Code };
diff --git a/src/arm/lithium-arm.cc b/src/arm/lithium-arm.cc
index 6fdbbb5..0ea235c 100644
--- a/src/arm/lithium-arm.cc
+++ b/src/arm/lithium-arm.cc
@@ -412,18 +412,19 @@
}
-int LPlatformChunk::GetNextSpillIndex(bool is_double) {
+int LPlatformChunk::GetNextSpillIndex(RegisterKind kind) {
// Skip a slot if for a double-width slot.
- if (is_double) spill_slot_count_++;
+ if (kind == DOUBLE_REGISTERS) spill_slot_count_++;
return spill_slot_count_++;
}
-LOperand* LPlatformChunk::GetNextSpillSlot(bool is_double) {
- int index = GetNextSpillIndex(is_double);
- if (is_double) {
+LOperand* LPlatformChunk::GetNextSpillSlot(RegisterKind kind) {
+ int index = GetNextSpillIndex(kind);
+ if (kind == DOUBLE_REGISTERS) {
return LDoubleStackSlot::Create(index, zone());
} else {
+ ASSERT(kind == GENERAL_REGISTERS);
return LStackSlot::Create(index, zone());
}
}
@@ -439,7 +440,7 @@
// which will be subsumed into this frame.
if (graph()->has_osr()) {
for (int i = graph()->osr()->UnoptimizedFrameSlots(); i > 0; i--) {
- chunk_->GetNextSpillIndex(false);
+ chunk_->GetNextSpillIndex(GENERAL_REGISTERS);
}
}
@@ -779,10 +780,11 @@
HValue* right = instr->right();
ASSERT(left->representation().IsTagged());
ASSERT(right->representation().IsTagged());
+ LOperand* context = UseFixed(instr->context(), cp);
LOperand* left_operand = UseFixed(left, r1);
LOperand* right_operand = UseFixed(right, r0);
LArithmeticT* result =
- new(zone()) LArithmeticT(op, left_operand, right_operand);
+ new(zone()) LArithmeticT(op, context, left_operand, right_operand);
return MarkAsCall(DefineFixed(result, r0), instr);
}
@@ -1044,9 +1046,10 @@
LInstruction* LChunkBuilder::DoInstanceOf(HInstanceOf* instr) {
+ LOperand* context = UseFixed(instr->context(), cp);
LInstanceOf* result =
- new(zone()) LInstanceOf(UseFixed(instr->left(), r0),
- UseFixed(instr->right(), r1));
+ new(zone()) LInstanceOf(context, UseFixed(instr->left(), r0),
+ UseFixed(instr->right(), r1));
return MarkAsCall(DefineFixed(result, r0), instr);
}
@@ -1054,8 +1057,10 @@
LInstruction* LChunkBuilder::DoInstanceOfKnownGlobal(
HInstanceOfKnownGlobal* instr) {
LInstanceOfKnownGlobal* result =
- new(zone()) LInstanceOfKnownGlobal(UseFixed(instr->left(), r0),
- FixedTemp(r4));
+ new(zone()) LInstanceOfKnownGlobal(
+ UseFixed(instr->context(), cp),
+ UseFixed(instr->left(), r0),
+ FixedTemp(r4));
return MarkAsCall(DefineFixed(result, r0), instr);
}
@@ -1119,14 +1124,13 @@
LInstruction* LChunkBuilder::DoContext(HContext* instr) {
- // If there is a non-return use, the context must be allocated in a register.
- for (HUseIterator it(instr->uses()); !it.Done(); it.Advance()) {
- if (!it.value()->IsReturn()) {
- return DefineAsRegister(new(zone()) LContext);
- }
+ if (instr->HasNoUses()) return NULL;
+
+ if (info()->IsStub()) {
+ return DefineFixed(new(zone()) LContext, cp);
}
- return NULL;
+ return DefineAsRegister(new(zone()) LContext);
}
@@ -1137,7 +1141,8 @@
LInstruction* LChunkBuilder::DoDeclareGlobals(HDeclareGlobals* instr) {
- return MarkAsCall(new(zone()) LDeclareGlobals, instr);
+ LOperand* context = UseFixed(instr->context(), cp);
+ return MarkAsCall(new(zone()) LDeclareGlobals(context), instr);
}
@@ -1161,9 +1166,10 @@
LInstruction* LChunkBuilder::DoInvokeFunction(HInvokeFunction* instr) {
+ LOperand* context = UseFixed(instr->context(), cp);
LOperand* function = UseFixed(instr->function(), r1);
argument_count_ -= instr->argument_count();
- LInvokeFunction* result = new(zone()) LInvokeFunction(function);
+ LInvokeFunction* result = new(zone()) LInvokeFunction(context, function);
return MarkAsCall(DefineFixed(result, r0), instr, CANNOT_DEOPTIMIZE_EAGERLY);
}
@@ -1203,8 +1209,12 @@
LInstruction* LChunkBuilder::DoMathAbs(HUnaryMathOperation* instr) {
+ Representation r = instr->value()->representation();
+ LOperand* context = (r.IsDouble() || r.IsSmiOrInteger32())
+ ? NULL
+ : UseFixed(instr->context(), cp);
LOperand* input = UseRegister(instr->value());
- LMathAbs* result = new(zone()) LMathAbs(input);
+ LMathAbs* result = new(zone()) LMathAbs(context, input);
return AssignEnvironment(AssignPointerMap(DefineAsRegister(result)));
}
@@ -1266,21 +1276,25 @@
LInstruction* LChunkBuilder::DoCallKeyed(HCallKeyed* instr) {
ASSERT(instr->key()->representation().IsTagged());
+ LOperand* context = UseFixed(instr->context(), cp);
argument_count_ -= instr->argument_count();
LOperand* key = UseFixed(instr->key(), r2);
- return MarkAsCall(DefineFixed(new(zone()) LCallKeyed(key), r0), instr);
+ return MarkAsCall(
+ DefineFixed(new(zone()) LCallKeyed(context, key), r0), instr);
}
LInstruction* LChunkBuilder::DoCallNamed(HCallNamed* instr) {
+ LOperand* context = UseFixed(instr->context(), cp);
argument_count_ -= instr->argument_count();
- return MarkAsCall(DefineFixed(new(zone()) LCallNamed, r0), instr);
+ return MarkAsCall(DefineFixed(new(zone()) LCallNamed(context), r0), instr);
}
LInstruction* LChunkBuilder::DoCallGlobal(HCallGlobal* instr) {
+ LOperand* context = UseFixed(instr->context(), cp);
argument_count_ -= instr->argument_count();
- return MarkAsCall(DefineFixed(new(zone()) LCallGlobal, r0), instr);
+ return MarkAsCall(DefineFixed(new(zone()) LCallGlobal(context), r0), instr);
}
@@ -1291,32 +1305,36 @@
LInstruction* LChunkBuilder::DoCallNew(HCallNew* instr) {
+ LOperand* context = UseFixed(instr->context(), cp);
LOperand* constructor = UseFixed(instr->constructor(), r1);
argument_count_ -= instr->argument_count();
- LCallNew* result = new(zone()) LCallNew(constructor);
+ LCallNew* result = new(zone()) LCallNew(context, constructor);
return MarkAsCall(DefineFixed(result, r0), instr);
}
LInstruction* LChunkBuilder::DoCallNewArray(HCallNewArray* instr) {
+ LOperand* context = UseFixed(instr->context(), cp);
LOperand* constructor = UseFixed(instr->constructor(), r1);
argument_count_ -= instr->argument_count();
- LCallNewArray* result = new(zone()) LCallNewArray(constructor);
+ LCallNewArray* result = new(zone()) LCallNewArray(context, constructor);
return MarkAsCall(DefineFixed(result, r0), instr);
}
LInstruction* LChunkBuilder::DoCallFunction(HCallFunction* instr) {
+ LOperand* context = UseFixed(instr->context(), cp);
LOperand* function = UseFixed(instr->function(), r1);
argument_count_ -= instr->argument_count();
- return MarkAsCall(DefineFixed(new(zone()) LCallFunction(function), r0),
- instr);
+ return MarkAsCall(
+ DefineFixed(new(zone()) LCallFunction(context, function), r0), instr);
}
LInstruction* LChunkBuilder::DoCallRuntime(HCallRuntime* instr) {
argument_count_ -= instr->argument_count();
- return MarkAsCall(DefineFixed(new(zone()) LCallRuntime, r0), instr);
+ LOperand* context = UseFixed(instr->context(), cp);
+ return MarkAsCall(DefineFixed(new(zone()) LCallRuntime(context), r0), instr);
}
@@ -1719,9 +1737,10 @@
LInstruction* LChunkBuilder::DoCompareGeneric(HCompareGeneric* instr) {
ASSERT(instr->left()->representation().IsTagged());
ASSERT(instr->right()->representation().IsTagged());
+ LOperand* context = UseFixed(instr->context(), cp);
LOperand* left = UseFixed(instr->left(), r1);
LOperand* right = UseFixed(instr->right(), r0);
- LCmpT* result = new(zone()) LCmpT(left, right);
+ LCmpT* result = new(zone()) LCmpT(context, left, right);
return MarkAsCall(DefineFixed(result, r0), instr);
}
@@ -1795,10 +1814,11 @@
HStringCompareAndBranch* instr) {
ASSERT(instr->left()->representation().IsTagged());
ASSERT(instr->right()->representation().IsTagged());
+ LOperand* context = UseFixed(instr->context(), cp);
LOperand* left = UseFixed(instr->left(), r1);
LOperand* right = UseFixed(instr->right(), r0);
LStringCompareAndBranch* result =
- new(zone()) LStringCompareAndBranch(left, right);
+ new(zone()) LStringCompareAndBranch(context, left, right);
return MarkAsCall(result, instr);
}
@@ -1885,9 +1905,17 @@
}
+LInstruction* LChunkBuilder::DoAbnormalExit(HAbnormalExit* instr) {
+ // The control instruction marking the end of a block that completed
+ // abruptly (e.g., threw an exception). There is nothing specific to do.
+ return NULL;
+}
+
+
LInstruction* LChunkBuilder::DoThrow(HThrow* instr) {
+ LOperand* context = UseFixed(instr->context(), cp);
LOperand* value = UseFixed(instr->value(), r0);
- return MarkAsCall(new(zone()) LThrow(value), instr);
+ return MarkAsCall(new(zone()) LThrow(context, value), instr);
}
@@ -2067,8 +2095,11 @@
LInstruction* LChunkBuilder::DoReturn(HReturn* instr) {
+ LOperand* context = info()->IsStub()
+ ? UseFixed(instr->context(), cp)
+ : NULL;
LOperand* parameter_count = UseRegisterOrConstant(instr->parameter_count());
- return new(zone()) LReturn(UseFixed(instr->value(), r0),
+ return new(zone()) LReturn(UseFixed(instr->value(), r0), context,
parameter_count);
}
@@ -2101,8 +2132,10 @@
LInstruction* LChunkBuilder::DoLoadGlobalGeneric(HLoadGlobalGeneric* instr) {
+ LOperand* context = UseFixed(instr->context(), cp);
LOperand* global_object = UseFixed(instr->global_object(), r0);
- LLoadGlobalGeneric* result = new(zone()) LLoadGlobalGeneric(global_object);
+ LLoadGlobalGeneric* result =
+ new(zone()) LLoadGlobalGeneric(context, global_object);
return MarkAsCall(DefineFixed(result, r0), instr);
}
@@ -2118,10 +2151,11 @@
LInstruction* LChunkBuilder::DoStoreGlobalGeneric(HStoreGlobalGeneric* instr) {
+ LOperand* context = UseFixed(instr->context(), cp);
LOperand* global_object = UseFixed(instr->global_object(), r1);
LOperand* value = UseFixed(instr->value(), r0);
LStoreGlobalGeneric* result =
- new(zone()) LStoreGlobalGeneric(global_object, value);
+ new(zone()) LStoreGlobalGeneric(context, global_object, value);
return MarkAsCall(result, instr);
}
@@ -2156,8 +2190,10 @@
LInstruction* LChunkBuilder::DoLoadNamedGeneric(HLoadNamedGeneric* instr) {
+ LOperand* context = UseFixed(instr->context(), cp);
LOperand* object = UseFixed(instr->object(), r0);
- LInstruction* result = DefineFixed(new(zone()) LLoadNamedGeneric(object), r0);
+ LInstruction* result =
+ DefineFixed(new(zone()) LLoadNamedGeneric(context, object), r0);
return MarkAsCall(result, instr);
}
@@ -2218,11 +2254,12 @@
LInstruction* LChunkBuilder::DoLoadKeyedGeneric(HLoadKeyedGeneric* instr) {
+ LOperand* context = UseFixed(instr->context(), cp);
LOperand* object = UseFixed(instr->object(), r1);
LOperand* key = UseFixed(instr->key(), r0);
LInstruction* result =
- DefineFixed(new(zone()) LLoadKeyedGeneric(object, key), r0);
+ DefineFixed(new(zone()) LLoadKeyedGeneric(context, object, key), r0);
return MarkAsCall(result, instr);
}
@@ -2271,6 +2308,7 @@
LInstruction* LChunkBuilder::DoStoreKeyedGeneric(HStoreKeyedGeneric* instr) {
+ LOperand* context = UseFixed(instr->context(), cp);
LOperand* obj = UseFixed(instr->object(), r2);
LOperand* key = UseFixed(instr->key(), r1);
LOperand* val = UseFixed(instr->value(), r0);
@@ -2279,7 +2317,8 @@
ASSERT(instr->key()->representation().IsTagged());
ASSERT(instr->value()->representation().IsTagged());
- return MarkAsCall(new(zone()) LStoreKeyedGeneric(obj, key, val), instr);
+ return MarkAsCall(
+ new(zone()) LStoreKeyedGeneric(context, obj, key, val), instr);
}
@@ -2289,11 +2328,12 @@
if (IsSimpleMapChangeTransition(instr->from_kind(), instr->to_kind())) {
LOperand* new_map_reg = TempRegister();
LTransitionElementsKind* result =
- new(zone()) LTransitionElementsKind(object, new_map_reg);
+ new(zone()) LTransitionElementsKind(object, NULL, new_map_reg);
return result;
} else {
+ LOperand* context = UseFixed(instr->context(), cp);
LTransitionElementsKind* result =
- new(zone()) LTransitionElementsKind(object, NULL);
+ new(zone()) LTransitionElementsKind(object, context, NULL);
return AssignPointerMap(result);
}
}
@@ -2352,56 +2392,68 @@
LInstruction* LChunkBuilder::DoStoreNamedGeneric(HStoreNamedGeneric* instr) {
+ LOperand* context = UseFixed(instr->context(), cp);
LOperand* obj = UseFixed(instr->object(), r1);
LOperand* val = UseFixed(instr->value(), r0);
- LInstruction* result = new(zone()) LStoreNamedGeneric(obj, val);
+ LInstruction* result = new(zone()) LStoreNamedGeneric(context, obj, val);
return MarkAsCall(result, instr);
}
LInstruction* LChunkBuilder::DoStringAdd(HStringAdd* instr) {
+ LOperand* context = UseFixed(instr->context(), cp);
LOperand* left = UseRegisterAtStart(instr->left());
LOperand* right = UseRegisterAtStart(instr->right());
- return MarkAsCall(DefineFixed(new(zone()) LStringAdd(left, right), r0),
- instr);
+ return MarkAsCall(
+ DefineFixed(new(zone()) LStringAdd(context, left, right), r0),
+ instr);
}
LInstruction* LChunkBuilder::DoStringCharCodeAt(HStringCharCodeAt* instr) {
LOperand* string = UseTempRegister(instr->string());
LOperand* index = UseTempRegister(instr->index());
- LStringCharCodeAt* result = new(zone()) LStringCharCodeAt(string, index);
+ LOperand* context = UseAny(instr->context());
+ LStringCharCodeAt* result =
+ new(zone()) LStringCharCodeAt(context, string, index);
return AssignEnvironment(AssignPointerMap(DefineAsRegister(result)));
}
LInstruction* LChunkBuilder::DoStringCharFromCode(HStringCharFromCode* instr) {
LOperand* char_code = UseRegister(instr->value());
- LStringCharFromCode* result = new(zone()) LStringCharFromCode(char_code);
+ LOperand* context = UseAny(instr->context());
+ LStringCharFromCode* result =
+ new(zone()) LStringCharFromCode(context, char_code);
return AssignPointerMap(DefineAsRegister(result));
}
LInstruction* LChunkBuilder::DoAllocate(HAllocate* instr) {
info()->MarkAsDeferredCalling();
+ LOperand* context = UseAny(instr->context());
LOperand* size = instr->size()->IsConstant()
? UseConstant(instr->size())
: UseTempRegister(instr->size());
LOperand* temp1 = TempRegister();
LOperand* temp2 = TempRegister();
- LAllocate* result = new(zone()) LAllocate(size, temp1, temp2);
+ LAllocate* result = new(zone()) LAllocate(context, size, temp1, temp2);
return AssignPointerMap(DefineAsRegister(result));
}
LInstruction* LChunkBuilder::DoRegExpLiteral(HRegExpLiteral* instr) {
- return MarkAsCall(DefineFixed(new(zone()) LRegExpLiteral, r0), instr);
+ LOperand* context = UseFixed(instr->context(), cp);
+ return MarkAsCall(
+ DefineFixed(new(zone()) LRegExpLiteral(context), r0), instr);
}
LInstruction* LChunkBuilder::DoFunctionLiteral(HFunctionLiteral* instr) {
- return MarkAsCall(DefineFixed(new(zone()) LFunctionLiteral, r0), instr);
+ LOperand* context = UseFixed(instr->context(), cp);
+ return MarkAsCall(
+ DefineFixed(new(zone()) LFunctionLiteral(context), r0), instr);
}
@@ -2448,8 +2500,9 @@
LInstruction* LChunkBuilder::DoCallStub(HCallStub* instr) {
+ LOperand* context = UseFixed(instr->context(), cp);
argument_count_ -= instr->argument_count();
- return MarkAsCall(DefineFixed(new(zone()) LCallStub, r0), instr);
+ return MarkAsCall(DefineFixed(new(zone()) LCallStub(context), r0), instr);
}
@@ -2494,7 +2547,8 @@
LInstruction* LChunkBuilder::DoTypeof(HTypeof* instr) {
- LTypeof* result = new(zone()) LTypeof(UseFixed(instr->value(), r0));
+ LOperand* context = UseFixed(instr->context(), cp);
+ LTypeof* result = new(zone()) LTypeof(context, UseFixed(instr->value(), r0));
return MarkAsCall(DefineFixed(result, r0), instr);
}
@@ -2533,10 +2587,13 @@
LInstruction* LChunkBuilder::DoStackCheck(HStackCheck* instr) {
if (instr->is_function_entry()) {
- return MarkAsCall(new(zone()) LStackCheck, instr);
+ LOperand* context = UseFixed(instr->context(), cp);
+ return MarkAsCall(new(zone()) LStackCheck(context), instr);
} else {
ASSERT(instr->is_backwards_branch());
- return AssignEnvironment(AssignPointerMap(new(zone()) LStackCheck));
+ LOperand* context = UseAny(instr->context());
+ return AssignEnvironment(
+ AssignPointerMap(new(zone()) LStackCheck(context)));
}
}
@@ -2581,8 +2638,9 @@
LInstruction* LChunkBuilder::DoForInPrepareMap(HForInPrepareMap* instr) {
+ LOperand* context = UseFixed(instr->context(), cp);
LOperand* object = UseFixed(instr->enumerable(), r0);
- LForInPrepareMap* result = new(zone()) LForInPrepareMap(object);
+ LForInPrepareMap* result = new(zone()) LForInPrepareMap(context, object);
return MarkAsCall(DefineFixed(result, r0), instr, CAN_DEOPTIMIZE_EAGERLY);
}
diff --git a/src/arm/lithium-arm.h b/src/arm/lithium-arm.h
index 76867c8..e82c7c2 100644
--- a/src/arm/lithium-arm.h
+++ b/src/arm/lithium-arm.h
@@ -483,8 +483,14 @@
};
-class LCallStub V8_FINAL : public LTemplateInstruction<1, 0, 0> {
+class LCallStub V8_FINAL : public LTemplateInstruction<1, 1, 0> {
public:
+ explicit LCallStub(LOperand* context) {
+ inputs_[0] = context;
+ }
+
+ LOperand* context() { return inputs_[0]; }
+
DECLARE_CONCRETE_INSTRUCTION(CallStub, "call-stub")
DECLARE_HYDROGEN_ACCESSOR(CallStub)
@@ -785,12 +791,14 @@
};
-class LMathAbs V8_FINAL : public LTemplateInstruction<1, 1, 0> {
+class LMathAbs V8_FINAL : public LTemplateInstruction<1, 2, 0> {
public:
- explicit LMathAbs(LOperand* value) {
+ LMathAbs(LOperand* context, LOperand* value) {
+ inputs_[1] = context;
inputs_[0] = value;
}
+ LOperand* context() { return inputs_[1]; }
LOperand* value() { return inputs_[0]; }
DECLARE_CONCRETE_INSTRUCTION(MathAbs, "math-abs")
@@ -989,15 +997,17 @@
};
-class LStringCompareAndBranch V8_FINAL : public LControlInstruction<2, 0> {
+class LStringCompareAndBranch V8_FINAL : public LControlInstruction<3, 0> {
public:
- LStringCompareAndBranch(LOperand* left, LOperand* right) {
- inputs_[0] = left;
- inputs_[1] = right;
+ LStringCompareAndBranch(LOperand* context, LOperand* left, LOperand* right) {
+ inputs_[0] = context;
+ inputs_[1] = left;
+ inputs_[2] = right;
}
- LOperand* left() { return inputs_[0]; }
- LOperand* right() { return inputs_[1]; }
+ LOperand* context() { return inputs_[0]; }
+ LOperand* left() { return inputs_[1]; }
+ LOperand* right() { return inputs_[2]; }
DECLARE_CONCRETE_INSTRUCTION(StringCompareAndBranch,
"string-compare-and-branch")
@@ -1073,15 +1083,17 @@
};
-class LCmpT V8_FINAL : public LTemplateInstruction<1, 2, 0> {
+class LCmpT V8_FINAL : public LTemplateInstruction<1, 3, 0> {
public:
- LCmpT(LOperand* left, LOperand* right) {
- inputs_[0] = left;
- inputs_[1] = right;
+ LCmpT(LOperand* context, LOperand* left, LOperand* right) {
+ inputs_[0] = context;
+ inputs_[1] = left;
+ inputs_[2] = right;
}
- LOperand* left() { return inputs_[0]; }
- LOperand* right() { return inputs_[1]; }
+ LOperand* context() { return inputs_[0]; }
+ LOperand* left() { return inputs_[1]; }
+ LOperand* right() { return inputs_[2]; }
DECLARE_CONCRETE_INSTRUCTION(CmpT, "cmp-t")
DECLARE_HYDROGEN_ACCESSOR(CompareGeneric)
@@ -1090,28 +1102,32 @@
};
-class LInstanceOf V8_FINAL : public LTemplateInstruction<1, 2, 0> {
+class LInstanceOf V8_FINAL : public LTemplateInstruction<1, 3, 0> {
public:
- LInstanceOf(LOperand* left, LOperand* right) {
- inputs_[0] = left;
- inputs_[1] = right;
+ LInstanceOf(LOperand* context, LOperand* left, LOperand* right) {
+ inputs_[0] = context;
+ inputs_[1] = left;
+ inputs_[2] = right;
}
- LOperand* left() { return inputs_[0]; }
- LOperand* right() { return inputs_[1]; }
+ LOperand* context() { return inputs_[0]; }
+ LOperand* left() { return inputs_[1]; }
+ LOperand* right() { return inputs_[2]; }
DECLARE_CONCRETE_INSTRUCTION(InstanceOf, "instance-of")
};
-class LInstanceOfKnownGlobal V8_FINAL : public LTemplateInstruction<1, 1, 1> {
+class LInstanceOfKnownGlobal V8_FINAL : public LTemplateInstruction<1, 2, 1> {
public:
- LInstanceOfKnownGlobal(LOperand* value, LOperand* temp) {
- inputs_[0] = value;
+ LInstanceOfKnownGlobal(LOperand* context, LOperand* value, LOperand* temp) {
+ inputs_[0] = context;
+ inputs_[1] = value;
temps_[0] = temp;
}
- LOperand* value() { return inputs_[0]; }
+ LOperand* context() { return inputs_[0]; }
+ LOperand* value() { return inputs_[1]; }
LOperand* temp() { return temps_[0]; }
DECLARE_CONCRETE_INSTRUCTION(InstanceOfKnownGlobal,
@@ -1392,13 +1408,15 @@
};
-class LThrow V8_FINAL : public LTemplateInstruction<0, 1, 0> {
+class LThrow V8_FINAL : public LTemplateInstruction<0, 2, 0> {
public:
- explicit LThrow(LOperand* value) {
- inputs_[0] = value;
+ LThrow(LOperand* context, LOperand* value) {
+ inputs_[0] = context;
+ inputs_[1] = value;
}
- LOperand* value() { return inputs_[0]; }
+ LOperand* context() { return inputs_[0]; }
+ LOperand* value() { return inputs_[1]; }
DECLARE_CONCRETE_INSTRUCTION(Throw, "throw")
};
@@ -1494,16 +1512,21 @@
};
-class LArithmeticT V8_FINAL : public LTemplateInstruction<1, 2, 0> {
+class LArithmeticT V8_FINAL : public LTemplateInstruction<1, 3, 0> {
public:
- LArithmeticT(Token::Value op, LOperand* left, LOperand* right)
+ LArithmeticT(Token::Value op,
+ LOperand* context,
+ LOperand* left,
+ LOperand* right)
: op_(op) {
- inputs_[0] = left;
- inputs_[1] = right;
+ inputs_[0] = context;
+ inputs_[1] = left;
+ inputs_[2] = right;
}
- LOperand* left() { return inputs_[0]; }
- LOperand* right() { return inputs_[1]; }
+ LOperand* context() { return inputs_[0]; }
+ LOperand* left() { return inputs_[1]; }
+ LOperand* right() { return inputs_[2]; }
Token::Value op() const { return op_; }
virtual Opcode opcode() const V8_OVERRIDE {
@@ -1517,11 +1540,12 @@
};
-class LReturn V8_FINAL : public LTemplateInstruction<0, 2, 0> {
+class LReturn V8_FINAL : public LTemplateInstruction<0, 3, 0> {
public:
- explicit LReturn(LOperand* value, LOperand* parameter_count) {
+ LReturn(LOperand* value, LOperand* context, LOperand* parameter_count) {
inputs_[0] = value;
- inputs_[1] = parameter_count;
+ inputs_[1] = context;
+ inputs_[2] = parameter_count;
}
LOperand* value() { return inputs_[0]; }
@@ -1533,7 +1557,7 @@
ASSERT(has_constant_parameter_count());
return LConstantOperand::cast(parameter_count());
}
- LOperand* parameter_count() { return inputs_[1]; }
+ LOperand* parameter_count() { return inputs_[2]; }
DECLARE_CONCRETE_INSTRUCTION(Return, "return")
};
@@ -1552,13 +1576,15 @@
};
-class LLoadNamedGeneric V8_FINAL : public LTemplateInstruction<1, 1, 0> {
+class LLoadNamedGeneric V8_FINAL : public LTemplateInstruction<1, 2, 0> {
public:
- explicit LLoadNamedGeneric(LOperand* object) {
- inputs_[0] = object;
+ LLoadNamedGeneric(LOperand* context, LOperand* object) {
+ inputs_[0] = context;
+ inputs_[1] = object;
}
- LOperand* object() { return inputs_[0]; }
+ LOperand* context() { return inputs_[0]; }
+ LOperand* object() { return inputs_[1]; }
DECLARE_CONCRETE_INSTRUCTION(LoadNamedGeneric, "load-named-generic")
DECLARE_HYDROGEN_ACCESSOR(LoadNamedGeneric)
@@ -1627,15 +1653,17 @@
};
-class LLoadKeyedGeneric V8_FINAL : public LTemplateInstruction<1, 2, 0> {
+class LLoadKeyedGeneric V8_FINAL : public LTemplateInstruction<1, 3, 0> {
public:
- LLoadKeyedGeneric(LOperand* object, LOperand* key) {
- inputs_[0] = object;
- inputs_[1] = key;
+ LLoadKeyedGeneric(LOperand* context, LOperand* object, LOperand* key) {
+ inputs_[0] = context;
+ inputs_[1] = object;
+ inputs_[2] = key;
}
- LOperand* object() { return inputs_[0]; }
- LOperand* key() { return inputs_[1]; }
+ LOperand* context() { return inputs_[0]; }
+ LOperand* object() { return inputs_[1]; }
+ LOperand* key() { return inputs_[2]; }
DECLARE_CONCRETE_INSTRUCTION(LoadKeyedGeneric, "load-keyed-generic")
};
@@ -1648,13 +1676,15 @@
};
-class LLoadGlobalGeneric V8_FINAL : public LTemplateInstruction<1, 1, 0> {
+class LLoadGlobalGeneric V8_FINAL : public LTemplateInstruction<1, 2, 0> {
public:
- explicit LLoadGlobalGeneric(LOperand* global_object) {
- inputs_[0] = global_object;
+ LLoadGlobalGeneric(LOperand* context, LOperand* global_object) {
+ inputs_[0] = context;
+ inputs_[1] = global_object;
}
- LOperand* global_object() { return inputs_[0]; }
+ LOperand* context() { return inputs_[0]; }
+ LOperand* global_object() { return inputs_[1]; }
DECLARE_CONCRETE_INSTRUCTION(LoadGlobalGeneric, "load-global-generic")
DECLARE_HYDROGEN_ACCESSOR(LoadGlobalGeneric)
@@ -1679,16 +1709,19 @@
};
-class LStoreGlobalGeneric V8_FINAL : public LTemplateInstruction<0, 2, 0> {
+class LStoreGlobalGeneric V8_FINAL : public LTemplateInstruction<0, 3, 0> {
public:
- explicit LStoreGlobalGeneric(LOperand* global_object,
- LOperand* value) {
- inputs_[0] = global_object;
- inputs_[1] = value;
+ LStoreGlobalGeneric(LOperand* context,
+ LOperand* global_object,
+ LOperand* value) {
+ inputs_[0] = context;
+ inputs_[1] = global_object;
+ inputs_[2] = value;
}
- LOperand* global_object() { return inputs_[0]; }
- LOperand* value() { return inputs_[1]; }
+ LOperand* context() { return inputs_[0]; }
+ LOperand* global_object() { return inputs_[1]; }
+ LOperand* value() { return inputs_[2]; }
DECLARE_CONCRETE_INSTRUCTION(StoreGlobalGeneric, "store-global-generic")
DECLARE_HYDROGEN_ACCESSOR(StoreGlobalGeneric)
@@ -1818,8 +1851,14 @@
};
-class LDeclareGlobals V8_FINAL : public LTemplateInstruction<0, 0, 0> {
+class LDeclareGlobals V8_FINAL : public LTemplateInstruction<0, 1, 0> {
public:
+ explicit LDeclareGlobals(LOperand* context) {
+ inputs_[0] = context;
+ }
+
+ LOperand* context() { return inputs_[0]; }
+
DECLARE_CONCRETE_INSTRUCTION(DeclareGlobals, "declare-globals")
DECLARE_HYDROGEN_ACCESSOR(DeclareGlobals)
};
@@ -1861,13 +1900,15 @@
};
-class LInvokeFunction V8_FINAL : public LTemplateInstruction<1, 1, 0> {
+class LInvokeFunction V8_FINAL : public LTemplateInstruction<1, 2, 0> {
public:
- explicit LInvokeFunction(LOperand* function) {
- inputs_[0] = function;
+ LInvokeFunction(LOperand* context, LOperand* function) {
+ inputs_[0] = context;
+ inputs_[1] = function;
}
- LOperand* function() { return inputs_[0]; }
+ LOperand* context() { return inputs_[0]; }
+ LOperand* function() { return inputs_[1]; }
DECLARE_CONCRETE_INSTRUCTION(InvokeFunction, "invoke-function")
DECLARE_HYDROGEN_ACCESSOR(InvokeFunction)
@@ -1878,13 +1919,15 @@
};
-class LCallKeyed V8_FINAL : public LTemplateInstruction<1, 1, 0> {
+class LCallKeyed V8_FINAL : public LTemplateInstruction<1, 2, 0> {
public:
- explicit LCallKeyed(LOperand* key) {
- inputs_[0] = key;
+ LCallKeyed(LOperand* context, LOperand* key) {
+ inputs_[0] = context;
+ inputs_[1] = key;
}
- LOperand* key() { return inputs_[0]; }
+ LOperand* context() { return inputs_[0]; }
+ LOperand* key() { return inputs_[1]; }
DECLARE_CONCRETE_INSTRUCTION(CallKeyed, "call-keyed")
DECLARE_HYDROGEN_ACCESSOR(CallKeyed)
@@ -1896,8 +1939,14 @@
-class LCallNamed V8_FINAL : public LTemplateInstruction<1, 0, 0> {
+class LCallNamed V8_FINAL : public LTemplateInstruction<1, 1, 0> {
public:
+ explicit LCallNamed(LOperand* context) {
+ inputs_[0] = context;
+ }
+
+ LOperand* context() { return inputs_[0]; }
+
DECLARE_CONCRETE_INSTRUCTION(CallNamed, "call-named")
DECLARE_HYDROGEN_ACCESSOR(CallNamed)
@@ -1908,13 +1957,15 @@
};
-class LCallFunction V8_FINAL : public LTemplateInstruction<1, 1, 0> {
+class LCallFunction V8_FINAL : public LTemplateInstruction<1, 2, 0> {
public:
- explicit LCallFunction(LOperand* function) {
- inputs_[0] = function;
+ LCallFunction(LOperand* context, LOperand* function) {
+ inputs_[0] = context;
+ inputs_[1] = function;
}
- LOperand* function() { return inputs_[0]; }
+ LOperand* context() { return inputs_[0]; }
+ LOperand* function() { return inputs_[1]; }
DECLARE_CONCRETE_INSTRUCTION(CallFunction, "call-function")
DECLARE_HYDROGEN_ACCESSOR(CallFunction)
@@ -1923,8 +1974,14 @@
};
-class LCallGlobal V8_FINAL : public LTemplateInstruction<1, 0, 0> {
+class LCallGlobal V8_FINAL : public LTemplateInstruction<1, 1, 0> {
public:
+ explicit LCallGlobal(LOperand* context) {
+ inputs_[0] = context;
+ }
+
+ LOperand* context() { return inputs_[0]; }
+
DECLARE_CONCRETE_INSTRUCTION(CallGlobal, "call-global")
DECLARE_HYDROGEN_ACCESSOR(CallGlobal)
@@ -1946,13 +2003,15 @@
};
-class LCallNew V8_FINAL : public LTemplateInstruction<1, 1, 0> {
+class LCallNew V8_FINAL : public LTemplateInstruction<1, 2, 0> {
public:
- explicit LCallNew(LOperand* constructor) {
- inputs_[0] = constructor;
+ LCallNew(LOperand* context, LOperand* constructor) {
+ inputs_[0] = context;
+ inputs_[1] = constructor;
}
- LOperand* constructor() { return inputs_[0]; }
+ LOperand* context() { return inputs_[0]; }
+ LOperand* constructor() { return inputs_[1]; }
DECLARE_CONCRETE_INSTRUCTION(CallNew, "call-new")
DECLARE_HYDROGEN_ACCESSOR(CallNew)
@@ -1963,13 +2022,15 @@
};
-class LCallNewArray V8_FINAL : public LTemplateInstruction<1, 1, 0> {
+class LCallNewArray V8_FINAL : public LTemplateInstruction<1, 2, 0> {
public:
- explicit LCallNewArray(LOperand* constructor) {
- inputs_[0] = constructor;
+ LCallNewArray(LOperand* context, LOperand* constructor) {
+ inputs_[0] = context;
+ inputs_[1] = constructor;
}
- LOperand* constructor() { return inputs_[0]; }
+ LOperand* context() { return inputs_[0]; }
+ LOperand* constructor() { return inputs_[1]; }
DECLARE_CONCRETE_INSTRUCTION(CallNewArray, "call-new-array")
DECLARE_HYDROGEN_ACCESSOR(CallNewArray)
@@ -1980,8 +2041,14 @@
};
-class LCallRuntime V8_FINAL : public LTemplateInstruction<1, 0, 0> {
+class LCallRuntime V8_FINAL : public LTemplateInstruction<1, 1, 0> {
public:
+ explicit LCallRuntime(LOperand* context) {
+ inputs_[0] = context;
+ }
+
+ LOperand* context() { return inputs_[0]; }
+
DECLARE_CONCRETE_INSTRUCTION(CallRuntime, "call-runtime")
DECLARE_HYDROGEN_ACCESSOR(CallRuntime)
@@ -2187,15 +2254,17 @@
};
-class LStoreNamedGeneric V8_FINAL : public LTemplateInstruction<0, 2, 0> {
+class LStoreNamedGeneric V8_FINAL : public LTemplateInstruction<0, 3, 0> {
public:
- LStoreNamedGeneric(LOperand* object, LOperand* value) {
- inputs_[0] = object;
- inputs_[1] = value;
+ LStoreNamedGeneric(LOperand* context, LOperand* object, LOperand* value) {
+ inputs_[0] = context;
+ inputs_[1] = object;
+ inputs_[2] = value;
}
- LOperand* object() { return inputs_[0]; }
- LOperand* value() { return inputs_[1]; }
+ LOperand* context() { return inputs_[0]; }
+ LOperand* object() { return inputs_[1]; }
+ LOperand* value() { return inputs_[2]; }
DECLARE_CONCRETE_INSTRUCTION(StoreNamedGeneric, "store-named-generic")
DECLARE_HYDROGEN_ACCESSOR(StoreNamedGeneric)
@@ -2238,17 +2307,22 @@
};
-class LStoreKeyedGeneric V8_FINAL : public LTemplateInstruction<0, 3, 0> {
+class LStoreKeyedGeneric V8_FINAL : public LTemplateInstruction<0, 4, 0> {
public:
- LStoreKeyedGeneric(LOperand* obj, LOperand* key, LOperand* value) {
- inputs_[0] = obj;
- inputs_[1] = key;
- inputs_[2] = value;
+ LStoreKeyedGeneric(LOperand* context,
+ LOperand* obj,
+ LOperand* key,
+ LOperand* value) {
+ inputs_[0] = context;
+ inputs_[1] = obj;
+ inputs_[2] = key;
+ inputs_[3] = value;
}
- LOperand* object() { return inputs_[0]; }
- LOperand* key() { return inputs_[1]; }
- LOperand* value() { return inputs_[2]; }
+ LOperand* context() { return inputs_[0]; }
+ LOperand* object() { return inputs_[1]; }
+ LOperand* key() { return inputs_[2]; }
+ LOperand* value() { return inputs_[3]; }
DECLARE_CONCRETE_INSTRUCTION(StoreKeyedGeneric, "store-keyed-generic")
DECLARE_HYDROGEN_ACCESSOR(StoreKeyedGeneric)
@@ -2259,14 +2333,17 @@
};
-class LTransitionElementsKind V8_FINAL : public LTemplateInstruction<0, 1, 1> {
+class LTransitionElementsKind V8_FINAL : public LTemplateInstruction<0, 2, 1> {
public:
LTransitionElementsKind(LOperand* object,
+ LOperand* context,
LOperand* new_map_temp) {
inputs_[0] = object;
+ inputs_[1] = context;
temps_[0] = new_map_temp;
}
+ LOperand* context() { return inputs_[1]; }
LOperand* object() { return inputs_[0]; }
LOperand* new_map_temp() { return temps_[0]; }
@@ -2301,15 +2378,17 @@
};
-class LStringAdd V8_FINAL : public LTemplateInstruction<1, 2, 0> {
+class LStringAdd V8_FINAL : public LTemplateInstruction<1, 3, 0> {
public:
- LStringAdd(LOperand* left, LOperand* right) {
- inputs_[0] = left;
- inputs_[1] = right;
+ LStringAdd(LOperand* context, LOperand* left, LOperand* right) {
+ inputs_[0] = context;
+ inputs_[1] = left;
+ inputs_[2] = right;
}
- LOperand* left() { return inputs_[0]; }
- LOperand* right() { return inputs_[1]; }
+ LOperand* context() { return inputs_[0]; }
+ LOperand* left() { return inputs_[1]; }
+ LOperand* right() { return inputs_[2]; }
DECLARE_CONCRETE_INSTRUCTION(StringAdd, "string-add")
DECLARE_HYDROGEN_ACCESSOR(StringAdd)
@@ -2317,28 +2396,32 @@
-class LStringCharCodeAt V8_FINAL : public LTemplateInstruction<1, 2, 0> {
+class LStringCharCodeAt V8_FINAL : public LTemplateInstruction<1, 3, 0> {
public:
- LStringCharCodeAt(LOperand* string, LOperand* index) {
- inputs_[0] = string;
- inputs_[1] = index;
+ LStringCharCodeAt(LOperand* context, LOperand* string, LOperand* index) {
+ inputs_[0] = context;
+ inputs_[1] = string;
+ inputs_[2] = index;
}
- LOperand* string() { return inputs_[0]; }
- LOperand* index() { return inputs_[1]; }
+ LOperand* context() { return inputs_[0]; }
+ LOperand* string() { return inputs_[1]; }
+ LOperand* index() { return inputs_[2]; }
DECLARE_CONCRETE_INSTRUCTION(StringCharCodeAt, "string-char-code-at")
DECLARE_HYDROGEN_ACCESSOR(StringCharCodeAt)
};
-class LStringCharFromCode V8_FINAL : public LTemplateInstruction<1, 1, 0> {
+class LStringCharFromCode V8_FINAL : public LTemplateInstruction<1, 2, 0> {
public:
- explicit LStringCharFromCode(LOperand* char_code) {
- inputs_[0] = char_code;
+ explicit LStringCharFromCode(LOperand* context, LOperand* char_code) {
+ inputs_[0] = context;
+ inputs_[1] = char_code;
}
- LOperand* char_code() { return inputs_[0]; }
+ LOperand* context() { return inputs_[0]; }
+ LOperand* char_code() { return inputs_[1]; }
DECLARE_CONCRETE_INSTRUCTION(StringCharFromCode, "string-char-from-code")
DECLARE_HYDROGEN_ACCESSOR(StringCharFromCode)
@@ -2449,12 +2532,17 @@
class LAllocate V8_FINAL : public LTemplateInstruction<1, 2, 2> {
public:
- LAllocate(LOperand* size, LOperand* temp1, LOperand* temp2) {
+ LAllocate(LOperand* context,
+ LOperand* size,
+ LOperand* temp1,
+ LOperand* temp2) {
+ inputs_[0] = context;
inputs_[1] = size;
temps_[0] = temp1;
temps_[1] = temp2;
}
+ LOperand* context() { return inputs_[0]; }
LOperand* size() { return inputs_[1]; }
LOperand* temp1() { return temps_[0]; }
LOperand* temp2() { return temps_[1]; }
@@ -2464,15 +2552,27 @@
};
-class LRegExpLiteral V8_FINAL : public LTemplateInstruction<1, 0, 0> {
+class LRegExpLiteral V8_FINAL : public LTemplateInstruction<1, 1, 0> {
public:
+ explicit LRegExpLiteral(LOperand* context) {
+ inputs_[0] = context;
+ }
+
+ LOperand* context() { return inputs_[0]; }
+
DECLARE_CONCRETE_INSTRUCTION(RegExpLiteral, "regexp-literal")
DECLARE_HYDROGEN_ACCESSOR(RegExpLiteral)
};
-class LFunctionLiteral V8_FINAL : public LTemplateInstruction<1, 0, 0> {
+class LFunctionLiteral V8_FINAL : public LTemplateInstruction<1, 1, 0> {
public:
+ explicit LFunctionLiteral(LOperand* context) {
+ inputs_[0] = context;
+ }
+
+ LOperand* context() { return inputs_[0]; }
+
DECLARE_CONCRETE_INSTRUCTION(FunctionLiteral, "function-literal")
DECLARE_HYDROGEN_ACCESSOR(FunctionLiteral)
};
@@ -2491,13 +2591,15 @@
};
-class LTypeof V8_FINAL : public LTemplateInstruction<1, 1, 0> {
+class LTypeof V8_FINAL : public LTemplateInstruction<1, 2, 0> {
public:
- explicit LTypeof(LOperand* value) {
- inputs_[0] = value;
+ LTypeof(LOperand* context, LOperand* value) {
+ inputs_[0] = context;
+ inputs_[1] = value;
}
- LOperand* value() { return inputs_[0]; }
+ LOperand* context() { return inputs_[0]; }
+ LOperand* value() { return inputs_[1]; }
DECLARE_CONCRETE_INSTRUCTION(Typeof, "typeof")
};
@@ -2544,8 +2646,14 @@
};
-class LStackCheck V8_FINAL : public LTemplateInstruction<0, 0, 0> {
+class LStackCheck V8_FINAL : public LTemplateInstruction<0, 1, 0> {
public:
+ explicit LStackCheck(LOperand* context) {
+ inputs_[0] = context;
+ }
+
+ LOperand* context() { return inputs_[0]; }
+
DECLARE_CONCRETE_INSTRUCTION(StackCheck, "stack-check")
DECLARE_HYDROGEN_ACCESSOR(StackCheck)
@@ -2556,13 +2664,15 @@
};
-class LForInPrepareMap V8_FINAL : public LTemplateInstruction<1, 1, 0> {
+class LForInPrepareMap V8_FINAL : public LTemplateInstruction<1, 2, 0> {
public:
- explicit LForInPrepareMap(LOperand* object) {
- inputs_[0] = object;
+ LForInPrepareMap(LOperand* context, LOperand* object) {
+ inputs_[0] = context;
+ inputs_[1] = object;
}
- LOperand* object() { return inputs_[0]; }
+ LOperand* context() { return inputs_[0]; }
+ LOperand* object() { return inputs_[1]; }
DECLARE_CONCRETE_INSTRUCTION(ForInPrepareMap, "for-in-prepare-map")
};
@@ -2618,8 +2728,8 @@
LPlatformChunk(CompilationInfo* info, HGraph* graph)
: LChunk(info, graph) { }
- int GetNextSpillIndex(bool is_double);
- LOperand* GetNextSpillSlot(bool is_double);
+ int GetNextSpillIndex(RegisterKind kind);
+ LOperand* GetNextSpillSlot(RegisterKind kind);
};
diff --git a/src/arm/lithium-codegen-arm.cc b/src/arm/lithium-codegen-arm.cc
index ca38743..e7734c1 100644
--- a/src/arm/lithium-codegen-arm.cc
+++ b/src/arm/lithium-codegen-arm.cc
@@ -248,6 +248,8 @@
// Trace the call.
if (FLAG_trace && info()->IsOptimizing()) {
+ // We have not executed any compiled code yet, so cp still holds the
+ // incoming context.
__ CallRuntime(Runtime::kTraceEnter, 0);
}
return !is_aborted();
@@ -759,9 +761,22 @@
}
+void LCodeGen::LoadContextFromDeferred(LOperand* context) {
+ if (context->IsRegister()) {
+ __ Move(cp, ToRegister(context));
+ } else if (context->IsStackSlot()) {
+ __ ldr(cp, ToMemOperand(context));
+ } else {
+ UNREACHABLE();
+ }
+}
+
+
void LCodeGen::CallRuntimeFromDeferred(Runtime::FunctionId id,
int argc,
- LInstruction* instr) {
+ LInstruction* instr,
+ LOperand* context) {
+ LoadContextFromDeferred(context);
__ CallRuntimeSaveDoubles(id);
RecordSafepointWithRegisters(
instr->pointer_map(), argc, Safepoint::kNoLazyDeopt);
@@ -977,10 +992,6 @@
safepoint.DefinePointerRegister(ToRegister(pointer), zone());
}
}
- if (kind & Safepoint::kWithRegisters) {
- // Register cp always contains a pointer to the context.
- safepoint.DefinePointerRegister(cp, zone());
- }
}
@@ -1073,6 +1084,7 @@
void LCodeGen::DoCallStub(LCallStub* instr) {
+ ASSERT(ToRegister(instr->context()).is(cp));
ASSERT(ToRegister(instr->result()).is(r0));
switch (instr->hydrogen()->major_key()) {
case CodeStub::RegExpConstructResult: {
@@ -2023,6 +2035,7 @@
void LCodeGen::DoThrow(LThrow* instr) {
Register input_reg = EmitLoadRegister(instr->value(), ip);
__ push(input_reg);
+ ASSERT(ToRegister(instr->context()).is(cp));
CallRuntime(Runtime::kThrow, 1, instr);
if (FLAG_debug_code) {
@@ -2160,6 +2173,7 @@
void LCodeGen::DoArithmeticT(LArithmeticT* instr) {
+ ASSERT(ToRegister(instr->context()).is(cp));
ASSERT(ToRegister(instr->left()).is(r1));
ASSERT(ToRegister(instr->right()).is(r0));
ASSERT(ToRegister(instr->result()).is(r0));
@@ -2571,6 +2585,7 @@
void LCodeGen::DoStringCompareAndBranch(LStringCompareAndBranch* instr) {
+ ASSERT(ToRegister(instr->context()).is(cp));
Token::Value op = instr->op();
Handle<Code> ic = CompareIC::GetUninitialized(isolate(), op);
@@ -2731,6 +2746,7 @@
void LCodeGen::DoInstanceOf(LInstanceOf* instr) {
+ ASSERT(ToRegister(instr->context()).is(cp));
ASSERT(ToRegister(instr->left()).is(r0)); // Object is in r0.
ASSERT(ToRegister(instr->right()).is(r1)); // Function is in r1.
@@ -2840,6 +2856,7 @@
InstanceofStub stub(flags);
PushSafepointRegistersScope scope(this, Safepoint::kWithRegisters);
+ LoadContextFromDeferred(instr->context());
// Get the temp register reserved by the instruction. This needs to be r4 as
// its slot of the pushing of safepoint registers is used to communicate the
@@ -2884,6 +2901,7 @@
void LCodeGen::DoCmpT(LCmpT* instr) {
+ ASSERT(ToRegister(instr->context()).is(cp));
Token::Value op = instr->op();
Handle<Code> ic = CompareIC::GetUninitialized(isolate(), op);
@@ -2904,8 +2922,11 @@
void LCodeGen::DoReturn(LReturn* instr) {
if (FLAG_trace && info()->IsOptimizing()) {
// Push the return value on the stack as the parameter.
- // Runtime::TraceExit returns its parameter in r0.
+ // Runtime::TraceExit returns its parameter in r0. We're leaving the code
+ // managed by the register allocator and tearing down the frame, it's
+ // safe to write to the context register.
__ push(r0);
+ __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
__ CallRuntime(Runtime::kTraceExit, 1);
}
if (info()->saves_caller_doubles()) {
@@ -2960,6 +2981,7 @@
void LCodeGen::DoLoadGlobalGeneric(LLoadGlobalGeneric* instr) {
+ ASSERT(ToRegister(instr->context()).is(cp));
ASSERT(ToRegister(instr->global_object()).is(r0));
ASSERT(ToRegister(instr->result()).is(r0));
@@ -2997,6 +3019,7 @@
void LCodeGen::DoStoreGlobalGeneric(LStoreGlobalGeneric* instr) {
+ ASSERT(ToRegister(instr->context()).is(cp));
ASSERT(ToRegister(instr->global_object()).is(r1));
ASSERT(ToRegister(instr->value()).is(r0));
@@ -3090,6 +3113,7 @@
void LCodeGen::DoLoadNamedGeneric(LLoadNamedGeneric* instr) {
+ ASSERT(ToRegister(instr->context()).is(cp));
ASSERT(ToRegister(instr->object()).is(r0));
ASSERT(ToRegister(instr->result()).is(r0));
@@ -3383,6 +3407,7 @@
void LCodeGen::DoLoadKeyedGeneric(LLoadKeyedGeneric* instr) {
+ ASSERT(ToRegister(instr->context()).is(cp));
ASSERT(ToRegister(instr->object()).is(r1));
ASSERT(ToRegister(instr->key()).is(r0));
@@ -3527,7 +3552,6 @@
ParameterCount actual(receiver);
__ InvokeFunction(function, actual, CALL_FUNCTION,
safepoint_generator, CALL_AS_METHOD);
- __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
}
@@ -3556,11 +3580,11 @@
void LCodeGen::DoContext(LContext* instr) {
// If there is a non-return use, the context must be moved to a register.
Register result = ToRegister(instr->result());
- for (HUseIterator it(instr->hydrogen()->uses()); !it.Done(); it.Advance()) {
- if (!it.value()->IsReturn()) {
- __ mov(result, cp);
- return;
- }
+ if (info()->IsOptimizing()) {
+ __ ldr(result, MemOperand(fp, StandardFrameConstants::kContextOffset));
+ } else {
+ // If there is no frame, the context must be in cp.
+ ASSERT(result.is(cp));
}
}
@@ -3574,6 +3598,7 @@
void LCodeGen::DoDeclareGlobals(LDeclareGlobals* instr) {
+ ASSERT(ToRegister(instr->context()).is(cp));
__ push(cp); // The context is the first argument.
__ LoadHeapObject(scratch0(), instr->hydrogen()->pairs());
__ push(scratch0());
@@ -3584,8 +3609,9 @@
void LCodeGen::DoGlobalObject(LGlobalObject* instr) {
+ Register context = ToRegister(instr->context());
Register result = ToRegister(instr->result());
- __ ldr(result, ContextOperand(cp, Context::GLOBAL_OBJECT_INDEX));
+ __ ldr(result, ContextOperand(context, Context::GLOBAL_OBJECT_INDEX));
}
@@ -3638,9 +3664,6 @@
__ InvokeFunction(
function, expected, count, CALL_FUNCTION, generator, call_kind);
}
-
- // Restore context.
- __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
}
@@ -3656,6 +3679,8 @@
void LCodeGen::DoDeferredMathAbsTaggedHeapNumber(LMathAbs* instr) {
+ ASSERT(instr->context() != NULL);
+ ASSERT(ToRegister(instr->context()).is(cp));
Register input = ToRegister(instr->value());
Register result = ToRegister(instr->result());
Register scratch = scratch0();
@@ -3699,7 +3724,8 @@
// Slow case: Call the runtime system to do the number allocation.
__ bind(&slow);
- CallRuntimeFromDeferred(Runtime::kAllocateHeapNumber, 0, instr);
+ CallRuntimeFromDeferred(Runtime::kAllocateHeapNumber, 0, instr,
+ instr->context());
// Set the pointer to the new heap number in tmp.
if (!tmp1.is(r0)) __ mov(tmp1, Operand(r0));
// Restore input_reg after call to runtime.
@@ -3970,6 +3996,9 @@
void LCodeGen::DoMathLog(LMathLog* instr) {
ASSERT(ToDoubleRegister(instr->result()).is(d2));
+ // Set the context register to a GC-safe fake value. Clobbering it is
+ // OK because this instruction is marked as a call.
+ __ mov(cp, Operand::Zero());
TranscendentalCacheStub stub(TranscendentalCache::LOG,
TranscendentalCacheStub::UNTAGGED);
CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
@@ -3978,6 +4007,9 @@
void LCodeGen::DoMathTan(LMathTan* instr) {
ASSERT(ToDoubleRegister(instr->result()).is(d2));
+ // Set the context register to a GC-safe fake value. Clobbering it is
+ // OK because this instruction is marked as a call.
+ __ mov(cp, Operand::Zero());
TranscendentalCacheStub stub(TranscendentalCache::TAN,
TranscendentalCacheStub::UNTAGGED);
CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
@@ -3986,6 +4018,9 @@
void LCodeGen::DoMathCos(LMathCos* instr) {
ASSERT(ToDoubleRegister(instr->result()).is(d2));
+ // Set the context register to a GC-safe fake value. Clobbering it is
+ // OK because this instruction is marked as a call.
+ __ mov(cp, Operand::Zero());
TranscendentalCacheStub stub(TranscendentalCache::COS,
TranscendentalCacheStub::UNTAGGED);
CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
@@ -3994,6 +4029,9 @@
void LCodeGen::DoMathSin(LMathSin* instr) {
ASSERT(ToDoubleRegister(instr->result()).is(d2));
+ // Set the context register to a GC-safe fake value. Clobbering it is
+ // OK because this instruction is marked as a call.
+ __ mov(cp, Operand::Zero());
TranscendentalCacheStub stub(TranscendentalCache::SIN,
TranscendentalCacheStub::UNTAGGED);
CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
@@ -4001,6 +4039,7 @@
void LCodeGen::DoInvokeFunction(LInvokeFunction* instr) {
+ ASSERT(ToRegister(instr->context()).is(cp));
ASSERT(ToRegister(instr->function()).is(r1));
ASSERT(instr->HasPointerMap());
@@ -4011,7 +4050,6 @@
SafepointGenerator generator(this, pointers, Safepoint::kLazyDeopt);
ParameterCount count(instr->arity());
__ InvokeFunction(r1, count, CALL_FUNCTION, generator, CALL_AS_METHOD);
- __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
} else {
CallKnownFunction(known_function,
instr->hydrogen()->formal_parameter_count(),
@@ -4024,17 +4062,18 @@
void LCodeGen::DoCallKeyed(LCallKeyed* instr) {
+ ASSERT(ToRegister(instr->context()).is(cp));
ASSERT(ToRegister(instr->result()).is(r0));
int arity = instr->arity();
Handle<Code> ic =
isolate()->stub_cache()->ComputeKeyedCallInitialize(arity);
CallCode(ic, RelocInfo::CODE_TARGET, instr, NEVER_INLINE_TARGET_ADDRESS);
- __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
}
void LCodeGen::DoCallNamed(LCallNamed* instr) {
+ ASSERT(ToRegister(instr->context()).is(cp));
ASSERT(ToRegister(instr->result()).is(r0));
int arity = instr->arity();
@@ -4043,23 +4082,22 @@
isolate()->stub_cache()->ComputeCallInitialize(arity, mode);
__ mov(r2, Operand(instr->name()));
CallCode(ic, mode, instr, NEVER_INLINE_TARGET_ADDRESS);
- // Restore context register.
- __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
}
void LCodeGen::DoCallFunction(LCallFunction* instr) {
+ ASSERT(ToRegister(instr->context()).is(cp));
ASSERT(ToRegister(instr->function()).is(r1));
ASSERT(ToRegister(instr->result()).is(r0));
int arity = instr->arity();
CallFunctionStub stub(arity, NO_CALL_FUNCTION_FLAGS);
CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
- __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
}
void LCodeGen::DoCallGlobal(LCallGlobal* instr) {
+ ASSERT(ToRegister(instr->context()).is(cp));
ASSERT(ToRegister(instr->result()).is(r0));
int arity = instr->arity();
@@ -4068,7 +4106,6 @@
isolate()->stub_cache()->ComputeCallInitialize(arity, mode);
__ mov(r2, Operand(instr->name()));
CallCode(ic, mode, instr, NEVER_INLINE_TARGET_ADDRESS);
- __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
}
@@ -4084,6 +4121,7 @@
void LCodeGen::DoCallNew(LCallNew* instr) {
+ ASSERT(ToRegister(instr->context()).is(cp));
ASSERT(ToRegister(instr->constructor()).is(r1));
ASSERT(ToRegister(instr->result()).is(r0));
@@ -4097,6 +4135,7 @@
void LCodeGen::DoCallNewArray(LCallNewArray* instr) {
+ ASSERT(ToRegister(instr->context()).is(cp));
ASSERT(ToRegister(instr->constructor()).is(r1));
ASSERT(ToRegister(instr->result()).is(r0));
@@ -4248,6 +4287,7 @@
void LCodeGen::DoStoreNamedGeneric(LStoreNamedGeneric* instr) {
+ ASSERT(ToRegister(instr->context()).is(cp));
ASSERT(ToRegister(instr->object()).is(r1));
ASSERT(ToRegister(instr->value()).is(r0));
@@ -4471,6 +4511,7 @@
void LCodeGen::DoStoreKeyedGeneric(LStoreKeyedGeneric* instr) {
+ ASSERT(ToRegister(instr->context()).is(cp));
ASSERT(ToRegister(instr->object()).is(r2));
ASSERT(ToRegister(instr->key()).is(r1));
ASSERT(ToRegister(instr->value()).is(r0));
@@ -4504,6 +4545,7 @@
__ RecordWriteField(object_reg, HeapObject::kMapOffset, new_map_reg,
scratch, GetLinkRegisterState(), kDontSaveFPRegs);
} else {
+ ASSERT(ToRegister(instr->context()).is(cp));
PushSafepointRegistersScope scope(
this, Safepoint::kWithRegistersAndDoubles);
__ Move(r0, object_reg);
@@ -4526,6 +4568,7 @@
void LCodeGen::DoStringAdd(LStringAdd* instr) {
+ ASSERT(ToRegister(instr->context()).is(cp));
__ push(ToRegister(instr->left()));
__ push(ToRegister(instr->right()));
StringAddStub stub(instr->hydrogen()->flags());
@@ -4581,7 +4624,8 @@
__ SmiTag(index);
__ push(index);
}
- CallRuntimeFromDeferred(Runtime::kStringCharCodeAt, 2, instr);
+ CallRuntimeFromDeferred(Runtime::kStringCharCodeAt, 2, instr,
+ instr->context());
__ AssertSmi(r0);
__ SmiUntag(r0);
__ StoreToSafepointRegisterSlot(r0, result);
@@ -4633,7 +4677,7 @@
PushSafepointRegistersScope scope(this, Safepoint::kWithRegisters);
__ SmiTag(char_code);
__ push(char_code);
- CallRuntimeFromDeferred(Runtime::kCharFromCode, 1, instr);
+ CallRuntimeFromDeferred(Runtime::kCharFromCode, 1, instr, instr->context());
__ StoreToSafepointRegisterSlot(r0, result);
}
@@ -4772,7 +4816,15 @@
// integer value.
__ mov(ip, Operand::Zero());
__ StoreToSafepointRegisterSlot(ip, dst);
- CallRuntimeFromDeferred(Runtime::kAllocateHeapNumber, 0, instr);
+ // NumberTagI and NumberTagD use the context from the frame, rather than
+ // the environment's HContext or HInlinedContext value.
+ // They only call Runtime::kAllocateHeapNumber.
+ // The corresponding HChange instructions are added in a phase that does
+ // not have easy access to the local context.
+ __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
+ __ CallRuntimeSaveDoubles(Runtime::kAllocateHeapNumber);
+ RecordSafepointWithRegisters(
+ instr->pointer_map(), 0, Safepoint::kNoLazyDeopt);
__ Move(dst, r0);
__ sub(dst, dst, Operand(kHeapObjectTag));
@@ -4828,7 +4880,15 @@
__ mov(reg, Operand::Zero());
PushSafepointRegistersScope scope(this, Safepoint::kWithRegisters);
- CallRuntimeFromDeferred(Runtime::kAllocateHeapNumber, 0, instr);
+ // NumberTagI and NumberTagD use the context from the frame, rather than
+ // the environment's HContext or HInlinedContext value.
+ // They only call Runtime::kAllocateHeapNumber.
+ // The corresponding HChange instructions are added in a phase that does
+ // not have easy access to the local context.
+ __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
+ __ CallRuntimeSaveDoubles(Runtime::kAllocateHeapNumber);
+ RecordSafepointWithRegisters(
+ instr->pointer_map(), 0, Safepoint::kNoLazyDeopt);
__ sub(r0, r0, Operand(kHeapObjectTag));
__ StoreToSafepointRegisterSlot(r0, reg);
}
@@ -5157,7 +5217,10 @@
{
PushSafepointRegistersScope scope(this, Safepoint::kWithRegisters);
__ push(object);
- CallRuntimeFromDeferred(Runtime::kMigrateInstance, 1, instr);
+ __ mov(cp, Operand::Zero());
+ __ CallRuntimeSaveDoubles(Runtime::kMigrateInstance);
+ RecordSafepointWithRegisters(
+ instr->pointer_map(), 1, Safepoint::kNoLazyDeopt);
__ StoreToSafepointRegisterSlot(r0, scratch0());
}
__ tst(scratch0(), Operand(kSmiTagMask));
@@ -5360,12 +5423,15 @@
if (instr->hydrogen()->IsOldPointerSpaceAllocation()) {
ASSERT(!instr->hydrogen()->IsOldDataSpaceAllocation());
ASSERT(!instr->hydrogen()->IsNewSpaceAllocation());
- CallRuntimeFromDeferred(Runtime::kAllocateInOldPointerSpace, 1, instr);
+ CallRuntimeFromDeferred(Runtime::kAllocateInOldPointerSpace, 1, instr,
+ instr->context());
} else if (instr->hydrogen()->IsOldDataSpaceAllocation()) {
ASSERT(!instr->hydrogen()->IsNewSpaceAllocation());
- CallRuntimeFromDeferred(Runtime::kAllocateInOldDataSpace, 1, instr);
+ CallRuntimeFromDeferred(Runtime::kAllocateInOldDataSpace, 1, instr,
+ instr->context());
} else {
- CallRuntimeFromDeferred(Runtime::kAllocateInNewSpace, 1, instr);
+ CallRuntimeFromDeferred(Runtime::kAllocateInNewSpace, 1, instr,
+ instr->context());
}
__ StoreToSafepointRegisterSlot(r0, result);
}
@@ -5379,6 +5445,7 @@
void LCodeGen::DoRegExpLiteral(LRegExpLiteral* instr) {
+ ASSERT(ToRegister(instr->context()).is(cp));
Label materialized;
// Registers will be used as follows:
// r6 = literals array.
@@ -5422,6 +5489,7 @@
void LCodeGen::DoFunctionLiteral(LFunctionLiteral* instr) {
+ ASSERT(ToRegister(instr->context()).is(cp));
// Use the fast case closure allocation code that allocates in new
// space for nested functions that don't need literals cloning.
bool pretenure = instr->hydrogen()->pretenure();
@@ -5616,6 +5684,7 @@
void LCodeGen::DoDeferredStackCheck(LStackCheck* instr) {
PushSafepointRegistersScope scope(this, Safepoint::kWithRegisters);
+ LoadContextFromDeferred(instr->context());
__ CallRuntimeSaveDoubles(Runtime::kStackGuard);
RecordSafepointWithLazyDeopt(
instr, RECORD_SAFEPOINT_WITH_REGISTERS_AND_NO_ARGUMENTS);
@@ -5649,9 +5718,11 @@
__ cmp(sp, Operand(ip));
__ b(hs, &done);
PredictableCodeSizeScope predictable(masm_, 2 * Assembler::kInstrSize);
+ ASSERT(instr->context()->IsRegister());
+ ASSERT(ToRegister(instr->context()).is(cp));
CallCode(isolate()->builtins()->StackCheck(),
- RelocInfo::CODE_TARGET,
- instr);
+ RelocInfo::CODE_TARGET,
+ instr);
EnsureSpaceForLazyDeopt();
last_lazy_deopt_pc_ = masm()->pc_offset();
__ bind(&done);
diff --git a/src/arm/lithium-codegen-arm.h b/src/arm/lithium-codegen-arm.h
index 4b6b5ca..3016b45 100644
--- a/src/arm/lithium-codegen-arm.h
+++ b/src/arm/lithium-codegen-arm.h
@@ -258,9 +258,11 @@
CallRuntime(function, num_arguments, instr);
}
+ void LoadContextFromDeferred(LOperand* context);
void CallRuntimeFromDeferred(Runtime::FunctionId id,
int argc,
- LInstruction* instr);
+ LInstruction* instr,
+ LOperand* context);
enum R1State {
R1_UNINITIALIZED,
diff --git a/src/arm/macro-assembler-arm.cc b/src/arm/macro-assembler-arm.cc
index fd51521..8fcde6b 100644
--- a/src/arm/macro-assembler-arm.cc
+++ b/src/arm/macro-assembler-arm.cc
@@ -478,11 +478,6 @@
SaveFPRegsMode fp_mode,
RememberedSetAction remembered_set_action,
SmiCheck smi_check) {
- // The compiled code assumes that record write doesn't change the
- // context register, so we check that none of the clobbered
- // registers are cp.
- ASSERT(!address.is(cp) && !value.is(cp));
-
if (emit_debug_code()) {
ldr(ip, MemOperand(address));
cmp(ip, value);
diff --git a/src/compiler.h b/src/compiler.h
index dc7c19f..84416fe 100644
--- a/src/compiler.h
+++ b/src/compiler.h
@@ -534,7 +534,7 @@
}
void WaitForInstall() {
- ASSERT(!info_->osr_ast_id().IsNone());
+ ASSERT(info_->is_osr());
awaiting_install_ = true;
}
diff --git a/src/d8.cc b/src/d8.cc
index 1c6e453..6eb7248 100644
--- a/src/d8.cc
+++ b/src/d8.cc
@@ -1528,7 +1528,7 @@
// Start preemption if threads have been created and preemption is enabled.
if (threads.length() > 0
&& options.use_preemption) {
- Locker::StartPreemption(options.preemption_interval);
+ Locker::StartPreemption(isolate, options.preemption_interval);
}
#endif // V8_SHARED
}
@@ -1546,7 +1546,7 @@
if (threads.length() > 0 && options.use_preemption) {
Locker lock(isolate);
- Locker::StopPreemption();
+ Locker::StopPreemption(isolate);
}
#endif // V8_SHARED
return 0;
diff --git a/src/global-handles.cc b/src/global-handles.cc
index 1a98e49..2ebe1c0 100644
--- a/src/global-handles.cc
+++ b/src/global-handles.cc
@@ -79,7 +79,7 @@
Internals::kNodeIsPartiallyDependentShift);
}
-#ifdef ENABLE_EXTRA_CHECKS
+#ifdef ENABLE_HANDLE_ZAPPING
~Node() {
// TODO(1428): if it's a weak handle we should have invoked its callback.
// Zap the values for eager trapping.
diff --git a/src/handles-inl.h b/src/handles-inl.h
index 5b879d8..ec69c3f 100644
--- a/src/handles-inl.h
+++ b/src/handles-inl.h
@@ -130,16 +130,17 @@
v8::ImplementationUtilities::HandleScopeData* current =
isolate->handle_scope_data();
- current->next = prev_next;
+ std::swap(current->next, prev_next);
current->level--;
if (current->limit != prev_limit) {
current->limit = prev_limit;
DeleteExtensions(isolate);
- }
-
-#ifdef ENABLE_EXTRA_CHECKS
- ZapRange(prev_next, prev_limit);
+#ifdef ENABLE_HANDLE_ZAPPING
+ ZapRange(current->next, prev_limit);
+ } else {
+ ZapRange(current->next, prev_next);
#endif
+ }
}
diff --git a/src/handles.cc b/src/handles.cc
index 6b9025d..054dde3 100644
--- a/src/handles.cc
+++ b/src/handles.cc
@@ -101,7 +101,7 @@
}
-#ifdef ENABLE_EXTRA_CHECKS
+#ifdef ENABLE_HANDLE_ZAPPING
void HandleScope::ZapRange(Object** start, Object** end) {
ASSERT(end - start <= kHandleBlockSize);
for (Object** p = start; p != end; p++) {
diff --git a/src/handles.h b/src/handles.h
index 0f619d5..05b0c5e 100644
--- a/src/handles.h
+++ b/src/handles.h
@@ -177,7 +177,7 @@
// Extend the handle scope making room for more handles.
static internal::Object** Extend(Isolate* isolate);
-#ifdef ENABLE_EXTRA_CHECKS
+#ifdef ENABLE_HANDLE_ZAPPING
// Zaps the handles in the half-open interval [start, end).
static void ZapRange(Object** start, Object** end);
#endif
diff --git a/src/hydrogen-instructions.h b/src/hydrogen-instructions.h
index 97e1b0e..382dc16 100644
--- a/src/hydrogen-instructions.h
+++ b/src/hydrogen-instructions.h
@@ -64,6 +64,7 @@
#define HYDROGEN_CONCRETE_INSTRUCTION_LIST(V) \
+ V(AbnormalExit) \
V(AccessArgumentsAt) \
V(Add) \
V(Allocate) \
@@ -1457,6 +1458,16 @@
};
+class HAbnormalExit V8_FINAL : public HTemplateControlInstruction<0, 0> {
+ public:
+ virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
+ return Representation::None();
+ }
+
+ DECLARE_CONCRETE_INSTRUCTION(AbnormalExit)
+};
+
+
class HUnaryOperation : public HTemplateInstruction<1> {
public:
HUnaryOperation(HValue* value, HType type = HType::Tagged())
diff --git a/src/hydrogen-osr.cc b/src/hydrogen-osr.cc
index e95967e..3492deb 100644
--- a/src/hydrogen-osr.cc
+++ b/src/hydrogen-osr.cc
@@ -37,19 +37,8 @@
}
-// Build a new loop header block and set it as the current block.
-HBasicBlock *HOsrBuilder::BuildLoopEntry() {
- HBasicBlock* loop_entry = builder_->CreateLoopHeaderBlock();
- builder_->current_block()->Goto(loop_entry);
- builder_->set_current_block(loop_entry);
- return loop_entry;
-}
-
-
-HBasicBlock* HOsrBuilder::BuildPossibleOsrLoopEntry(
- IterationStatement* statement) {
- // Check if there is an OSR here first.
- if (!HasOsrEntryAt(statement)) return BuildLoopEntry();
+HBasicBlock* HOsrBuilder::BuildOsrLoopEntry(IterationStatement* statement) {
+ ASSERT(HasOsrEntryAt(statement));
Zone* zone = builder_->zone();
HGraph* graph = builder_->graph();
@@ -113,7 +102,7 @@
builder_->set_current_block(loop_predecessor);
// Create the final loop entry
- osr_loop_entry_ = BuildLoopEntry();
+ osr_loop_entry_ = builder_->BuildLoopEntry();
return osr_loop_entry_;
}
diff --git a/src/hydrogen-osr.h b/src/hydrogen-osr.h
index 5014a75..ae72ce6 100644
--- a/src/hydrogen-osr.h
+++ b/src/hydrogen-osr.h
@@ -45,9 +45,10 @@
osr_entry_(NULL),
osr_loop_entry_(NULL),
osr_values_(NULL) { }
+
// Creates the loop entry block for the given statement, setting up OSR
// entries as necessary, and sets the current block to the new block.
- HBasicBlock* BuildPossibleOsrLoopEntry(IterationStatement* statement);
+ HBasicBlock* BuildOsrLoopEntry(IterationStatement* statement);
// Process the hydrogen graph after it has been completed, performing
// any OSR-specific cleanups or changes.
@@ -61,10 +62,9 @@
return unoptimized_frame_slots_;
}
- private:
- HBasicBlock* BuildLoopEntry();
bool HasOsrEntryAt(IterationStatement* statement);
+ private:
int unoptimized_frame_slots_;
HOptimizedGraphBuilder* builder_;
HBasicBlock* osr_entry_;
diff --git a/src/hydrogen.cc b/src/hydrogen.cc
index 57ea173..8681026 100644
--- a/src/hydrogen.cc
+++ b/src/hydrogen.cc
@@ -2246,6 +2246,24 @@
}
+// Build a new loop header block and set it as the current block.
+HBasicBlock* HOptimizedGraphBuilder::BuildLoopEntry() {
+ HBasicBlock* loop_entry = CreateLoopHeaderBlock();
+ current_block()->Goto(loop_entry);
+ set_current_block(loop_entry);
+ return loop_entry;
+}
+
+
+HBasicBlock* HOptimizedGraphBuilder::BuildLoopEntry(
+ IterationStatement* statement) {
+ HBasicBlock* loop_entry = osr()->HasOsrEntryAt(statement)
+ ? osr()->BuildOsrLoopEntry(statement)
+ : BuildLoopEntry();
+ return loop_entry;
+}
+
+
void HBasicBlock::FinishExit(HControlInstruction* instruction) {
Finish(instruction);
ClearEnvironment();
@@ -3087,7 +3105,7 @@
type_info->set_inlined_type_change_checksum(composite_checksum);
// Perform any necessary OSR-specific cleanups or changes to the graph.
- osr_->FinishGraph();
+ osr()->FinishGraph();
return true;
}
@@ -3670,7 +3688,7 @@
ASSERT(current_block() != NULL);
ASSERT(current_block()->HasPredecessor());
ASSERT(current_block() != NULL);
- HBasicBlock* loop_entry = osr_->BuildPossibleOsrLoopEntry(stmt);
+ HBasicBlock* loop_entry = BuildLoopEntry(stmt);
BreakAndContinueInfo break_info(stmt);
CHECK_BAILOUT(VisitLoopBody(stmt, loop_entry, &break_info));
@@ -3709,7 +3727,7 @@
ASSERT(current_block() != NULL);
ASSERT(current_block()->HasPredecessor());
ASSERT(current_block() != NULL);
- HBasicBlock* loop_entry = osr_->BuildPossibleOsrLoopEntry(stmt);
+ HBasicBlock* loop_entry = BuildLoopEntry(stmt);
// If the condition is constant true, do not generate a branch.
HBasicBlock* loop_successor = NULL;
@@ -3751,7 +3769,7 @@
CHECK_ALIVE(Visit(stmt->init()));
}
ASSERT(current_block() != NULL);
- HBasicBlock* loop_entry = osr_->BuildPossibleOsrLoopEntry(stmt);
+ HBasicBlock* loop_entry = BuildLoopEntry(stmt);
HBasicBlock* loop_successor = NULL;
if (stmt->cond() != NULL) {
@@ -3834,7 +3852,7 @@
HForInCacheArray::cast(array)->set_index_cache(
HForInCacheArray::cast(index_cache));
- HBasicBlock* loop_entry = osr_->BuildPossibleOsrLoopEntry(stmt);
+ HBasicBlock* loop_entry = BuildLoopEntry(stmt);
HValue* index = environment()->ExpressionStackAt(0);
HValue* limit = environment()->ExpressionStackAt(1);
@@ -5473,6 +5491,14 @@
HThrow* instr = Add<HThrow>(value);
instr->set_position(expr->position());
Add<HSimulate>(expr->id());
+
+ // If the throw definitely exits the function, we can finish with a dummy
+ // control flow at this point. This is not the case if the throw is inside
+ // an inlined function which may be replaced.
+ if (call_context() == NULL) {
+ current_block()->FinishExit(new(zone()) HAbnormalExit);
+ set_current_block(NULL);
+ }
}
diff --git a/src/hydrogen.h b/src/hydrogen.h
index be23fa8..9b998c9 100644
--- a/src/hydrogen.h
+++ b/src/hydrogen.h
@@ -1781,6 +1781,8 @@
HValue* context() { return environment()->context(); }
+ HOsrBuilder* osr() const { return osr_; }
+
void Bailout(BailoutReason reason);
HBasicBlock* CreateJoin(HBasicBlock* first,
@@ -1886,6 +1888,12 @@
HBasicBlock* loop_successor,
HBasicBlock* break_block);
+ // Build a loop entry
+ HBasicBlock* BuildLoopEntry();
+
+ // Builds a loop entry respectful of OSR requirements
+ HBasicBlock* BuildLoopEntry(IterationStatement* statement);
+
HBasicBlock* JoinContinue(IterationStatement* statement,
HBasicBlock* exit_block,
HBasicBlock* continue_block);
diff --git a/src/ia32/lithium-codegen-ia32.cc b/src/ia32/lithium-codegen-ia32.cc
index 86ac466..385ad2c 100644
--- a/src/ia32/lithium-codegen-ia32.cc
+++ b/src/ia32/lithium-codegen-ia32.cc
@@ -5741,6 +5741,7 @@
ASSERT(instr->unclamped()->Equals(instr->result()));
Register input_reg = ToRegister(instr->unclamped());
+ XMMRegister temp_xmm_reg = ToDoubleRegister(instr->temp_xmm());
XMMRegister xmm_scratch = double_scratch0();
Label is_smi, done, heap_number;
@@ -5761,7 +5762,7 @@
// Heap number
__ bind(&heap_number);
__ movdbl(xmm_scratch, FieldOperand(input_reg, HeapNumber::kValueOffset));
- __ ClampDoubleToUint8(xmm_scratch, xmm1, input_reg);
+ __ ClampDoubleToUint8(xmm_scratch, temp_xmm_reg, input_reg);
__ jmp(&done, Label::kNear);
// smi
diff --git a/src/ia32/lithium-ia32.cc b/src/ia32/lithium-ia32.cc
index c73d073..bfcbfb9 100644
--- a/src/ia32/lithium-ia32.cc
+++ b/src/ia32/lithium-ia32.cc
@@ -386,9 +386,9 @@
}
-int LPlatformChunk::GetNextSpillIndex(bool is_double) {
+int LPlatformChunk::GetNextSpillIndex(RegisterKind kind) {
// Skip a slot if for a double-width slot.
- if (is_double) {
+ if (kind == DOUBLE_REGISTERS) {
spill_slot_count_++;
spill_slot_count_ |= 1;
num_double_slots_++;
@@ -397,11 +397,12 @@
}
-LOperand* LPlatformChunk::GetNextSpillSlot(bool is_double) {
- int index = GetNextSpillIndex(is_double);
- if (is_double) {
+LOperand* LPlatformChunk::GetNextSpillSlot(RegisterKind kind) {
+ int index = GetNextSpillIndex(kind);
+ if (kind == DOUBLE_REGISTERS) {
return LDoubleStackSlot::Create(index, zone());
} else {
+ ASSERT(kind == GENERAL_REGISTERS);
return LStackSlot::Create(index, zone());
}
}
@@ -479,7 +480,7 @@
// Reserve the first spill slot for the state of dynamic alignment.
if (info()->IsOptimizing()) {
- int alignment_state_index = chunk_->GetNextSpillIndex(false);
+ int alignment_state_index = chunk_->GetNextSpillIndex(GENERAL_REGISTERS);
ASSERT_EQ(alignment_state_index, 0);
USE(alignment_state_index);
}
@@ -488,7 +489,7 @@
// which will be subsumed into this frame.
if (graph()->has_osr()) {
for (int i = graph()->osr()->UnoptimizedFrameSlots(); i > 0; i--) {
- chunk_->GetNextSpillIndex(false);
+ chunk_->GetNextSpillIndex(GENERAL_REGISTERS);
}
}
@@ -1883,6 +1884,13 @@
}
+LInstruction* LChunkBuilder::DoAbnormalExit(HAbnormalExit* instr) {
+ // The control instruction marking the end of a block that completed
+ // abruptly (e.g., threw an exception). There is nothing specific to do.
+ return NULL;
+}
+
+
LInstruction* LChunkBuilder::DoThrow(HThrow* instr) {
LOperand* context = UseFixed(instr->context(), esi);
LOperand* value = UseFixed(instr->value(), eax);
diff --git a/src/ia32/lithium-ia32.h b/src/ia32/lithium-ia32.h
index 379d64b..27d432f 100644
--- a/src/ia32/lithium-ia32.h
+++ b/src/ia32/lithium-ia32.h
@@ -2508,12 +2508,13 @@
class LClampTToUint8 V8_FINAL : public LTemplateInstruction<1, 1, 1> {
public:
- LClampTToUint8(LOperand* value, LOperand* temp) {
+ LClampTToUint8(LOperand* value, LOperand* temp_xmm) {
inputs_[0] = value;
- temps_[0] = temp;
+ temps_[0] = temp_xmm;
}
LOperand* unclamped() { return inputs_[0]; }
+ LOperand* temp_xmm() { return temps_[0]; }
DECLARE_CONCRETE_INSTRUCTION(ClampTToUint8, "clamp-t-to-uint8")
};
@@ -2735,8 +2736,8 @@
: LChunk(info, graph),
num_double_slots_(0) { }
- int GetNextSpillIndex(bool is_double);
- LOperand* GetNextSpillSlot(bool is_double);
+ int GetNextSpillIndex(RegisterKind kind);
+ LOperand* GetNextSpillSlot(RegisterKind kind);
int num_double_slots() const { return num_double_slots_; }
diff --git a/src/isolate.cc b/src/isolate.cc
index 3e5d2b9..de67a1c 100644
--- a/src/isolate.cc
+++ b/src/isolate.cc
@@ -1929,7 +1929,7 @@
deoptimizer_data_ = NULL;
if (FLAG_preemption) {
v8::Locker locker(reinterpret_cast<v8::Isolate*>(this));
- v8::Locker::StopPreemption();
+ v8::Locker::StopPreemption(reinterpret_cast<v8::Isolate*>(this));
}
builtins_.TearDown();
bootstrapper_->TearDown();
@@ -2271,7 +2271,7 @@
if (FLAG_preemption) {
v8::Locker locker(reinterpret_cast<v8::Isolate*>(this));
- v8::Locker::StartPreemption(100);
+ v8::Locker::StartPreemption(reinterpret_cast<v8::Isolate*>(this), 100);
}
#ifdef ENABLE_DEBUGGER_SUPPORT
diff --git a/src/lithium-allocator-inl.h b/src/lithium-allocator-inl.h
index 8cca19b..deee988 100644
--- a/src/lithium-allocator-inl.h
+++ b/src/lithium-allocator-inl.h
@@ -145,16 +145,14 @@
}
-void LAllocator::SetLiveRangeAssignedRegister(
- LiveRange* range,
- int reg,
- RegisterKind register_kind) {
- if (register_kind == DOUBLE_REGISTERS) {
+void LAllocator::SetLiveRangeAssignedRegister(LiveRange* range, int reg) {
+ if (range->Kind() == DOUBLE_REGISTERS) {
assigned_double_registers_->Add(reg);
} else {
+ ASSERT(range->Kind() == GENERAL_REGISTERS);
assigned_registers_->Add(reg);
}
- range->set_assigned_register(reg, register_kind, chunk()->zone());
+ range->set_assigned_register(reg, chunk()->zone());
}
diff --git a/src/lithium-allocator.cc b/src/lithium-allocator.cc
index 3c5abd1..29c3194 100644
--- a/src/lithium-allocator.cc
+++ b/src/lithium-allocator.cc
@@ -131,7 +131,7 @@
LiveRange::LiveRange(int id, Zone* zone)
: id_(id),
spilled_(false),
- is_double_(false),
+ kind_(UNALLOCATED_REGISTERS),
assigned_register_(kInvalidAssignment),
last_interval_(NULL),
first_interval_(NULL),
@@ -145,12 +145,9 @@
spill_start_index_(kMaxInt) { }
-void LiveRange::set_assigned_register(int reg,
- RegisterKind register_kind,
- Zone* zone) {
+void LiveRange::set_assigned_register(int reg, Zone* zone) {
ASSERT(!HasRegisterAssigned() && !IsSpilled());
assigned_register_ = reg;
- is_double_ = (register_kind == DOUBLE_REGISTERS);
ConvertOperands(zone);
}
@@ -234,10 +231,15 @@
LOperand* op = NULL;
if (HasRegisterAssigned()) {
ASSERT(!IsSpilled());
- if (IsDouble()) {
- op = LDoubleRegister::Create(assigned_register(), zone);
- } else {
- op = LRegister::Create(assigned_register(), zone);
+ switch (Kind()) {
+ case GENERAL_REGISTERS:
+ op = LRegister::Create(assigned_register(), zone);
+ break;
+ case DOUBLE_REGISTERS:
+ op = LDoubleRegister::Create(assigned_register(), zone);
+ break;
+ default:
+ UNREACHABLE();
}
} else if (IsSpilled()) {
ASSERT(!HasRegisterAssigned());
@@ -352,6 +354,7 @@
// Link the new live range in the chain before any of the other
// ranges linked from the range before the split.
result->parent_ = (parent_ == NULL) ? this : parent_;
+ result->kind_ = result->parent_->kind_;
result->next_ = next_;
next_ = result;
@@ -553,7 +556,7 @@
reusable_slots_(8, zone()),
next_virtual_register_(num_values),
first_artificial_register_(num_values),
- mode_(GENERAL_REGISTERS),
+ mode_(UNALLOCATED_REGISTERS),
num_registers_(-1),
graph_(graph),
has_osr_entry_(false),
@@ -653,7 +656,8 @@
if (result == NULL) {
result = new(zone()) LiveRange(FixedLiveRangeID(index), chunk()->zone());
ASSERT(result->IsFixed());
- SetLiveRangeAssignedRegister(result, index, GENERAL_REGISTERS);
+ result->kind_ = GENERAL_REGISTERS;
+ SetLiveRangeAssignedRegister(result, index);
fixed_live_ranges_[index] = result;
}
return result;
@@ -667,7 +671,8 @@
result = new(zone()) LiveRange(FixedDoubleLiveRangeID(index),
chunk()->zone());
ASSERT(result->IsFixed());
- SetLiveRangeAssignedRegister(result, index, DOUBLE_REGISTERS);
+ result->kind_ = DOUBLE_REGISTERS;
+ SetLiveRangeAssignedRegister(result, index);
fixed_double_live_ranges_[index] = result;
}
return result;
@@ -1375,6 +1380,12 @@
}
#endif
}
+
+ for (int i = 0; i < live_ranges_.length(); ++i) {
+ if (live_ranges_[i] != NULL) {
+ live_ranges_[i]->kind_ = RequiredRegisterKind(live_ranges_[i]->id());
+ }
+ }
}
@@ -1481,6 +1492,7 @@
void LAllocator::AllocateGeneralRegisters() {
LAllocatorPhase phase("L_Allocate general registers", this);
num_registers_ = Register::NumAllocatableRegisters();
+ mode_ = GENERAL_REGISTERS;
AllocateRegisters();
}
@@ -1498,7 +1510,7 @@
for (int i = 0; i < live_ranges_.length(); ++i) {
if (live_ranges_[i] != NULL) {
- if (RequiredRegisterKind(live_ranges_[i]->id()) == mode_) {
+ if (live_ranges_[i]->Kind() == mode_) {
AddToUnhandledUnsorted(live_ranges_[i]);
}
}
@@ -1518,6 +1530,7 @@
}
}
} else {
+ ASSERT(mode_ == GENERAL_REGISTERS);
for (int i = 0; i < fixed_live_ranges_.length(); ++i) {
LiveRange* current = fixed_live_ranges_.at(i);
if (current != NULL) {
@@ -1812,7 +1825,7 @@
TraceAlloc("Assigning preferred reg %s to live range %d\n",
RegisterName(register_index),
current->id());
- SetLiveRangeAssignedRegister(current, register_index, mode_);
+ SetLiveRangeAssignedRegister(current, register_index);
return true;
}
}
@@ -1847,7 +1860,7 @@
TraceAlloc("Assigning free reg %s to live range %d\n",
RegisterName(reg),
current->id());
- SetLiveRangeAssignedRegister(current, reg, mode_);
+ SetLiveRangeAssignedRegister(current, reg);
return true;
}
@@ -1932,7 +1945,7 @@
TraceAlloc("Assigning blocked reg %s to live range %d\n",
RegisterName(reg),
current->id());
- SetLiveRangeAssignedRegister(current, reg, mode_);
+ SetLiveRangeAssignedRegister(current, reg);
// This register was not free. Thus we need to find and spill
// parts of active and inactive live regions that use the same register
@@ -2149,7 +2162,7 @@
if (!first->HasAllocatedSpillOperand()) {
LOperand* op = TryReuseSpillSlot(range);
- if (op == NULL) op = chunk_->GetNextSpillSlot(mode_ == DOUBLE_REGISTERS);
+ if (op == NULL) op = chunk_->GetNextSpillSlot(range->Kind());
first->SetSpillOperand(op);
}
range->MakeSpilled(chunk()->zone());
diff --git a/src/lithium-allocator.h b/src/lithium-allocator.h
index e5edd3c..9908ea8 100644
--- a/src/lithium-allocator.h
+++ b/src/lithium-allocator.h
@@ -146,6 +146,7 @@
enum RegisterKind {
+ UNALLOCATED_REGISTERS,
GENERAL_REGISTERS,
DOUBLE_REGISTERS
};
@@ -290,9 +291,7 @@
LOperand* CreateAssignedOperand(Zone* zone);
int assigned_register() const { return assigned_register_; }
int spill_start_index() const { return spill_start_index_; }
- void set_assigned_register(int reg,
- RegisterKind register_kind,
- Zone* zone);
+ void set_assigned_register(int reg, Zone* zone);
void MakeSpilled(Zone* zone);
// Returns use position in this live range that follows both start
@@ -323,7 +322,7 @@
// live range to the result live range.
void SplitAt(LifetimePosition position, LiveRange* result, Zone* zone);
- bool IsDouble() const { return is_double_; }
+ RegisterKind Kind() const { return kind_; }
bool HasRegisterAssigned() const {
return assigned_register_ != kInvalidAssignment;
}
@@ -392,7 +391,7 @@
int id_;
bool spilled_;
- bool is_double_;
+ RegisterKind kind_;
int assigned_register_;
UseInterval* last_interval_;
UseInterval* first_interval_;
@@ -406,6 +405,8 @@
LOperand* current_hint_operand_;
LOperand* spill_operand_;
int spill_start_index_;
+
+ friend class LAllocator; // Assigns to kind_.
};
@@ -568,9 +569,7 @@
HBasicBlock* block,
HBasicBlock* pred);
- inline void SetLiveRangeAssignedRegister(LiveRange* range,
- int reg,
- RegisterKind register_kind);
+ inline void SetLiveRangeAssignedRegister(LiveRange* range, int reg);
// Return parallel move that should be used to connect ranges split at the
// given position.
diff --git a/src/mips/lithium-codegen-mips.cc b/src/mips/lithium-codegen-mips.cc
index c869184..97dcd16 100644
--- a/src/mips/lithium-codegen-mips.cc
+++ b/src/mips/lithium-codegen-mips.cc
@@ -1403,11 +1403,11 @@
Register left = ToRegister(instr->left());
LOperand* right_op = instr->right();
- bool can_overflow = instr->hydrogen()->CheckFlag(HValue::kCanOverflow);
bool bailout_on_minus_zero =
instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero);
+ bool overflow = instr->hydrogen()->CheckFlag(HValue::kCanOverflow);
- if (right_op->IsConstantOperand() && !can_overflow) {
+ if (right_op->IsConstantOperand()) {
int32_t constant = ToInteger32(LConstantOperand::cast(right_op));
if (bailout_on_minus_zero && (constant < 0)) {
@@ -1418,7 +1418,12 @@
switch (constant) {
case -1:
- __ Subu(result, zero_reg, left);
+ if (overflow) {
+ __ SubuAndCheckForOverflow(result, zero_reg, left, scratch);
+ DeoptimizeIf(lt, instr->environment(), scratch, Operand(zero_reg));
+ } else {
+ __ Subu(result, zero_reg, left);
+ }
break;
case 0:
if (bailout_on_minus_zero) {
@@ -1439,27 +1444,23 @@
int32_t mask = constant >> 31;
uint32_t constant_abs = (constant + mask) ^ mask;
- if (IsPowerOf2(constant_abs) ||
- IsPowerOf2(constant_abs - 1) ||
- IsPowerOf2(constant_abs + 1)) {
- if (IsPowerOf2(constant_abs)) {
- int32_t shift = WhichPowerOf2(constant_abs);
- __ sll(result, left, shift);
- } else if (IsPowerOf2(constant_abs - 1)) {
- int32_t shift = WhichPowerOf2(constant_abs - 1);
- __ sll(scratch, left, shift);
- __ Addu(result, scratch, left);
- } else if (IsPowerOf2(constant_abs + 1)) {
- int32_t shift = WhichPowerOf2(constant_abs + 1);
- __ sll(scratch, left, shift);
- __ Subu(result, scratch, left);
- }
-
- // Correct the sign of the result is the constant is negative.
- if (constant < 0) {
- __ Subu(result, zero_reg, result);
- }
-
+ if (IsPowerOf2(constant_abs)) {
+ int32_t shift = WhichPowerOf2(constant_abs);
+ __ sll(result, left, shift);
+ // Correct the sign of the result if the constant is negative.
+ if (constant < 0) __ Subu(result, zero_reg, result);
+ } else if (IsPowerOf2(constant_abs - 1)) {
+ int32_t shift = WhichPowerOf2(constant_abs - 1);
+ __ sll(scratch, left, shift);
+ __ Addu(result, scratch, left);
+ // Correct the sign of the result if the constant is negative.
+ if (constant < 0) __ Subu(result, zero_reg, result);
+ } else if (IsPowerOf2(constant_abs + 1)) {
+ int32_t shift = WhichPowerOf2(constant_abs + 1);
+ __ sll(scratch, left, shift);
+ __ Subu(result, scratch, left);
+ // Correct the sign of the result if the constant is negative.
+ if (constant < 0) __ Subu(result, zero_reg, result);
} else {
// Generate standard code.
__ li(at, constant);
@@ -1468,12 +1469,10 @@
}
} else {
- Register right = EmitLoadRegister(right_op, scratch);
- if (bailout_on_minus_zero) {
- __ Or(ToRegister(instr->temp()), left, right);
- }
+ ASSERT(right_op->IsRegister());
+ Register right = ToRegister(right_op);
- if (can_overflow) {
+ if (overflow) {
// hi:lo = left * right.
if (instr->hydrogen()->representation().IsSmi()) {
__ SmiUntag(result, left);
@@ -1497,12 +1496,13 @@
}
if (bailout_on_minus_zero) {
- // Bail out if the result is supposed to be negative zero.
Label done;
- __ Branch(&done, ne, result, Operand(zero_reg));
- DeoptimizeIf(lt,
+ __ Xor(at, left, right);
+ __ Branch(&done, ge, at, Operand(zero_reg));
+ // Bail out if the result is minus zero.
+ DeoptimizeIf(eq,
instr->environment(),
- ToRegister(instr->temp()),
+ result,
Operand(zero_reg));
__ bind(&done);
}
diff --git a/src/mips/lithium-mips.cc b/src/mips/lithium-mips.cc
index 730c1d0..8a34912 100644
--- a/src/mips/lithium-mips.cc
+++ b/src/mips/lithium-mips.cc
@@ -417,18 +417,19 @@
}
-int LPlatformChunk::GetNextSpillIndex(bool is_double) {
+int LPlatformChunk::GetNextSpillIndex(RegisterKind kind) {
// Skip a slot if for a double-width slot.
- if (is_double) spill_slot_count_++;
+ if (kind == DOUBLE_REGISTERS) spill_slot_count_++;
return spill_slot_count_++;
}
-LOperand* LPlatformChunk::GetNextSpillSlot(bool is_double) {
- int index = GetNextSpillIndex(is_double);
- if (is_double) {
+LOperand* LPlatformChunk::GetNextSpillSlot(RegisterKind kind) {
+ int index = GetNextSpillIndex(kind);
+ if (kind == DOUBLE_REGISTERS) {
return LDoubleStackSlot::Create(index, zone());
} else {
+ ASSERT(kind == GENERAL_REGISTERS);
return LStackSlot::Create(index, zone());
}
}
@@ -444,7 +445,7 @@
// which will be subsumed into this frame.
if (graph()->has_osr()) {
for (int i = graph()->osr()->UnoptimizedFrameSlots(); i > 0; i--) {
- chunk_->GetNextSpillIndex(false);
+ chunk_->GetNextSpillIndex(GENERAL_REGISTERS);
}
}
@@ -1469,20 +1470,39 @@
if (instr->representation().IsSmiOrInteger32()) {
ASSERT(instr->left()->representation().Equals(instr->representation()));
ASSERT(instr->right()->representation().Equals(instr->representation()));
- LOperand* left;
- LOperand* right = UseOrConstant(instr->BetterRightOperand());
- LOperand* temp = NULL;
- if (instr->CheckFlag(HValue::kBailoutOnMinusZero) &&
- (instr->CheckFlag(HValue::kCanOverflow) ||
- !right->IsConstantOperand())) {
- left = UseRegister(instr->BetterLeftOperand());
- temp = TempRegister();
+ HValue* left = instr->BetterLeftOperand();
+ HValue* right = instr->BetterRightOperand();
+ LOperand* left_op;
+ LOperand* right_op;
+ bool can_overflow = instr->CheckFlag(HValue::kCanOverflow);
+ bool bailout_on_minus_zero = instr->CheckFlag(HValue::kBailoutOnMinusZero);
+
+ if (right->IsConstant()) {
+ HConstant* constant = HConstant::cast(right);
+ int32_t constant_value = constant->Integer32Value();
+ // Constants -1, 0 and 1 can be optimized if the result can overflow.
+ // For other constants, it can be optimized only without overflow.
+ if (!can_overflow || ((constant_value >= -1) && (constant_value <= 1))) {
+ left_op = UseRegisterAtStart(left);
+ right_op = UseConstant(right);
+ } else {
+ if (bailout_on_minus_zero) {
+ left_op = UseRegister(left);
+ } else {
+ left_op = UseRegisterAtStart(left);
+ }
+ right_op = UseRegister(right);
+ }
} else {
- left = UseRegisterAtStart(instr->BetterLeftOperand());
+ if (bailout_on_minus_zero) {
+ left_op = UseRegister(left);
+ } else {
+ left_op = UseRegisterAtStart(left);
+ }
+ right_op = UseRegister(right);
}
- LMulI* mul = new(zone()) LMulI(left, right, temp);
- if (instr->CheckFlag(HValue::kCanOverflow) ||
- instr->CheckFlag(HValue::kBailoutOnMinusZero)) {
+ LMulI* mul = new(zone()) LMulI(left_op, right_op);
+ if (can_overflow || bailout_on_minus_zero) {
AssignEnvironment(mul);
}
return DefineAsRegister(mul);
@@ -1786,6 +1806,13 @@
}
+LInstruction* LChunkBuilder::DoAbnormalExit(HAbnormalExit* instr) {
+ // The control instruction marking the end of a block that completed
+ // abruptly (e.g., threw an exception). There is nothing specific to do.
+ return NULL;
+}
+
+
LInstruction* LChunkBuilder::DoThrow(HThrow* instr) {
LOperand* value = UseFixed(instr->value(), a0);
return MarkAsCall(new(zone()) LThrow(value), instr);
diff --git a/src/mips/lithium-mips.h b/src/mips/lithium-mips.h
index a8ca620..a48422e 100644
--- a/src/mips/lithium-mips.h
+++ b/src/mips/lithium-mips.h
@@ -688,17 +688,15 @@
};
-class LMulI V8_FINAL : public LTemplateInstruction<1, 2, 1> {
+class LMulI V8_FINAL : public LTemplateInstruction<1, 2, 0> {
public:
- LMulI(LOperand* left, LOperand* right, LOperand* temp) {
+ LMulI(LOperand* left, LOperand* right) {
inputs_[0] = left;
inputs_[1] = right;
- temps_[0] = temp;
}
LOperand* left() { return inputs_[0]; }
LOperand* right() { return inputs_[1]; }
- LOperand* temp() { return temps_[0]; }
DECLARE_CONCRETE_INSTRUCTION(MulI, "mul-i")
DECLARE_HYDROGEN_ACCESSOR(Mul)
@@ -2594,8 +2592,8 @@
LPlatformChunk(CompilationInfo* info, HGraph* graph)
: LChunk(info, graph) { }
- int GetNextSpillIndex(bool is_double);
- LOperand* GetNextSpillSlot(bool is_double);
+ int GetNextSpillIndex(RegisterKind kind);
+ LOperand* GetNextSpillSlot(RegisterKind kind);
};
diff --git a/src/mips/simulator-mips.cc b/src/mips/simulator-mips.cc
index ea8b659..5a96efe 100644
--- a/src/mips/simulator-mips.cc
+++ b/src/mips/simulator-mips.cc
@@ -2274,9 +2274,13 @@
break;
case DIV:
// Divide by zero and overflow was not checked in the configuration
- // step - div and divu do not raise exceptions. On division by 0 and
- // on overflow (INT_MIN/-1), the result will be UNPREDICTABLE.
- if (rt != 0 && !(rs == INT_MIN && rt == -1)) {
+ // step - div and divu do not raise exceptions. On division by 0
+ // the result will be UNPREDICTABLE. On overflow (INT_MIN/-1),
+ // return INT_MIN which is what the hardware does.
+ if (rs == INT_MIN && rt == -1) {
+ set_register(LO, INT_MIN);
+ set_register(HI, 0);
+ } else if (rt != 0) {
set_register(LO, rs / rt);
set_register(HI, rs % rt);
}
diff --git a/src/objects.cc b/src/objects.cc
index 1399e33..6ca8bdf 100644
--- a/src/objects.cc
+++ b/src/objects.cc
@@ -5583,7 +5583,53 @@
}
-Handle<JSObject> JSObject::DeepCopy(Handle<JSObject> object) {
+class JSObjectWalkVisitor {
+ public:
+ explicit JSObjectWalkVisitor() {}
+ virtual ~JSObjectWalkVisitor() {}
+
+ Handle<JSObject> Visit(Handle<JSObject> object) {
+ return StructureWalk(object);
+ }
+
+ // Returns true if the visitor is a copying visitor.
+ virtual bool is_copying() = 0;
+
+ protected:
+ Handle<JSObject> StructureWalk(Handle<JSObject> object);
+
+ // The returned handle should point to a new object if the visitor is a
+ // copying visitor, otherwise it should be the same as the input object.
+ virtual Handle<JSObject> VisitObject(Handle<JSObject> object) = 0;
+
+ // The returned handle should point to a new value if the visitor is a
+ // copying visitor, otherwise it should be the same as the input value.
+ virtual Handle<JSObject> VisitElementOrProperty(Handle<JSObject> object,
+ Handle<JSObject> value) = 0;
+};
+
+
+class JSObjectCopyVisitor: public JSObjectWalkVisitor {
+ public:
+ explicit JSObjectCopyVisitor() {}
+
+ virtual bool is_copying() V8_OVERRIDE { return true; }
+
+ protected:
+ virtual Handle<JSObject> VisitObject(Handle<JSObject> object) V8_OVERRIDE {
+ return JSObject::Copy(object);
+ }
+
+ virtual Handle<JSObject> VisitElementOrProperty(
+ Handle<JSObject> object,
+ Handle<JSObject> value) V8_OVERRIDE {
+ return StructureWalk(value);
+ }
+};
+
+
+Handle<JSObject> JSObjectWalkVisitor::StructureWalk(Handle<JSObject> object) {
+ bool copying = is_copying();
Isolate* isolate = object->GetIsolate();
StackLimitCheck check(isolate);
if (check.HasOverflowed()) {
@@ -5592,10 +5638,11 @@
}
if (object->map()->is_deprecated()) {
- MigrateInstance(object);
+ JSObject::MigrateInstance(object);
}
- Handle<JSObject> copy = Copy(object);
+ Handle<JSObject> copy = VisitObject(object);
+ ASSERT(copying || copy.is_identical_to(object));
HandleScope scope(isolate);
@@ -5609,13 +5656,15 @@
int index = descriptors->GetFieldIndex(i);
Handle<Object> value(object->RawFastPropertyAt(index), isolate);
if (value->IsJSObject()) {
- value = DeepCopy(Handle<JSObject>::cast(value));
+ value = VisitElementOrProperty(copy, Handle<JSObject>::cast(value));
RETURN_IF_EMPTY_HANDLE_VALUE(isolate, value, Handle<JSObject>());
} else {
Representation representation = details.representation();
value = NewStorageFor(isolate, value, representation);
}
- copy->FastPropertyAtPut(index, *value);
+ if (copying) {
+ copy->FastPropertyAtPut(index, *value);
+ }
}
} else {
Handle<FixedArray> names =
@@ -5634,11 +5683,14 @@
copy->GetProperty(*key_string, &attributes)->ToObjectUnchecked(),
isolate);
if (value->IsJSObject()) {
- Handle<Object> result = DeepCopy(Handle<JSObject>::cast(value));
+ Handle<JSObject> result = VisitElementOrProperty(
+ copy, Handle<JSObject>::cast(value));
RETURN_IF_EMPTY_HANDLE_VALUE(isolate, result, Handle<JSObject>());
- // Creating object copy for literals. No strict mode needed.
- CHECK_NOT_EMPTY_HANDLE(isolate, SetProperty(
- copy, key_string, result, NONE, kNonStrictMode));
+ if (copying) {
+ // Creating object copy for literals. No strict mode needed.
+ CHECK_NOT_EMPTY_HANDLE(isolate, JSObject::SetProperty(
+ copy, key_string, result, NONE, kNonStrictMode));
+ }
}
}
}
@@ -5666,9 +5718,12 @@
value->IsTheHole() ||
(IsFastObjectElementsKind(copy->GetElementsKind())));
if (value->IsJSObject()) {
- Handle<Object> result = DeepCopy(Handle<JSObject>::cast(value));
+ Handle<JSObject> result = VisitElementOrProperty(
+ copy, Handle<JSObject>::cast(value));
RETURN_IF_EMPTY_HANDLE_VALUE(isolate, result, Handle<JSObject>());
- elements->set(i, *result);
+ if (copying) {
+ elements->set(i, *result);
+ }
}
}
}
@@ -5683,9 +5738,12 @@
if (element_dictionary->IsKey(k)) {
Handle<Object> value(element_dictionary->ValueAt(i), isolate);
if (value->IsJSObject()) {
- Handle<Object> result = DeepCopy(Handle<JSObject>::cast(value));
+ Handle<JSObject> result = VisitElementOrProperty(
+ copy, Handle<JSObject>::cast(value));
RETURN_IF_EMPTY_HANDLE_VALUE(isolate, result, Handle<JSObject>());
- element_dictionary->ValueAtPut(i, *result);
+ if (copying) {
+ element_dictionary->ValueAtPut(i, *result);
+ }
}
}
}
@@ -5712,6 +5770,14 @@
}
+Handle<JSObject> JSObject::DeepCopy(Handle<JSObject> object) {
+ JSObjectCopyVisitor v;
+ Handle<JSObject> copy = v.Visit(object);
+ ASSERT(v.is_copying() && !copy.is_identical_to(object));
+ return copy;
+}
+
+
// Tests for the fast common case for property enumeration:
// - This object and all prototypes has an enum cache (which means that
// it is no proxy, has no interceptors and needs no access checks).
diff --git a/src/optimizing-compiler-thread.cc b/src/optimizing-compiler-thread.cc
index e6467f1..202e6e5 100644
--- a/src/optimizing-compiler-thread.cc
+++ b/src/optimizing-compiler-thread.cc
@@ -108,19 +108,22 @@
// The function may have already been optimized by OSR. Simply continue.
// Use a mutex to make sure that functions marked for install
// are always also queued.
- LockGuard<Mutex> access_queue(&queue_mutex_);
output_queue_.Enqueue(job);
isolate_->stack_guard()->RequestInstallCode();
}
-static void DisposeRecompileJob(RecompileJob* compiler,
+static void DisposeRecompileJob(RecompileJob* job,
bool restore_function_code) {
// The recompile job is allocated in the CompilationInfo's zone.
- CompilationInfo* info = compiler->info();
+ CompilationInfo* info = job->info();
if (restore_function_code) {
- Handle<JSFunction> function = info->closure();
- function->ReplaceCode(function->shared()->code());
+ if (info->is_osr()) {
+ if (!job->IsWaitingForInstall()) BackEdgeTable::RemoveStackCheck(info);
+ } else {
+ Handle<JSFunction> function = info->closure();
+ function->ReplaceCode(function->shared()->code());
+ }
}
delete info;
}
@@ -132,8 +135,8 @@
// This should not block, since we have one signal on the input queue
// semaphore corresponding to each element in the input queue.
input_queue_semaphore_.Wait();
- if (job->info()->osr_ast_id().IsNone()) {
- // OSR jobs are dealt with separately.
+ // OSR jobs are dealt with separately.
+ if (!job->info()->is_osr()) {
DisposeRecompileJob(job, restore_function_code);
}
}
@@ -143,12 +146,9 @@
void OptimizingCompilerThread::FlushOutputQueue(bool restore_function_code) {
RecompileJob* job;
- while (true) {
- { LockGuard<Mutex> access_queue(&queue_mutex_);
- if (!output_queue_.Dequeue(&job)) break;
- }
- if (job->info()->osr_ast_id().IsNone()) {
- // OSR jobs are dealt with separately.
+ while (output_queue_.Dequeue(&job)) {
+ // OSR jobs are dealt with separately.
+ if (!job->info()->is_osr()) {
DisposeRecompileJob(job, restore_function_code);
}
}
@@ -216,14 +216,9 @@
HandleScope handle_scope(isolate_);
RecompileJob* job;
- while (true) {
- { LockGuard<Mutex> access_queue(&queue_mutex_);
- if (!output_queue_.Dequeue(&job)) break;
- }
+ while (output_queue_.Dequeue(&job)) {
CompilationInfo* info = job->info();
- if (info->osr_ast_id().IsNone()) {
- Compiler::InstallOptimizedCode(job);
- } else {
+ if (info->is_osr()) {
if (FLAG_trace_osr) {
PrintF("[COSR - ");
info->closure()->PrintName();
@@ -232,6 +227,8 @@
}
job->WaitForInstall();
BackEdgeTable::RemoveStackCheck(info);
+ } else {
+ Compiler::InstallOptimizedCode(job);
}
}
}
@@ -242,9 +239,7 @@
ASSERT(!IsOptimizerThread());
Barrier_AtomicIncrement(&queue_length_, static_cast<Atomic32>(1));
CompilationInfo* info = job->info();
- if (info->osr_ast_id().IsNone()) {
- info->closure()->MarkInRecompileQueue();
- } else {
+ if (info->is_osr()) {
if (FLAG_trace_concurrent_recompilation) {
PrintF(" ** Queueing ");
info->closure()->PrintName();
@@ -253,6 +248,8 @@
AddToOsrBuffer(job);
osr_attempts_++;
BackEdgeTable::AddStackCheck(info);
+ } else {
+ info->closure()->MarkInRecompileQueue();
}
input_queue_.Enqueue(job);
input_queue_semaphore_.Signal();
@@ -317,7 +314,6 @@
info->closure()->PrintName();
PrintF(", AST id %d]\n", info->osr_ast_id().ToInt());
}
- BackEdgeTable::RemoveStackCheck(info);
DisposeRecompileJob(stale, false);
break;
}
diff --git a/src/optimizing-compiler-thread.h b/src/optimizing-compiler-thread.h
index 2165a4f..d98a8b2 100644
--- a/src/optimizing-compiler-thread.h
+++ b/src/optimizing-compiler-thread.h
@@ -139,8 +139,6 @@
TimeDelta time_spent_compiling_;
TimeDelta time_spent_total_;
- // TODO(yangguo): remove this once the memory leak has been figured out.
- Mutex queue_mutex_;
int osr_hits_;
int osr_attempts_;
};
diff --git a/src/v8threads.cc b/src/v8threads.cc
index 94a5e80..cc4f439 100644
--- a/src/v8threads.cc
+++ b/src/v8threads.cc
@@ -42,11 +42,6 @@
bool Locker::active_ = false;
-Locker::Locker() {
- Initialize(i::Isolate::GetDefaultIsolateForLocking());
-}
-
-
// Once the Locker is initialized, the current thread will be guaranteed to have
// the lock for a given isolate.
void Locker::Initialize(v8::Isolate* isolate) {
@@ -116,11 +111,6 @@
}
-Unlocker::Unlocker() {
- Initialize(i::Isolate::GetDefaultIsolateForLocking());
-}
-
-
void Unlocker::Initialize(v8::Isolate* isolate) {
ASSERT(isolate != NULL);
isolate_ = reinterpret_cast<i::Isolate*>(isolate);
@@ -143,14 +133,15 @@
}
-void Locker::StartPreemption(int every_n_ms) {
+void Locker::StartPreemption(v8::Isolate* isolate, int every_n_ms) {
v8::internal::ContextSwitcher::StartPreemption(
- i::Isolate::Current(), every_n_ms);
+ reinterpret_cast<i::Isolate*>(isolate), every_n_ms);
}
-void Locker::StopPreemption() {
- v8::internal::ContextSwitcher::StopPreemption(i::Isolate::Current());
+void Locker::StopPreemption(v8::Isolate* isolate) {
+ v8::internal::ContextSwitcher::StopPreemption(
+ reinterpret_cast<i::Isolate*>(isolate));
}
diff --git a/src/version.cc b/src/version.cc
index e310df0..be3b9cb 100644
--- a/src/version.cc
+++ b/src/version.cc
@@ -34,8 +34,8 @@
// system so their names cannot be changed without changing the scripts.
#define MAJOR_VERSION 3
#define MINOR_VERSION 22
-#define BUILD_NUMBER 3
-#define PATCH_LEVEL 2
+#define BUILD_NUMBER 4
+#define PATCH_LEVEL 0
// Use 1 for candidates and 0 otherwise.
// (Boolean macro values are not supported by all preprocessors.)
#define IS_CANDIDATE_VERSION 0
diff --git a/src/x64/lithium-codegen-x64.cc b/src/x64/lithium-codegen-x64.cc
index 27d064d..df168b8 100644
--- a/src/x64/lithium-codegen-x64.cc
+++ b/src/x64/lithium-codegen-x64.cc
@@ -4523,16 +4523,17 @@
Label slow;
Register reg = ToRegister(instr->value());
Register tmp = reg.is(rax) ? rcx : rax;
+ XMMRegister temp_xmm = ToDoubleRegister(instr->temp());
// Preserve the value of all registers.
PushSafepointRegistersScope scope(this);
Label done;
- // Load value into xmm1 which will be preserved across potential call to
+ // Load value into temp_xmm which will be preserved across potential call to
// runtime (MacroAssembler::EnterExitFrameEpilogue preserves only allocatable
// XMM registers on x64).
XMMRegister xmm_scratch = double_scratch0();
- __ LoadUint32(xmm1, reg, xmm_scratch);
+ __ LoadUint32(temp_xmm, reg, xmm_scratch);
if (FLAG_inline_new) {
__ AllocateHeapNumber(reg, tmp, &slow);
@@ -4550,10 +4551,10 @@
CallRuntimeFromDeferred(Runtime::kAllocateHeapNumber, 0, instr);
if (!reg.is(rax)) __ movq(reg, rax);
- // Done. Put the value in xmm1 into the value of the allocated heap
+ // Done. Put the value in temp_xmm into the value of the allocated heap
// number.
__ bind(&done);
- __ movsd(FieldOperand(reg, HeapNumber::kValueOffset), xmm1);
+ __ movsd(FieldOperand(reg, HeapNumber::kValueOffset), temp_xmm);
__ StoreToSafepointRegisterSlot(reg, reg);
}
diff --git a/src/x64/lithium-x64.cc b/src/x64/lithium-x64.cc
index ddaae82..7487603 100644
--- a/src/x64/lithium-x64.cc
+++ b/src/x64/lithium-x64.cc
@@ -353,19 +353,20 @@
}
-int LPlatformChunk::GetNextSpillIndex(bool is_double) {
+int LPlatformChunk::GetNextSpillIndex(RegisterKind kind) {
return spill_slot_count_++;
}
-LOperand* LPlatformChunk::GetNextSpillSlot(bool is_double) {
+LOperand* LPlatformChunk::GetNextSpillSlot(RegisterKind kind) {
// All stack slots are Double stack slots on x64.
// Alternatively, at some point, start using half-size
// stack slots for int32 values.
- int index = GetNextSpillIndex(is_double);
- if (is_double) {
+ int index = GetNextSpillIndex(kind);
+ if (kind == DOUBLE_REGISTERS) {
return LDoubleStackSlot::Create(index, zone());
} else {
+ ASSERT(kind == GENERAL_REGISTERS);
return LStackSlot::Create(index, zone());
}
}
@@ -445,7 +446,7 @@
// which will be subsumed into this frame.
if (graph()->has_osr()) {
for (int i = graph()->osr()->UnoptimizedFrameSlots(); i > 0; i--) {
- chunk_->GetNextSpillIndex(false);
+ chunk_->GetNextSpillIndex(GENERAL_REGISTERS);
}
}
@@ -1780,6 +1781,13 @@
}
+LInstruction* LChunkBuilder::DoAbnormalExit(HAbnormalExit* instr) {
+ // The control instruction marking the end of a block that completed
+ // abruptly (e.g., threw an exception). There is nothing specific to do.
+ return NULL;
+}
+
+
LInstruction* LChunkBuilder::DoThrow(HThrow* instr) {
LOperand* value = UseFixed(instr->value(), rax);
return MarkAsCall(new(zone()) LThrow(value), instr);
diff --git a/src/x64/lithium-x64.h b/src/x64/lithium-x64.h
index 0ccbeb8..e0c4458 100644
--- a/src/x64/lithium-x64.h
+++ b/src/x64/lithium-x64.h
@@ -2542,8 +2542,8 @@
LPlatformChunk(CompilationInfo* info, HGraph* graph)
: LChunk(info, graph) { }
- int GetNextSpillIndex(bool is_double);
- LOperand* GetNextSpillSlot(bool is_double);
+ int GetNextSpillIndex(RegisterKind kind);
+ LOperand* GetNextSpillSlot(RegisterKind kind);
};
diff --git a/src/x64/macro-assembler-x64.cc b/src/x64/macro-assembler-x64.cc
index 96fa4fc..0809ccd 100644
--- a/src/x64/macro-assembler-x64.cc
+++ b/src/x64/macro-assembler-x64.cc
@@ -1447,28 +1447,6 @@
}
-void MacroAssembler::SmiTryAddConstant(Register dst,
- Register src,
- Smi* constant,
- Label* on_not_smi_result,
- Label::Distance near_jump) {
- // Does not assume that src is a smi.
- ASSERT_EQ(static_cast<int>(1), static_cast<int>(kSmiTagMask));
- STATIC_ASSERT(kSmiTag == 0);
- ASSERT(!dst.is(kScratchRegister));
- ASSERT(!src.is(kScratchRegister));
-
- JumpIfNotSmi(src, on_not_smi_result, near_jump);
- Register tmp = (dst.is(src) ? kScratchRegister : dst);
- LoadSmiConstant(tmp, constant);
- addq(tmp, src);
- j(overflow, on_not_smi_result, near_jump);
- if (dst.is(src)) {
- movq(dst, tmp);
- }
-}
-
-
void MacroAssembler::SmiAddConstant(Register dst, Register src, Smi* constant) {
if (constant->value() == 0) {
if (!dst.is(src)) {
@@ -1699,6 +1677,29 @@
}
+template<class T>
+static void SmiSubHelper(MacroAssembler* masm,
+ Register dst,
+ Register src1,
+ T src2,
+ Label* on_not_smi_result,
+ Label::Distance near_jump) {
+ if (dst.is(src1)) {
+ Label done;
+ masm->subq(dst, src2);
+ masm->j(no_overflow, &done, Label::kNear);
+ // Restore src1.
+ masm->addq(dst, src2);
+ masm->jmp(on_not_smi_result, near_jump);
+ masm->bind(&done);
+ } else {
+ masm->movq(dst, src1);
+ masm->subq(dst, src2);
+ masm->j(overflow, on_not_smi_result, near_jump);
+ }
+}
+
+
void MacroAssembler::SmiSub(Register dst,
Register src1,
Register src2,
@@ -1706,27 +1707,7 @@
Label::Distance near_jump) {
ASSERT_NOT_NULL(on_not_smi_result);
ASSERT(!dst.is(src2));
- if (dst.is(src1)) {
- cmpq(dst, src2);
- j(overflow, on_not_smi_result, near_jump);
- subq(dst, src2);
- } else {
- movq(dst, src1);
- subq(dst, src2);
- j(overflow, on_not_smi_result, near_jump);
- }
-}
-
-
-void MacroAssembler::SmiSub(Register dst, Register src1, Register src2) {
- // No overflow checking. Use only when it's known that
- // overflowing is impossible (e.g., subtracting two positive smis).
- ASSERT(!dst.is(src2));
- if (!dst.is(src1)) {
- movq(dst, src1);
- }
- subq(dst, src2);
- Assert(no_overflow, kSmiSubtractionOverflow);
+ SmiSubHelper<Register>(this, dst, src1, src2, on_not_smi_result, near_jump);
}
@@ -1736,29 +1717,36 @@
Label* on_not_smi_result,
Label::Distance near_jump) {
ASSERT_NOT_NULL(on_not_smi_result);
- if (dst.is(src1)) {
- movq(kScratchRegister, src2);
- cmpq(src1, kScratchRegister);
- j(overflow, on_not_smi_result, near_jump);
- subq(src1, kScratchRegister);
- } else {
- movq(dst, src1);
- subq(dst, src2);
- j(overflow, on_not_smi_result, near_jump);
+ ASSERT(!src2.AddressUsesRegister(dst));
+ SmiSubHelper<Operand>(this, dst, src1, src2, on_not_smi_result, near_jump);
+}
+
+
+template<class T>
+static void SmiSubNoOverflowHelper(MacroAssembler* masm,
+ Register dst,
+ Register src1,
+ T src2) {
+ // No overflow checking. Use only when it's known that
+ // overflowing is impossible (e.g., subtracting two positive smis).
+ if (!dst.is(src1)) {
+ masm->movq(dst, src1);
}
+ masm->subq(dst, src2);
+ masm->Assert(no_overflow, kSmiSubtractionOverflow);
+}
+
+
+void MacroAssembler::SmiSub(Register dst, Register src1, Register src2) {
+ ASSERT(!dst.is(src2));
+ SmiSubNoOverflowHelper<Register>(this, dst, src1, src2);
}
void MacroAssembler::SmiSub(Register dst,
Register src1,
const Operand& src2) {
- // No overflow checking. Use only when it's known that
- // overflowing is impossible (e.g., subtracting two positive smis).
- if (!dst.is(src1)) {
- movq(dst, src1);
- }
- subq(dst, src2);
- Assert(no_overflow, kSmiSubtractionOverflow);
+ SmiSubNoOverflowHelper<Operand>(this, dst, src1, src2);
}
@@ -3728,7 +3716,7 @@
#endif
// Optionally save all XMM registers.
if (save_doubles) {
- int space = XMMRegister::kMaxNumRegisters * kDoubleSize +
+ int space = XMMRegister::kMaxNumAllocatableRegisters * kDoubleSize +
arg_stack_space * kPointerSize;
subq(rsp, Immediate(space));
int offset = -2 * kPointerSize;
diff --git a/src/x64/macro-assembler-x64.h b/src/x64/macro-assembler-x64.h
index 09dae3e..8c73dd9 100644
--- a/src/x64/macro-assembler-x64.h
+++ b/src/x64/macro-assembler-x64.h
@@ -532,15 +532,6 @@
// Smis represent a subset of integers. The subset is always equivalent to
// a two's complement interpretation of a fixed number of bits.
- // Optimistically adds an integer constant to a supposed smi.
- // If the src is not a smi, or the result is not a smi, jump to
- // the label.
- void SmiTryAddConstant(Register dst,
- Register src,
- Smi* constant,
- Label* on_not_smi_result,
- Label::Distance near_jump = Label::kFar);
-
// Add an integer constant to a tagged smi, giving a tagged smi as result.
// No overflow testing on the result is done.
void SmiAddConstant(Register dst, Register src, Smi* constant);
@@ -596,13 +587,18 @@
Register src2);
// Subtracts smi values and return the result as a smi.
- // If dst is src1, then src1 will be destroyed, even if
- // the operation is unsuccessful.
+ // If dst is src1, then src1 will be destroyed if the operation is
+ // successful, otherwise kept intact.
void SmiSub(Register dst,
Register src1,
Register src2,
Label* on_not_smi_result,
Label::Distance near_jump = Label::kFar);
+ void SmiSub(Register dst,
+ Register src1,
+ const Operand& src2,
+ Label* on_not_smi_result,
+ Label::Distance near_jump = Label::kFar);
void SmiSub(Register dst,
Register src1,
@@ -610,12 +606,6 @@
void SmiSub(Register dst,
Register src1,
- const Operand& src2,
- Label* on_not_smi_result,
- Label::Distance near_jump = Label::kFar);
-
- void SmiSub(Register dst,
- Register src1,
const Operand& src2);
// Multiplies smi values and return the result as a smi,
diff --git a/test/cctest/test-api.cc b/test/cctest/test-api.cc
index 7a2f9de..5caa6ae 100644
--- a/test/cctest/test-api.cc
+++ b/test/cctest/test-api.cc
@@ -4011,7 +4011,8 @@
THREADED_TEST(FunctionCall) {
LocalContext context;
- v8::HandleScope scope(context->GetIsolate());
+ v8::Isolate* isolate = context->GetIsolate();
+ v8::HandleScope scope(isolate);
CompileRun(
"function Foo() {"
" var result = [];"
@@ -4019,9 +4020,20 @@
" result.push(arguments[i]);"
" }"
" return result;"
+ "}"
+ "function ReturnThisSloppy() {"
+ " return this;"
+ "}"
+ "function ReturnThisStrict() {"
+ " 'use strict';"
+ " return this;"
"}");
Local<Function> Foo =
Local<Function>::Cast(context->Global()->Get(v8_str("Foo")));
+ Local<Function> ReturnThisSloppy =
+ Local<Function>::Cast(context->Global()->Get(v8_str("ReturnThisSloppy")));
+ Local<Function> ReturnThisStrict =
+ Local<Function>::Cast(context->Global()->Get(v8_str("ReturnThisStrict")));
v8::Handle<Value>* args0 = NULL;
Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->Call(Foo, 0, args0));
@@ -4058,6 +4070,31 @@
CHECK_EQ(8.8, a4->Get(v8::Integer::New(1))->NumberValue());
CHECK_EQ(9.9, a4->Get(v8::Integer::New(2))->NumberValue());
CHECK_EQ(10.11, a4->Get(v8::Integer::New(3))->NumberValue());
+
+ Local<v8::Value> r1 = ReturnThisSloppy->Call(v8::Undefined(isolate), 0, NULL);
+ CHECK(r1->StrictEquals(context->Global()));
+ Local<v8::Value> r2 = ReturnThisSloppy->Call(v8::Null(isolate), 0, NULL);
+ CHECK(r2->StrictEquals(context->Global()));
+ Local<v8::Value> r3 = ReturnThisSloppy->Call(v8_num(42), 0, NULL);
+ CHECK(r3->IsNumberObject());
+ CHECK_EQ(42.0, r3.As<v8::NumberObject>()->ValueOf());
+ Local<v8::Value> r4 = ReturnThisSloppy->Call(v8_str("hello"), 0, NULL);
+ CHECK(r4->IsStringObject());
+ CHECK(r4.As<v8::StringObject>()->ValueOf()->StrictEquals(v8_str("hello")));
+ Local<v8::Value> r5 = ReturnThisSloppy->Call(v8::True(isolate), 0, NULL);
+ CHECK(r5->IsBooleanObject());
+ CHECK(r5.As<v8::BooleanObject>()->ValueOf());
+
+ Local<v8::Value> r6 = ReturnThisStrict->Call(v8::Undefined(isolate), 0, NULL);
+ CHECK(r6->IsUndefined());
+ Local<v8::Value> r7 = ReturnThisStrict->Call(v8::Null(isolate), 0, NULL);
+ CHECK(r7->IsNull());
+ Local<v8::Value> r8 = ReturnThisStrict->Call(v8_num(42), 0, NULL);
+ CHECK(r8->StrictEquals(v8_num(42)));
+ Local<v8::Value> r9 = ReturnThisStrict->Call(v8_str("hello"), 0, NULL);
+ CHECK(r9->StrictEquals(v8_str("hello")));
+ Local<v8::Value> r10 = ReturnThisStrict->Call(v8::True(isolate), 0, NULL);
+ CHECK(r10->StrictEquals(v8::True(isolate)));
}
@@ -10177,6 +10214,11 @@
}
+static void ReturnThis(const v8::FunctionCallbackInfo<v8::Value>& args) {
+ args.GetReturnValue().Set(args.This());
+}
+
+
// Test that a call handler can be set for objects which will allow
// non-function objects created through the API to be called as
// functions.
@@ -10289,6 +10331,81 @@
CHECK_EQ("23", *exception_value2);
try_catch.Reset();
}
+
+ { v8::Isolate* isolate = context->GetIsolate();
+ Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
+ Local<ObjectTemplate> instance_template = t->InstanceTemplate();
+ instance_template->SetCallAsFunctionHandler(ReturnThis);
+ Local<v8::Object> instance = t->GetFunction()->NewInstance();
+
+ Local<v8::Value> a1 =
+ instance->CallAsFunction(v8::Undefined(isolate), 0, NULL);
+ CHECK(a1->StrictEquals(instance));
+ Local<v8::Value> a2 =
+ instance->CallAsFunction(v8::Null(isolate), 0, NULL);
+ CHECK(a2->StrictEquals(instance));
+ Local<v8::Value> a3 =
+ instance->CallAsFunction(v8_num(42), 0, NULL);
+ CHECK(a3->StrictEquals(instance));
+ Local<v8::Value> a4 =
+ instance->CallAsFunction(v8_str("hello"), 0, NULL);
+ CHECK(a4->StrictEquals(instance));
+ Local<v8::Value> a5 =
+ instance->CallAsFunction(v8::True(isolate), 0, NULL);
+ CHECK(a5->StrictEquals(instance));
+ }
+
+ { v8::Isolate* isolate = context->GetIsolate();
+ CompileRun(
+ "function ReturnThisSloppy() {"
+ " return this;"
+ "}"
+ "function ReturnThisStrict() {"
+ " 'use strict';"
+ " return this;"
+ "}");
+ Local<Function> ReturnThisSloppy =
+ Local<Function>::Cast(
+ context->Global()->Get(v8_str("ReturnThisSloppy")));
+ Local<Function> ReturnThisStrict =
+ Local<Function>::Cast(
+ context->Global()->Get(v8_str("ReturnThisStrict")));
+
+ Local<v8::Value> a1 =
+ ReturnThisSloppy->CallAsFunction(v8::Undefined(isolate), 0, NULL);
+ CHECK(a1->StrictEquals(context->Global()));
+ Local<v8::Value> a2 =
+ ReturnThisSloppy->CallAsFunction(v8::Null(isolate), 0, NULL);
+ CHECK(a2->StrictEquals(context->Global()));
+ Local<v8::Value> a3 =
+ ReturnThisSloppy->CallAsFunction(v8_num(42), 0, NULL);
+ CHECK(a3->IsNumberObject());
+ CHECK_EQ(42.0, a3.As<v8::NumberObject>()->ValueOf());
+ Local<v8::Value> a4 =
+ ReturnThisSloppy->CallAsFunction(v8_str("hello"), 0, NULL);
+ CHECK(a4->IsStringObject());
+ CHECK(a4.As<v8::StringObject>()->ValueOf()->StrictEquals(v8_str("hello")));
+ Local<v8::Value> a5 =
+ ReturnThisSloppy->CallAsFunction(v8::True(isolate), 0, NULL);
+ CHECK(a5->IsBooleanObject());
+ CHECK(a5.As<v8::BooleanObject>()->ValueOf());
+
+ Local<v8::Value> a6 =
+ ReturnThisStrict->CallAsFunction(v8::Undefined(isolate), 0, NULL);
+ CHECK(a6->IsUndefined());
+ Local<v8::Value> a7 =
+ ReturnThisStrict->CallAsFunction(v8::Null(isolate), 0, NULL);
+ CHECK(a7->IsNull());
+ Local<v8::Value> a8 =
+ ReturnThisStrict->CallAsFunction(v8_num(42), 0, NULL);
+ CHECK(a8->StrictEquals(v8_num(42)));
+ Local<v8::Value> a9 =
+ ReturnThisStrict->CallAsFunction(v8_str("hello"), 0, NULL);
+ CHECK(a9->StrictEquals(v8_str("hello")));
+ Local<v8::Value> a10 =
+ ReturnThisStrict->CallAsFunction(v8::True(isolate), 0, NULL);
+ CHECK(a10->StrictEquals(v8::True(isolate)));
+ }
}
@@ -14218,14 +14335,15 @@
gc_success_ = false;
GCThread gc_thread(this);
gc_thread.Start();
- v8::Locker::StartPreemption(1);
+ v8::Isolate* isolate = CcTest::isolate();
+ v8::Locker::StartPreemption(isolate, 1);
LongRunningRegExp();
{
- v8::Unlocker unlock(CcTest::isolate());
+ v8::Unlocker unlock(isolate);
gc_thread.Join();
}
- v8::Locker::StopPreemption();
+ v8::Locker::StopPreemption(isolate);
CHECK(regexp_success_);
CHECK(gc_success_);
}
@@ -14340,14 +14458,15 @@
gc_success_ = false;
GCThread gc_thread(this);
gc_thread.Start();
- v8::Locker::StartPreemption(1);
+ v8::Isolate* isolate = CcTest::isolate();
+ v8::Locker::StartPreemption(isolate, 1);
LongRunningApply();
{
- v8::Unlocker unlock(CcTest::isolate());
+ v8::Unlocker unlock(isolate);
gc_thread.Join();
}
- v8::Locker::StopPreemption();
+ v8::Locker::StopPreemption(isolate);
CHECK(apply_success_);
CHECK(gc_success_);
}
@@ -14627,6 +14746,7 @@
uc16_resource_(i::Vector<const uint16_t>(two_byte_content_, 15)) {}
~RegExpStringModificationTest() {}
void RunTest() {
+ v8::Isolate* isolate = CcTest::isolate();
i::Factory* factory = CcTest::i_isolate()->factory();
regexp_success_ = false;
@@ -14655,13 +14775,13 @@
MorphThread morph_thread(this);
morph_thread.Start();
- v8::Locker::StartPreemption(1);
+ v8::Locker::StartPreemption(isolate, 1);
LongRunningRegExp();
{
- v8::Unlocker unlock(CcTest::isolate());
+ v8::Unlocker unlock(isolate);
morph_thread.Join();
}
- v8::Locker::StopPreemption();
+ v8::Locker::StopPreemption(isolate);
CHECK(regexp_success_);
CHECK(morph_success_);
}
diff --git a/test/cctest/test-debug.cc b/test/cctest/test-debug.cc
index df6d1f5..d24f28e 100644
--- a/test/cctest/test-debug.cc
+++ b/test/cctest/test-debug.cc
@@ -29,7 +29,6 @@
#include <stdlib.h>
-#define V8_DISABLE_DEPRECATIONS 1
#include "v8.h"
#include "api.h"
@@ -43,7 +42,6 @@
#include "platform/socket.h"
#include "stub-cache.h"
#include "utils.h"
-#undef V8_DISABLE_DEPRECATIONS
using ::v8::internal::Mutex;
diff --git a/test/cctest/test-threads.cc b/test/cctest/test-threads.cc
index 518d460..4709961 100644
--- a/test/cctest/test-threads.cc
+++ b/test/cctest/test-threads.cc
@@ -41,14 +41,14 @@
v8::Handle<v8::Context> context = v8::Context::New(isolate);
v8::Context::Scope context_scope(context);
- v8::Locker::StartPreemption(100);
+ v8::Locker::StartPreemption(isolate, 100);
v8::Handle<v8::Script> script = v8::Script::Compile(
v8::String::New("var count = 0; var obj = new Object(); count++;\n"));
script->Run();
- v8::Locker::StopPreemption();
+ v8::Locker::StopPreemption(isolate);
v8::internal::OS::Sleep(500); // Make sure the timer fires.
script->Run();
diff --git a/test/mjsunit/big-array-literal.js b/test/mjsunit/big-array-literal.js
index 9f06179..13f91f8 100644
--- a/test/mjsunit/big-array-literal.js
+++ b/test/mjsunit/big-array-literal.js
@@ -92,16 +92,25 @@
testLiteral(sizes[i], true);
}
+
+function checkExpectedException(e) {
+ assertInstanceof(e, RangeError);
+ assertTrue(e.message.indexOf("Maximum call stack size exceeded") >= 0);
+}
+
+
function testLiteralAndCatch(size) {
var big_enough = false;
try {
testLiteral(size, false);
} catch (e) {
+ checkExpectedException(e);
big_enough = true;
}
try {
testLiteral(size, true);
} catch (e) {
+ checkExpectedException(e);
big_enough = true;
}
return big_enough;
diff --git a/test/mjsunit/big-object-literal.js b/test/mjsunit/big-object-literal.js
index c937f54..92c6ab7 100644
--- a/test/mjsunit/big-object-literal.js
+++ b/test/mjsunit/big-object-literal.js
@@ -92,16 +92,25 @@
testLiteral(sizes[i], true);
}
+
+function checkExpectedException(e) {
+ assertInstanceof(e, RangeError);
+ assertTrue(e.message.indexOf("Maximum call stack size exceeded") >= 0);
+}
+
+
function testLiteralAndCatch(size) {
var big_enough = false;
try {
testLiteral(size, false);
} catch (e) {
+ checkExpectedException(e);
big_enough = true;
}
try {
testLiteral(size, true);
} catch (e) {
+ checkExpectedException(e);
big_enough = true;
}
return big_enough;
diff --git a/test/mjsunit/timer.js b/test/mjsunit/timer.js
index bac474c..0b03550 100644
--- a/test/mjsunit/timer.js
+++ b/test/mjsunit/timer.js
@@ -25,8 +25,15 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+// Flags: --allow-natives-syntax
+
// Tests timer milliseconds granularity.
+// Don't run this test in gc stress mode. Time differences may be long
+// due to garbage collections.
+%SetFlags("--gc-interval=-1");
+%SetFlags("--nostress-compaction");
+
(function run() {
var start_test = Date.now();
// Let the retry run for maximum 100ms to reduce flakiness.
diff --git a/tools/profviz/composer.js b/tools/profviz/composer.js
index 44dd763..0c9437f 100644
--- a/tools/profviz/composer.js
+++ b/tools/profviz/composer.js
@@ -497,6 +497,8 @@
}
// Label the longest pauses.
+ execution_pauses =
+ RestrictRangesTo(execution_pauses, range_start, range_end);
execution_pauses.sort(
function(a, b) { return b.duration() - a.duration(); });
diff --git a/tools/status-file-converter.py b/tools/status-file-converter.py
deleted file mode 100755
index ba063ee..0000000
--- a/tools/status-file-converter.py
+++ /dev/null
@@ -1,39 +0,0 @@
-#!/usr/bin/env python
-#
-# Copyright 2012 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.
-
-
-import sys
-from testrunner.local import old_statusfile
-
-if len(sys.argv) != 2:
- print "Usage: %s foo.status" % sys.argv[0]
- print "Will read foo.status and print the converted version to stdout."
- sys.exit(1)
-
-print old_statusfile.ConvertNotation(sys.argv[1]).GetOutput()
diff --git a/tools/testrunner/README b/tools/testrunner/README
index 8f0c01f..0771ef9 100644
--- a/tools/testrunner/README
+++ b/tools/testrunner/README
@@ -87,12 +87,6 @@
Implementation needed to run tests locally. Used by run-tests.py. Inspired by
(and partly copied verbatim from) the original test.py script.
-./testrunner/local/old_statusfile.py:
- Provides functionality to read an old-style <testsuite>.status file and
- convert it to new-style syntax. This can be removed once the new-style
- syntax becomes authoritative (and old-style syntax is no longer supported).
- ./status-file-converter.py provides a stand-alone interface to this.
-
./testrunner/objects/*:
A bunch of data container classes, used by the scripts in the various other
directories; serializable for transmission over the network.