Version 3.20.3
Performance and stability improvements on all platforms.
git-svn-id: http://v8.googlecode.com/svn/trunk@15538 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
diff --git a/ChangeLog b/ChangeLog
index 3c113b2..2b6b491 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+2013-07-08: Version 3.20.3
+
+ Performance and stability improvements on all platforms.
+
+
2013-07-05: Version 3.20.2
Remove deprecated heap profiler methods from V8 public API
diff --git a/PRESUBMIT.py b/PRESUBMIT.py
index 7d66203..1f176e0 100644
--- a/PRESUBMIT.py
+++ b/PRESUBMIT.py
@@ -44,7 +44,8 @@
results.append(output_api.PresubmitError("C++ lint check failed"))
if not SourceProcessor().Run(input_api.PresubmitLocalPath()):
results.append(output_api.PresubmitError(
- "Copyright header and trailing whitespaces check failed"))
+ "Copyright header, trailing whitespaces and two empty lines " \
+ "between declarations check failed"))
return results
diff --git a/include/v8-profiler.h b/include/v8-profiler.h
index df3bd9f..cf28341 100644
--- a/include/v8-profiler.h
+++ b/include/v8-profiler.h
@@ -181,18 +181,9 @@
*/
int GetProfileCount();
- /** Deprecated. Use GetCpuProfile with single parameter. */
- V8_DEPRECATED(const CpuProfile* GetCpuProfile(
- int index,
- Handle<Value> security_token));
/** Returns a profile by index. */
const CpuProfile* GetCpuProfile(int index);
- /** Returns a profile by uid. */
- V8_DEPRECATED(const CpuProfile* FindCpuProfile(
- unsigned uid,
- Handle<Value> security_token = Handle<Value>()));
-
/**
* Starts collecting CPU profile. Title may be an empty string. It
* is allowed to have several profiles being collected at
@@ -207,12 +198,6 @@
void StartCpuProfiling(Handle<String> title, bool record_samples = false);
/**
- * Deprecated. Use StopCpuProfiling with one parameter instead.
- */
- V8_DEPRECATED(const CpuProfile* StopCpuProfiling(
- Handle<String> title,
- Handle<Value> security_token));
- /**
* Stops collecting CPU profile with a given title and returns it.
* If the title given is empty, finishes the last profile started.
*/
diff --git a/include/v8.h b/include/v8.h
index 3afb835..e27c094 100644
--- a/include/v8.h
+++ b/include/v8.h
@@ -2377,6 +2377,7 @@
};
#ifndef V8_ARRAY_BUFFER_INTERNAL_FIELD_COUNT
+// The number of required internal fields can be defined by embedder.
#define V8_ARRAY_BUFFER_INTERNAL_FIELD_COUNT 2
#endif
@@ -2489,6 +2490,12 @@
};
+#ifndef V8_ARRAY_BUFFER_VIEW_INTERNAL_FIELD_COUNT
+// The number of required internal fields can be defined by embedder.
+#define V8_ARRAY_BUFFER_VIEW_INTERNAL_FIELD_COUNT 2
+#endif
+
+
/**
* A base class for an instance of one of "views" over ArrayBuffer,
* including TypedArrays and DataView (ES6 draft 15.13).
@@ -2516,6 +2523,9 @@
V8_INLINE(static ArrayBufferView* Cast(Value* obj));
+ static const int kInternalFieldCount =
+ V8_ARRAY_BUFFER_VIEW_INTERNAL_FIELD_COUNT;
+
private:
ArrayBufferView();
static void CheckCast(Value* obj);
diff --git a/samples/lineprocessor.cc b/samples/lineprocessor.cc
index 214af05..adc5b13 100644
--- a/samples/lineprocessor.cc
+++ b/samples/lineprocessor.cc
@@ -322,6 +322,7 @@
return true;
}
+
int main(int argc, char* argv[]) {
int result = RunMain(argc, argv);
v8::V8::Dispose();
@@ -421,6 +422,7 @@
args.GetReturnValue().Set(ReadLine());
}
+
v8::Handle<v8::String> ReadLine() {
const int kBufferSize = 1024 + 1;
char buffer[kBufferSize];
diff --git a/samples/process.cc b/samples/process.cc
index 97eec14..1f1f92b 100644
--- a/samples/process.cc
+++ b/samples/process.cc
@@ -54,6 +54,7 @@
virtual const string& UserAgent() = 0;
};
+
/**
* The abstract superclass of http request processors.
*/
@@ -72,6 +73,7 @@
static void Log(const char* event);
};
+
/**
* An http request processor that is scriptable using JavaScript.
*/
@@ -135,6 +137,7 @@
static Persistent<ObjectTemplate> map_template_;
};
+
// -------------------------
// --- P r o c e s s o r ---
// -------------------------
diff --git a/src/api.cc b/src/api.cc
index 638a25f..c56bc05 100644
--- a/src/api.cc
+++ b/src/api.cc
@@ -298,6 +298,7 @@
return (obj == 0) ? ReportEmptyHandle(location) : false;
}
+
// --- S t a t i c s ---
@@ -322,6 +323,7 @@
return ApiCheck(InitializeHelper(isolate), location, "Error initializing V8");
}
+
// Some initializing API functions are called early and may be
// called on a thread different from static initializer thread.
// If Isolate API is used, Isolate::Enter() will initialize TLS so
@@ -401,6 +403,7 @@
kCompressedStartupDataCount
};
+
int V8::GetCompressedStartupDataCount() {
#ifdef COMPRESS_STARTUP_DATA_BZ2
return kCompressedStartupDataCount;
@@ -670,6 +673,7 @@
i::GlobalHandles::Destroy(obj);
}
+
// --- H a n d l e s ---
@@ -4422,6 +4426,7 @@
return str->HasOnlyOneByteChars();
}
+
// Helpers for ContainsOnlyOneByteHelper
template<size_t size> struct OneByteMask;
template<> struct OneByteMask<4> {
@@ -4435,6 +4440,8 @@
static inline bool Unaligned(const uint16_t* chars) {
return reinterpret_cast<const uintptr_t>(chars) & kAlignmentMask;
}
+
+
static inline const uint16_t* Align(const uint16_t* chars) {
return reinterpret_cast<uint16_t*>(
reinterpret_cast<uintptr_t>(chars) & ~kAlignmentMask);
@@ -6281,6 +6288,7 @@
return Utils::OpenHandle(this)->is_external();
}
+
v8::ArrayBuffer::Contents v8::ArrayBuffer::Externalize() {
i::Handle<i::JSArrayBuffer> obj = Utils::OpenHandle(this);
ApiCheck(!obj->is_external(),
@@ -6581,6 +6589,7 @@
disallow_heap_allocation_ = new i::DisallowHeapAllocation();
}
+
v8::AssertNoGCScope::~AssertNoGCScope() {
delete static_cast<i::DisallowHeapAllocation*>(disallow_heap_allocation_);
}
@@ -6644,6 +6653,7 @@
isolate->stats_table()->SetCounterFunction(callback);
}
+
void V8::SetCreateHistogramFunction(CreateHistogramCallback callback) {
i::Isolate* isolate = EnterIsolateIfNeeded();
if (IsDeadCheck(isolate, "v8::V8::SetCreateHistogramFunction()")) return;
@@ -6652,6 +6662,7 @@
isolate->counters()->ResetHistograms();
}
+
void V8::SetAddHistogramSampleFunction(AddHistogramSampleCallback callback) {
i::Isolate* isolate = EnterIsolateIfNeeded();
if (IsDeadCheck(isolate, "v8::V8::SetAddHistogramSampleFunction()")) return;
@@ -6999,6 +7010,7 @@
i::DeleteArray(str_);
}
+
Local<Value> Exception::RangeError(v8::Handle<v8::String> raw_message) {
i::Isolate* isolate = i::Isolate::Current();
LOG_API(isolate, "RangeError");
@@ -7015,6 +7027,7 @@
return Utils::ToLocal(result);
}
+
Local<Value> Exception::ReferenceError(v8::Handle<v8::String> raw_message) {
i::Isolate* isolate = i::Isolate::Current();
LOG_API(isolate, "ReferenceError");
@@ -7032,6 +7045,7 @@
return Utils::ToLocal(result);
}
+
Local<Value> Exception::SyntaxError(v8::Handle<v8::String> raw_message) {
i::Isolate* isolate = i::Isolate::Current();
LOG_API(isolate, "SyntaxError");
@@ -7048,6 +7062,7 @@
return Utils::ToLocal(result);
}
+
Local<Value> Exception::TypeError(v8::Handle<v8::String> raw_message) {
i::Isolate* isolate = i::Isolate::Current();
LOG_API(isolate, "TypeError");
@@ -7064,6 +7079,7 @@
return Utils::ToLocal(result);
}
+
Local<Value> Exception::Error(v8::Handle<v8::String> raw_message) {
i::Isolate* isolate = i::Isolate::Current();
LOG_API(isolate, "Error");
@@ -7437,7 +7453,7 @@
i::CpuProfiler* profiler = isolate->cpu_profiler();
ASSERT(profiler != NULL);
profiler->DeleteProfile(reinterpret_cast<i::CpuProfile*>(this));
- if (profiler->GetProfilesCount() == 0 && !profiler->HasDetachedProfiles()) {
+ if (profiler->GetProfilesCount() == 0) {
// If this was the last profile, clean up all accessory data as well.
profiler->DeleteAllProfiles();
}
@@ -7484,27 +7500,9 @@
}
-const CpuProfile* CpuProfiler::GetCpuProfile(int index,
- Handle<Value> security_token) {
- return reinterpret_cast<const CpuProfile*>(
- reinterpret_cast<i::CpuProfiler*>(this)->GetProfile(
- security_token.IsEmpty() ? NULL : *Utils::OpenHandle(*security_token),
- index));
-}
-
-
const CpuProfile* CpuProfiler::GetCpuProfile(int index) {
return reinterpret_cast<const CpuProfile*>(
- reinterpret_cast<i::CpuProfiler*>(this)->GetProfile(NULL, index));
-}
-
-
-const CpuProfile* CpuProfiler::FindCpuProfile(unsigned uid,
- Handle<Value> security_token) {
- return reinterpret_cast<const CpuProfile*>(
- reinterpret_cast<i::CpuProfiler*>(this)->FindProfile(
- security_token.IsEmpty() ? NULL : *Utils::OpenHandle(*security_token),
- uid));
+ reinterpret_cast<i::CpuProfiler*>(this)->GetProfile(index));
}
@@ -7514,19 +7512,9 @@
}
-const CpuProfile* CpuProfiler::StopCpuProfiling(Handle<String> title,
- Handle<Value> security_token) {
- return reinterpret_cast<const CpuProfile*>(
- reinterpret_cast<i::CpuProfiler*>(this)->StopProfiling(
- security_token.IsEmpty() ? NULL : *Utils::OpenHandle(*security_token),
- *Utils::OpenHandle(*title)));
-}
-
-
const CpuProfile* CpuProfiler::StopCpuProfiling(Handle<String> title) {
return reinterpret_cast<const CpuProfile*>(
reinterpret_cast<i::CpuProfiler*>(this)->StopProfiling(
- NULL,
*Utils::OpenHandle(*title)));
}
@@ -7808,6 +7796,7 @@
internal::Testing::set_stress_type(type);
}
+
int Testing::GetStressRuns() {
if (internal::FLAG_stress_runs != 0) return internal::FLAG_stress_runs;
#ifdef DEBUG
diff --git a/src/arm/assembler-arm.cc b/src/arm/assembler-arm.cc
index 89c0a3b..e8afc5d 100644
--- a/src/arm/assembler-arm.cc
+++ b/src/arm/assembler-arm.cc
@@ -56,6 +56,7 @@
return ExternalReference(&CpuFeatures::supported_);
}
+
// Get the CPU features enabled by the build. For cross compilation the
// preprocessor symbols CAN_USE_ARMV7_INSTRUCTIONS and CAN_USE_VFP3_INSTRUCTIONS
// can be defined to enable ARMv7 and VFPv3 instructions when building the
@@ -356,6 +357,7 @@
am_ = am;
}
+
MemOperand::MemOperand(Register rn, Register rm, AddrMode am) {
rn_ = rn;
rm_ = rm;
@@ -677,6 +679,7 @@
return instr & kOff12Mask;
}
+
// Labels refer to positions in the (to be) generated code.
// There are bound, linked, and unused labels.
//
@@ -1640,6 +1643,7 @@
addrmod3(cond | B7 | B6 | B5 | B4, src1, dst);
}
+
// Load/Store multiple instructions.
void Assembler::ldm(BlockAddrMode am,
Register base,
@@ -2074,6 +2078,7 @@
0xA*B8 | count);
}
+
static void DoubleAsTwoUInt32(double d, uint32_t* lo, uint32_t* hi) {
uint64_t i;
OS::MemCopy(&i, &d, 8);
@@ -2082,6 +2087,7 @@
*hi = i >> 32;
}
+
// Only works for little endian floating point formats.
// We don't support VFP on the mixed endian floating point platform.
static bool FitsVMOVDoubleImmediate(double d, uint32_t *encoding) {
@@ -2774,6 +2780,7 @@
#endif
}
+
void Assembler::GrowBuffer() {
if (!own_buffer_) FATAL("external code buffer is too small");
@@ -2894,6 +2901,7 @@
}
}
+
void Assembler::RecordRelocInfo(double data) {
// We do not try to reuse pool constants.
RelocInfo rinfo(pc_, data);
diff --git a/src/arm/code-stubs-arm.cc b/src/arm/code-stubs-arm.cc
old mode 100755
new mode 100644
index 6af5cce..c5e4db8
--- a/src/arm/code-stubs-arm.cc
+++ b/src/arm/code-stubs-arm.cc
@@ -226,8 +226,31 @@
}
+void UnaryOpStub::InitializeInterfaceDescriptor(
+ Isolate* isolate,
+ CodeStubInterfaceDescriptor* descriptor) {
+ static Register registers[] = { r0 };
+ descriptor->register_param_count_ = 1;
+ descriptor->register_params_ = registers;
+ descriptor->deoptimization_handler_ =
+ FUNCTION_ADDR(UnaryOpIC_Miss);
+}
+
+
+void StoreGlobalStub::InitializeInterfaceDescriptor(
+ Isolate* isolate,
+ CodeStubInterfaceDescriptor* descriptor) {
+ static Register registers[] = { r1, r2, r0 };
+ descriptor->register_param_count_ = 3;
+ descriptor->register_params_ = registers;
+ descriptor->deoptimization_handler_ =
+ FUNCTION_ADDR(StoreIC_MissFromStubFailure);
+}
+
+
#define __ ACCESS_MASM(masm)
+
static void EmitIdenticalObjectComparison(MacroAssembler* masm,
Label* slow,
Condition cond);
@@ -1289,277 +1312,6 @@
}
-void UnaryOpStub::PrintName(StringStream* stream) {
- const char* op_name = Token::Name(op_);
- const char* overwrite_name = NULL; // Make g++ happy.
- switch (mode_) {
- case UNARY_NO_OVERWRITE: overwrite_name = "Alloc"; break;
- case UNARY_OVERWRITE: overwrite_name = "Overwrite"; break;
- }
- stream->Add("UnaryOpStub_%s_%s_%s",
- op_name,
- overwrite_name,
- UnaryOpIC::GetName(operand_type_));
-}
-
-
-// TODO(svenpanne): Use virtual functions instead of switch.
-void UnaryOpStub::Generate(MacroAssembler* masm) {
- switch (operand_type_) {
- case UnaryOpIC::UNINITIALIZED:
- GenerateTypeTransition(masm);
- break;
- case UnaryOpIC::SMI:
- GenerateSmiStub(masm);
- break;
- case UnaryOpIC::NUMBER:
- GenerateNumberStub(masm);
- break;
- case UnaryOpIC::GENERIC:
- GenerateGenericStub(masm);
- break;
- }
-}
-
-
-void UnaryOpStub::GenerateTypeTransition(MacroAssembler* masm) {
- __ mov(r3, Operand(r0)); // the operand
- __ mov(r2, Operand(Smi::FromInt(op_)));
- __ mov(r1, Operand(Smi::FromInt(mode_)));
- __ mov(r0, Operand(Smi::FromInt(operand_type_)));
- __ Push(r3, r2, r1, r0);
-
- __ TailCallExternalReference(
- ExternalReference(IC_Utility(IC::kUnaryOp_Patch), masm->isolate()), 4, 1);
-}
-
-
-// TODO(svenpanne): Use virtual functions instead of switch.
-void UnaryOpStub::GenerateSmiStub(MacroAssembler* masm) {
- switch (op_) {
- case Token::SUB:
- GenerateSmiStubSub(masm);
- break;
- case Token::BIT_NOT:
- GenerateSmiStubBitNot(masm);
- break;
- default:
- UNREACHABLE();
- }
-}
-
-
-void UnaryOpStub::GenerateSmiStubSub(MacroAssembler* masm) {
- Label non_smi, slow;
- GenerateSmiCodeSub(masm, &non_smi, &slow);
- __ bind(&non_smi);
- __ bind(&slow);
- GenerateTypeTransition(masm);
-}
-
-
-void UnaryOpStub::GenerateSmiStubBitNot(MacroAssembler* masm) {
- Label non_smi;
- GenerateSmiCodeBitNot(masm, &non_smi);
- __ bind(&non_smi);
- GenerateTypeTransition(masm);
-}
-
-
-void UnaryOpStub::GenerateSmiCodeSub(MacroAssembler* masm,
- Label* non_smi,
- Label* slow) {
- __ JumpIfNotSmi(r0, non_smi);
-
- // The result of negating zero or the smallest negative smi is not a smi.
- __ bic(ip, r0, Operand(0x80000000), SetCC);
- __ b(eq, slow);
-
- // Return '0 - value'.
- __ rsb(r0, r0, Operand::Zero());
- __ Ret();
-}
-
-
-void UnaryOpStub::GenerateSmiCodeBitNot(MacroAssembler* masm,
- Label* non_smi) {
- __ JumpIfNotSmi(r0, non_smi);
-
- // Flip bits and revert inverted smi-tag.
- __ mvn(r0, Operand(r0));
- __ bic(r0, r0, Operand(kSmiTagMask));
- __ Ret();
-}
-
-
-// TODO(svenpanne): Use virtual functions instead of switch.
-void UnaryOpStub::GenerateNumberStub(MacroAssembler* masm) {
- switch (op_) {
- case Token::SUB:
- GenerateNumberStubSub(masm);
- break;
- case Token::BIT_NOT:
- GenerateNumberStubBitNot(masm);
- break;
- default:
- UNREACHABLE();
- }
-}
-
-
-void UnaryOpStub::GenerateNumberStubSub(MacroAssembler* masm) {
- Label non_smi, slow, call_builtin;
- GenerateSmiCodeSub(masm, &non_smi, &call_builtin);
- __ bind(&non_smi);
- GenerateHeapNumberCodeSub(masm, &slow);
- __ bind(&slow);
- GenerateTypeTransition(masm);
- __ bind(&call_builtin);
- GenerateGenericCodeFallback(masm);
-}
-
-
-void UnaryOpStub::GenerateNumberStubBitNot(MacroAssembler* masm) {
- Label non_smi, slow;
- GenerateSmiCodeBitNot(masm, &non_smi);
- __ bind(&non_smi);
- GenerateHeapNumberCodeBitNot(masm, &slow);
- __ bind(&slow);
- GenerateTypeTransition(masm);
-}
-
-void UnaryOpStub::GenerateHeapNumberCodeSub(MacroAssembler* masm,
- Label* slow) {
- EmitCheckForHeapNumber(masm, r0, r1, r6, slow);
- // r0 is a heap number. Get a new heap number in r1.
- if (mode_ == UNARY_OVERWRITE) {
- __ ldr(r2, FieldMemOperand(r0, HeapNumber::kExponentOffset));
- __ eor(r2, r2, Operand(HeapNumber::kSignMask)); // Flip sign.
- __ str(r2, FieldMemOperand(r0, HeapNumber::kExponentOffset));
- } else {
- Label slow_allocate_heapnumber, heapnumber_allocated;
- __ AllocateHeapNumber(r1, r2, r3, r6, &slow_allocate_heapnumber);
- __ jmp(&heapnumber_allocated);
-
- __ bind(&slow_allocate_heapnumber);
- {
- FrameScope scope(masm, StackFrame::INTERNAL);
- __ push(r0);
- __ CallRuntime(Runtime::kNumberAlloc, 0);
- __ mov(r1, Operand(r0));
- __ pop(r0);
- }
-
- __ bind(&heapnumber_allocated);
- __ ldr(r3, FieldMemOperand(r0, HeapNumber::kMantissaOffset));
- __ ldr(r2, FieldMemOperand(r0, HeapNumber::kExponentOffset));
- __ str(r3, FieldMemOperand(r1, HeapNumber::kMantissaOffset));
- __ eor(r2, r2, Operand(HeapNumber::kSignMask)); // Flip sign.
- __ str(r2, FieldMemOperand(r1, HeapNumber::kExponentOffset));
- __ mov(r0, Operand(r1));
- }
- __ Ret();
-}
-
-
-void UnaryOpStub::GenerateHeapNumberCodeBitNot(MacroAssembler* masm,
- Label* slow) {
- EmitCheckForHeapNumber(masm, r0, r1, r6, slow);
-
- // Convert the heap number in r0 to an untagged integer in r1.
- __ vldr(d0, FieldMemOperand(r0, HeapNumber::kValueOffset));
- __ ECMAToInt32(r1, d0, r2, r3, r4, d1);
-
- // Do the bitwise operation and check if the result fits in a smi.
- Label try_float;
- __ mvn(r1, Operand(r1));
- __ cmn(r1, Operand(0x40000000));
- __ b(mi, &try_float);
-
- // Tag the result as a smi and we're done.
- __ SmiTag(r0, r1);
- __ Ret();
-
- // Try to store the result in a heap number.
- __ bind(&try_float);
- if (mode_ == UNARY_NO_OVERWRITE) {
- Label slow_allocate_heapnumber, heapnumber_allocated;
- __ AllocateHeapNumber(r0, r3, r4, r6, &slow_allocate_heapnumber);
- __ jmp(&heapnumber_allocated);
-
- __ bind(&slow_allocate_heapnumber);
- {
- FrameScope scope(masm, StackFrame::INTERNAL);
- // Push the lower bit of the result (left shifted to look like a smi).
- __ mov(r2, Operand(r1, LSL, 31));
- // Push the 31 high bits (bit 0 cleared to look like a smi).
- __ bic(r1, r1, Operand(1));
- __ Push(r2, r1);
- __ CallRuntime(Runtime::kNumberAlloc, 0);
- __ Pop(r2, r1); // Restore the result.
- __ orr(r1, r1, Operand(r2, LSR, 31));
- }
- __ bind(&heapnumber_allocated);
- }
-
- __ vmov(s0, r1);
- __ vcvt_f64_s32(d0, s0);
- __ vstr(d0, FieldMemOperand(r0, HeapNumber::kValueOffset));
- __ Ret();
-}
-
-
-// TODO(svenpanne): Use virtual functions instead of switch.
-void UnaryOpStub::GenerateGenericStub(MacroAssembler* masm) {
- switch (op_) {
- case Token::SUB:
- GenerateGenericStubSub(masm);
- break;
- case Token::BIT_NOT:
- GenerateGenericStubBitNot(masm);
- break;
- default:
- UNREACHABLE();
- }
-}
-
-
-void UnaryOpStub::GenerateGenericStubSub(MacroAssembler* masm) {
- Label non_smi, slow;
- GenerateSmiCodeSub(masm, &non_smi, &slow);
- __ bind(&non_smi);
- GenerateHeapNumberCodeSub(masm, &slow);
- __ bind(&slow);
- GenerateGenericCodeFallback(masm);
-}
-
-
-void UnaryOpStub::GenerateGenericStubBitNot(MacroAssembler* masm) {
- Label non_smi, slow;
- GenerateSmiCodeBitNot(masm, &non_smi);
- __ bind(&non_smi);
- GenerateHeapNumberCodeBitNot(masm, &slow);
- __ bind(&slow);
- GenerateGenericCodeFallback(masm);
-}
-
-
-void UnaryOpStub::GenerateGenericCodeFallback(MacroAssembler* masm) {
- // Handle the slow case by jumping to the JavaScript builtin.
- __ push(r0);
- switch (op_) {
- case Token::SUB:
- __ InvokeBuiltin(Builtins::UNARY_MINUS, JUMP_FUNCTION);
- break;
- case Token::BIT_NOT:
- __ InvokeBuiltin(Builtins::BIT_NOT, JUMP_FUNCTION);
- break;
- default:
- UNREACHABLE();
- }
-}
-
-
// Generates code to call a C function to do a double operation.
// This code never falls through, but returns with a heap number containing
// the result in r0.
@@ -6711,6 +6463,7 @@
RememberedSetAction action;
};
+
#define REG(Name) { kRegister_ ## Name ## _Code }
static const AheadOfTimeWriteBarrierStubList kAheadOfTime[] = {
diff --git a/src/arm/code-stubs-arm.h b/src/arm/code-stubs-arm.h
index 1f663f5..0202a8a 100644
--- a/src/arm/code-stubs-arm.h
+++ b/src/arm/code-stubs-arm.h
@@ -80,71 +80,6 @@
};
-class UnaryOpStub: public PlatformCodeStub {
- public:
- UnaryOpStub(Token::Value op,
- UnaryOverwriteMode mode,
- UnaryOpIC::TypeInfo operand_type = UnaryOpIC::UNINITIALIZED)
- : op_(op),
- mode_(mode),
- operand_type_(operand_type) {
- }
-
- private:
- Token::Value op_;
- UnaryOverwriteMode mode_;
-
- // Operand type information determined at runtime.
- UnaryOpIC::TypeInfo operand_type_;
-
- virtual void PrintName(StringStream* stream);
-
- class ModeBits: public BitField<UnaryOverwriteMode, 0, 1> {};
- class OpBits: public BitField<Token::Value, 1, 7> {};
- class OperandTypeInfoBits: public BitField<UnaryOpIC::TypeInfo, 8, 3> {};
-
- Major MajorKey() { return UnaryOp; }
- int MinorKey() {
- return ModeBits::encode(mode_)
- | OpBits::encode(op_)
- | OperandTypeInfoBits::encode(operand_type_);
- }
-
- // Note: A lot of the helper functions below will vanish when we use virtual
- // function instead of switch more often.
- void Generate(MacroAssembler* masm);
-
- void GenerateTypeTransition(MacroAssembler* masm);
-
- void GenerateSmiStub(MacroAssembler* masm);
- void GenerateSmiStubSub(MacroAssembler* masm);
- void GenerateSmiStubBitNot(MacroAssembler* masm);
- void GenerateSmiCodeSub(MacroAssembler* masm, Label* non_smi, Label* slow);
- void GenerateSmiCodeBitNot(MacroAssembler* masm, Label* slow);
-
- void GenerateNumberStub(MacroAssembler* masm);
- void GenerateNumberStubSub(MacroAssembler* masm);
- void GenerateNumberStubBitNot(MacroAssembler* masm);
- void GenerateHeapNumberCodeSub(MacroAssembler* masm, Label* slow);
- void GenerateHeapNumberCodeBitNot(MacroAssembler* masm, Label* slow);
-
- void GenerateGenericStub(MacroAssembler* masm);
- void GenerateGenericStubSub(MacroAssembler* masm);
- void GenerateGenericStubBitNot(MacroAssembler* masm);
- void GenerateGenericCodeFallback(MacroAssembler* masm);
-
- virtual Code::Kind GetCodeKind() const { return Code::UNARY_OP_IC; }
-
- virtual InlineCacheState GetICState() {
- return UnaryOpIC::ToState(operand_type_);
- }
-
- virtual void FinishCode(Handle<Code> code) {
- code->set_unary_op_type(operand_type_);
- }
-};
-
-
class StringHelper : public AllStatic {
public:
// Generate code for copying characters using a simple loop. This should only
diff --git a/src/arm/codegen-arm.cc b/src/arm/codegen-arm.cc
index 60de5fc..f411b13 100644
--- a/src/arm/codegen-arm.cc
+++ b/src/arm/codegen-arm.cc
@@ -120,6 +120,7 @@
return &sqrt;
}
+
// -------------------------------------------------------------------------
// Platform-specific RuntimeCallHelper functions.
diff --git a/src/arm/disasm-arm.cc b/src/arm/disasm-arm.cc
index 6101bec..b0f3ec0 100644
--- a/src/arm/disasm-arm.cc
+++ b/src/arm/disasm-arm.cc
@@ -187,11 +187,13 @@
Print(converter_.NameOfCPURegister(reg));
}
+
// Print the VFP S register name according to the active name converter.
void Decoder::PrintSRegister(int reg) {
Print(VFPRegisters::Name(reg, false));
}
+
// Print the VFP D register name according to the active name converter.
void Decoder::PrintDRegister(int reg) {
Print(VFPRegisters::Name(reg, true));
diff --git a/src/arm/full-codegen-arm.cc b/src/arm/full-codegen-arm.cc
index 41f02be..7716e85 100644
--- a/src/arm/full-codegen-arm.cc
+++ b/src/arm/full-codegen-arm.cc
@@ -4366,10 +4366,7 @@
const char* comment) {
// TODO(svenpanne): Allowing format strings in Comment would be nice here...
Comment cmt(masm_, comment);
- bool can_overwrite = expr->expression()->ResultOverwriteAllowed();
- UnaryOverwriteMode overwrite =
- can_overwrite ? UNARY_OVERWRITE : UNARY_NO_OVERWRITE;
- UnaryOpStub stub(expr->op(), overwrite);
+ UnaryOpStub stub(expr->op());
// UnaryOpStub expects the argument to be in the
// accumulator register r0.
VisitForAccumulatorValue(expr->expression());
diff --git a/src/arm/lithium-arm.cc b/src/arm/lithium-arm.cc
index b08353e..c8d0fdb 100644
--- a/src/arm/lithium-arm.cc
+++ b/src/arm/lithium-arm.cc
@@ -182,7 +182,7 @@
}
-void LCmpIDAndBranch::PrintDataTo(StringStream* stream) {
+void LCompareNumericAndBranch::PrintDataTo(StringStream* stream) {
stream->Add("if ");
left()->PrintTo(stream);
stream->Add(" %s ", Token::String(op()));
@@ -1685,8 +1685,8 @@
}
-LInstruction* LChunkBuilder::DoCompareIDAndBranch(
- HCompareIDAndBranch* instr) {
+LInstruction* LChunkBuilder::DoCompareNumericAndBranch(
+ HCompareNumericAndBranch* instr) {
Representation r = instr->representation();
if (r.IsSmiOrInteger32()) {
ASSERT(instr->left()->representation().IsSmiOrInteger32());
@@ -1694,14 +1694,14 @@
instr->right()->representation()));
LOperand* left = UseRegisterOrConstantAtStart(instr->left());
LOperand* right = UseRegisterOrConstantAtStart(instr->right());
- return new(zone()) LCmpIDAndBranch(left, right);
+ return new(zone()) LCompareNumericAndBranch(left, right);
} else {
ASSERT(r.IsDouble());
ASSERT(instr->left()->representation().IsDouble());
ASSERT(instr->right()->representation().IsDouble());
LOperand* left = UseRegisterAtStart(instr->left());
LOperand* right = UseRegisterAtStart(instr->right());
- return new(zone()) LCmpIDAndBranch(left, right);
+ return new(zone()) LCompareNumericAndBranch(left, right);
}
}
@@ -1998,6 +1998,18 @@
}
+LInstruction* LChunkBuilder::DoCheckSmi(HCheckSmi* instr) {
+ LOperand* value = UseRegisterAtStart(instr->value());
+ return AssignEnvironment(new(zone()) LCheckSmi(value));
+}
+
+
+LInstruction* LChunkBuilder::DoIsNumberAndBranch(HIsNumberAndBranch* instr) {
+ return new(zone())
+ LIsNumberAndBranch(UseRegisterOrConstantAtStart(instr->value()));
+}
+
+
LInstruction* LChunkBuilder::DoCheckInstanceType(HCheckInstanceType* instr) {
LOperand* value = UseRegisterAtStart(instr->value());
LInstruction* result = new(zone()) LCheckInstanceType(value);
diff --git a/src/arm/lithium-arm.h b/src/arm/lithium-arm.h
index 39cab8f..4adf026 100644
--- a/src/arm/lithium-arm.h
+++ b/src/arm/lithium-arm.h
@@ -81,7 +81,7 @@
V(ClampTToUint8) \
V(ClassOfTestAndBranch) \
V(CmpConstantEqAndBranch) \
- V(CmpIDAndBranch) \
+ V(CompareNumericAndBranch) \
V(CmpObjectEqAndBranch) \
V(CmpMapAndBranch) \
V(CmpT) \
@@ -118,6 +118,7 @@
V(IsConstructCallAndBranch) \
V(IsObjectAndBranch) \
V(IsStringAndBranch) \
+ V(IsNumberAndBranch) \
V(IsSmiAndBranch) \
V(IsUndetectableAndBranch) \
V(Label) \
@@ -719,9 +720,9 @@
};
-class LCmpIDAndBranch: public LControlInstruction<2, 0> {
+class LCompareNumericAndBranch: public LControlInstruction<2, 0> {
public:
- LCmpIDAndBranch(LOperand* left, LOperand* right) {
+ LCompareNumericAndBranch(LOperand* left, LOperand* right) {
inputs_[0] = left;
inputs_[1] = right;
}
@@ -729,8 +730,9 @@
LOperand* left() { return inputs_[0]; }
LOperand* right() { return inputs_[1]; }
- DECLARE_CONCRETE_INSTRUCTION(CmpIDAndBranch, "cmp-id-and-branch")
- DECLARE_HYDROGEN_ACCESSOR(CompareIDAndBranch)
+ DECLARE_CONCRETE_INSTRUCTION(CompareNumericAndBranch,
+ "compare-numeric-and-branch")
+ DECLARE_HYDROGEN_ACCESSOR(CompareNumericAndBranch)
Token::Value op() const { return hydrogen()->token(); }
bool is_double() const {
@@ -925,6 +927,19 @@
};
+class LIsNumberAndBranch: public LControlInstruction<1, 0> {
+ public:
+ explicit LIsNumberAndBranch(LOperand* value) {
+ inputs_[0] = value;
+ }
+
+ LOperand* value() { return inputs_[0]; }
+
+ DECLARE_CONCRETE_INSTRUCTION(IsNumberAndBranch, "is-number-and-branch")
+ DECLARE_HYDROGEN_ACCESSOR(IsNumberAndBranch)
+};
+
+
class LIsStringAndBranch: public LControlInstruction<1, 1> {
public:
LIsStringAndBranch(LOperand* value, LOperand* temp) {
diff --git a/src/arm/lithium-codegen-arm.cc b/src/arm/lithium-codegen-arm.cc
index 272db15..191ee49 100644
--- a/src/arm/lithium-codegen-arm.cc
+++ b/src/arm/lithium-codegen-arm.cc
@@ -2130,12 +2130,12 @@
template<class InstrType>
void LCodeGen::EmitBranch(InstrType instr, Condition cc) {
- int right_block = instr->FalseDestination(chunk_);
int left_block = instr->TrueDestination(chunk_);
+ int right_block = instr->FalseDestination(chunk_);
int next_block = GetNextEmittedBlock();
- if (right_block == left_block) {
+ if (right_block == left_block || cc == al) {
EmitGoto(left_block);
} else if (left_block == next_block) {
__ b(NegateCondition(cc), chunk_->GetAssemblyLabel(right_block));
@@ -2153,6 +2153,25 @@
}
+void LCodeGen::DoIsNumberAndBranch(LIsNumberAndBranch* instr) {
+ Representation r = instr->hydrogen()->value()->representation();
+ if (r.IsSmiOrInteger32() || r.IsDouble()) {
+ EmitBranch(instr, al);
+ } else {
+ ASSERT(r.IsTagged());
+ Register reg = ToRegister(instr->value());
+ HType type = instr->hydrogen()->value()->type();
+ if (type.IsTaggedNumber()) {
+ EmitBranch(instr, al);
+ }
+ __ JumpIfSmi(reg, instr->TrueLabel(chunk_));
+ __ ldr(scratch0(), FieldMemOperand(reg, HeapObject::kMapOffset));
+ __ CompareRoot(scratch0(), Heap::kHeapNumberMapRootIndex);
+ EmitBranch(instr, eq);
+ }
+}
+
+
void LCodeGen::DoBranch(LBranch* instr) {
Representation r = instr->hydrogen()->value()->representation();
if (r.IsInteger32() || r.IsSmi()) {
@@ -2329,7 +2348,7 @@
}
-void LCodeGen::DoCmpIDAndBranch(LCmpIDAndBranch* instr) {
+void LCodeGen::DoCompareNumericAndBranch(LCompareNumericAndBranch* instr) {
LOperand* left = instr->left();
LOperand* right = instr->right();
Condition cond = TokenToCondition(instr->op(), false);
diff --git a/src/arm/lithium-gap-resolver-arm.cc b/src/arm/lithium-gap-resolver-arm.cc
index 352fbb9..902817e 100644
--- a/src/arm/lithium-gap-resolver-arm.cc
+++ b/src/arm/lithium-gap-resolver-arm.cc
@@ -219,7 +219,6 @@
ASSERT(destination->IsStackSlot());
__ str(source_register, cgen_->ToMemOperand(destination));
}
-
} else if (source->IsStackSlot()) {
MemOperand source_operand = cgen_->ToMemOperand(source);
if (destination->IsRegister()) {
@@ -255,6 +254,10 @@
} else {
__ LoadObject(dst, cgen_->ToHandle(constant_source));
}
+ } else if (source->IsDoubleRegister()) {
+ DwVfpRegister result = cgen_->ToDoubleRegister(destination);
+ double v = cgen_->ToDouble(constant_source);
+ __ Vmov(result, v, ip);
} else {
ASSERT(destination->IsStackSlot());
ASSERT(!in_cycle_); // Constant moves happen after all cycles are gone.
diff --git a/src/arm/macro-assembler-arm.cc b/src/arm/macro-assembler-arm.cc
index cce20ff..5e38785 100644
--- a/src/arm/macro-assembler-arm.cc
+++ b/src/arm/macro-assembler-arm.cc
@@ -1033,6 +1033,7 @@
}
}
+
void MacroAssembler::GetCFunctionDoubleResult(const DwVfpRegister dst) {
if (use_eabi_hardfloat()) {
Move(dst, d0);
diff --git a/src/arm/simulator-arm.cc b/src/arm/simulator-arm.cc
index 238632a..b07e7be 100644
--- a/src/arm/simulator-arm.cc
+++ b/src/arm/simulator-arm.cc
@@ -1026,6 +1026,7 @@
registers_[12] = 0x50Bad4U;
}
+
// Some Operating Systems allow unaligned access on ARMv7 targets. We
// assume that unaligned accesses are not allowed unless the v8 build system
// defines the CAN_USE_UNALIGNED_ACCESSES macro to be non-zero.
@@ -1525,6 +1526,7 @@
}
}
+
// Addressing Mode 4 - Load and Store Multiple
void Simulator::HandleRList(Instruction* instr, bool load) {
int rlist = instr->RlistValue();
@@ -1954,6 +1956,7 @@
FixedDoubleArray::canonical_not_the_hole_nan_as_double() : value;
}
+
// Stop helper functions.
bool Simulator::isStopInstruction(Instruction* instr) {
return (instr->Bits(27, 24) == 0xF) && (instr->SvcValue() >= kStopCode);
diff --git a/src/assembler.cc b/src/assembler.cc
index b669e09..16a73a7 100644
--- a/src/assembler.cc
+++ b/src/assembler.cc
@@ -381,6 +381,7 @@
}
}
+
void RelocInfoWriter::WriteExtraTaggedConstPoolData(int data) {
WriteExtraTag(kConstPoolExtraTag, kConstPoolTag);
for (int i = 0; i < kIntSize; i++) {
@@ -390,6 +391,7 @@
}
}
+
void RelocInfoWriter::WriteExtraTaggedData(intptr_t data_delta, int top_tag) {
WriteExtraTag(kDataJumpExtraTag, top_tag);
for (int i = 0; i < kIntptrSize; i++) {
@@ -1322,6 +1324,7 @@
return ExternalReference(Redirect(isolate, function));
}
+
ExternalReference ExternalReference::re_grow_stack(Isolate* isolate) {
return ExternalReference(
Redirect(isolate, FUNCTION_ADDR(NativeRegExpMacroAssembler::GrowStack)));
@@ -1334,6 +1337,7 @@
FUNCTION_ADDR(NativeRegExpMacroAssembler::CaseInsensitiveCompareUC16)));
}
+
ExternalReference ExternalReference::re_word_character_map() {
return ExternalReference(
NativeRegExpMacroAssembler::word_character_map_address());
diff --git a/src/ast.cc b/src/ast.cc
index 589bd5a..7da9b33 100644
--- a/src/ast.cc
+++ b/src/ast.cc
@@ -675,6 +675,7 @@
if (is_monomorphic_) {
target_ = oracle->GetCallNewTarget(this);
Object* value = allocation_info_cell_->value();
+ ASSERT(!value->IsTheHole());
if (value->IsSmi()) {
elements_kind_ = static_cast<ElementsKind>(Smi::cast(value)->value());
}
diff --git a/src/ast.h b/src/ast.h
index b9a98e0..6336b3a 100644
--- a/src/ast.h
+++ b/src/ast.h
@@ -1884,9 +1884,6 @@
BailoutId RightId() const { return right_id_; }
TypeFeedbackId BinaryOperationFeedbackId() const { return reuse(id()); }
- // TODO(rossberg): result_type should be subsumed by lower_type.
- Handle<Type> result_type() const { return result_type_; }
- void set_result_type(Handle<Type> type) { result_type_ = type; }
Maybe<int> fixed_right_arg() const { return fixed_right_arg_; }
void set_fixed_right_arg(Maybe<int> arg) { fixed_right_arg_ = arg; }
@@ -1913,7 +1910,6 @@
Expression* right_;
int pos_;
- Handle<Type> result_type_;
// TODO(rossberg): the fixed arg should probably be represented as a Constant
// type for the RHS.
Maybe<int> fixed_right_arg_;
diff --git a/src/atomicops.h b/src/atomicops.h
index b18b54d..789721e 100644
--- a/src/atomicops.h
+++ b/src/atomicops.h
@@ -153,14 +153,11 @@
// Include our platform specific implementation.
#if defined(THREAD_SANITIZER)
#include "atomicops_internals_tsan.h"
-#elif defined(_MSC_VER) && \
- (V8_HOST_ARCH_IA32 || V8_HOST_ARCH_X64)
+#elif defined(_MSC_VER) && (V8_HOST_ARCH_IA32 || V8_HOST_ARCH_X64)
#include "atomicops_internals_x86_msvc.h"
-#elif defined(__APPLE__) && \
- (V8_HOST_ARCH_IA32 || V8_HOST_ARCH_X64)
+#elif defined(__APPLE__) && (V8_HOST_ARCH_IA32 || V8_HOST_ARCH_X64)
#include "atomicops_internals_x86_macosx.h"
-#elif defined(__GNUC__) && \
- (V8_HOST_ARCH_IA32 || V8_HOST_ARCH_X64)
+#elif defined(__GNUC__) && (V8_HOST_ARCH_IA32 || V8_HOST_ARCH_X64)
#include "atomicops_internals_x86_gcc.h"
#elif defined(__GNUC__) && V8_HOST_ARCH_ARM
#include "atomicops_internals_arm_gcc.h"
diff --git a/src/atomicops_internals_x86_gcc.cc b/src/atomicops_internals_x86_gcc.cc
index b5078cf..950b423 100644
--- a/src/atomicops_internals_x86_gcc.cc
+++ b/src/atomicops_internals_x86_gcc.cc
@@ -124,6 +124,7 @@
}
};
+
// A global to get use initialized on startup via static initialization :/
AtomicOpsx86Initializer g_initer;
diff --git a/src/bignum.cc b/src/bignum.cc
index c8b61ee..af0edde 100644
--- a/src/bignum.cc
+++ b/src/bignum.cc
@@ -45,6 +45,7 @@
return 8 * sizeof(value);
}
+
// Guaranteed to lie in one Bigit.
void Bignum::AssignUInt16(uint16_t value) {
ASSERT(kBigitSize >= BitSize(value));
diff --git a/src/bootstrapper.cc b/src/bootstrapper.cc
index 49333eb..dd3e94b 100644
--- a/src/bootstrapper.cc
+++ b/src/bootstrapper.cc
@@ -1289,7 +1289,7 @@
Builtins::kIllegal, false, true);
Handle<Map> initial_map = isolate()->factory()->NewMap(
- JS_TYPED_ARRAY_TYPE, JSTypedArray::kSize, elementsKind);
+ JS_TYPED_ARRAY_TYPE, JSTypedArray::kSizeWithInternalFields, elementsKind);
result->set_initial_map(*initial_map);
initial_map->set_constructor(*result);
return result;
@@ -1373,7 +1373,7 @@
Handle<JSFunction> data_view_fun =
InstallFunction(
global, "DataView", JS_DATA_VIEW_TYPE,
- JSDataView::kSize,
+ JSDataView::kSizeWithInternalFields,
isolate()->initial_object_prototype(),
Builtins::kIllegal, true, true);
native_context()->set_data_view_fun(*data_view_fun);
@@ -1586,6 +1586,7 @@
to_complete_property_descriptor);
}
+
void Genesis::InstallExperimentalNativeFunctions() {
if (FLAG_harmony_proxies) {
INSTALL_NATIVE(JSFunction, "DerivedHasTrap", derived_has_trap);
@@ -2239,10 +2240,12 @@
#endif
}
+
static uint32_t Hash(RegisteredExtension* extension) {
return v8::internal::ComputePointerHash(extension);
}
+
static bool MatchRegisteredExtensions(void* key1, void* key2) {
return key1 == key2;
}
diff --git a/src/builtins.cc b/src/builtins.cc
index be04ddf..f4ebdc2 100644
--- a/src/builtins.cc
+++ b/src/builtins.cc
@@ -182,6 +182,7 @@
return result;
}
+
// ----------------------------------------------------------------------------
BUILTIN(Illegal) {
@@ -1153,6 +1154,7 @@
"strict_poison_pill", HandleVector<Object>(NULL, 0)));
}
+
// -----------------------------------------------------------------------------
//
@@ -1432,14 +1434,17 @@
KeyedLoadIC::GeneratePreMonomorphic(masm);
}
+
static void Generate_KeyedLoadIC_IndexedInterceptor(MacroAssembler* masm) {
KeyedLoadIC::GenerateIndexedInterceptor(masm);
}
+
static void Generate_KeyedLoadIC_NonStrictArguments(MacroAssembler* masm) {
KeyedLoadIC::GenerateNonStrictArguments(masm);
}
+
static void Generate_StoreIC_Slow(MacroAssembler* masm) {
StoreIC::GenerateSlow(masm);
}
@@ -1539,14 +1544,17 @@
KeyedStoreIC::GenerateInitialize(masm);
}
+
static void Generate_KeyedStoreIC_NonStrictArguments(MacroAssembler* masm) {
KeyedStoreIC::GenerateNonStrictArguments(masm);
}
+
static void Generate_TransitionElementsSmiToDouble(MacroAssembler* masm) {
KeyedStoreIC::GenerateTransitionElementsSmiToDouble(masm);
}
+
static void Generate_TransitionElementsDoubleToObject(MacroAssembler* masm) {
KeyedStoreIC::GenerateTransitionElementsDoubleToObject(masm);
}
@@ -1716,6 +1724,7 @@
#undef DEF_FUNCTION_PTR_A
}
+
void Builtins::SetUp(bool create_heap_objects) {
ASSERT(!initialized_);
Isolate* isolate = Isolate::Current();
diff --git a/src/code-stubs-hydrogen.cc b/src/code-stubs-hydrogen.cc
index 96266af..9792096 100644
--- a/src/code-stubs-hydrogen.cc
+++ b/src/code-stubs-hydrogen.cc
@@ -329,7 +329,7 @@
HValue* elements = AddLoadElements(boilerplate);
IfBuilder if_fixed_cow(this);
- if_fixed_cow.IfCompareMap(elements, factory->fixed_cow_array_map());
+ if_fixed_cow.If<HCompareMap>(elements, factory->fixed_cow_array_map());
if_fixed_cow.Then();
environment()->Push(BuildCloneShallowArray(context(),
boilerplate,
@@ -339,7 +339,7 @@
if_fixed_cow.Else();
IfBuilder if_fixed(this);
- if_fixed.IfCompareMap(elements, factory->fixed_array_map());
+ if_fixed.If<HCompareMap>(elements, factory->fixed_array_map());
if_fixed.Then();
environment()->Push(BuildCloneShallowArray(context(),
boilerplate,
@@ -392,7 +392,8 @@
AddInstruction(new(zone) HInstanceSize(boilerplate));
HValue* size_in_words =
AddInstruction(new(zone) HConstant(size >> kPointerSizeLog2));
- checker.IfCompare(boilerplate_size, size_in_words, Token::EQ);
+ checker.If<HCompareNumericAndBranch>(boilerplate_size,
+ size_in_words, Token::EQ);
checker.Then();
HValue* size_in_bytes = AddInstruction(new(zone) HConstant(size));
@@ -501,7 +502,9 @@
IfBuilder if_builder(this);
- if_builder.IfCompare(array_length, graph()->GetConstant0(), Token::EQ);
+ if_builder.If<HCompareNumericAndBranch>(array_length,
+ graph()->GetConstant0(),
+ Token::EQ);
if_builder.Then();
// Nothing to do, just change the map.
@@ -606,7 +609,8 @@
HBoundsCheck* checked_arg = Add<HBoundsCheck>(argument, max_alloc_length);
IfBuilder if_builder(this);
- if_builder.IfCompare(checked_arg, constant_zero, Token::EQ);
+ if_builder.If<HCompareNumericAndBranch>(checked_arg, constant_zero,
+ Token::EQ);
if_builder.Then();
Push(initial_capacity_node); // capacity
Push(constant_zero); // length
@@ -764,13 +768,52 @@
template <>
+HValue* CodeStubGraphBuilder<UnaryOpStub>::BuildCodeInitializedStub() {
+ UnaryOpStub* stub = casted_stub();
+ Handle<Type> type = stub->GetType(graph()->isolate());
+ HValue* input = GetParameter(0);
+
+ // Prevent unwanted HChange being inserted to ensure that the stub
+ // deopts on newly encountered types.
+ if (!type->Maybe(Type::Double())) {
+ input = AddInstruction(new(zone())
+ HForceRepresentation(input, Representation::Smi()));
+ }
+
+ if (!type->Is(Type::Number())) {
+ // If we expect to see other things than Numbers, we will create a generic
+ // stub, which handles all numbers and calls into the runtime for the rest.
+ IfBuilder if_number(this);
+ if_number.If<HIsNumberAndBranch>(input);
+ if_number.Then();
+ HInstruction* res = BuildUnaryMathOp(input, type, stub->operation());
+ if_number.Return(AddInstruction(res));
+ if_number.Else();
+ HValue* function = AddLoadJSBuiltin(stub->ToJSBuiltin(), context());
+ Add<HPushArgument>(GetParameter(0));
+ HValue* result = Add<HInvokeFunction>(context(), function, 1);
+ if_number.Return(result);
+ if_number.End();
+ return graph()->GetConstantUndefined();
+ }
+
+ return AddInstruction(BuildUnaryMathOp(input, type, stub->operation()));
+}
+
+
+Handle<Code> UnaryOpStub::GenerateCode() {
+ return DoGenerateCode(this);
+}
+
+
+template <>
HValue* CodeStubGraphBuilder<ToBooleanStub>::BuildCodeInitializedStub() {
ToBooleanStub* stub = casted_stub();
IfBuilder if_true(this);
if_true.If<HBranch>(GetParameter(0), stub->GetTypes());
if_true.Then();
- if_true.Return(graph()->GetConstant1());
+ if_true.Return(graph()->GetConstant1());
if_true.Else();
if_true.End();
return graph()->GetConstant0();
@@ -782,4 +825,50 @@
}
+template <>
+HValue* CodeStubGraphBuilder<StoreGlobalStub>::BuildCodeInitializedStub() {
+ StoreGlobalStub* stub = casted_stub();
+ Handle<Object> hole(isolate()->heap()->the_hole_value(), isolate());
+ Handle<Object> placeholer_value(Smi::FromInt(0), isolate());
+ Handle<PropertyCell> placeholder_cell =
+ isolate()->factory()->NewPropertyCell(placeholer_value);
+
+ HParameter* receiver = GetParameter(0);
+ HParameter* value = GetParameter(2);
+
+ if (stub->is_constant()) {
+ // Assume every store to a constant value changes it.
+ current_block()->FinishExitWithDeoptimization(HDeoptimize::kUseAll);
+ set_current_block(NULL);
+ } else {
+ HValue* cell = Add<HConstant>(placeholder_cell, Representation::Tagged());
+
+ // Check that the map of the global has not changed: use a placeholder map
+ // that will be replaced later with the global object's map.
+ Handle<Map> placeholder_map = isolate()->factory()->meta_map();
+ AddInstruction(HCheckMaps::New(receiver, placeholder_map, zone()));
+
+ // Load the payload of the global parameter cell. A hole indicates that the
+ // property has been deleted and that the store must be handled by the
+ // runtime.
+ HObjectAccess access(HObjectAccess::ForCellPayload(isolate()));
+ HValue* cell_contents = Add<HLoadNamedField>(cell, access);
+ IfBuilder builder(this);
+ HValue* hole_value = Add<HConstant>(hole, Representation::Tagged());
+ builder.If<HCompareObjectEqAndBranch>(cell_contents, hole_value);
+ builder.Then();
+ builder.Deopt();
+ builder.Else();
+ Add<HStoreNamedField>(cell, access, value);
+ builder.End();
+ }
+ return value;
+}
+
+
+Handle<Code> StoreGlobalStub::GenerateCode() {
+ return DoGenerateCode(this);
+}
+
+
} } // namespace v8::internal
diff --git a/src/code-stubs.cc b/src/code-stubs.cc
index 2ed2ba3..802e720 100644
--- a/src/code-stubs.cc
+++ b/src/code-stubs.cc
@@ -85,6 +85,14 @@
}
+Handle<Code> CodeStub::GetCodeCopyFromTemplate(Isolate* isolate) {
+ Handle<Code> ic = GetCode(isolate);
+ ic = isolate->factory()->CopyCode(ic);
+ RecordCodeGeneration(*ic, isolate);
+ return ic;
+}
+
+
Handle<Code> PlatformCodeStub::GenerateCode() {
Isolate* isolate = Isolate::Current();
Factory* factory = isolate->factory();
@@ -185,11 +193,82 @@
}
-void CodeStub::PrintName(StringStream* stream) {
+void CodeStub::PrintBaseName(StringStream* stream) {
stream->Add("%s", MajorName(MajorKey(), false));
}
+void CodeStub::PrintName(StringStream* stream) {
+ PrintBaseName(stream);
+ PrintState(stream);
+}
+
+
+Builtins::JavaScript UnaryOpStub::ToJSBuiltin() {
+ switch (operation_) {
+ default:
+ UNREACHABLE();
+ case Token::SUB:
+ return Builtins::UNARY_MINUS;
+ case Token::BIT_NOT:
+ return Builtins::BIT_NOT;
+ }
+}
+
+
+Handle<JSFunction> UnaryOpStub::ToJSFunction(Isolate* isolate) {
+ Handle<JSBuiltinsObject> builtins(isolate->js_builtins_object());
+ Object* builtin = builtins->javascript_builtin(ToJSBuiltin());
+ return Handle<JSFunction>(JSFunction::cast(builtin), isolate);
+}
+
+
+MaybeObject* UnaryOpStub::Result(Handle<Object> object, Isolate* isolate) {
+ Handle<JSFunction> builtin_function = ToJSFunction(isolate);
+ bool caught_exception;
+ Handle<Object> result = Execution::Call(builtin_function, object,
+ 0, NULL, &caught_exception);
+ if (caught_exception) {
+ return Failure::Exception();
+ }
+ return *result;
+}
+
+
+void UnaryOpStub::UpdateStatus(Handle<Object> object) {
+ State old_state(state_);
+ if (object->IsSmi()) {
+ state_.Add(SMI);
+ if (operation_ == Token::SUB && *object == 0) {
+ // The result (-0) has to be represented as double.
+ state_.Add(HEAP_NUMBER);
+ }
+ } else if (object->IsHeapNumber()) {
+ state_.Add(HEAP_NUMBER);
+ } else {
+ state_.Add(GENERIC);
+ }
+ TraceTransition(old_state, state_);
+}
+
+
+Handle<Type> UnaryOpStub::GetType(Isolate* isolate) {
+ if (state_.Contains(GENERIC)) {
+ return handle(Type::Any(), isolate);
+ }
+ Handle<Type> type = handle(Type::None(), isolate);
+ if (state_.Contains(SMI)) {
+ type = handle(
+ Type::Union(type, handle(Type::Smi(), isolate)), isolate);
+ }
+ if (state_.Contains(HEAP_NUMBER)) {
+ type = handle(
+ Type::Union(type, handle(Type::Double(), isolate)), isolate);
+ }
+ return type;
+}
+
+
void BinaryOpStub::Generate(MacroAssembler* masm) {
// Explicitly allow generation of nested stubs. It is safe here because
// generation code does not use any raw pointers.
@@ -275,6 +354,29 @@
#undef __
+void UnaryOpStub::PrintBaseName(StringStream* stream) {
+ CodeStub::PrintBaseName(stream);
+ if (operation_ == Token::SUB) stream->Add("Minus");
+ if (operation_ == Token::BIT_NOT) stream->Add("Not");
+}
+
+
+void UnaryOpStub::PrintState(StringStream* stream) {
+ state_.Print(stream);
+}
+
+
+void UnaryOpStub::State::Print(StringStream* stream) const {
+ stream->Add("(");
+ SimpleListPrinter printer(stream);
+ if (IsEmpty()) printer.Add("None");
+ if (Contains(GENERIC)) printer.Add("Generic");
+ if (Contains(HEAP_NUMBER)) printer.Add("HeapNumber");
+ if (Contains(SMI)) printer.Add("Smi");
+ stream->Add(")");
+}
+
+
void BinaryOpStub::PrintName(StringStream* stream) {
const char* op_name = Token::Name(op_);
const char* overwrite_name;
@@ -431,8 +533,9 @@
}
-void CompareNilICStub::Record(Handle<Object> object) {
+void CompareNilICStub::UpdateStatus(Handle<Object> object) {
ASSERT(state_ != State::Generic());
+ State old_state(state_);
if (object->IsNull()) {
state_.Add(NULL_TYPE);
} else if (object->IsUndefined()) {
@@ -446,18 +549,22 @@
} else {
state_.Add(MONOMORPHIC_MAP);
}
+ TraceTransition(old_state, state_);
}
-void CompareNilICStub::State::TraceTransition(State to) const {
+template<class StateType>
+void HydrogenCodeStub::TraceTransition(StateType from, StateType to) {
#ifdef DEBUG
if (!FLAG_trace_ic) return;
char buffer[100];
NoAllocationStringAllocator allocator(buffer,
static_cast<unsigned>(sizeof(buffer)));
StringStream stream(&allocator);
- stream.Add("[CompareNilIC : ");
- Print(&stream);
+ stream.Add("[");
+ PrintBaseName(&stream);
+ stream.Add(": ");
+ from.Print(&stream);
stream.Add("=>");
to.Print(&stream);
stream.Add("]\n");
@@ -466,11 +573,15 @@
}
-void CompareNilICStub::PrintName(StringStream* stream) {
- stream->Add("CompareNilICStub_");
+void CompareNilICStub::PrintBaseName(StringStream* stream) {
+ CodeStub::PrintBaseName(stream);
+ stream->Add((nil_value_ == kNullValue) ? "(NullValue)":
+ "(UndefinedValue)");
+}
+
+
+void CompareNilICStub::PrintState(StringStream* stream) {
state_.Print(stream);
- stream->Add((nil_value_ == kNullValue) ? "(NullValue|":
- "(UndefinedValue|");
}
@@ -615,16 +726,15 @@
}
-bool ToBooleanStub::Record(Handle<Object> object) {
+bool ToBooleanStub::UpdateStatus(Handle<Object> object) {
Types old_types(types_);
- bool to_boolean_value = types_.Record(object);
- old_types.TraceTransition(types_);
+ bool to_boolean_value = types_.UpdateStatus(object);
+ TraceTransition(old_types, types_);
return to_boolean_value;
}
-void ToBooleanStub::PrintName(StringStream* stream) {
- stream->Add("ToBooleanStub_");
+void ToBooleanStub::PrintState(StringStream* stream) {
types_.Print(stream);
}
@@ -645,24 +755,7 @@
}
-void ToBooleanStub::Types::TraceTransition(Types to) const {
- #ifdef DEBUG
- if (!FLAG_trace_ic) return;
- char buffer[100];
- NoAllocationStringAllocator allocator(buffer,
- static_cast<unsigned>(sizeof(buffer)));
- StringStream stream(&allocator);
- stream.Add("[ToBooleanIC : ");
- Print(&stream);
- stream.Add("=>");
- to.Print(&stream);
- stream.Add("]\n");
- stream.OutputToStdOut();
- #endif
-}
-
-
-bool ToBooleanStub::Types::Record(Handle<Object> object) {
+bool ToBooleanStub::Types::UpdateStatus(Handle<Object> object) {
if (object->IsUndefined()) {
Add(UNDEFINED);
return false;
diff --git a/src/code-stubs.h b/src/code-stubs.h
index d197c84..0eefe8c 100644
--- a/src/code-stubs.h
+++ b/src/code-stubs.h
@@ -90,6 +90,7 @@
V(ArrayConstructor) \
V(InternalArrayConstructor) \
V(ProfileEntryHook) \
+ V(StoreGlobal) \
/* IC Handler stubs */ \
V(LoadField) \
V(KeyedLoadField)
@@ -123,8 +124,6 @@
// Mode to overwrite BinaryExpression values.
enum OverwriteMode { NO_OVERWRITE, OVERWRITE_LEFT, OVERWRITE_RIGHT };
-enum UnaryOverwriteMode { UNARY_OVERWRITE, UNARY_NO_OVERWRITE };
-
// Stub is base classes of all stubs.
class CodeStub BASE_EMBEDDED {
@@ -140,6 +139,8 @@
// Retrieve the code for the stub. Generate the code if needed.
Handle<Code> GetCode(Isolate* isolate);
+ // Retrieve the code for the stub, make and return a copy of the code.
+ Handle<Code> GetCodeCopyFromTemplate(Isolate* isolate);
static Major MajorKeyFromKey(uint32_t key) {
return static_cast<Major>(MajorKeyBits::decode(key));
}
@@ -197,6 +198,8 @@
return -1;
}
+ virtual void PrintName(StringStream* stream);
+
protected:
static bool CanUseFPRegisters();
@@ -208,6 +211,11 @@
// a fixed (non-moveable) code object.
virtual bool NeedsImmovableCode() { return false; }
+ // Returns a name for logging/debugging purposes.
+ SmartArrayPointer<const char> GetName();
+ virtual void PrintBaseName(StringStream* stream);
+ virtual void PrintState(StringStream* stream) { }
+
private:
// Perform bookkeeping required after code generation when stub code is
// initially generated.
@@ -236,10 +244,6 @@
// If a stub uses a special cache override this.
virtual bool UseSpecialCache() { return false; }
- // Returns a name for logging/debugging purposes.
- SmartArrayPointer<const char> GetName();
- virtual void PrintName(StringStream* stream);
-
// Computes the key based on major and minor.
uint32_t GetKey() {
ASSERT(static_cast<int>(MajorKey()) < NUMBER_OF_IDS);
@@ -354,6 +358,9 @@
Handle<Code> GenerateLightweightMissCode(Isolate* isolate);
+ template<class StateType>
+ void TraceTransition(StateType from, StateType to);
+
private:
class MinorKeyBits: public BitField<int, 0, kStubMinorKeyBits - 1> {};
class IsMissBits: public BitField<bool, kStubMinorKeyBits - 1, 1> {};
@@ -519,6 +526,117 @@
int MinorKey() { return slots_; }
};
+class StoreGlobalStub : public HydrogenCodeStub {
+ public:
+ StoreGlobalStub(StrictModeFlag strict_mode, bool is_constant) {
+ bit_field_ = StrictModeBits::encode(strict_mode) |
+ IsConstantBits::encode(is_constant);
+ }
+
+ virtual Handle<Code> GenerateCode();
+
+ virtual void InitializeInterfaceDescriptor(
+ Isolate* isolate,
+ CodeStubInterfaceDescriptor* descriptor);
+
+ virtual Code::Kind GetCodeKind() const { return Code::STORE_IC; }
+ virtual InlineCacheState GetICState() { return MONOMORPHIC; }
+ virtual Code::ExtraICState GetExtraICState() { return bit_field_; }
+
+ bool is_constant() {
+ return IsConstantBits::decode(bit_field_);
+ }
+ void set_is_constant(bool value) {
+ bit_field_ = IsConstantBits::update(bit_field_, value);
+ }
+
+ Representation representation() {
+ return Representation::FromKind(RepresentationBits::decode(bit_field_));
+ }
+ void set_representation(Representation r) {
+ bit_field_ = RepresentationBits::update(bit_field_, r.kind());
+ }
+
+ private:
+ virtual int NotMissMinorKey() { return GetExtraICState(); }
+ Major MajorKey() { return StoreGlobal; }
+
+ class StrictModeBits: public BitField<StrictModeFlag, 0, 1> {};
+ class IsConstantBits: public BitField<bool, 1, 1> {};
+ class RepresentationBits: public BitField<Representation::Kind, 2, 8> {};
+
+ int bit_field_;
+
+ DISALLOW_COPY_AND_ASSIGN(StoreGlobalStub);
+};
+
+
+class UnaryOpStub : public HydrogenCodeStub {
+ public:
+ // Stub without type info available -> construct uninitialized
+ explicit UnaryOpStub(Token::Value operation)
+ : HydrogenCodeStub(UNINITIALIZED), operation_(operation) { }
+ explicit UnaryOpStub(Code::ExtraICState ic_state) :
+ state_(StateBits::decode(ic_state)),
+ operation_(OperatorBits::decode(ic_state)) { }
+
+ virtual void InitializeInterfaceDescriptor(
+ Isolate* isolate,
+ CodeStubInterfaceDescriptor* descriptor);
+
+ virtual Code::Kind GetCodeKind() const { return Code::UNARY_OP_IC; }
+ virtual InlineCacheState GetICState() {
+ if (state_.Contains(GENERIC)) {
+ return MEGAMORPHIC;
+ } else if (state_.IsEmpty()) {
+ return PREMONOMORPHIC;
+ } else {
+ return MONOMORPHIC;
+ }
+ }
+ virtual Code::ExtraICState GetExtraICState() {
+ return OperatorBits::encode(operation_) |
+ StateBits::encode(state_.ToIntegral());
+ }
+
+ Token::Value operation() { return operation_; }
+ Handle<JSFunction> ToJSFunction(Isolate* isolate);
+ Builtins::JavaScript ToJSBuiltin();
+
+ void UpdateStatus(Handle<Object> object);
+ MaybeObject* Result(Handle<Object> object, Isolate* isolate);
+ Handle<Code> GenerateCode();
+ Handle<Type> GetType(Isolate* isolate);
+
+ protected:
+ void PrintState(StringStream* stream);
+ void PrintBaseName(StringStream* stream);
+
+ private:
+ enum UnaryOpType {
+ SMI,
+ HEAP_NUMBER,
+ GENERIC,
+ NUMBER_OF_TYPES
+ };
+
+ class State : public EnumSet<UnaryOpType, byte> {
+ public:
+ State() : EnumSet<UnaryOpType, byte>() { }
+ explicit State(byte bits) : EnumSet<UnaryOpType, byte>(bits) { }
+ void Print(StringStream* stream) const;
+ };
+
+ class StateBits : public BitField<int, 0, NUMBER_OF_TYPES> { };
+ class OperatorBits : public BitField<Token::Value, NUMBER_OF_TYPES, 8> { };
+
+ State state_;
+ Token::Value operation_;
+
+ virtual CodeStub::Major MajorKey() { return UnaryOp; }
+ virtual int NotMissMinorKey() { return GetExtraICState(); }
+};
+
class FastCloneShallowArrayStub : public HydrogenCodeStub {
public:
@@ -1143,7 +1261,6 @@
}
void Print(StringStream* stream) const;
- void TraceTransition(State to) const;
};
static Handle<Type> StateToType(
@@ -1206,14 +1323,15 @@
return NilValueField::decode(state);
}
- void Record(Handle<Object> object);
+ void UpdateStatus(Handle<Object> object);
bool IsMonomorphic() const { return state_.Contains(MONOMORPHIC_MAP); }
NilValue GetNilValue() const { return nil_value_; }
State GetState() const { return state_; }
void ClearState() { state_.RemoveAll(); }
- virtual void PrintName(StringStream* stream);
+ virtual void PrintState(StringStream* stream);
+ virtual void PrintBaseName(StringStream* stream);
private:
friend class CompareNilIC;
@@ -2009,8 +2127,7 @@
byte ToByte() const { return ToIntegral(); }
void Print(StringStream* stream) const;
- void TraceTransition(Types to) const;
- bool Record(Handle<Object> object);
+ bool UpdateStatus(Handle<Object> object);
bool NeedsMap() const;
bool CanBeUndetectable() const;
bool IsGeneric() const { return ToIntegral() == Generic().ToIntegral(); }
@@ -2023,7 +2140,7 @@
explicit ToBooleanStub(Code::ExtraICState state)
: types_(static_cast<byte>(state)) { }
- bool Record(Handle<Object> object);
+ bool UpdateStatus(Handle<Object> object);
Types GetTypes() { return types_; }
virtual Handle<Code> GenerateCode();
@@ -2032,7 +2149,7 @@
CodeStubInterfaceDescriptor* descriptor);
virtual Code::Kind GetCodeKind() const { return Code::TO_BOOLEAN_IC; }
- virtual void PrintName(StringStream* stream);
+ virtual void PrintState(StringStream* stream);
virtual bool SometimesSetsUpAFrame() { return false; }
diff --git a/src/compilation-cache.cc b/src/compilation-cache.cc
index 7ace2f7..18c82e9 100644
--- a/src/compilation-cache.cc
+++ b/src/compilation-cache.cc
@@ -86,6 +86,7 @@
return result;
}
+
void CompilationSubCache::Age() {
// Age the generations implicitly killing off the oldest.
for (int i = generations_ - 1; i > 0; i--) {
diff --git a/src/compiler.cc b/src/compiler.cc
index 8edb41d..7497f09 100644
--- a/src/compiler.cc
+++ b/src/compiler.cc
@@ -449,6 +449,7 @@
return SetLastStatus(SUCCEEDED);
}
+
OptimizingCompiler::Status OptimizingCompiler::OptimizeGraph() {
DisallowHeapAllocation no_allocation;
DisallowHandleAllocation no_handles;
@@ -1199,9 +1200,9 @@
Handle<Code> code = info->code();
if (*code == info->isolate()->builtins()->builtin(Builtins::kLazyCompile))
return;
+ int line_num = GetScriptLineNumber(script, shared->start_position()) + 1;
+ USE(line_num);
if (script->name()->IsString()) {
- int line_num = GetScriptLineNumber(script, shared->start_position()) + 1;
- USE(line_num);
PROFILE(info->isolate(),
CodeCreateEvent(Logger::ToNativeByScript(tag, *script),
*code,
@@ -1215,7 +1216,8 @@
*code,
*shared,
info,
- shared->DebugName()));
+ info->isolate()->heap()->empty_string(),
+ line_num));
}
}
diff --git a/src/contexts.cc b/src/contexts.cc
index 5edbc5a..58f23e7 100644
--- a/src/contexts.cc
+++ b/src/contexts.cc
@@ -88,6 +88,7 @@
return native_context()->global_proxy_object();
}
+
void Context::set_global_proxy(JSObject* object) {
native_context()->set_global_proxy_object(object);
}
diff --git a/src/counters.cc b/src/counters.cc
index fa192ba..1839412 100644
--- a/src/counters.cc
+++ b/src/counters.cc
@@ -56,6 +56,7 @@
CreateHistogram(name_, min_, max_, num_buckets_);
}
+
// Start the timer.
void HistogramTimer::Start() {
if (Enabled()) {
@@ -67,6 +68,7 @@
}
}
+
// Stop the timer and record the results.
void HistogramTimer::Stop() {
if (Enabled()) {
diff --git a/src/cpu-profiler-inl.h b/src/cpu-profiler-inl.h
index c3cc27c..bafea06 100644
--- a/src/cpu-profiler-inl.h
+++ b/src/cpu-profiler-inl.h
@@ -70,7 +70,7 @@
TickSample* ProfilerEventsProcessor::TickSampleEvent() {
generator_->Tick();
TickSampleEventRecord* evt =
- new(ticks_buffer_.Enqueue()) TickSampleEventRecord(enqueue_order_);
+ new(ticks_buffer_.Enqueue()) TickSampleEventRecord(last_code_event_id_);
return &evt->sample;
}
diff --git a/src/cpu-profiler.cc b/src/cpu-profiler.cc
index b3800f5..d3fadb5 100644
--- a/src/cpu-profiler.cc
+++ b/src/cpu-profiler.cc
@@ -52,18 +52,18 @@
ticks_buffer_(sizeof(TickSampleEventRecord),
kTickSamplesBufferChunkSize,
kTickSamplesBufferChunksCount),
- enqueue_order_(0) {
+ last_code_event_id_(0), last_processed_code_event_id_(0) {
}
void ProfilerEventsProcessor::Enqueue(const CodeEventsContainer& event) {
- event.generic.order = ++enqueue_order_;
+ event.generic.order = ++last_code_event_id_;
events_buffer_.Enqueue(event);
}
void ProfilerEventsProcessor::AddCurrentStack(Isolate* isolate) {
- TickSampleEventRecord record(enqueue_order_);
+ TickSampleEventRecord record(last_code_event_id_);
TickSample* sample = &record.sample;
sample->state = isolate->current_vm_state();
sample->pc = reinterpret_cast<Address>(sample); // Not NULL.
@@ -76,7 +76,14 @@
}
-bool ProfilerEventsProcessor::ProcessCodeEvent(unsigned* dequeue_order) {
+void ProfilerEventsProcessor::StopSynchronously() {
+ if (!running_) return;
+ running_ = false;
+ Join();
+}
+
+
+bool ProfilerEventsProcessor::ProcessCodeEvent() {
CodeEventsContainer record;
if (events_buffer_.Dequeue(&record)) {
switch (record.generic.type) {
@@ -90,17 +97,18 @@
#undef PROFILER_TYPE_CASE
default: return true; // Skip record.
}
- *dequeue_order = record.generic.order;
+ last_processed_code_event_id_ = record.generic.order;
return true;
}
return false;
}
-bool ProfilerEventsProcessor::ProcessTicks(unsigned dequeue_order) {
+bool ProfilerEventsProcessor::ProcessTicks() {
while (true) {
if (!ticks_from_vm_buffer_.IsEmpty()
- && ticks_from_vm_buffer_.Peek()->order == dequeue_order) {
+ && ticks_from_vm_buffer_.Peek()->order ==
+ last_processed_code_event_id_) {
TickSampleEventRecord record;
ticks_from_vm_buffer_.Dequeue(&record);
generator_->RecordTickSample(record.sample);
@@ -115,56 +123,46 @@
// will get far behind, a record may be modified right under its
// feet.
TickSampleEventRecord record = *rec;
- if (record.order == dequeue_order) {
- // A paranoid check to make sure that we don't get a memory overrun
- // in case of frames_count having a wild value.
- if (record.sample.frames_count < 0
- || record.sample.frames_count > TickSample::kMaxFramesCount)
- record.sample.frames_count = 0;
- generator_->RecordTickSample(record.sample);
- ticks_buffer_.FinishDequeue();
- } else {
- return true;
- }
+ if (record.order != last_processed_code_event_id_) return true;
+
+ // A paranoid check to make sure that we don't get a memory overrun
+ // in case of frames_count having a wild value.
+ if (record.sample.frames_count < 0
+ || record.sample.frames_count > TickSample::kMaxFramesCount)
+ record.sample.frames_count = 0;
+ generator_->RecordTickSample(record.sample);
+ ticks_buffer_.FinishDequeue();
}
}
void ProfilerEventsProcessor::Run() {
- unsigned dequeue_order = 0;
-
while (running_) {
// Process ticks until we have any.
- if (ProcessTicks(dequeue_order)) {
- // All ticks of the current dequeue_order are processed,
+ if (ProcessTicks()) {
+ // All ticks of the current last_processed_code_event_id_ are processed,
// proceed to the next code event.
- ProcessCodeEvent(&dequeue_order);
+ ProcessCodeEvent();
}
YieldCPU();
}
// Process remaining tick events.
ticks_buffer_.FlushResidualRecords();
- // Perform processing until we have tick events, skip remaining code events.
- while (ProcessTicks(dequeue_order) && ProcessCodeEvent(&dequeue_order)) { }
+ do {
+ ProcessTicks();
+ } while (ProcessCodeEvent());
}
int CpuProfiler::GetProfilesCount() {
// The count of profiles doesn't depend on a security token.
- return profiles_->Profiles(TokenEnumerator::kNoSecurityToken)->length();
+ return profiles_->profiles()->length();
}
-CpuProfile* CpuProfiler::GetProfile(Object* security_token, int index) {
- const int token = token_enumerator_->GetTokenId(security_token);
- return profiles_->Profiles(token)->at(index);
-}
-
-
-CpuProfile* CpuProfiler::FindProfile(Object* security_token, unsigned uid) {
- const int token = token_enumerator_->GetTokenId(security_token);
- return profiles_->GetProfile(token, uid);
+CpuProfile* CpuProfiler::GetProfile(int index) {
+ return profiles_->profiles()->at(index);
}
@@ -186,11 +184,6 @@
}
-bool CpuProfiler::HasDetachedProfiles() {
- return profiles_->HasDetachedProfiles();
-}
-
-
static bool FilterOutCodeCreateEvent(Logger::LogEventsAndTags tag) {
return FLAG_prof_browser_mode
&& (tag != Logger::CALLBACK_TAG
@@ -208,8 +201,7 @@
rec->start = entry_point;
rec->entry = profiles_->NewCodeEntry(
Logger::CALLBACK_TAG,
- profiles_->GetName(name),
- TokenEnumerator::kInheritsSecurityToken);
+ profiles_->GetName(name));
rec->size = 1;
rec->shared = NULL;
processor_->Enqueue(evt_rec);
@@ -280,7 +272,6 @@
rec->entry = profiles_->NewCodeEntry(
tag,
profiles_->GetFunctionName(shared->DebugName()),
- TokenEnumerator::kNoSecurityToken,
CodeEntry::kEmptyNamePrefix,
profiles_->GetName(source),
line);
@@ -306,7 +297,6 @@
rec->entry = profiles_->NewCodeEntry(
tag,
profiles_->GetName(args_count),
- TokenEnumerator::kInheritsSecurityToken,
"args_count: ");
rec->size = code->ExecutableSize();
rec->shared = NULL;
@@ -345,7 +335,6 @@
rec->entry = profiles_->NewCodeEntry(
Logger::CALLBACK_TAG,
profiles_->GetName(name),
- TokenEnumerator::kInheritsSecurityToken,
"get ");
rec->size = 1;
rec->shared = NULL;
@@ -361,7 +350,6 @@
rec->entry = profiles_->NewCodeEntry(
Logger::REG_EXP_TAG,
profiles_->GetName(source),
- TokenEnumerator::kInheritsSecurityToken,
"RegExp: ");
rec->size = code->ExecutableSize();
processor_->Enqueue(evt_rec);
@@ -376,7 +364,6 @@
rec->entry = profiles_->NewCodeEntry(
Logger::CALLBACK_TAG,
profiles_->GetName(name),
- TokenEnumerator::kInheritsSecurityToken,
"set ");
rec->size = 1;
rec->shared = NULL;
@@ -388,7 +375,6 @@
: isolate_(isolate),
profiles_(new CpuProfilesCollection()),
next_profile_uid_(1),
- token_enumerator_(new TokenEnumerator()),
generator_(NULL),
processor_(NULL),
need_to_stop_sampler_(false),
@@ -403,7 +389,6 @@
: isolate_(isolate),
profiles_(test_profiles),
next_profile_uid_(1),
- token_enumerator_(new TokenEnumerator()),
generator_(test_generator),
processor_(test_processor),
need_to_stop_sampler_(false),
@@ -413,7 +398,6 @@
CpuProfiler::~CpuProfiler() {
ASSERT(!is_profiling_);
- delete token_enumerator_;
delete profiles_;
}
@@ -423,6 +407,7 @@
profiles_ = new CpuProfilesCollection();
}
+
void CpuProfiler::StartProfiling(const char* title, bool record_samples) {
if (profiles_->StartProfiling(title, next_profile_uid_++, record_samples)) {
StartProcessorIfNotStarted();
@@ -469,10 +454,7 @@
if (!is_profiling_) return NULL;
const double actual_sampling_rate = generator_->actual_sampling_rate();
StopProcessorIfLastProfile(title);
- CpuProfile* result =
- profiles_->StopProfiling(TokenEnumerator::kNoSecurityToken,
- title,
- actual_sampling_rate);
+ CpuProfile* result = profiles_->StopProfiling(title, actual_sampling_rate);
if (result != NULL) {
result->Print();
}
@@ -480,13 +462,12 @@
}
-CpuProfile* CpuProfiler::StopProfiling(Object* security_token, String* title) {
+CpuProfile* CpuProfiler::StopProfiling(String* title) {
if (!is_profiling_) return NULL;
const double actual_sampling_rate = generator_->actual_sampling_rate();
const char* profile_title = profiles_->GetName(title);
StopProcessorIfLastProfile(profile_title);
- int token = token_enumerator_->GetTokenId(security_token);
- return profiles_->StopProfiling(token, profile_title, actual_sampling_rate);
+ return profiles_->StopProfiling(profile_title, actual_sampling_rate);
}
@@ -504,8 +485,7 @@
need_to_stop_sampler_ = false;
}
is_profiling_ = false;
- processor_->Stop();
- processor_->Join();
+ processor_->StopSynchronously();
delete processor_;
delete generator_;
processor_ = NULL;
diff --git a/src/cpu-profiler.h b/src/cpu-profiler.h
index 77fdb06..0718a89 100644
--- a/src/cpu-profiler.h
+++ b/src/cpu-profiler.h
@@ -44,7 +44,6 @@
class CpuProfile;
class CpuProfilesCollection;
class ProfileGenerator;
-class TokenEnumerator;
#define CODE_EVENTS_TYPE_LIST(V) \
V(CODE_CREATION, CodeCreateEventRecord) \
@@ -156,7 +155,7 @@
// Thread control.
virtual void Run();
- inline void Stop() { running_ = false; }
+ void StopSynchronously();
INLINE(bool running()) { return running_; }
void Enqueue(const CodeEventsContainer& event);
@@ -171,15 +170,16 @@
private:
// Called from events processing thread (Run() method.)
- bool ProcessCodeEvent(unsigned* dequeue_order);
- bool ProcessTicks(unsigned dequeue_order);
+ bool ProcessCodeEvent();
+ bool ProcessTicks();
ProfileGenerator* generator_;
bool running_;
UnboundQueue<CodeEventsContainer> events_buffer_;
SamplingCircularQueue ticks_buffer_;
UnboundQueue<TickSampleEventRecord> ticks_from_vm_buffer_;
- unsigned enqueue_order_;
+ unsigned last_code_event_id_;
+ unsigned last_processed_code_event_id_;
};
@@ -208,13 +208,11 @@
void StartProfiling(const char* title, bool record_samples = false);
void StartProfiling(String* title, bool record_samples);
CpuProfile* StopProfiling(const char* title);
- CpuProfile* StopProfiling(Object* security_token, String* title);
+ CpuProfile* StopProfiling(String* title);
int GetProfilesCount();
- CpuProfile* GetProfile(Object* security_token, int index);
- CpuProfile* FindProfile(Object* security_token, unsigned uid);
+ CpuProfile* GetProfile(int index);
void DeleteAllProfiles();
void DeleteProfile(CpuProfile* profile);
- bool HasDetachedProfiles();
// Invoked from stack sampler (thread or signal handler.)
TickSample* TickSampleEvent();
@@ -251,6 +249,9 @@
return &is_profiling_;
}
+ ProfileGenerator* generator() const { return generator_; }
+ ProfilerEventsProcessor* processor() const { return processor_; }
+
private:
void StartProcessorIfNotStarted();
void StopProcessorIfLastProfile(const char* title);
@@ -261,7 +262,6 @@
Isolate* isolate_;
CpuProfilesCollection* profiles_;
unsigned next_profile_uid_;
- TokenEnumerator* token_enumerator_;
ProfileGenerator* generator_;
ProfilerEventsProcessor* processor_;
int saved_logging_nesting_;
diff --git a/src/d8.cc b/src/d8.cc
index 65af987..cb43d2f 100644
--- a/src/d8.cc
+++ b/src/d8.cc
@@ -1087,6 +1087,7 @@
array_buffer->Dispose();
}
+
void Shell::ReadBuffer(const v8::FunctionCallbackInfo<v8::Value>& args) {
ASSERT(sizeof(char) == sizeof(uint8_t)); // NOLINT
String::Utf8Value filename(args[0]);
diff --git a/src/dateparser.cc b/src/dateparser.cc
index 4a0721f..3964e81 100644
--- a/src/dateparser.cc
+++ b/src/dateparser.cc
@@ -112,6 +112,7 @@
return true;
}
+
bool DateParser::TimeZoneComposer::Write(FixedArray* output) {
if (sign_ != kNone) {
if (hour_ == kNone) hour_ = 0;
diff --git a/src/debug.cc b/src/debug.cc
index 07c1a0c..5d39a1c 100644
--- a/src/debug.cc
+++ b/src/debug.cc
@@ -1811,6 +1811,7 @@
thread_local_.step_count_ = 0;
}
+
// Clears all the one-shot break points that are currently set. Normally this
// function is called each time a break point is hit as one shot break points
// are used to support stepping.
diff --git a/src/disassembler.cc b/src/disassembler.cc
index 5ec1dcb..fa8ae1f 100644
--- a/src/disassembler.cc
+++ b/src/disassembler.cc
@@ -360,6 +360,8 @@
int Disassembler::Decode(Isolate* isolate, FILE* f, byte* begin, byte* end) {
return 0;
}
+
+
void Disassembler::Decode(FILE* f, Code* code) {}
#endif // ENABLE_DISASSEMBLER
diff --git a/src/elements-kind.cc b/src/elements-kind.cc
index 7b1651a..213aa35 100644
--- a/src/elements-kind.cc
+++ b/src/elements-kind.cc
@@ -83,6 +83,7 @@
return fast_elements_kind_sequence.Get()[sequence_number];
}
+
int GetSequenceIndexFromFastElementsKind(ElementsKind elements_kind) {
for (int i = 0; i < kFastElementsKindCount; ++i) {
if (fast_elements_kind_sequence.Get()[i] == elements_kind) {
diff --git a/src/execution.cc b/src/execution.cc
index 38e7a3b..d7b9cf5 100644
--- a/src/execution.cc
+++ b/src/execution.cc
@@ -865,6 +865,7 @@
return isolate->heap()->undefined_value();
}
+
void Execution::ProcessDebugMessages(bool debug_command_only) {
Isolate* isolate = Isolate::Current();
// Clear the debug command request flag.
diff --git a/src/extensions/i18n/break-iterator.cc b/src/extensions/i18n/break-iterator.cc
index 1225360..0681e26 100644
--- a/src/extensions/i18n/break-iterator.cc
+++ b/src/extensions/i18n/break-iterator.cc
@@ -82,6 +82,7 @@
object->Dispose(isolate);
}
+
// Throws a JavaScript exception.
static v8::Handle<v8::Value> ThrowUnexpectedObjectError() {
// Returns undefined, and schedules an exception to be thrown.
@@ -90,6 +91,7 @@
"that is not a BreakIterator.")));
}
+
// Deletes the old value and sets the adopted text in corresponding
// JavaScript object.
icu::UnicodeString* ResetAdoptedText(
diff --git a/src/extensions/i18n/collator.cc b/src/extensions/i18n/collator.cc
index 4ffa414..61b1d63 100644
--- a/src/extensions/i18n/collator.cc
+++ b/src/extensions/i18n/collator.cc
@@ -76,6 +76,7 @@
object->Dispose(isolate);
}
+
// Throws a JavaScript exception.
static v8::Handle<v8::Value> ThrowUnexpectedObjectError() {
// Returns undefined, and schedules an exception to be thrown.
@@ -84,11 +85,13 @@
"that is not a Collator.")));
}
+
// When there's an ICU error, throw a JavaScript error with |message|.
static v8::Handle<v8::Value> ThrowExceptionForICUError(const char* message) {
return v8::ThrowException(v8::Exception::Error(v8::String::New(message)));
}
+
// static
void Collator::JSInternalCompare(
const v8::FunctionCallbackInfo<v8::Value>& args) {
diff --git a/src/extensions/i18n/i18n-extension.cc b/src/extensions/i18n/i18n-extension.cc
index eb7652e..1c77b88 100644
--- a/src/extensions/i18n/i18n-extension.cc
+++ b/src/extensions/i18n/i18n-extension.cc
@@ -108,6 +108,7 @@
return v8::Handle<v8::FunctionTemplate>();
}
+
void Extension::Register() {
static Extension i18n_extension;
static v8::DeclareExtension extension_declaration(&i18n_extension);
diff --git a/src/extensions/i18n/i18n-utils.cc b/src/extensions/i18n/i18n-utils.cc
index d8d3c12..b720329 100644
--- a/src/extensions/i18n/i18n-utils.cc
+++ b/src/extensions/i18n/i18n-utils.cc
@@ -42,6 +42,7 @@
dest[length - 1] = '\0';
}
+
// static
bool Utils::V8StringToUnicodeString(const v8::Handle<v8::Value>& input,
icu::UnicodeString* output) {
@@ -54,6 +55,7 @@
return true;
}
+
// static
bool Utils::ExtractStringSetting(const v8::Handle<v8::Object>& settings,
const char* setting,
@@ -74,6 +76,7 @@
return false;
}
+
// static
bool Utils::ExtractIntegerSetting(const v8::Handle<v8::Object>& settings,
const char* setting,
@@ -95,6 +98,7 @@
return false;
}
+
// static
bool Utils::ExtractBooleanSetting(const v8::Handle<v8::Object>& settings,
const char* setting,
@@ -116,6 +120,7 @@
return false;
}
+
// static
void Utils::AsciiToUChar(const char* source,
int32_t source_length,
@@ -135,6 +140,7 @@
target[length - 1] = 0x0u;
}
+
// static
// Chrome Linux doesn't like static initializers in class, so we create
// template on demand.
@@ -153,6 +159,7 @@
return v8::Local<v8::ObjectTemplate>::New(isolate, icu_template);
}
+
// static
// Chrome Linux doesn't like static initializers in class, so we create
// template on demand. This one has 2 internal fields.
diff --git a/src/extensions/i18n/locale.cc b/src/extensions/i18n/locale.cc
index b32cc30..6b6f9ac 100644
--- a/src/extensions/i18n/locale.cc
+++ b/src/extensions/i18n/locale.cc
@@ -82,6 +82,7 @@
args.GetReturnValue().Set(v8::String::New(result));
}
+
void JSAvailableLocalesOf(const v8::FunctionCallbackInfo<v8::Value>& args) {
// Expect service name which is a string.
if (args.Length() != 1 || !args[0]->IsString()) {
@@ -131,6 +132,7 @@
args.GetReturnValue().Set(locales);
}
+
void JSGetDefaultICULocale(const v8::FunctionCallbackInfo<v8::Value>& args) {
icu::Locale default_locale;
@@ -147,6 +149,7 @@
args.GetReturnValue().Set(v8::String::New("und"));
}
+
void JSGetLanguageTagVariants(const v8::FunctionCallbackInfo<v8::Value>& args) {
v8::TryCatch try_catch;
diff --git a/src/factory.cc b/src/factory.cc
index 63b2379..6efc2c2 100644
--- a/src/factory.cc
+++ b/src/factory.cc
@@ -178,6 +178,7 @@
String);
}
+
// Internalized strings are created in the old generation (data space).
Handle<String> Factory::InternalizeString(Handle<String> string) {
CALL_HEAP_FUNCTION(isolate(),
@@ -185,6 +186,7 @@
String);
}
+
Handle<String> Factory::InternalizeOneByteString(Vector<const uint8_t> string) {
CALL_HEAP_FUNCTION(isolate(),
isolate()->heap()->InternalizeOneByteString(string),
@@ -1235,6 +1237,7 @@
JSMessageObject);
}
+
Handle<SharedFunctionInfo> Factory::NewSharedFunctionInfo(Handle<String> name) {
CALL_HEAP_FUNCTION(isolate(),
isolate()->heap()->AllocateSharedFunctionInfo(*name),
diff --git a/src/factory.h b/src/factory.h
index 0cb7157..b39c4f4 100644
--- a/src/factory.h
+++ b/src/factory.h
@@ -564,6 +564,82 @@
}
+// Used to "safely" transition from pointer-based runtime code to Handle-based
+// runtime code. When a GC happens during the called Handle-based code, a
+// failure object is returned to the pointer-based code to cause it abort and
+// re-trigger a gc of it's own. Since this double-gc will cause the Handle-based
+// code to be called twice, it must be idempotent.
+class IdempotentPointerToHandleCodeTrampoline {
+ public:
+ explicit IdempotentPointerToHandleCodeTrampoline(Isolate* isolate)
+ : isolate_(isolate) {}
+
+ template<typename R>
+ MUST_USE_RESULT MaybeObject* Call(R (*function)()) {
+ int collections = isolate_->heap()->gc_count();
+ (*function)();
+ return (collections == isolate_->heap()->gc_count())
+ ? isolate_->heap()->true_value()
+ : reinterpret_cast<MaybeObject*>(Failure::RetryAfterGC());
+ }
+
+ template<typename R>
+ MUST_USE_RESULT MaybeObject* CallWithReturnValue(R (*function)()) {
+ int collections = isolate_->heap()->gc_count();
+ Object* result = (*function)();
+ return (collections == isolate_->heap()->gc_count())
+ ? result
+ : reinterpret_cast<MaybeObject*>(Failure::RetryAfterGC());
+ }
+
+ template<typename R, typename P1>
+ MUST_USE_RESULT MaybeObject* Call(R (*function)(P1), P1 p1) {
+ int collections = isolate_->heap()->gc_count();
+ (*function)(p1);
+ return (collections == isolate_->heap()->gc_count())
+ ? isolate_->heap()->true_value()
+ : reinterpret_cast<MaybeObject*>(Failure::RetryAfterGC());
+ }
+
+ template<typename R, typename P1>
+ MUST_USE_RESULT MaybeObject* CallWithReturnValue(
+ R (*function)(P1),
+ P1 p1) {
+ int collections = isolate_->heap()->gc_count();
+ Object* result = (*function)(p1);
+ return (collections == isolate_->heap()->gc_count())
+ ? result
+ : reinterpret_cast<MaybeObject*>(Failure::RetryAfterGC());
+ }
+
+ template<typename R, typename P1, typename P2>
+ MUST_USE_RESULT MaybeObject* Call(
+ R (*function)(P1, P2),
+ P1 p1,
+ P2 p2) {
+ int collections = isolate_->heap()->gc_count();
+ (*function)(p1, p2);
+ return (collections == isolate_->heap()->gc_count())
+ ? isolate_->heap()->true_value()
+ : reinterpret_cast<MaybeObject*>(Failure::RetryAfterGC());
+ }
+
+ template<typename R, typename P1, typename P2>
+ MUST_USE_RESULT MaybeObject* CallWithReturnValue(
+ R (*function)(P1, P2),
+ P1 p1,
+ P2 p2) {
+ int collections = isolate_->heap()->gc_count();
+ Object* result = (*function)(p1, p2);
+ return (collections == isolate_->heap()->gc_count())
+ ? result
+ : reinterpret_cast<MaybeObject*>(Failure::RetryAfterGC());
+ }
+
+ private:
+ Isolate* isolate_;
+};
+
} } // namespace v8::internal
diff --git a/src/frames.cc b/src/frames.cc
index 0408aa9..b20a7ea 100644
--- a/src/frames.cc
+++ b/src/frames.cc
@@ -202,6 +202,7 @@
}
}
+
bool StackTraceFrameIterator::IsValidFrame() {
if (!frame()->function()->IsJSFunction()) return false;
Object* script = JSFunction::cast(frame()->function())->shared()->script();
@@ -1568,6 +1569,7 @@
ASSERT(i == kNumJSCallerSaved);
}
+
int JSCallerSavedCode(int n) {
ASSERT(0 <= n && n < kNumJSCallerSaved);
return caller_saved_code_data.reg_code[n];
@@ -1600,6 +1602,7 @@
return NULL;
}
+
Vector<StackFrame*> CreateStackMap(Isolate* isolate, Zone* zone) {
ZoneList<StackFrame*> list(10, zone);
for (StackFrameIterator it(isolate); !it.done(); it.Advance()) {
diff --git a/src/full-codegen.cc b/src/full-codegen.cc
index c1350a1..82d4f7c 100644
--- a/src/full-codegen.cc
+++ b/src/full-codegen.cc
@@ -76,12 +76,15 @@
void BreakableStatementChecker::VisitModuleLiteral(ModuleLiteral* module) {
}
+
void BreakableStatementChecker::VisitModuleVariable(ModuleVariable* module) {
}
+
void BreakableStatementChecker::VisitModulePath(ModulePath* module) {
}
+
void BreakableStatementChecker::VisitModuleUrl(ModuleUrl* module) {
}
diff --git a/src/gdb-jit.cc b/src/gdb-jit.cc
index 825d1e7..74db807 100644
--- a/src/gdb-jit.cc
+++ b/src/gdb-jit.cc
@@ -2015,6 +2015,7 @@
}
}
+
static void AddUnwindInfo(CodeDescription* desc) {
#if V8_TARGET_ARCH_X64
if (desc->tag() == GDBJITInterface::FUNCTION) {
diff --git a/src/global-handles.cc b/src/global-handles.cc
index b601e99..c69b9e2 100644
--- a/src/global-handles.cc
+++ b/src/global-handles.cc
@@ -799,6 +799,7 @@
PrintF(" # total = %d\n", total);
}
+
void GlobalHandles::Print() {
PrintF("Global handles:\n");
for (NodeIterator it(this); !it.done(); it.Advance()) {
diff --git a/src/handles.cc b/src/handles.cc
index 7d4b25f..fc45aaa 100644
--- a/src/handles.cc
+++ b/src/handles.cc
@@ -499,6 +499,7 @@
return right + script->line_offset()->value();
}
+
// Convert code position into column number.
int GetScriptColumnNumber(Handle<Script> script, int code_pos) {
int line_number = GetScriptLineNumber(script, code_pos);
@@ -513,6 +514,7 @@
return code_pos - (prev_line_end_pos + 1);
}
+
int GetScriptLineNumberSafe(Handle<Script> script, int code_pos) {
DisallowHeapAllocation no_allocation;
if (!script->line_ends()->IsUndefined()) {
diff --git a/src/handles.h b/src/handles.h
index 5976b75..140c34e 100644
--- a/src/handles.h
+++ b/src/handles.h
@@ -106,6 +106,13 @@
}
+// Convenience wrapper.
+template<class T>
+inline Handle<T> handle(T* t) {
+ return Handle<T>(t, t->GetIsolate());
+}
+
+
class DeferredHandles;
class HandleScopeImplementer;
diff --git a/src/heap-profiler.cc b/src/heap-profiler.cc
index e517df4..e66af33 100644
--- a/src/heap-profiler.cc
+++ b/src/heap-profiler.cc
@@ -94,6 +94,7 @@
return TakeSnapshot(snapshots_->names()->GetName(name), control, resolver);
}
+
void HeapProfiler::StartHeapObjectsTracking() {
snapshots_->StartHeapObjectsTracking();
}
diff --git a/src/heap-snapshot-generator.cc b/src/heap-snapshot-generator.cc
index f959aee..d65b814 100644
--- a/src/heap-snapshot-generator.cc
+++ b/src/heap-snapshot-generator.cc
@@ -459,6 +459,7 @@
time_intervals_.Clear();
}
+
void HeapObjectsMap::UpdateHeapObjectsMap() {
HEAP->CollectAllGarbage(Heap::kMakeHeapIterableMask,
"HeapSnapshotsCollection::UpdateHeapObjectsMap");
@@ -572,7 +573,6 @@
HeapSnapshotsCollection::HeapSnapshotsCollection(Heap* heap)
: is_tracking_objects_(false),
- token_enumerator_(new TokenEnumerator()),
ids_(heap) {
}
@@ -583,7 +583,6 @@
HeapSnapshotsCollection::~HeapSnapshotsCollection() {
- delete token_enumerator_;
snapshots_.Iterate(DeleteHeapSnapshot);
}
@@ -1963,6 +1962,7 @@
embedder_queried_ = true;
}
+
void NativeObjectsExplorer::FillImplicitReferences() {
Isolate* isolate = Isolate::Current();
List<ImplicitRefGroup*>* groups =
@@ -2588,6 +2588,7 @@
w->AddCharacter(hex_chars[u & 0xf]);
}
+
void HeapSnapshotJSONSerializer::SerializeString(const unsigned char* s) {
writer_->AddCharacter('\n');
writer_->AddCharacter('\"');
diff --git a/src/heap-snapshot-generator.h b/src/heap-snapshot-generator.h
index cd1ec29..70881ef 100644
--- a/src/heap-snapshot-generator.h
+++ b/src/heap-snapshot-generator.h
@@ -306,7 +306,6 @@
void RemoveSnapshot(HeapSnapshot* snapshot);
StringsStorage* names() { return &names_; }
- TokenEnumerator* token_enumerator() { return token_enumerator_; }
SnapshotObjectId FindObjectId(Address object_addr) {
return ids_.FindEntry(object_addr);
@@ -325,7 +324,6 @@
bool is_tracking_objects_; // Whether tracking object moves is needed.
List<HeapSnapshot*> snapshots_;
StringsStorage names_;
- TokenEnumerator* token_enumerator_;
// Mapping from HeapObject addresses to objects' uids.
HeapObjectsMap ids_;
diff --git a/src/heap.cc b/src/heap.cc
index 9d1ac8c..90f8837 100644
--- a/src/heap.cc
+++ b/src/heap.cc
@@ -2855,9 +2855,9 @@
MaybeObject* Heap::AllocatePropertyCell(Object* value) {
Object* result;
- { MaybeObject* maybe_result = AllocateRawPropertyCell();
- if (!maybe_result->ToObject(&result)) return maybe_result;
- }
+ MaybeObject* maybe_result = AllocateRawPropertyCell();
+ if (!maybe_result->ToObject(&result)) return maybe_result;
+
HeapObject::cast(result)->set_map_no_write_barrier(
global_property_cell_map());
PropertyCell* cell = PropertyCell::cast(result);
@@ -2865,6 +2865,8 @@
SKIP_WRITE_BARRIER);
cell->set_value(value);
cell->set_type(Type::None());
+ maybe_result = cell->SetValueInferType(value);
+ if (maybe_result->IsFailure()) return maybe_result;
return result;
}
@@ -3501,6 +3503,7 @@
}
}
+
ExternalArray* Heap::EmptyExternalArrayForMap(Map* map) {
return ExternalArray::cast(
roots_[RootIndexForEmptyExternalArray(map->elements_kind())]);
@@ -5231,6 +5234,7 @@
String::WriteToFlat(s, chars, 0, len);
}
+
static inline void WriteTwoByteData(String* s, uint16_t* chars, int len) {
ASSERT(s->length() == len);
String::WriteToFlat(s, chars, 0, len);
@@ -5415,6 +5419,7 @@
return result;
}
+
MaybeObject* Heap::AllocateEmptyExternalArray(ExternalArrayType array_type) {
return AllocateExternalArray(0, array_type, NULL, TENURED);
}
@@ -6751,6 +6756,7 @@
MarkCompactCollector::Initialize();
}
+
bool Heap::SetUp() {
#ifdef DEBUG
allocation_timeout_ = FLAG_gc_interval;
@@ -6861,6 +6867,7 @@
return true;
}
+
bool Heap::CreateHeapObjects() {
// Create initial maps.
if (!CreateInitialMaps()) return false;
@@ -7026,6 +7033,7 @@
}
};
+
void Heap::PrintHandles() {
PrintF("Handles:\n");
PrintHandleVisitor v;
diff --git a/src/heap.h b/src/heap.h
index d254b60..d6f41a8 100644
--- a/src/heap.h
+++ b/src/heap.h
@@ -261,6 +261,7 @@
V(map_field_string, "%map") \
V(elements_field_string, "%elements") \
V(length_field_string, "%length") \
+ V(cell_value_string, "%cell_value") \
V(function_class_string, "Function") \
V(properties_field_symbol, "%properties") \
V(payload_field_symbol, "%payload") \
@@ -1812,6 +1813,8 @@
void QueueMemoryChunkForFree(MemoryChunk* chunk);
void FreeQueuedChunks();
+ int gc_count() const { return gc_count_; }
+
// Completely clear the Instanceof cache (to stop it keeping objects alive
// around a GC).
inline void CompletelyClearInstanceofCache();
diff --git a/src/hydrogen-dce.cc b/src/hydrogen-dce.cc
new file mode 100644
index 0000000..4ad32d2
--- /dev/null
+++ b/src/hydrogen-dce.cc
@@ -0,0 +1,125 @@
+// Copyright 2013 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "hydrogen-dce.h"
+#include "v8.h"
+
+namespace v8 {
+namespace internal {
+
+bool HDeadCodeEliminationPhase::MarkLive(HValue* ref, HValue* instr) {
+ if (instr->CheckFlag(HValue::kIsLive)) return false;
+ instr->SetFlag(HValue::kIsLive);
+
+ if (FLAG_trace_dead_code_elimination) {
+ HeapStringAllocator allocator;
+ StringStream stream(&allocator);
+ if (ref != NULL) {
+ ref->PrintTo(&stream);
+ } else {
+ stream.Add("root ");
+ }
+ stream.Add(" -> ");
+ instr->PrintTo(&stream);
+ PrintF("[MarkLive %s]\n", *stream.ToCString());
+ }
+
+ return true;
+}
+
+
+void HDeadCodeEliminationPhase::MarkLiveInstructions() {
+ ZoneList<HValue*> worklist(graph()->blocks()->length(), zone());
+
+ // Mark initial root instructions for dead code elimination.
+ for (int i = 0; i < graph()->blocks()->length(); ++i) {
+ HBasicBlock* block = graph()->blocks()->at(i);
+ for (HInstructionIterator it(block); !it.Done(); it.Advance()) {
+ HInstruction* instr = it.Current();
+ if (instr->CannotBeEliminated() && MarkLive(NULL, instr)) {
+ worklist.Add(instr, zone());
+ }
+ }
+ for (int j = 0; j < block->phis()->length(); j++) {
+ HPhi* phi = block->phis()->at(j);
+ if (phi->CannotBeEliminated() && MarkLive(NULL, phi)) {
+ worklist.Add(phi, zone());
+ }
+ }
+ }
+
+ // Transitively mark all inputs of live instructions live.
+ while (!worklist.is_empty()) {
+ HValue* instr = worklist.RemoveLast();
+ for (int i = 0; i < instr->OperandCount(); ++i) {
+ if (MarkLive(instr, instr->OperandAt(i))) {
+ worklist.Add(instr->OperandAt(i), zone());
+ }
+ }
+ }
+}
+
+
+void HDeadCodeEliminationPhase::RemoveDeadInstructions() {
+ ZoneList<HPhi*> worklist(graph()->blocks()->length(), zone());
+
+ // Remove any instruction not marked kIsLive.
+ for (int i = 0; i < graph()->blocks()->length(); ++i) {
+ HBasicBlock* block = graph()->blocks()->at(i);
+ for (HInstructionIterator it(block); !it.Done(); it.Advance()) {
+ HInstruction* instr = it.Current();
+ if (!instr->CheckFlag(HValue::kIsLive)) {
+ // Instruction has not been marked live; assume it is dead and remove.
+ // TODO(titzer): we don't remove constants because some special ones
+ // might be used by later phases and are assumed to be in the graph
+ if (!instr->IsConstant()) instr->DeleteAndReplaceWith(NULL);
+ } else {
+ // Clear the liveness flag to leave the graph clean for the next DCE.
+ instr->ClearFlag(HValue::kIsLive);
+ }
+ }
+ // Collect phis that are dead and remove them in the next pass.
+ for (int j = 0; j < block->phis()->length(); j++) {
+ HPhi* phi = block->phis()->at(j);
+ if (!phi->CheckFlag(HValue::kIsLive)) {
+ worklist.Add(phi, zone());
+ } else {
+ phi->ClearFlag(HValue::kIsLive);
+ }
+ }
+ }
+
+ // Process phis separately to avoid simultaneously mutating the phi list.
+ while (!worklist.is_empty()) {
+ HPhi* phi = worklist.RemoveLast();
+ HBasicBlock* block = phi->block();
+ phi->DeleteAndReplaceWith(NULL);
+ block->RecordDeletedPhi(phi->merged_index());
+ }
+}
+
+} } // namespace v8::internal
diff --git a/src/hydrogen-dce.h b/src/hydrogen-dce.h
new file mode 100644
index 0000000..19749f2
--- /dev/null
+++ b/src/hydrogen-dce.h
@@ -0,0 +1,56 @@
+// Copyright 2013 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef V8_HYDROGEN_DCE_H_
+#define V8_HYDROGEN_DCE_H_
+
+#include "hydrogen.h"
+
+namespace v8 {
+namespace internal {
+
+
+class HDeadCodeEliminationPhase : public HPhase {
+ public:
+ explicit HDeadCodeEliminationPhase(HGraph* graph)
+ : HPhase("H_Dead code elimination", graph) { }
+
+ void Run() {
+ MarkLiveInstructions();
+ RemoveDeadInstructions();
+ }
+
+ private:
+ bool MarkLive(HValue* ref, HValue* instr);
+ void MarkLiveInstructions();
+ void RemoveDeadInstructions();
+};
+
+
+} } // namespace v8::internal
+
+#endif // V8_HYDROGEN_DCE_H_
diff --git a/src/hydrogen-gvn.cc b/src/hydrogen-gvn.cc
index 7ea2f16..fd7430c 100644
--- a/src/hydrogen-gvn.cc
+++ b/src/hydrogen-gvn.cc
@@ -123,6 +123,7 @@
va_end(arguments);
}
+
// Wrap TraceGVN in macros to avoid the expense of evaluating its arguments when
// --trace-gvn is off.
#define TRACE_GVN_1(msg, a1) \
@@ -339,6 +340,7 @@
return *this;
}
+
void HSideEffectMap::Kill(GVNFlagSet flags) {
for (int i = 0; i < kNumberOfTrackedSideEffects; i++) {
GVNFlag changes_flag = HValue::ChangesFlagFromInt(i);
@@ -748,6 +750,7 @@
int length_;
};
+
// This is a recursive traversal of the dominator tree but it has been turned
// into a loop to avoid stack overflows.
// The logical "stack frames" of the recursion are kept in a list of
diff --git a/src/hydrogen-infer-types.cc b/src/hydrogen-infer-types.cc
new file mode 100644
index 0000000..01c6084
--- /dev/null
+++ b/src/hydrogen-infer-types.cc
@@ -0,0 +1,77 @@
+// Copyright 2013 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "hydrogen-infer-types.h"
+
+namespace v8 {
+namespace internal {
+
+void HInferTypesPhase::InferTypes(int from_inclusive, int to_inclusive) {
+ for (int i = from_inclusive; i <= to_inclusive; ++i) {
+ HBasicBlock* block = graph()->blocks()->at(i);
+
+ const ZoneList<HPhi*>* phis = block->phis();
+ for (int j = 0; j < phis->length(); j++) {
+ phis->at(j)->UpdateInferredType();
+ }
+
+ for (HInstructionIterator it(block); !it.Done(); it.Advance()) {
+ it.Current()->UpdateInferredType();
+ }
+
+ if (block->IsLoopHeader()) {
+ HBasicBlock* last_back_edge =
+ block->loop_information()->GetLastBackEdge();
+ InferTypes(i + 1, last_back_edge->block_id());
+ // Skip all blocks already processed by the recursive call.
+ i = last_back_edge->block_id();
+ // Update phis of the loop header now after the whole loop body is
+ // guaranteed to be processed.
+ for (int j = 0; j < block->phis()->length(); ++j) {
+ HPhi* phi = block->phis()->at(j);
+ worklist_.Add(phi, zone());
+ in_worklist_.Add(phi->id());
+ }
+ while (!worklist_.is_empty()) {
+ HValue* current = worklist_.RemoveLast();
+ in_worklist_.Remove(current->id());
+ if (current->UpdateInferredType()) {
+ for (HUseIterator it(current->uses()); !it.Done(); it.Advance()) {
+ HValue* use = it.value();
+ if (!in_worklist_.Contains(use->id())) {
+ in_worklist_.Add(use->id());
+ worklist_.Add(use, zone());
+ }
+ }
+ }
+ }
+ ASSERT(in_worklist_.IsEmpty());
+ }
+ }
+}
+
+} } // namespace v8::internal
diff --git a/src/hydrogen-infer-types.h b/src/hydrogen-infer-types.h
new file mode 100644
index 0000000..cfcbf35
--- /dev/null
+++ b/src/hydrogen-infer-types.h
@@ -0,0 +1,59 @@
+// Copyright 2013 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef V8_HYDROGEN_INFER_TYPES_H_
+#define V8_HYDROGEN_INFER_TYPES_H_
+
+#include "hydrogen.h"
+
+namespace v8 {
+namespace internal {
+
+
+class HInferTypesPhase : public HPhase {
+ public:
+ explicit HInferTypesPhase(HGraph* graph)
+ : HPhase("H_Inferring types", graph), worklist_(8, zone()),
+ in_worklist_(graph->GetMaximumValueID(), zone()) { }
+
+ void Run() {
+ InferTypes(0, graph()->blocks()->length() - 1);
+ }
+
+ private:
+ void InferTypes(int from_inclusive, int to_inclusive);
+
+ ZoneList<HValue*> worklist_;
+ BitVector in_worklist_;
+
+ DISALLOW_COPY_AND_ASSIGN(HInferTypesPhase);
+};
+
+
+} } // namespace v8::internal
+
+#endif // V8_HYDROGEN_INFER_TYPES_H_
diff --git a/src/hydrogen-instructions.cc b/src/hydrogen-instructions.cc
index 932fd47..041ef8b 100644
--- a/src/hydrogen-instructions.cc
+++ b/src/hydrogen-instructions.cc
@@ -1701,6 +1701,7 @@
return "";
}
+
void HCheckInstanceType::PrintDataTo(StringStream* stream) {
stream->Add("%s ", GetCheckName());
HUnaryOperation::PrintDataTo(stream);
@@ -2174,6 +2175,7 @@
has_double_value_(false),
is_internalized_string_(false),
is_not_in_new_space_(true),
+ is_cell_(false),
boolean_value_(handle->BooleanValue()) {
if (handle_->IsHeapObject()) {
Heap* heap = Handle<HeapObject>::cast(handle)->GetHeap();
@@ -2190,6 +2192,9 @@
type_from_value_ = HType::TypeFromValue(handle_);
is_internalized_string_ = handle_->IsInternalizedString();
}
+
+ is_cell_ = !handle_.is_null() &&
+ (handle_->IsCell() || handle_->IsPropertyCell());
Initialize(r);
}
@@ -2200,6 +2205,7 @@
HType type,
bool is_internalize_string,
bool is_not_in_new_space,
+ bool is_cell,
bool boolean_value)
: handle_(handle),
unique_id_(unique_id),
@@ -2208,6 +2214,7 @@
has_double_value_(false),
is_internalized_string_(is_internalize_string),
is_not_in_new_space_(is_not_in_new_space),
+ is_cell_(is_cell),
boolean_value_(boolean_value),
type_from_value_(type) {
ASSERT(!handle.is_null());
@@ -2227,6 +2234,7 @@
has_double_value_(true),
is_internalized_string_(false),
is_not_in_new_space_(is_not_in_new_space),
+ is_cell_(false),
boolean_value_(integer_value != 0),
int32_value_(integer_value),
double_value_(FastI2D(integer_value)) {
@@ -2245,6 +2253,7 @@
has_double_value_(true),
is_internalized_string_(false),
is_not_in_new_space_(is_not_in_new_space),
+ is_cell_(false),
boolean_value_(double_value != 0 && !std::isnan(double_value)),
int32_value_(DoubleToInt32(double_value)),
double_value_(double_value) {
@@ -2267,9 +2276,17 @@
}
set_representation(r);
SetFlag(kUseGVN);
- if (representation().IsInteger32()) {
- ClearGVNFlag(kDependsOnOsrEntries);
+}
+
+
+bool HConstant::EmitAtUses() {
+ ASSERT(IsLinked());
+ if (block()->graph()->has_osr()) {
+ return block()->graph()->IsStandardConstant(this);
}
+ if (IsCell()) return false;
+ if (representation().IsDouble()) return false;
+ return true;
}
@@ -2290,6 +2307,7 @@
type_from_value_,
is_internalized_string_,
is_not_in_new_space_,
+ is_cell_,
boolean_value_);
}
@@ -2540,7 +2558,7 @@
}
-void HCompareIDAndBranch::AddInformativeDefinitions() {
+void HCompareNumericAndBranch::AddInformativeDefinitions() {
NumericRelation r = NumericRelation::FromToken(token());
if (r.IsNone()) return;
@@ -2550,7 +2568,7 @@
}
-void HCompareIDAndBranch::PrintDataTo(StringStream* stream) {
+void HCompareNumericAndBranch::PrintDataTo(StringStream* stream) {
stream->Add(Token::Name(token()));
stream->Add(" ");
left()->PrintNameTo(stream);
@@ -2573,7 +2591,7 @@
}
-void HCompareIDAndBranch::InferRepresentation(
+void HCompareNumericAndBranch::InferRepresentation(
HInferRepresentationPhase* h_infer) {
Representation left_rep = left()->representation();
Representation right_rep = right()->representation();
@@ -2595,9 +2613,9 @@
// and !=) have special handling of undefined, e.g. undefined == undefined
// is 'true'. Relational comparisons have a different semantic, first
// calling ToPrimitive() on their arguments. The standard Crankshaft
- // tagged-to-double conversion to ensure the HCompareIDAndBranch's inputs
- // are doubles caused 'undefined' to be converted to NaN. That's compatible
- // out-of-the box with ordered relational comparisons (<, >, <=,
+ // tagged-to-double conversion to ensure the HCompareNumericAndBranch's
+ // inputs are doubles caused 'undefined' to be converted to NaN. That's
+ // compatible out-of-the box with ordered relational comparisons (<, >, <=,
// >=). However, for equality comparisons (and for 'in' and 'instanceof'),
// it is not consistent with the spec. For example, it would cause undefined
// == undefined (should be true) to be evaluated as NaN == NaN
@@ -3078,6 +3096,11 @@
}
+HType HCheckSmi::CalculateInferredType() {
+ return HType::Smi();
+}
+
+
HType HPhi::CalculateInferredType() {
HType result = HType::Uninitialized();
for (int i = 0; i < OperandCount(); ++i) {
@@ -3824,6 +3847,13 @@
}
+HObjectAccess HObjectAccess::ForCellPayload(Isolate* isolate) {
+ return HObjectAccess(
+ kInobject, Cell::kValueOffset,
+ Handle<String>(isolate->heap()->cell_value_string()));
+}
+
+
void HObjectAccess::SetGVNFlags(HValue *instr, bool is_store) {
// set the appropriate GVN flags for a given load or store instruction
if (is_store) {
diff --git a/src/hydrogen-instructions.h b/src/hydrogen-instructions.h
index 26bda87..4227b8e 100644
--- a/src/hydrogen-instructions.h
+++ b/src/hydrogen-instructions.h
@@ -92,10 +92,11 @@
V(CheckHeapObject) \
V(CheckInstanceType) \
V(CheckMaps) \
+ V(CheckSmi) \
V(CheckPrototypeMaps) \
V(ClampToUint8) \
V(ClassOfTestAndBranch) \
- V(CompareIDAndBranch) \
+ V(CompareNumericAndBranch) \
V(CompareGeneric) \
V(CompareObjectEqAndBranch) \
V(CompareMap) \
@@ -128,6 +129,7 @@
V(InvokeFunction) \
V(IsConstructCallAndBranch) \
V(IsObjectAndBranch) \
+ V(IsNumberAndBranch) \
V(IsStringAndBranch) \
V(IsSmiAndBranch) \
V(IsUndetectableAndBranch) \
@@ -1604,21 +1606,11 @@
class HBranch: public HUnaryControlInstruction {
public:
HBranch(HValue* value,
- HBasicBlock* true_target,
- HBasicBlock* false_target,
- ToBooleanStub::Types expected_input_types = ToBooleanStub::Types())
+ ToBooleanStub::Types expected_input_types = ToBooleanStub::Types(),
+ HBasicBlock* true_target = NULL,
+ HBasicBlock* false_target = NULL)
: HUnaryControlInstruction(value, true_target, false_target),
expected_input_types_(expected_input_types) {
- ASSERT(true_target != NULL && false_target != NULL);
- SetFlag(kAllowUndefinedAsNaN);
- }
- explicit HBranch(HValue* value)
- : HUnaryControlInstruction(value, NULL, NULL) {
- SetFlag(kAllowUndefinedAsNaN);
- }
- HBranch(HValue* value, ToBooleanStub::Types expected_input_types)
- : HUnaryControlInstruction(value, NULL, NULL),
- expected_input_types_(expected_input_types) {
SetFlag(kAllowUndefinedAsNaN);
}
@@ -1642,12 +1634,10 @@
public:
HCompareMap(HValue* value,
Handle<Map> map,
- HBasicBlock* true_target,
- HBasicBlock* false_target)
+ HBasicBlock* true_target = NULL,
+ HBasicBlock* false_target = NULL)
: HUnaryControlInstruction(value, true_target, false_target),
- map_(map) {
- ASSERT(true_target != NULL);
- ASSERT(false_target != NULL);
+ map_(map) {
ASSERT(!map.is_null());
}
@@ -2934,6 +2924,49 @@
};
+class HCheckSmi: public HUnaryOperation {
+ public:
+ explicit HCheckSmi(HValue* value) : HUnaryOperation(value) {
+ set_representation(Representation::Smi());
+ SetFlag(kUseGVN);
+ }
+
+ virtual Representation RequiredInputRepresentation(int index) {
+ return Representation::Tagged();
+ }
+
+ virtual HType CalculateInferredType();
+
+ virtual HValue* Canonicalize() {
+ HType value_type = value()->type();
+ if (value_type.IsSmi()) {
+ return NULL;
+ }
+ return this;
+ }
+
+ DECLARE_CONCRETE_INSTRUCTION(CheckSmi)
+
+ protected:
+ virtual bool DataEquals(HValue* other) { return true; }
+};
+
+
+class HIsNumberAndBranch: public HUnaryControlInstruction {
+ public:
+ explicit HIsNumberAndBranch(HValue* value)
+ : HUnaryControlInstruction(value, NULL, NULL) {
+ SetFlag(kFlexibleRepresentation);
+ }
+
+ virtual Representation RequiredInputRepresentation(int index) {
+ return Representation::None();
+ }
+
+ DECLARE_CONCRETE_INSTRUCTION(IsNumberAndBranch)
+};
+
+
class HCheckHeapObject: public HUnaryOperation {
public:
explicit HCheckHeapObject(HValue* value) : HUnaryOperation(value) {
@@ -3246,6 +3279,7 @@
HType type,
bool is_internalized_string,
bool is_not_in_new_space,
+ bool is_cell,
bool boolean_value);
Handle<Object> handle() {
@@ -3294,6 +3328,10 @@
unique_id_ == UniqueValueId(heap->empty_string());
}
+ bool IsCell() const {
+ return is_cell_;
+ }
+
virtual Representation RequiredInputRepresentation(int index) {
return Representation::None();
}
@@ -3305,7 +3343,7 @@
return Representation::Tagged();
}
- virtual bool EmitAtUses() { return !representation().IsDouble(); }
+ virtual bool EmitAtUses();
virtual void PrintDataTo(StringStream* stream);
virtual HType CalculateInferredType();
bool IsInteger() { return handle()->IsSmi(); }
@@ -3420,6 +3458,7 @@
bool has_double_value_ : 1;
bool is_internalized_string_ : 1; // TODO(yangguo): make this part of HType.
bool is_not_in_new_space_ : 1;
+ bool is_cell_ : 1;
bool boolean_value_ : 1;
int32_t int32_value_;
double double_value_;
@@ -3909,9 +3948,9 @@
};
-class HCompareIDAndBranch: public HTemplateControlInstruction<2, 2> {
+class HCompareNumericAndBranch: public HTemplateControlInstruction<2, 2> {
public:
- HCompareIDAndBranch(HValue* left, HValue* right, Token::Value token)
+ HCompareNumericAndBranch(HValue* left, HValue* right, Token::Value token)
: token_(token) {
SetFlag(kFlexibleRepresentation);
ASSERT(Token::IsCompareOp(token));
@@ -3941,7 +3980,7 @@
virtual void AddInformativeDefinitions();
- DECLARE_CONCRETE_INSTRUCTION(CompareIDAndBranch)
+ DECLARE_CONCRETE_INSTRUCTION(CompareNumericAndBranch)
private:
Representation observed_input_representation_[2];
@@ -4718,6 +4757,7 @@
public:
explicit HOsrEntry(BailoutId ast_id) : ast_id_(ast_id) {
SetGVNFlag(kChangesOsrEntries);
+ SetGVNFlag(kChangesNewSpacePromotion);
}
BailoutId ast_id() const { return ast_id_; }
@@ -5072,6 +5112,9 @@
HInnerAllocatedObject::cast(object)->base_object(),
new_space_dominator);
}
+ if (object->IsConstant() && HConstant::cast(object)->IsCell()) {
+ return false;
+ }
if (object != new_space_dominator) return true;
if (object->IsAllocateObject()) return false;
if (object->IsAllocate()) {
@@ -5333,6 +5376,9 @@
static HObjectAccess ForField(Handle<Map> map,
LookupResult *lookup, Handle<String> name = Handle<String>::null());
+ // Create an access for the payload of a Cell or JSGlobalPropertyCell.
+ static HObjectAccess ForCellPayload(Isolate* isolate);
+
void PrintTo(StringStream* stream);
inline bool Equals(HObjectAccess that) const {
diff --git a/src/hydrogen-osr.cc b/src/hydrogen-osr.cc
index 19a1c77..a2fa0bf 100644
--- a/src/hydrogen-osr.cc
+++ b/src/hydrogen-osr.cc
@@ -63,7 +63,8 @@
HBasicBlock* non_osr_entry = graph->CreateBasicBlock();
osr_entry_ = graph->CreateBasicBlock();
HValue* true_value = graph->GetConstantTrue();
- HBranch* test = new(zone) HBranch(true_value, non_osr_entry, osr_entry_);
+ HBranch* test = new(zone) HBranch(true_value, ToBooleanStub::Types(),
+ non_osr_entry, osr_entry_);
builder_->current_block()->Finish(test);
HBasicBlock* loop_predecessor = graph->CreateBasicBlock();
diff --git a/src/hydrogen-range-analysis.cc b/src/hydrogen-range-analysis.cc
index 0d4d970..ed254db 100644
--- a/src/hydrogen-range-analysis.cc
+++ b/src/hydrogen-range-analysis.cc
@@ -49,8 +49,9 @@
// Infer range based on control flow.
if (block->predecessors()->length() == 1) {
HBasicBlock* pred = block->predecessors()->first();
- if (pred->end()->IsCompareIDAndBranch()) {
- InferControlFlowRange(HCompareIDAndBranch::cast(pred->end()), block);
+ if (pred->end()->IsCompareNumericAndBranch()) {
+ InferControlFlowRange(HCompareNumericAndBranch::cast(pred->end()),
+ block);
}
}
@@ -74,7 +75,7 @@
}
-void HRangeAnalysisPhase::InferControlFlowRange(HCompareIDAndBranch* test,
+void HRangeAnalysisPhase::InferControlFlowRange(HCompareNumericAndBranch* test,
HBasicBlock* dest) {
ASSERT((test->FirstSuccessor() == dest) == (test->SecondSuccessor() != dest));
if (test->representation().IsSmiOrInteger32()) {
diff --git a/src/hydrogen-range-analysis.h b/src/hydrogen-range-analysis.h
index 52ce109..b699d3a 100644
--- a/src/hydrogen-range-analysis.h
+++ b/src/hydrogen-range-analysis.h
@@ -46,7 +46,8 @@
private:
void TraceRange(const char* msg, ...);
void Analyze(HBasicBlock* block);
- void InferControlFlowRange(HCompareIDAndBranch* test, HBasicBlock* dest);
+ void InferControlFlowRange(HCompareNumericAndBranch* test,
+ HBasicBlock* dest);
void UpdateControlFlowRange(Token::Value op, HValue* value, HValue* other);
void InferRange(HValue* value);
void RollBackTo(int index);
diff --git a/src/hydrogen-redundant-phi.cc b/src/hydrogen-redundant-phi.cc
new file mode 100644
index 0000000..9c38200
--- /dev/null
+++ b/src/hydrogen-redundant-phi.cc
@@ -0,0 +1,76 @@
+// Copyright 2013 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "hydrogen-redundant-phi.h"
+
+namespace v8 {
+namespace internal {
+
+void HRedundantPhiEliminationPhase::Run() {
+ // We do a simple fixed point iteration without any work list, because
+ // machine-generated JavaScript can lead to a very dense Hydrogen graph with
+ // an enormous work list and will consequently result in OOM. Experiments
+ // showed that this simple algorithm is good enough, and even e.g. tracking
+ // the set or range of blocks to consider is not a real improvement.
+ bool need_another_iteration;
+ const ZoneList<HBasicBlock*>* blocks(graph()->blocks());
+ ZoneList<HPhi*> redundant_phis(blocks->length(), zone());
+ do {
+ need_another_iteration = false;
+ for (int i = 0; i < blocks->length(); ++i) {
+ HBasicBlock* block = blocks->at(i);
+ for (int j = 0; j < block->phis()->length(); j++) {
+ HPhi* phi = block->phis()->at(j);
+ HValue* replacement = phi->GetRedundantReplacement();
+ if (replacement != NULL) {
+ // Remember phi to avoid concurrent modification of the block's phis.
+ redundant_phis.Add(phi, zone());
+ for (HUseIterator it(phi->uses()); !it.Done(); it.Advance()) {
+ HValue* value = it.value();
+ value->SetOperandAt(it.index(), replacement);
+ need_another_iteration |= value->IsPhi();
+ }
+ }
+ }
+ for (int i = 0; i < redundant_phis.length(); i++) {
+ block->RemovePhi(redundant_phis[i]);
+ }
+ redundant_phis.Clear();
+ }
+ } while (need_another_iteration);
+
+#if DEBUG
+ // Make sure that we *really* removed all redundant phis.
+ for (int i = 0; i < blocks->length(); ++i) {
+ for (int j = 0; j < blocks->at(i)->phis()->length(); j++) {
+ ASSERT(blocks->at(i)->phis()->at(j)->GetRedundantReplacement() == NULL);
+ }
+ }
+#endif
+}
+
+} } // namespace v8::internal
diff --git a/src/hydrogen-redundant-phi.h b/src/hydrogen-redundant-phi.h
new file mode 100644
index 0000000..6291fa5
--- /dev/null
+++ b/src/hydrogen-redundant-phi.h
@@ -0,0 +1,53 @@
+// Copyright 2013 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef V8_HYDROGEN_REDUNDANT_PHI_H_
+#define V8_HYDROGEN_REDUNDANT_PHI_H_
+
+#include "hydrogen.h"
+
+namespace v8 {
+namespace internal {
+
+
+// Replace all phis consisting of a single non-loop operand plus any number of
+// loop operands by that single non-loop operand.
+class HRedundantPhiEliminationPhase : public HPhase {
+ public:
+ explicit HRedundantPhiEliminationPhase(HGraph* graph)
+ : HPhase("H_Redundant phi elimination", graph) { }
+
+ void Run();
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(HRedundantPhiEliminationPhase);
+};
+
+
+} } // namespace v8::internal
+
+#endif // V8_HYDROGEN_REDUNDANT_PHI_H_
diff --git a/src/hydrogen-sce.cc b/src/hydrogen-sce.cc
new file mode 100644
index 0000000..a6995f6
--- /dev/null
+++ b/src/hydrogen-sce.cc
@@ -0,0 +1,62 @@
+// Copyright 2013 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "hydrogen-sce.h"
+#include "v8.h"
+
+namespace v8 {
+namespace internal {
+
+void HStackCheckEliminationPhase::Run() {
+ // For each loop block walk the dominator tree from the backwards branch to
+ // the loop header. If a call instruction is encountered the backwards branch
+ // is dominated by a call and the stack check in the backwards branch can be
+ // removed.
+ for (int i = 0; i < graph()->blocks()->length(); i++) {
+ HBasicBlock* block = graph()->blocks()->at(i);
+ if (block->IsLoopHeader()) {
+ HBasicBlock* back_edge = block->loop_information()->GetLastBackEdge();
+ HBasicBlock* dominator = back_edge;
+ while (true) {
+ for (HInstructionIterator it(dominator); !it.Done(); it.Advance()) {
+ if (it.Current()->IsCall()) {
+ block->loop_information()->stack_check()->Eliminate();
+ break;
+ }
+ }
+
+ // Done when the loop header is processed.
+ if (dominator == block) break;
+
+ // Move up the dominator tree.
+ dominator = dominator->dominator();
+ }
+ }
+ }
+}
+
+} } // namespace v8::internal
diff --git a/src/hydrogen-sce.h b/src/hydrogen-sce.h
new file mode 100644
index 0000000..55e153e
--- /dev/null
+++ b/src/hydrogen-sce.h
@@ -0,0 +1,48 @@
+// Copyright 2013 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef V8_HYDROGEN_SCE_H_
+#define V8_HYDROGEN_SCE_H_
+
+#include "hydrogen.h"
+
+namespace v8 {
+namespace internal {
+
+
+class HStackCheckEliminationPhase : public HPhase {
+ public:
+ explicit HStackCheckEliminationPhase(HGraph* graph)
+ : HPhase("H_Stack check elimination", graph) { }
+
+ void Run();
+};
+
+
+} } // namespace v8::internal
+
+#endif // V8_HYDROGEN_SCE_H_
diff --git a/src/hydrogen.cc b/src/hydrogen.cc
index 7679f93..3a785ac 100644
--- a/src/hydrogen.cc
+++ b/src/hydrogen.cc
@@ -1,4 +1,4 @@
-// Copyright 2012 the V8 project authors. All rights reserved.
+// Copyright 2013 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
@@ -33,12 +33,16 @@
#include "codegen.h"
#include "full-codegen.h"
#include "hashmap.h"
+#include "hydrogen-dce.h"
#include "hydrogen-environment-liveness.h"
#include "hydrogen-escape-analysis.h"
#include "hydrogen-infer-representation.h"
+#include "hydrogen-infer-types.h"
#include "hydrogen-gvn.h"
#include "hydrogen-osr.h"
#include "hydrogen-range-analysis.h"
+#include "hydrogen-redundant-phi.h"
+#include "hydrogen-sce.h"
#include "hydrogen-uint32-analysis.h"
#include "lithium-allocator.h"
#include "parser.h"
@@ -649,6 +653,7 @@
htype, \
false, \
true, \
+ false, \
boolean_value); \
constant->InsertAfter(GetConstantUndefined()); \
constant_##name##_.set(constant); \
@@ -671,6 +676,19 @@
}
+bool HGraph::IsStandardConstant(HConstant* constant) {
+ if (constant == GetConstantUndefined()) return true;
+ if (constant == GetConstant0()) return true;
+ if (constant == GetConstant1()) return true;
+ if (constant == GetConstantMinus1()) return true;
+ if (constant == GetConstantTrue()) return true;
+ if (constant == GetConstantFalse()) return true;
+ if (constant == GetConstantHole()) return true;
+ if (constant == GetConstantNull()) return true;
+ return false;
+}
+
+
HGraphBuilder::IfBuilder::IfBuilder(HGraphBuilder* builder, int position)
: builder_(builder),
position_(position),
@@ -711,26 +729,6 @@
}
-HInstruction* HGraphBuilder::IfBuilder::IfCompare(
- HValue* left,
- HValue* right,
- Token::Value token) {
- HCompareIDAndBranch* compare =
- new(zone()) HCompareIDAndBranch(left, right, token);
- AddCompare(compare);
- return compare;
-}
-
-
-HInstruction* HGraphBuilder::IfBuilder::IfCompareMap(HValue* left,
- Handle<Map> map) {
- HCompareMap* compare =
- new(zone()) HCompareMap(left, map, first_true_block_, first_false_block_);
- AddCompare(compare);
- return compare;
-}
-
-
void HGraphBuilder::IfBuilder::AddCompare(HControlInstruction* compare) {
if (split_edge_merge_block_ != NULL) {
HEnvironment* env = first_false_block_->last_environment();
@@ -811,8 +809,8 @@
ToBooleanStub::Types boolean_type = ToBooleanStub::Types();
boolean_type.Add(ToBooleanStub::BOOLEAN);
HBranch* branch =
- new(zone()) HBranch(constant_false, first_true_block_,
- first_false_block_, boolean_type);
+ new(zone()) HBranch(constant_false, boolean_type, first_true_block_,
+ first_false_block_);
builder_->current_block()->Finish(branch);
}
builder_->set_current_block(first_true_block_);
@@ -916,8 +914,8 @@
body_env->Pop();
builder_->set_current_block(header_block_);
- HCompareIDAndBranch* compare =
- new(zone()) HCompareIDAndBranch(phi_, terminating, token);
+ HCompareNumericAndBranch* compare =
+ new(zone()) HCompareNumericAndBranch(phi_, terminating, token);
compare->SetSuccessorAt(0, body_block_);
compare->SetSuccessorAt(1, exit_block_);
builder_->current_block()->Finish(compare);
@@ -1005,6 +1003,17 @@
}
+void HGraphBuilder::AddSoftDeoptimize(SoftDeoptimizeMode mode) {
+ isolate()->counters()->soft_deopts_requested()->Increment();
+ if (FLAG_always_opt && mode == CAN_OMIT_SOFT_DEOPT) return;
+ if (current_block()->IsDeoptimizing()) return;
+ Add<HSoftDeoptimize>();
+ isolate()->counters()->soft_deopts_inserted()->Increment();
+ current_block()->MarkAsDeoptimizing();
+ graph()->set_has_soft_deoptimize(true);
+}
+
+
HBasicBlock* HGraphBuilder::CreateBasicBlock(HEnvironment* env) {
HBasicBlock* b = graph()->CreateBasicBlock();
b->SetInitialEnvironment(env);
@@ -1131,14 +1140,15 @@
Zone* zone = this->zone();
IfBuilder length_checker(this);
- length_checker.IfCompare(length, key, Token::EQ);
+ length_checker.If<HCompareNumericAndBranch>(length, key, Token::EQ);
length_checker.Then();
HValue* current_capacity = AddLoadFixedArrayLength(elements);
IfBuilder capacity_checker(this);
- capacity_checker.IfCompare(length, current_capacity, Token::EQ);
+ capacity_checker.If<HCompareNumericAndBranch>(length, current_capacity,
+ Token::EQ);
capacity_checker.Then();
HValue* context = environment()->LookupContext();
@@ -1182,12 +1192,11 @@
HValue* elements,
ElementsKind kind,
HValue* length) {
- Heap* heap = isolate()->heap();
+ Factory* factory = isolate()->factory();
IfBuilder cow_checker(this);
- cow_checker.IfCompareMap(elements,
- Handle<Map>(heap->fixed_cow_array_map()));
+ cow_checker.If<HCompareMap>(elements, factory->fixed_cow_array_map());
cow_checker.Then();
HValue* capacity = AddLoadFixedArrayLength(elements);
@@ -1256,10 +1265,10 @@
HLoadExternalArrayPointer* external_elements =
Add<HLoadExternalArrayPointer>(elements);
IfBuilder length_checker(this);
- length_checker.IfCompare(key, length, Token::LT);
+ length_checker.If<HCompareNumericAndBranch>(key, length, Token::LT);
length_checker.Then();
IfBuilder negative_checker(this);
- HValue* bounds_check = negative_checker.IfCompare(
+ HValue* bounds_check = negative_checker.If<HCompareNumericAndBranch>(
key, graph()->GetConstant0(), Token::GTE);
negative_checker.Then();
HInstruction* result = BuildExternalArrayElementAccess(
@@ -1654,6 +1663,39 @@
}
+HInstruction* HGraphBuilder::BuildUnaryMathOp(
+ HValue* input, Handle<Type> type, Token::Value operation) {
+ // We only handle the numeric cases here
+ type = handle(
+ Type::Intersect(type, handle(Type::Number(), isolate())), isolate());
+
+ switch (operation) {
+ default:
+ UNREACHABLE();
+ case Token::SUB: {
+ HInstruction* instr =
+ HMul::New(zone(), environment()->LookupContext(),
+ input, graph()->GetConstantMinus1());
+ Representation rep = Representation::FromType(type);
+ if (type->Is(Type::None())) {
+ AddSoftDeoptimize();
+ }
+ if (instr->IsBinaryOperation()) {
+ HBinaryOperation* binop = HBinaryOperation::cast(instr);
+ binop->set_observed_input_representation(1, rep);
+ binop->set_observed_input_representation(2, rep);
+ }
+ return instr;
+ }
+ case Token::BIT_NOT:
+ if (type->Is(Type::None())) {
+ AddSoftDeoptimize();
+ }
+ return new(zone()) HBitNot(input);
+ }
+}
+
+
void HGraphBuilder::BuildCompareNil(
HValue* value,
Handle<Type> type,
@@ -1909,6 +1951,18 @@
}
+HValue* HGraphBuilder::AddLoadJSBuiltin(Builtins::JavaScript builtin,
+ HContext* context) {
+ HGlobalObject* global_object = Add<HGlobalObject>(context);
+ HObjectAccess access = HObjectAccess::ForJSObjectOffset(
+ GlobalObject::kBuiltinsOffset);
+ HValue* builtins = AddLoad(global_object, access);
+ HObjectAccess function_access = HObjectAccess::ForJSObjectOffset(
+ JSBuiltinsObject::OffsetOfFunctionWithId(builtin));
+ return AddLoad(builtins, function_access);
+}
+
+
HOptimizedGraphBuilder::HOptimizedGraphBuilder(CompilationInfo* info)
: HGraphBuilder(info),
function_state_(NULL),
@@ -2055,6 +2109,7 @@
}
}
+
// Block ordering was implemented with two mutually recursive methods,
// HGraph::Postorder and HGraph::PostorderLoopBlocks.
// The recursion could lead to stack overflow so the algorithm has been
@@ -2470,53 +2525,6 @@
}
-// Replace all phis consisting of a single non-loop operand plus any number of
-// loop operands by that single non-loop operand.
-void HGraph::EliminateRedundantPhis() {
- HPhase phase("H_Redundant phi elimination", this);
-
- // We do a simple fixed point iteration without any work list, because
- // machine-generated JavaScript can lead to a very dense Hydrogen graph with
- // an enormous work list and will consequently result in OOM. Experiments
- // showed that this simple algorithm is good enough, and even e.g. tracking
- // the set or range of blocks to consider is not a real improvement.
- bool need_another_iteration;
- ZoneList<HPhi*> redundant_phis(blocks_.length(), zone());
- do {
- need_another_iteration = false;
- for (int i = 0; i < blocks_.length(); ++i) {
- HBasicBlock* block = blocks_[i];
- for (int j = 0; j < block->phis()->length(); j++) {
- HPhi* phi = block->phis()->at(j);
- HValue* replacement = phi->GetRedundantReplacement();
- if (replacement != NULL) {
- // Remember phi to avoid concurrent modification of the block's phis.
- redundant_phis.Add(phi, zone());
- for (HUseIterator it(phi->uses()); !it.Done(); it.Advance()) {
- HValue* value = it.value();
- value->SetOperandAt(it.index(), replacement);
- need_another_iteration |= value->IsPhi();
- }
- }
- }
- for (int i = 0; i < redundant_phis.length(); i++) {
- block->RemovePhi(redundant_phis[i]);
- }
- redundant_phis.Clear();
- }
- } while (need_another_iteration);
-
-#if DEBUG
- // Make sure that we *really* removed all redundant phis.
- for (int i = 0; i < blocks_.length(); ++i) {
- for (int j = 0; j < blocks_[i]->phis()->length(); j++) {
- ASSERT(blocks_[i]->phis()->at(j)->GetRedundantReplacement() == NULL);
- }
- }
-#endif
-}
-
-
bool HGraph::CheckArgumentsPhiUses() {
int block_count = blocks_.length();
for (int i = 0; i < block_count; ++i) {
@@ -2557,70 +2565,6 @@
}
-void HGraph::InferTypes(ZoneList<HValue*>* worklist) {
- BitVector in_worklist(GetMaximumValueID(), zone());
- for (int i = 0; i < worklist->length(); ++i) {
- ASSERT(!in_worklist.Contains(worklist->at(i)->id()));
- in_worklist.Add(worklist->at(i)->id());
- }
-
- while (!worklist->is_empty()) {
- HValue* current = worklist->RemoveLast();
- in_worklist.Remove(current->id());
- if (current->UpdateInferredType()) {
- for (HUseIterator it(current->uses()); !it.Done(); it.Advance()) {
- HValue* use = it.value();
- if (!in_worklist.Contains(use->id())) {
- in_worklist.Add(use->id());
- worklist->Add(use, zone());
- }
- }
- }
- }
-}
-
-
-class HStackCheckEliminator BASE_EMBEDDED {
- public:
- explicit HStackCheckEliminator(HGraph* graph) : graph_(graph) { }
-
- void Process();
-
- private:
- HGraph* graph_;
-};
-
-
-void HStackCheckEliminator::Process() {
- HPhase phase("H_Stack check elimination", graph_);
- // For each loop block walk the dominator tree from the backwards branch to
- // the loop header. If a call instruction is encountered the backwards branch
- // is dominated by a call and the stack check in the backwards branch can be
- // removed.
- for (int i = 0; i < graph_->blocks()->length(); i++) {
- HBasicBlock* block = graph_->blocks()->at(i);
- if (block->IsLoopHeader()) {
- HBasicBlock* back_edge = block->loop_information()->GetLastBackEdge();
- HBasicBlock* dominator = back_edge;
- while (true) {
- for (HInstructionIterator it(dominator); !it.Done(); it.Advance()) {
- if (it.Current()->IsCall()) {
- block->loop_information()->stack_check()->Eliminate();
- break;
- }
- }
-
- // Done when the loop header is processed.
- if (dominator == block) break;
-
- // Move up the dominator tree.
- dominator = dominator->dominator();
- }
- }
- }
-}
-
-
void HGraph::MergeRemovableSimulates() {
HPhase phase("H_Merge removable simulates", this);
ZoneList<HSimulate*> mergelist(2, zone());
@@ -2684,43 +2628,6 @@
}
-void HGraph::InitializeInferredTypes() {
- HPhase phase("H_Inferring types", this);
- InitializeInferredTypes(0, this->blocks_.length() - 1);
-}
-
-
-void HGraph::InitializeInferredTypes(int from_inclusive, int to_inclusive) {
- for (int i = from_inclusive; i <= to_inclusive; ++i) {
- HBasicBlock* block = blocks_[i];
-
- const ZoneList<HPhi*>* phis = block->phis();
- for (int j = 0; j < phis->length(); j++) {
- phis->at(j)->UpdateInferredType();
- }
-
- for (HInstructionIterator it(block); !it.Done(); it.Advance()) {
- it.Current()->UpdateInferredType();
- }
-
- if (block->IsLoopHeader()) {
- HBasicBlock* last_back_edge =
- block->loop_information()->GetLastBackEdge();
- InitializeInferredTypes(i + 1, last_back_edge->block_id());
- // Skip all blocks already processed by the recursive call.
- i = last_back_edge->block_id();
- // Update phis of the loop header now after the whole loop body is
- // guaranteed to be processed.
- ZoneList<HValue*> worklist(block->phis()->length(), zone());
- for (int j = 0; j < block->phis()->length(); ++j) {
- worklist.Add(block->phis()->at(j), zone());
- }
- InferTypes(&worklist);
- }
- }
-}
-
-
void HGraph::PropagateMinusZeroChecks(HValue* value, BitVector* visited) {
HValue* current = value;
while (current != NULL) {
@@ -2909,12 +2816,11 @@
void HGraph::MarkDeoptimizeOnUndefined() {
HPhase phase("H_MarkDeoptimizeOnUndefined", this);
- // Compute DeoptimizeOnUndefined flag for phis.
- // Any phi that can reach a use with DeoptimizeOnUndefined set must
- // have DeoptimizeOnUndefined set. Currently only HCompareIDAndBranch, with
- // double input representation, has this flag set.
- // The flag is used by HChange tagged->double, which must deoptimize
- // if one of its uses has this flag set.
+ // Compute DeoptimizeOnUndefined flag for phis. Any phi that can reach a use
+ // with DeoptimizeOnUndefined set must have DeoptimizeOnUndefined set.
+ // Currently only HCompareNumericAndBranch, with double input representation,
+ // has this flag set. The flag is used by HChange tagged->double, which must
+ // deoptimize if one of its uses has this flag set.
for (int i = 0; i < phi_list()->length(); i++) {
HPhi* phi = phi_list()->at(i);
for (HUseIterator it(phi->uses()); !it.Done(); it.Advance()) {
@@ -3215,7 +3121,7 @@
HBasicBlock* empty_true = builder->graph()->CreateBasicBlock();
HBasicBlock* empty_false = builder->graph()->CreateBasicBlock();
ToBooleanStub::Types expected(condition()->to_boolean_types());
- HBranch* test = new(zone()) HBranch(value, empty_true, empty_false, expected);
+ HBranch* test = new(zone()) HBranch(value, expected, empty_true, empty_false);
builder->current_block()->Finish(test);
empty_true->Goto(if_true(), builder->function_state());
@@ -3406,7 +3312,7 @@
"Unsupported phi use of const variable"));
return false;
}
- EliminateRedundantPhis();
+ Run<HRedundantPhiEliminationPhase>();
if (!CheckArgumentsPhiUses()) {
*bailout_reason = SmartArrayPointer<char>(StrDup(
"Unsupported phi use of arguments"));
@@ -3414,9 +3320,7 @@
}
// Remove dead code and phis
- if (FLAG_dead_code_elimination) {
- DeadCodeElimination("H_Eliminate early dead code");
- }
+ if (FLAG_dead_code_elimination) Run<HDeadCodeEliminationPhase>();
CollectPhis();
if (has_osr()) osr()->FinishOsrValues();
@@ -3431,7 +3335,7 @@
MarkDeoptimizeOnUndefined();
InsertRepresentationChanges();
- InitializeInferredTypes();
+ Run<HInferTypesPhase>();
// Must be performed before canonicalization to ensure that Canonicalize
// will not remove semantically meaningful ToInt32 operations e.g. BIT_OR with
@@ -3449,17 +3353,14 @@
ComputeMinusZeroChecks();
// Eliminate redundant stack checks on backwards branches.
- HStackCheckEliminator sce(this);
- sce.Process();
+ Run<HStackCheckEliminationPhase>();
if (FLAG_idefs) SetupInformativeDefinitions();
if (FLAG_array_bounds_checks_elimination && !FLAG_idefs) {
EliminateRedundantBoundsChecks();
}
if (FLAG_array_index_dehoisting) DehoistSimpleArrayIndexComputations();
- if (FLAG_dead_code_elimination) {
- DeadCodeElimination("H_Eliminate late dead code");
- }
+ if (FLAG_dead_code_elimination) Run<HDeadCodeEliminationPhase>();
RestoreActualValues();
@@ -3940,99 +3841,6 @@
}
-void HGraph::DeadCodeElimination(const char* phase_name) {
- HPhase phase(phase_name, this);
- MarkLiveInstructions();
- RemoveDeadInstructions();
-}
-
-
-void HGraph::MarkLiveInstructions() {
- ZoneList<HValue*> worklist(blocks_.length(), zone());
-
- // Mark initial root instructions for dead code elimination.
- for (int i = 0; i < blocks()->length(); ++i) {
- HBasicBlock* block = blocks()->at(i);
- for (HInstructionIterator it(block); !it.Done(); it.Advance()) {
- HInstruction* instr = it.Current();
- if (instr->CannotBeEliminated()) MarkLive(NULL, instr, &worklist);
- }
- for (int j = 0; j < block->phis()->length(); j++) {
- HPhi* phi = block->phis()->at(j);
- if (phi->CannotBeEliminated()) MarkLive(NULL, phi, &worklist);
- }
- }
-
- // Transitively mark all inputs of live instructions live.
- while (!worklist.is_empty()) {
- HValue* instr = worklist.RemoveLast();
- for (int i = 0; i < instr->OperandCount(); ++i) {
- MarkLive(instr, instr->OperandAt(i), &worklist);
- }
- }
-}
-
-
-void HGraph::MarkLive(HValue* ref, HValue* instr, ZoneList<HValue*>* worklist) {
- if (!instr->CheckFlag(HValue::kIsLive)) {
- instr->SetFlag(HValue::kIsLive);
- worklist->Add(instr, zone());
-
- if (FLAG_trace_dead_code_elimination) {
- HeapStringAllocator allocator;
- StringStream stream(&allocator);
- if (ref != NULL) {
- ref->PrintTo(&stream);
- } else {
- stream.Add("root ");
- }
- stream.Add(" -> ");
- instr->PrintTo(&stream);
- PrintF("[MarkLive %s]\n", *stream.ToCString());
- }
- }
-}
-
-
-void HGraph::RemoveDeadInstructions() {
- ZoneList<HPhi*> dead_phis(blocks_.length(), zone());
-
- // Remove any instruction not marked kIsLive.
- for (int i = 0; i < blocks()->length(); ++i) {
- HBasicBlock* block = blocks()->at(i);
- for (HInstructionIterator it(block); !it.Done(); it.Advance()) {
- HInstruction* instr = it.Current();
- if (!instr->CheckFlag(HValue::kIsLive)) {
- // Instruction has not been marked live; assume it is dead and remove.
- // TODO(titzer): we don't remove constants because some special ones
- // might be used by later phases and are assumed to be in the graph
- if (!instr->IsConstant()) instr->DeleteAndReplaceWith(NULL);
- } else {
- // Clear the liveness flag to leave the graph clean for the next DCE.
- instr->ClearFlag(HValue::kIsLive);
- }
- }
- // Collect phis that are dead and remove them in the next pass.
- for (int j = 0; j < block->phis()->length(); j++) {
- HPhi* phi = block->phis()->at(j);
- if (!phi->CheckFlag(HValue::kIsLive)) {
- dead_phis.Add(phi, zone());
- } else {
- phi->ClearFlag(HValue::kIsLive);
- }
- }
- }
-
- // Process phis separately to avoid simultaneously mutating the phi list.
- while (!dead_phis.is_empty()) {
- HPhi* phi = dead_phis.RemoveLast();
- HBasicBlock* block = phi->block();
- phi->DeleteAndReplaceWith(NULL);
- block->RecordDeletedPhi(phi->merged_index());
- }
-}
-
-
void HGraph::RestoreActualValues() {
HPhase phase("H_Restore actual values", this);
@@ -4067,17 +3875,6 @@
}
-void HOptimizedGraphBuilder::AddSoftDeoptimize() {
- isolate()->counters()->soft_deopts_requested()->Increment();
- if (FLAG_always_opt) return;
- if (current_block()->IsDeoptimizing()) return;
- Add<HSoftDeoptimize>();
- isolate()->counters()->soft_deopts_inserted()->Increment();
- current_block()->MarkAsDeoptimizing();
- graph()->set_has_soft_deoptimize(true);
-}
-
-
template <class Instruction>
HInstruction* HOptimizedGraphBuilder::PreProcessCall(Instruction* call) {
int count = call->argument_count();
@@ -4428,10 +4225,10 @@
AddSoftDeoptimize();
}
- HCompareIDAndBranch* compare_ =
- new(zone()) HCompareIDAndBranch(tag_value,
- label_value,
- Token::EQ_STRICT);
+ HCompareNumericAndBranch* compare_ =
+ new(zone()) HCompareNumericAndBranch(tag_value,
+ label_value,
+ Token::EQ_STRICT);
compare_->set_observed_input_representation(
Representation::Smi(), Representation::Smi());
compare = compare_;
@@ -4715,8 +4512,8 @@
HValue* limit = environment()->ExpressionStackAt(1);
// Check that we still have more keys.
- HCompareIDAndBranch* compare_index =
- new(zone()) HCompareIDAndBranch(index, limit, Token::LT);
+ HCompareNumericAndBranch* compare_index =
+ new(zone()) HCompareNumericAndBranch(index, limit, Token::LT);
compare_index->set_observed_input_representation(
Representation::Smi(), Representation::Smi());
@@ -4952,9 +4749,20 @@
if (type == kUseCell) {
Handle<GlobalObject> global(current_info()->global_object());
Handle<PropertyCell> cell(global->GetPropertyCell(&lookup));
- HLoadGlobalCell* instr =
- new(zone()) HLoadGlobalCell(cell, lookup.GetPropertyDetails());
- return ast_context()->ReturnInstruction(instr, expr->id());
+ if (cell->type()->IsConstant()) {
+ cell->AddDependentCompilationInfo(top_info());
+ Handle<Object> constant_object = cell->type()->AsConstant();
+ if (constant_object->IsConsString()) {
+ constant_object =
+ FlattenGetString(Handle<String>::cast(constant_object));
+ }
+ HConstant* constant = new(zone()) HConstant(constant_object);
+ return ast_context()->ReturnInstruction(constant, expr->id());
+ } else {
+ HLoadGlobalCell* instr =
+ new(zone()) HLoadGlobalCell(cell, lookup.GetPropertyDetails());
+ return ast_context()->ReturnInstruction(instr, expr->id());
+ }
} else {
HValue* context = environment()->LookupContext();
HGlobalObject* global_object = new(zone()) HGlobalObject(context);
@@ -5764,7 +5572,7 @@
HBasicBlock* if_true = graph()->CreateBasicBlock();
HBasicBlock* if_false = graph()->CreateBasicBlock();
HCompareMap* compare =
- new(zone()) HCompareMap(object, map, if_true, if_false);
+ new(zone()) HCompareMap(object, map, if_true, if_false);
current_block()->Finish(compare);
set_current_block(if_true);
@@ -5865,8 +5673,21 @@
if (type == kUseCell) {
Handle<GlobalObject> global(current_info()->global_object());
Handle<PropertyCell> cell(global->GetPropertyCell(&lookup));
- HInstruction* instr = Add<HStoreGlobalCell>(value, cell,
- lookup.GetPropertyDetails());
+ if (cell->type()->IsConstant()) {
+ IfBuilder builder(this);
+ HValue* constant = Add<HConstant>(cell->type()->AsConstant());
+ if (cell->type()->AsConstant()->IsNumber()) {
+ builder.If<HCompareNumericAndBranch>(value, constant, Token::EQ);
+ } else {
+ builder.If<HCompareObjectEqAndBranch>(value, constant);
+ }
+ builder.Then();
+ builder.Else();
+ AddSoftDeoptimize(MUST_EMIT_SOFT_DEOPT);
+ builder.End();
+ }
+ HInstruction* instr =
+ Add<HStoreGlobalCell>(value, cell, lookup.GetPropertyDetails());
instr->set_position(position);
if (instr->HasObservableSideEffects()) {
AddSimulate(ast_id, REMOVABLE_SIMULATE);
@@ -8292,18 +8113,8 @@
void HOptimizedGraphBuilder::VisitSub(UnaryOperation* expr) {
CHECK_ALIVE(VisitForValue(expr->expression()));
HValue* value = Pop();
- HValue* context = environment()->LookupContext();
- HInstruction* instr =
- HMul::New(zone(), context, value, graph()->GetConstantMinus1());
Handle<Type> operand_type = expr->expression()->lower_type();
- Representation rep = ToRepresentation(operand_type);
- if (operand_type->Is(Type::None())) {
- AddSoftDeoptimize();
- }
- if (instr->IsBinaryOperation()) {
- HBinaryOperation::cast(instr)->set_observed_input_representation(1, rep);
- HBinaryOperation::cast(instr)->set_observed_input_representation(2, rep);
- }
+ HInstruction* instr = BuildUnaryMathOp(value, operand_type, Token::SUB);
return ast_context()->ReturnInstruction(instr, expr->id());
}
@@ -8312,10 +8123,7 @@
CHECK_ALIVE(VisitForValue(expr->expression()));
HValue* value = Pop();
Handle<Type> operand_type = expr->expression()->lower_type();
- if (operand_type->Is(Type::None())) {
- AddSoftDeoptimize();
- }
- HInstruction* instr = new(zone()) HBitNot(value);
+ HInstruction* instr = BuildUnaryMathOp(value, operand_type, Token::BIT_NOT);
return ast_context()->ReturnInstruction(instr, expr->id());
}
@@ -8369,7 +8177,7 @@
CountOperation* expr) {
// The input to the count operation is on top of the expression stack.
TypeInfo info = expr->type();
- Representation rep = ToRepresentation(info);
+ Representation rep = Representation::FromType(info);
if (rep.IsNone() || rep.IsTagged()) {
rep = Representation::Smi();
}
@@ -8610,6 +8418,7 @@
return new(zone()) HStringCharCodeAt(context, string, checked_index);
}
+
// Checks if the given shift amounts have form: (sa) and (32 - sa).
static bool ShiftAmountsAllowReplaceByRotate(HValue* sa,
HValue* const32_minus_sa) {
@@ -8675,11 +8484,12 @@
HValue* context = environment()->LookupContext();
Handle<Type> left_type = expr->left()->lower_type();
Handle<Type> right_type = expr->right()->lower_type();
- Handle<Type> result_type = expr->result_type();
+ Handle<Type> result_type = expr->lower_type();
Maybe<int> fixed_right_arg = expr->fixed_right_arg();
- Representation left_rep = ToRepresentation(left_type);
- Representation right_rep = ToRepresentation(right_type);
- Representation result_rep = ToRepresentation(result_type);
+ Representation left_rep = Representation::FromType(left_type);
+ Representation right_rep = Representation::FromType(right_type);
+ Representation result_rep = Representation::FromType(result_type);
+
if (left_type->Is(Type::None())) {
AddSoftDeoptimize();
// TODO(rossberg): we should be able to get rid of non-continuous defaults.
@@ -8840,8 +8650,8 @@
HBasicBlock* eval_right = graph()->CreateBasicBlock();
ToBooleanStub::Types expected(expr->left()->to_boolean_types());
HBranch* test = is_logical_and
- ? new(zone()) HBranch(left_value, eval_right, empty_block, expected)
- : new(zone()) HBranch(left_value, empty_block, eval_right, expected);
+ ? new(zone()) HBranch(left_value, expected, eval_right, empty_block)
+ : new(zone()) HBranch(left_value, expected, empty_block, eval_right);
current_block()->Finish(test);
set_current_block(eval_right);
@@ -8907,26 +8717,6 @@
}
-// TODO(rossberg): this should die eventually.
-Representation HOptimizedGraphBuilder::ToRepresentation(TypeInfo info) {
- if (info.IsUninitialized()) return Representation::None();
- // TODO(verwaest): Return Smi rather than Integer32.
- if (info.IsSmi()) return Representation::Integer32();
- if (info.IsInteger32()) return Representation::Integer32();
- if (info.IsDouble()) return Representation::Double();
- if (info.IsNumber()) return Representation::Double();
- return Representation::Tagged();
-}
-
-
-Representation HOptimizedGraphBuilder::ToRepresentation(Handle<Type> type) {
- if (type->Is(Type::None())) return Representation::None();
- if (type->Is(Type::Signed32())) return Representation::Integer32();
- if (type->Is(Type::Number())) return Representation::Double();
- return Representation::Tagged();
-}
-
-
void HOptimizedGraphBuilder::HandleLiteralCompareTypeof(CompareOperation* expr,
HTypeof* typeof_expr,
Handle<String> check) {
@@ -9019,9 +8809,9 @@
Handle<Type> left_type = expr->left()->lower_type();
Handle<Type> right_type = expr->right()->lower_type();
Handle<Type> combined_type = expr->combined_type();
- Representation combined_rep = ToRepresentation(combined_type);
- Representation left_rep = ToRepresentation(left_type);
- Representation right_rep = ToRepresentation(right_type);
+ Representation combined_rep = Representation::FromType(combined_type);
+ Representation left_rep = Representation::FromType(left_type);
+ Representation right_rep = Representation::FromType(right_type);
CHECK_ALIVE(VisitForValue(expr->left()));
CHECK_ALIVE(VisitForValue(expr->right()));
@@ -9150,12 +8940,12 @@
result->set_position(expr->position());
return ast_context()->ReturnInstruction(result, expr->id());
} else {
- // TODO(verwaest): Remove once ToRepresentation properly returns Smi when
- // the IC measures Smi.
+ // TODO(verwaest): Remove once Representation::FromType properly
+ // returns Smi when the IC measures Smi.
if (left_type->Is(Type::Smi())) left_rep = Representation::Smi();
if (right_type->Is(Type::Smi())) right_rep = Representation::Smi();
- HCompareIDAndBranch* result =
- new(zone()) HCompareIDAndBranch(left, right, op);
+ HCompareNumericAndBranch* result =
+ new(zone()) HCompareNumericAndBranch(left, right, op);
result->set_observed_input_representation(left_rep, right_rep);
result->set_position(expr->position());
return ast_context()->ReturnControl(result, expr->id());
@@ -9522,6 +9312,7 @@
}
}
+
void HOptimizedGraphBuilder::VisitThisFunction(ThisFunction* expr) {
ASSERT(!HasStackOverflow());
ASSERT(current_block() != NULL);
diff --git a/src/hydrogen.h b/src/hydrogen.h
index f80aca1..7e4c691 100644
--- a/src/hydrogen.h
+++ b/src/hydrogen.h
@@ -291,14 +291,12 @@
HEnvironment* start_environment() const { return start_environment_; }
void FinalizeUniqueValueIds();
- void InitializeInferredTypes();
void InsertTypeConversions();
void MergeRemovableSimulates();
void InsertRepresentationChanges();
void MarkDeoptimizeOnUndefined();
void ComputeMinusZeroChecks();
bool ProcessArgumentsObject();
- void EliminateRedundantPhis();
void Canonicalize();
void OrderBlocks();
void AssignDominators();
@@ -306,7 +304,6 @@
void EliminateRedundantBoundsChecks();
void DehoistSimpleArrayIndexComputations();
void RestoreActualValues();
- void DeadCodeElimination(const char *phase_name);
void PropagateDeoptimizingMark();
void AnalyzeAndPruneEnvironmentLiveness();
@@ -333,6 +330,8 @@
HConstant* GetConstantNull();
HConstant* GetInvalidContext();
+ bool IsStandardConstant(HConstant* constant);
+
HBasicBlock* CreateBasicBlock();
HArgumentsObject* GetArgumentsObject() const {
return arguments_object_.get();
@@ -449,9 +448,6 @@
phase.Run();
}
- void MarkLive(HValue* ref, HValue* instr, ZoneList<HValue*>* worklist);
- void MarkLiveInstructions();
- void RemoveDeadInstructions();
void MarkAsDeoptimizingRecursively(HBasicBlock* block);
void NullifyUnreachableInstructions();
void InsertTypeConversions(HInstruction* instr);
@@ -462,8 +458,6 @@
int use_index,
Representation to);
void InsertRepresentationChangesForValue(HValue* value);
- void InferTypes(ZoneList<HValue*>* worklist);
- void InitializeInferredTypes(int from_inclusive, int to_inclusive);
void CheckForBackEdge(HBasicBlock* block, HBasicBlock* successor);
void SetupInformativeDefinitionsInBlock(HBasicBlock* block);
void SetupInformativeDefinitionsRecursively(HBasicBlock* block);
@@ -1129,6 +1123,15 @@
HLoadNamedField* AddLoadFixedArrayLength(HValue *object);
+ HValue* AddLoadJSBuiltin(Builtins::JavaScript builtin, HContext* context);
+
+ enum SoftDeoptimizeMode {
+ MUST_EMIT_SOFT_DEOPT,
+ CAN_OMIT_SOFT_DEOPT
+ };
+
+ void AddSoftDeoptimize(SoftDeoptimizeMode mode = CAN_OMIT_SOFT_DEOPT);
+
class IfBuilder {
public:
explicit IfBuilder(HGraphBuilder* builder,
@@ -1140,13 +1143,6 @@
if (!finished_) End();
}
- HInstruction* IfCompare(
- HValue* left,
- HValue* right,
- Token::Value token);
-
- HInstruction* IfCompareMap(HValue* left, Handle<Map> map);
-
template<class Condition>
HInstruction* If(HValue *p) {
HControlInstruction* compare = new(zone()) Condition(p);
@@ -1161,6 +1157,13 @@
return compare;
}
+ template<class Condition, class P2, class P3>
+ HInstruction* If(HValue* p1, P2 p2, P3 p3) {
+ HControlInstruction* compare = new(zone()) Condition(p1, p2, p3);
+ AddCompare(compare);
+ return compare;
+ }
+
template<class Condition, class P2>
HInstruction* IfNot(HValue* p1, P2 p2) {
HControlInstruction* compare = new(zone()) Condition(p1, p2);
@@ -1172,17 +1175,15 @@
return compare;
}
- HInstruction* OrIfCompare(
- HValue* p1,
- HValue* p2,
- Token::Value token) {
- Or();
- return IfCompare(p1, p2, token);
- }
-
- HInstruction* OrIfCompareMap(HValue* left, Handle<Map> map) {
- Or();
- return IfCompareMap(left, map);
+ template<class Condition, class P2, class P3>
+ HInstruction* IfNot(HValue* p1, P2 p2, P3 p3) {
+ HControlInstruction* compare = new(zone()) Condition(p1, p2, p3);
+ AddCompare(compare);
+ HBasicBlock* block0 = compare->SuccessorAt(0);
+ HBasicBlock* block1 = compare->SuccessorAt(1);
+ compare->SetSuccessorAt(0, block1);
+ compare->SetSuccessorAt(1, block0);
+ return compare;
}
template<class Condition>
@@ -1197,17 +1198,10 @@
return If<Condition>(p1, p2);
}
- HInstruction* AndIfCompare(
- HValue* p1,
- HValue* p2,
- Token::Value token) {
- And();
- return IfCompare(p1, p2, token);
- }
-
- HInstruction* AndIfCompareMap(HValue* left, Handle<Map> map) {
- And();
- return IfCompareMap(left, map);
+ template<class Condition, class P2, class P3>
+ HInstruction* OrIf(HValue* p1, P2 p2, P3 p3) {
+ Or();
+ return If<Condition>(p1, p2, p3);
}
template<class Condition>
@@ -1222,6 +1216,12 @@
return If<Condition>(p1, p2);
}
+ template<class Condition, class P2, class P3>
+ HInstruction* AndIf(HValue* p1, P2 p2, P3 p3) {
+ And();
+ return If<Condition>(p1, p2, p3);
+ }
+
void Or();
void And();
@@ -1409,6 +1409,9 @@
ElementsKind kind,
int length);
+ HInstruction* BuildUnaryMathOp(
+ HValue* value, Handle<Type> type, Token::Value token);
+
void BuildCompareNil(
HValue* value,
Handle<Type> type,
@@ -1495,8 +1498,6 @@
bool inline_bailout() { return inline_bailout_; }
- void AddSoftDeoptimize();
-
void Bailout(const char* reason);
HBasicBlock* CreateJoin(HBasicBlock* first,
@@ -1676,9 +1677,6 @@
// to push them as outgoing parameters.
template <class Instruction> HInstruction* PreProcessCall(Instruction* call);
- static Representation ToRepresentation(TypeInfo info);
- static Representation ToRepresentation(Handle<Type> type);
-
void SetUpScope(Scope* scope);
virtual void VisitStatements(ZoneList<Statement*>* statements);
diff --git a/src/ia32/assembler-ia32.cc b/src/ia32/assembler-ia32.cc
index 7bb643a..60b525f 100644
--- a/src/ia32/assembler-ia32.cc
+++ b/src/ia32/assembler-ia32.cc
@@ -1055,6 +1055,7 @@
}
}
+
void Assembler::ror(Register dst, uint8_t imm8) {
EnsureSpace ensure_space(this);
ASSERT(is_uint5(imm8)); // illegal shift count
@@ -1068,6 +1069,7 @@
}
}
+
void Assembler::ror_cl(Register dst) {
EnsureSpace ensure_space(this);
EMIT(0xD3);
@@ -2137,6 +2139,7 @@
EMIT(static_cast<byte>(mode) | 0x8);
}
+
void Assembler::movmskpd(Register dst, XMMRegister src) {
ASSERT(IsEnabled(SSE2));
EnsureSpace ensure_space(this);
diff --git a/src/ia32/code-stubs-ia32.cc b/src/ia32/code-stubs-ia32.cc
index 29a4be2..31f4f4b 100644
--- a/src/ia32/code-stubs-ia32.cc
+++ b/src/ia32/code-stubs-ia32.cc
@@ -230,6 +230,28 @@
}
+void UnaryOpStub::InitializeInterfaceDescriptor(
+ Isolate* isolate,
+ CodeStubInterfaceDescriptor* descriptor) {
+ static Register registers[] = { eax };
+ descriptor->register_param_count_ = 1;
+ descriptor->register_params_ = registers;
+ descriptor->deoptimization_handler_ =
+ FUNCTION_ADDR(UnaryOpIC_Miss);
+}
+
+
+void StoreGlobalStub::InitializeInterfaceDescriptor(
+ Isolate* isolate,
+ CodeStubInterfaceDescriptor* descriptor) {
+ static Register registers[] = { edx, ecx, eax };
+ descriptor->register_param_count_ = 3;
+ descriptor->register_params_ = registers;
+ descriptor->deoptimization_handler_ =
+ FUNCTION_ADDR(StoreIC_MissFromStubFailure);
+}
+
+
#define __ ACCESS_MASM(masm)
@@ -759,325 +781,6 @@
}
-void UnaryOpStub::PrintName(StringStream* stream) {
- const char* op_name = Token::Name(op_);
- const char* overwrite_name = NULL; // Make g++ happy.
- switch (mode_) {
- case UNARY_NO_OVERWRITE: overwrite_name = "Alloc"; break;
- case UNARY_OVERWRITE: overwrite_name = "Overwrite"; break;
- }
- stream->Add("UnaryOpStub_%s_%s_%s",
- op_name,
- overwrite_name,
- UnaryOpIC::GetName(operand_type_));
-}
-
-
-// TODO(svenpanne): Use virtual functions instead of switch.
-void UnaryOpStub::Generate(MacroAssembler* masm) {
- switch (operand_type_) {
- case UnaryOpIC::UNINITIALIZED:
- GenerateTypeTransition(masm);
- break;
- case UnaryOpIC::SMI:
- GenerateSmiStub(masm);
- break;
- case UnaryOpIC::NUMBER:
- GenerateNumberStub(masm);
- break;
- case UnaryOpIC::GENERIC:
- GenerateGenericStub(masm);
- break;
- }
-}
-
-
-void UnaryOpStub::GenerateTypeTransition(MacroAssembler* masm) {
- __ pop(ecx); // Save return address.
-
- __ push(eax); // the operand
- __ push(Immediate(Smi::FromInt(op_)));
- __ push(Immediate(Smi::FromInt(mode_)));
- __ push(Immediate(Smi::FromInt(operand_type_)));
-
- __ push(ecx); // Push return address.
-
- // Patch the caller to an appropriate specialized stub and return the
- // operation result to the caller of the stub.
- __ TailCallExternalReference(
- ExternalReference(IC_Utility(IC::kUnaryOp_Patch), masm->isolate()), 4, 1);
-}
-
-
-// TODO(svenpanne): Use virtual functions instead of switch.
-void UnaryOpStub::GenerateSmiStub(MacroAssembler* masm) {
- switch (op_) {
- case Token::SUB:
- GenerateSmiStubSub(masm);
- break;
- case Token::BIT_NOT:
- GenerateSmiStubBitNot(masm);
- break;
- default:
- UNREACHABLE();
- }
-}
-
-
-void UnaryOpStub::GenerateSmiStubSub(MacroAssembler* masm) {
- Label non_smi, undo, slow;
- GenerateSmiCodeSub(masm, &non_smi, &undo, &slow,
- Label::kNear, Label::kNear, Label::kNear);
- __ bind(&undo);
- GenerateSmiCodeUndo(masm);
- __ bind(&non_smi);
- __ bind(&slow);
- GenerateTypeTransition(masm);
-}
-
-
-void UnaryOpStub::GenerateSmiStubBitNot(MacroAssembler* masm) {
- Label non_smi;
- GenerateSmiCodeBitNot(masm, &non_smi);
- __ bind(&non_smi);
- GenerateTypeTransition(masm);
-}
-
-
-void UnaryOpStub::GenerateSmiCodeSub(MacroAssembler* masm,
- Label* non_smi,
- Label* undo,
- Label* slow,
- Label::Distance non_smi_near,
- Label::Distance undo_near,
- Label::Distance slow_near) {
- // Check whether the value is a smi.
- __ JumpIfNotSmi(eax, non_smi, non_smi_near);
-
- // We can't handle -0 with smis, so use a type transition for that case.
- __ test(eax, eax);
- __ j(zero, slow, slow_near);
-
- // Try optimistic subtraction '0 - value', saving operand in eax for undo.
- __ mov(edx, eax);
- __ Set(eax, Immediate(0));
- __ sub(eax, edx);
- __ j(overflow, undo, undo_near);
- __ ret(0);
-}
-
-
-void UnaryOpStub::GenerateSmiCodeBitNot(
- MacroAssembler* masm,
- Label* non_smi,
- Label::Distance non_smi_near) {
- // Check whether the value is a smi.
- __ JumpIfNotSmi(eax, non_smi, non_smi_near);
-
- // Flip bits and revert inverted smi-tag.
- __ not_(eax);
- __ and_(eax, ~kSmiTagMask);
- __ ret(0);
-}
-
-
-void UnaryOpStub::GenerateSmiCodeUndo(MacroAssembler* masm) {
- __ mov(eax, edx);
-}
-
-
-// TODO(svenpanne): Use virtual functions instead of switch.
-void UnaryOpStub::GenerateNumberStub(MacroAssembler* masm) {
- switch (op_) {
- case Token::SUB:
- GenerateNumberStubSub(masm);
- break;
- case Token::BIT_NOT:
- GenerateNumberStubBitNot(masm);
- break;
- default:
- UNREACHABLE();
- }
-}
-
-
-void UnaryOpStub::GenerateNumberStubSub(MacroAssembler* masm) {
- Label non_smi, undo, slow, call_builtin;
- GenerateSmiCodeSub(masm, &non_smi, &undo, &call_builtin, Label::kNear);
- __ bind(&non_smi);
- GenerateHeapNumberCodeSub(masm, &slow);
- __ bind(&undo);
- GenerateSmiCodeUndo(masm);
- __ bind(&slow);
- GenerateTypeTransition(masm);
- __ bind(&call_builtin);
- GenerateGenericCodeFallback(masm);
-}
-
-
-void UnaryOpStub::GenerateNumberStubBitNot(
- MacroAssembler* masm) {
- Label non_smi, slow;
- GenerateSmiCodeBitNot(masm, &non_smi, Label::kNear);
- __ bind(&non_smi);
- GenerateHeapNumberCodeBitNot(masm, &slow);
- __ bind(&slow);
- GenerateTypeTransition(masm);
-}
-
-
-void UnaryOpStub::GenerateHeapNumberCodeSub(MacroAssembler* masm,
- Label* slow) {
- __ mov(edx, FieldOperand(eax, HeapObject::kMapOffset));
- __ cmp(edx, masm->isolate()->factory()->heap_number_map());
- __ j(not_equal, slow);
-
- if (mode_ == UNARY_OVERWRITE) {
- __ xor_(FieldOperand(eax, HeapNumber::kExponentOffset),
- Immediate(HeapNumber::kSignMask)); // Flip sign.
- } else {
- __ mov(edx, eax);
- // edx: operand
-
- Label slow_allocate_heapnumber, heapnumber_allocated;
- __ AllocateHeapNumber(eax, ebx, ecx, &slow_allocate_heapnumber);
- __ jmp(&heapnumber_allocated, Label::kNear);
-
- __ bind(&slow_allocate_heapnumber);
- {
- FrameScope scope(masm, StackFrame::INTERNAL);
- __ push(edx);
- __ CallRuntime(Runtime::kNumberAlloc, 0);
- __ pop(edx);
- }
-
- __ bind(&heapnumber_allocated);
- // eax: allocated 'empty' number
- __ mov(ecx, FieldOperand(edx, HeapNumber::kExponentOffset));
- __ xor_(ecx, HeapNumber::kSignMask); // Flip sign.
- __ mov(FieldOperand(eax, HeapNumber::kExponentOffset), ecx);
- __ mov(ecx, FieldOperand(edx, HeapNumber::kMantissaOffset));
- __ mov(FieldOperand(eax, HeapNumber::kMantissaOffset), ecx);
- }
- __ ret(0);
-}
-
-
-void UnaryOpStub::GenerateHeapNumberCodeBitNot(MacroAssembler* masm,
- Label* slow) {
- __ mov(edx, FieldOperand(eax, HeapObject::kMapOffset));
- __ cmp(edx, masm->isolate()->factory()->heap_number_map());
- __ j(not_equal, slow);
-
- // Convert the heap number in eax to an untagged integer in ecx.
- IntegerConvert(masm, eax, CpuFeatures::IsSupported(SSE3), slow);
-
- // Do the bitwise operation and check if the result fits in a smi.
- Label try_float;
- __ not_(ecx);
- __ cmp(ecx, 0xc0000000);
- __ j(sign, &try_float, Label::kNear);
-
- // Tag the result as a smi and we're done.
- STATIC_ASSERT(kSmiTagSize == 1);
- __ lea(eax, Operand(ecx, times_2, kSmiTag));
- __ ret(0);
-
- // Try to store the result in a heap number.
- __ bind(&try_float);
- if (mode_ == UNARY_NO_OVERWRITE) {
- Label slow_allocate_heapnumber, heapnumber_allocated;
- __ mov(ebx, eax);
- __ AllocateHeapNumber(eax, edx, edi, &slow_allocate_heapnumber);
- __ jmp(&heapnumber_allocated);
-
- __ bind(&slow_allocate_heapnumber);
- {
- FrameScope scope(masm, StackFrame::INTERNAL);
- // Push the original HeapNumber on the stack. The integer value can't
- // be stored since it's untagged and not in the smi range (so we can't
- // smi-tag it). We'll recalculate the value after the GC instead.
- __ push(ebx);
- __ CallRuntime(Runtime::kNumberAlloc, 0);
- // New HeapNumber is in eax.
- __ pop(edx);
- }
- // IntegerConvert uses ebx and edi as scratch registers.
- // This conversion won't go slow-case.
- IntegerConvert(masm, edx, CpuFeatures::IsSupported(SSE3), slow);
- __ not_(ecx);
-
- __ bind(&heapnumber_allocated);
- }
- if (CpuFeatures::IsSupported(SSE2)) {
- CpuFeatureScope use_sse2(masm, SSE2);
- __ cvtsi2sd(xmm0, ecx);
- __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0);
- } else {
- __ push(ecx);
- __ fild_s(Operand(esp, 0));
- __ pop(ecx);
- __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset));
- }
- __ ret(0);
-}
-
-
-// TODO(svenpanne): Use virtual functions instead of switch.
-void UnaryOpStub::GenerateGenericStub(MacroAssembler* masm) {
- switch (op_) {
- case Token::SUB:
- GenerateGenericStubSub(masm);
- break;
- case Token::BIT_NOT:
- GenerateGenericStubBitNot(masm);
- break;
- default:
- UNREACHABLE();
- }
-}
-
-
-void UnaryOpStub::GenerateGenericStubSub(MacroAssembler* masm) {
- Label non_smi, undo, slow;
- GenerateSmiCodeSub(masm, &non_smi, &undo, &slow, Label::kNear);
- __ bind(&non_smi);
- GenerateHeapNumberCodeSub(masm, &slow);
- __ bind(&undo);
- GenerateSmiCodeUndo(masm);
- __ bind(&slow);
- GenerateGenericCodeFallback(masm);
-}
-
-
-void UnaryOpStub::GenerateGenericStubBitNot(MacroAssembler* masm) {
- Label non_smi, slow;
- GenerateSmiCodeBitNot(masm, &non_smi, Label::kNear);
- __ bind(&non_smi);
- GenerateHeapNumberCodeBitNot(masm, &slow);
- __ bind(&slow);
- GenerateGenericCodeFallback(masm);
-}
-
-
-void UnaryOpStub::GenerateGenericCodeFallback(MacroAssembler* masm) {
- // Handle the slow case by jumping to the corresponding JavaScript builtin.
- __ pop(ecx); // pop return address.
- __ push(eax);
- __ push(ecx); // push return address
- switch (op_) {
- case Token::SUB:
- __ InvokeBuiltin(Builtins::UNARY_MINUS, JUMP_FUNCTION);
- break;
- case Token::BIT_NOT:
- __ InvokeBuiltin(Builtins::BIT_NOT, JUMP_FUNCTION);
- break;
- default:
- UNREACHABLE();
- }
-}
-
-
void BinaryOpStub::Initialize() {
platform_specific_bit_ = CpuFeatures::IsSupported(SSE3);
}
diff --git a/src/ia32/code-stubs-ia32.h b/src/ia32/code-stubs-ia32.h
index 6dc63bd..dc21d40 100644
--- a/src/ia32/code-stubs-ia32.h
+++ b/src/ia32/code-stubs-ia32.h
@@ -86,80 +86,6 @@
};
-class UnaryOpStub: public PlatformCodeStub {
- public:
- UnaryOpStub(Token::Value op,
- UnaryOverwriteMode mode,
- UnaryOpIC::TypeInfo operand_type = UnaryOpIC::UNINITIALIZED)
- : op_(op),
- mode_(mode),
- operand_type_(operand_type) {
- }
-
- private:
- Token::Value op_;
- UnaryOverwriteMode mode_;
-
- // Operand type information determined at runtime.
- UnaryOpIC::TypeInfo operand_type_;
-
- virtual void PrintName(StringStream* stream);
-
- class ModeBits: public BitField<UnaryOverwriteMode, 0, 1> {};
- class OpBits: public BitField<Token::Value, 1, 7> {};
- class OperandTypeInfoBits: public BitField<UnaryOpIC::TypeInfo, 8, 3> {};
-
- Major MajorKey() { return UnaryOp; }
- int MinorKey() {
- return ModeBits::encode(mode_)
- | OpBits::encode(op_)
- | OperandTypeInfoBits::encode(operand_type_);
- }
-
- // Note: A lot of the helper functions below will vanish when we use virtual
- // function instead of switch more often.
- void Generate(MacroAssembler* masm);
-
- void GenerateTypeTransition(MacroAssembler* masm);
-
- void GenerateSmiStub(MacroAssembler* masm);
- void GenerateSmiStubSub(MacroAssembler* masm);
- void GenerateSmiStubBitNot(MacroAssembler* masm);
- void GenerateSmiCodeSub(MacroAssembler* masm,
- Label* non_smi,
- Label* undo,
- Label* slow,
- Label::Distance non_smi_near = Label::kFar,
- Label::Distance undo_near = Label::kFar,
- Label::Distance slow_near = Label::kFar);
- void GenerateSmiCodeBitNot(MacroAssembler* masm,
- Label* non_smi,
- Label::Distance non_smi_near = Label::kFar);
- void GenerateSmiCodeUndo(MacroAssembler* masm);
-
- void GenerateNumberStub(MacroAssembler* masm);
- void GenerateNumberStubSub(MacroAssembler* masm);
- void GenerateNumberStubBitNot(MacroAssembler* masm);
- void GenerateHeapNumberCodeSub(MacroAssembler* masm, Label* slow);
- void GenerateHeapNumberCodeBitNot(MacroAssembler* masm, Label* slow);
-
- void GenerateGenericStub(MacroAssembler* masm);
- void GenerateGenericStubSub(MacroAssembler* masm);
- void GenerateGenericStubBitNot(MacroAssembler* masm);
- void GenerateGenericCodeFallback(MacroAssembler* masm);
-
- virtual Code::Kind GetCodeKind() const { return Code::UNARY_OP_IC; }
-
- virtual InlineCacheState GetICState() {
- return UnaryOpIC::ToState(operand_type_);
- }
-
- virtual void FinishCode(Handle<Code> code) {
- code->set_unary_op_type(operand_type_);
- }
-};
-
-
class StringHelper : public AllStatic {
public:
// Generate code for copying characters using a simple loop. This should only
diff --git a/src/ia32/debug-ia32.cc b/src/ia32/debug-ia32.cc
index db1d5a6..68199f9 100644
--- a/src/ia32/debug-ia32.cc
+++ b/src/ia32/debug-ia32.cc
@@ -91,6 +91,7 @@
rinfo()->PatchCode(original_rinfo()->pc(), Assembler::kDebugBreakSlotLength);
}
+
// All debug break stubs support padding for LiveEdit.
const bool Debug::FramePaddingLayout::kIsSupported = true;
diff --git a/src/ia32/disasm-ia32.cc b/src/ia32/disasm-ia32.cc
index 14e5800..c43f11c 100644
--- a/src/ia32/disasm-ia32.cc
+++ b/src/ia32/disasm-ia32.cc
@@ -575,6 +575,7 @@
}
}
+
int DisassemblerIA32::D1D3C1Instruction(byte* data) {
byte op = *data;
ASSERT(op == 0xD1 || op == 0xD3 || op == 0xC1);
diff --git a/src/ia32/full-codegen-ia32.cc b/src/ia32/full-codegen-ia32.cc
index cf3132d..5b14afb 100644
--- a/src/ia32/full-codegen-ia32.cc
+++ b/src/ia32/full-codegen-ia32.cc
@@ -107,6 +107,7 @@
// formal parameter count expected by the function.
//
// The live registers are:
+// o ecx: CallKind
// o edi: the JS function object being called (i.e. ourselves)
// o esi: our context
// o ebp: our caller's frame pointer
@@ -4363,10 +4364,7 @@
void FullCodeGenerator::EmitUnaryOperation(UnaryOperation* expr,
const char* comment) {
Comment cmt(masm_, comment);
- bool can_overwrite = expr->expression()->ResultOverwriteAllowed();
- UnaryOverwriteMode overwrite =
- can_overwrite ? UNARY_OVERWRITE : UNARY_NO_OVERWRITE;
- UnaryOpStub stub(expr->op(), overwrite);
+ UnaryOpStub stub(expr->op());
// UnaryOpStub expects the argument to be in the
// accumulator register eax.
VisitForAccumulatorValue(expr->expression());
diff --git a/src/ia32/lithium-codegen-ia32.cc b/src/ia32/lithium-codegen-ia32.cc
index defae1c..0b56e8f 100644
--- a/src/ia32/lithium-codegen-ia32.cc
+++ b/src/ia32/lithium-codegen-ia32.cc
@@ -2036,6 +2036,16 @@
}
+void LCodeGen::DoNegateNoSSE2D(LNegateNoSSE2D* instr) {
+ __ push(Immediate(-1));
+ __ fild_s(Operand(esp, 0));
+ __ add(esp, Immediate(kPointerSize));
+ __ fmulp();
+ CurrentInstructionReturnsX87Result();
+}
+
+
+
void LCodeGen::DoArithmeticT(LArithmeticT* instr) {
ASSERT(ToRegister(instr->context()).is(esi));
ASSERT(ToRegister(instr->left()).is(edx));
@@ -2058,12 +2068,12 @@
template<class InstrType>
void LCodeGen::EmitBranch(InstrType instr, Condition cc) {
- int right_block = instr->FalseDestination(chunk_);
int left_block = instr->TrueDestination(chunk_);
+ int right_block = instr->FalseDestination(chunk_);
int next_block = GetNextEmittedBlock();
- if (right_block == left_block) {
+ if (right_block == left_block || cc == no_condition) {
EmitGoto(left_block);
} else if (left_block == next_block) {
__ j(NegateCondition(cc), chunk_->GetAssemblyLabel(right_block));
@@ -2076,6 +2086,25 @@
}
+void LCodeGen::DoIsNumberAndBranch(LIsNumberAndBranch* instr) {
+ Representation r = instr->hydrogen()->value()->representation();
+ if (r.IsSmiOrInteger32() || r.IsDouble()) {
+ EmitBranch(instr, no_condition);
+ } else {
+ ASSERT(r.IsTagged());
+ Register reg = ToRegister(instr->value());
+ HType type = instr->hydrogen()->value()->type();
+ if (type.IsTaggedNumber()) {
+ EmitBranch(instr, no_condition);
+ }
+ __ JumpIfSmi(reg, instr->TrueLabel(chunk_));
+ __ cmp(FieldOperand(reg, HeapObject::kMapOffset),
+ factory()->heap_number_map());
+ EmitBranch(instr, equal);
+ }
+}
+
+
void LCodeGen::DoBranch(LBranch* instr) {
Representation r = instr->hydrogen()->value()->representation();
if (r.IsSmiOrInteger32()) {
@@ -2256,7 +2285,7 @@
}
-void LCodeGen::DoCmpIDAndBranch(LCmpIDAndBranch* instr) {
+void LCodeGen::DoCompareNumericAndBranch(LCompareNumericAndBranch* instr) {
LOperand* left = instr->left();
LOperand* right = instr->right();
Condition cc = TokenToCondition(instr->op(), instr->is_double());
@@ -3777,6 +3806,7 @@
}
}
+
void LCodeGen::DoMathRound(LMathRound* instr) {
CpuFeatureScope scope(masm(), SSE2);
Register output_reg = ToRegister(instr->result());
diff --git a/src/ia32/lithium-codegen-ia32.h b/src/ia32/lithium-codegen-ia32.h
index d05da8a..7e66ac2 100644
--- a/src/ia32/lithium-codegen-ia32.h
+++ b/src/ia32/lithium-codegen-ia32.h
@@ -115,6 +115,7 @@
Immediate ToSmiImmediate(LOperand* op) const {
return Immediate(Smi::FromInt(ToInteger32(LConstantOperand::cast(op))));
}
+ double ToDouble(LConstantOperand* op) const;
// Support for non-sse2 (x87) floating point stack handling.
// These functions maintain the depth of the stack (either 0 or 1)
@@ -293,7 +294,6 @@
XMMRegister ToDoubleRegister(int index) const;
int ToInteger32(LConstantOperand* op) const;
- double ToDouble(LConstantOperand* op) const;
Operand BuildFastArrayOperand(LOperand* elements_pointer,
LOperand* key,
Representation key_representation,
diff --git a/src/ia32/lithium-gap-resolver-ia32.cc b/src/ia32/lithium-gap-resolver-ia32.cc
index 86bfe2f..a75ce21 100644
--- a/src/ia32/lithium-gap-resolver-ia32.cc
+++ b/src/ia32/lithium-gap-resolver-ia32.cc
@@ -313,6 +313,31 @@
} else {
__ LoadObject(dst, cgen_->ToHandle(constant_source));
}
+ } else if (destination->IsDoubleRegister()) {
+ double v = cgen_->ToDouble(constant_source);
+ uint64_t int_val = BitCast<uint64_t, double>(v);
+ int32_t lower = static_cast<int32_t>(int_val);
+ int32_t upper = static_cast<int32_t>(int_val >> kBitsPerInt);
+ if (CpuFeatures::IsSupported(SSE2)) {
+ CpuFeatureScope scope(cgen_->masm(), SSE2);
+ XMMRegister dst = cgen_->ToDoubleRegister(destination);
+ if (int_val == 0) {
+ __ xorps(dst, dst);
+ } else {
+ __ push(Immediate(upper));
+ __ push(Immediate(lower));
+ __ movdbl(dst, Operand(esp, 0));
+ __ add(esp, Immediate(kDoubleSize));
+ }
+ } else {
+ __ push(Immediate(upper));
+ __ push(Immediate(lower));
+ if (cgen_->X87StackNonEmpty()) {
+ cgen_->PopX87();
+ }
+ cgen_->PushX87DoubleOperand(MemOperand(esp, 0));
+ __ add(esp, Immediate(kDoubleSize));
+ }
} else {
ASSERT(destination->IsStackSlot());
Operand dst = cgen_->ToOperand(destination);
diff --git a/src/ia32/lithium-ia32.cc b/src/ia32/lithium-ia32.cc
index 8231c4e..1934e0a 100644
--- a/src/ia32/lithium-ia32.cc
+++ b/src/ia32/lithium-ia32.cc
@@ -201,7 +201,7 @@
}
-void LCmpIDAndBranch::PrintDataTo(StringStream* stream) {
+void LCompareNumericAndBranch::PrintDataTo(StringStream* stream) {
stream->Add("if ");
left()->PrintTo(stream);
stream->Add(" %s ", Token::String(op()));
@@ -1578,7 +1578,17 @@
}
return DefineSameAsFirst(mul);
} else if (instr->representation().IsDouble()) {
- return DoArithmeticD(Token::MUL, instr);
+ if (CpuFeatures::IsSafeForSnapshot(SSE2)) {
+ return DoArithmeticD(Token::MUL, instr);
+ }
+ ASSERT(instr->right()->IsConstant() &&
+ static_cast<HConstant*>(instr->right())->DoubleValue() == -1);
+ // TODO(olivf) This is currently just a hack to support the UnaryOp Minus
+ // Stub. This will go away once we can use more than one X87 register,
+ // thus fully support binary instructions without SSE2.
+ LOperand* left = UseX87TopOfStack(instr->left());
+ LNegateNoSSE2D* result = new(zone()) LNegateNoSSE2D(left);
+ return DefineX87TOS(result);
} else {
ASSERT(instr->representation().IsSmiOrTagged());
return DoArithmeticT(Token::MUL, instr);
@@ -1695,8 +1705,8 @@
}
-LInstruction* LChunkBuilder::DoCompareIDAndBranch(
- HCompareIDAndBranch* instr) {
+LInstruction* LChunkBuilder::DoCompareNumericAndBranch(
+ HCompareNumericAndBranch* instr) {
Representation r = instr->representation();
if (r.IsSmiOrInteger32()) {
ASSERT(instr->left()->representation().IsSmiOrInteger32());
@@ -1704,7 +1714,7 @@
instr->right()->representation()));
LOperand* left = UseRegisterOrConstantAtStart(instr->left());
LOperand* right = UseOrConstantAtStart(instr->right());
- return new(zone()) LCmpIDAndBranch(left, right);
+ return new(zone()) LCompareNumericAndBranch(left, right);
} else {
ASSERT(r.IsDouble());
ASSERT(instr->left()->representation().IsDouble());
@@ -1718,7 +1728,7 @@
left = UseRegisterAtStart(instr->left());
right = UseRegisterAtStart(instr->right());
}
- return new(zone()) LCmpIDAndBranch(left, right);
+ return new(zone()) LCompareNumericAndBranch(left, right);
}
}
@@ -2038,6 +2048,18 @@
}
+LInstruction* LChunkBuilder::DoCheckSmi(HCheckSmi* instr) {
+ LOperand* value = UseRegisterAtStart(instr->value());
+ return AssignEnvironment(new(zone()) LCheckSmi(value));
+}
+
+
+LInstruction* LChunkBuilder::DoIsNumberAndBranch(HIsNumberAndBranch* instr) {
+ return new(zone())
+ LIsNumberAndBranch(UseRegisterOrConstantAtStart(instr->value()));
+}
+
+
LInstruction* LChunkBuilder::DoCheckInstanceType(HCheckInstanceType* instr) {
LOperand* value = UseRegisterAtStart(instr->value());
LOperand* temp = TempRegister();
diff --git a/src/ia32/lithium-ia32.h b/src/ia32/lithium-ia32.h
index e48e881..7b332d2 100644
--- a/src/ia32/lithium-ia32.h
+++ b/src/ia32/lithium-ia32.h
@@ -75,7 +75,7 @@
V(ClampTToUint8) \
V(ClampTToUint8NoSSE2) \
V(ClassOfTestAndBranch) \
- V(CmpIDAndBranch) \
+ V(CompareNumericAndBranch) \
V(CmpObjectEqAndBranch) \
V(CmpMapAndBranch) \
V(CmpT) \
@@ -114,6 +114,7 @@
V(IsObjectAndBranch) \
V(IsStringAndBranch) \
V(IsSmiAndBranch) \
+ V(IsNumberAndBranch) \
V(IsUndetectableAndBranch) \
V(Label) \
V(LazyBailout) \
@@ -142,6 +143,7 @@
V(MathTan) \
V(ModI) \
V(MulI) \
+ V(NegateNoSSE2D) \
V(NumberTagD) \
V(NumberTagI) \
V(NumberTagU) \
@@ -659,6 +661,18 @@
};
+class LNegateNoSSE2D: public LTemplateInstruction<1, 1, 0> {
+ public:
+ explicit LNegateNoSSE2D(LOperand* value) {
+ inputs_[0] = value;
+ }
+
+ LOperand* value() { return inputs_[0]; }
+
+ DECLARE_CONCRETE_INSTRUCTION(NegateNoSSE2D, "negate-no-sse2-d")
+};
+
+
class LMulI: public LTemplateInstruction<1, 2, 1> {
public:
LMulI(LOperand* left, LOperand* right, LOperand* temp) {
@@ -676,9 +690,9 @@
};
-class LCmpIDAndBranch: public LControlInstruction<2, 0> {
+class LCompareNumericAndBranch: public LControlInstruction<2, 0> {
public:
- LCmpIDAndBranch(LOperand* left, LOperand* right) {
+ LCompareNumericAndBranch(LOperand* left, LOperand* right) {
inputs_[0] = left;
inputs_[1] = right;
}
@@ -686,8 +700,9 @@
LOperand* left() { return inputs_[0]; }
LOperand* right() { return inputs_[1]; }
- DECLARE_CONCRETE_INSTRUCTION(CmpIDAndBranch, "cmp-id-and-branch")
- DECLARE_HYDROGEN_ACCESSOR(CompareIDAndBranch)
+ DECLARE_CONCRETE_INSTRUCTION(CompareNumericAndBranch,
+ "compare-numeric-and-branch")
+ DECLARE_HYDROGEN_ACCESSOR(CompareNumericAndBranch)
Token::Value op() const { return hydrogen()->token(); }
bool is_double() const {
@@ -883,6 +898,19 @@
};
+class LIsNumberAndBranch: public LControlInstruction<1, 0> {
+ public:
+ explicit LIsNumberAndBranch(LOperand* value) {
+ inputs_[0] = value;
+ }
+
+ LOperand* value() { return inputs_[0]; }
+
+ DECLARE_CONCRETE_INSTRUCTION(IsNumberAndBranch, "is-number-and-branch")
+ DECLARE_HYDROGEN_ACCESSOR(IsNumberAndBranch)
+};
+
+
class LIsStringAndBranch: public LControlInstruction<1, 1> {
public:
LIsStringAndBranch(LOperand* value, LOperand* temp) {
diff --git a/src/ia32/macro-assembler-ia32.cc b/src/ia32/macro-assembler-ia32.cc
index a9a0268..989b83e 100644
--- a/src/ia32/macro-assembler-ia32.cc
+++ b/src/ia32/macro-assembler-ia32.cc
@@ -842,6 +842,7 @@
LeaveExitFrameEpilogue();
}
+
void MacroAssembler::LeaveExitFrameEpilogue() {
// Restore current context from top and clear it in debug mode.
ExternalReference context_address(Isolate::kContextAddress, isolate());
diff --git a/src/ia32/regexp-macro-assembler-ia32.cc b/src/ia32/regexp-macro-assembler-ia32.cc
index f478e57..dfcc869 100644
--- a/src/ia32/regexp-macro-assembler-ia32.cc
+++ b/src/ia32/regexp-macro-assembler-ia32.cc
@@ -1030,6 +1030,7 @@
__ bind(&after_position);
}
+
void RegExpMacroAssemblerIA32::SetRegister(int register_index, int to) {
ASSERT(register_index >= num_saved_registers_); // Reserved for positions!
__ mov(register_location(register_index), Immediate(to));
diff --git a/src/ic.cc b/src/ic.cc
index ff3a94d..02f2f0f 100644
--- a/src/ic.cc
+++ b/src/ic.cc
@@ -1668,7 +1668,7 @@
ASSERT(!lookup->IsHandler());
Handle<Code> code = ComputeStoreMonomorphic(
- lookup, strict_mode, receiver, name);
+ lookup, strict_mode, receiver, name, value);
if (code.is_null()) {
Handle<Code> stub = strict_mode == kStrictMode
? generic_stub_strict() : generic_stub();
@@ -1684,7 +1684,8 @@
Handle<Code> StoreIC::ComputeStoreMonomorphic(LookupResult* lookup,
StrictModeFlag strict_mode,
Handle<JSObject> receiver,
- Handle<String> name) {
+ Handle<String> name,
+ Handle<Object> value) {
Handle<JSObject> holder(lookup->holder());
switch (lookup->type()) {
case FIELD:
@@ -1699,7 +1700,7 @@
Handle<PropertyCell> cell(
global->GetPropertyCell(lookup), isolate());
return isolate()->stub_cache()->ComputeStoreGlobal(
- name, global, cell, strict_mode);
+ name, global, cell, value, strict_mode);
}
ASSERT(holder.is_identical_to(receiver));
return isolate()->stub_cache()->ComputeStoreNormal(strict_mode);
@@ -2093,7 +2094,8 @@
Handle<Code> KeyedStoreIC::ComputeStoreMonomorphic(LookupResult* lookup,
StrictModeFlag strict_mode,
Handle<JSObject> receiver,
- Handle<String> name) {
+ Handle<String> name,
+ Handle<Object> value) {
// If the property has a non-field type allowing map transitions
// where there is extra room in the object, we leave the IC in its
// current state.
@@ -2245,6 +2247,20 @@
}
+RUNTIME_FUNCTION(MaybeObject*, StoreIC_MissFromStubFailure) {
+ HandleScope scope(isolate);
+ ASSERT(args.length() == 3);
+ StoreIC ic(IC::EXTRA_CALL_FRAME, isolate);
+ IC::State state = IC::StateFrom(ic.target(), args[0], args[1]);
+ Code::ExtraICState extra_ic_state = ic.target()->extra_ic_state();
+ return ic.Store(state,
+ Code::GetStrictMode(extra_ic_state),
+ args.at<Object>(0),
+ args.at<String>(1),
+ args.at<Object>(2));
+}
+
+
RUNTIME_FUNCTION(MaybeObject*, StoreIC_ArrayLength) {
SealHandleScope shs(isolate);
@@ -2401,86 +2417,6 @@
}
-void UnaryOpIC::patch(Code* code) {
- set_target(code);
-}
-
-
-const char* UnaryOpIC::GetName(TypeInfo type_info) {
- switch (type_info) {
- case UNINITIALIZED: return "Uninitialized";
- case SMI: return "Smi";
- case NUMBER: return "Number";
- case GENERIC: return "Generic";
- default: return "Invalid";
- }
-}
-
-
-UnaryOpIC::State UnaryOpIC::ToState(TypeInfo type_info) {
- switch (type_info) {
- case UNINITIALIZED:
- return v8::internal::UNINITIALIZED;
- case SMI:
- case NUMBER:
- return MONOMORPHIC;
- case GENERIC:
- return v8::internal::GENERIC;
- }
- UNREACHABLE();
- return v8::internal::UNINITIALIZED;
-}
-
-
-Handle<Type> UnaryOpIC::TypeInfoToType(TypeInfo type_info, Isolate* isolate) {
- switch (type_info) {
- case UNINITIALIZED:
- return handle(Type::None(), isolate);
- case SMI:
- return handle(Type::Smi(), isolate);
- case NUMBER:
- return handle(Type::Number(), isolate);
- case GENERIC:
- return handle(Type::Any(), isolate);
- }
- UNREACHABLE();
- return handle(Type::Any(), isolate);
-}
-
-
-UnaryOpIC::TypeInfo UnaryOpIC::GetTypeInfo(Handle<Object> operand) {
- v8::internal::TypeInfo operand_type =
- v8::internal::TypeInfo::FromValue(operand);
- if (operand_type.IsSmi()) {
- return SMI;
- } else if (operand_type.IsNumber()) {
- return NUMBER;
- } else {
- return GENERIC;
- }
-}
-
-
-UnaryOpIC::TypeInfo UnaryOpIC::ComputeNewType(
- TypeInfo current_type,
- TypeInfo previous_type) {
- switch (previous_type) {
- case UNINITIALIZED:
- return current_type;
- case SMI:
- return (current_type == GENERIC) ? GENERIC : NUMBER;
- case NUMBER:
- return GENERIC;
- case GENERIC:
- // We should never do patching if we are in GENERIC state.
- UNREACHABLE();
- return GENERIC;
- }
- UNREACHABLE();
- return GENERIC;
-}
-
-
void BinaryOpIC::patch(Code* code) {
set_target(code);
}
@@ -2558,57 +2494,24 @@
}
-RUNTIME_FUNCTION(MaybeObject*, UnaryOp_Patch) {
- ASSERT(args.length() == 4);
+MaybeObject* UnaryOpIC::Transition(Handle<Object> object) {
+ Code::ExtraICState extra_ic_state = target()->extended_extra_ic_state();
+ UnaryOpStub stub(extra_ic_state);
+ stub.UpdateStatus(object);
+
+ Handle<Code> code = stub.GetCode(isolate());
+ set_target(*code);
+
+ return stub.Result(object, isolate());
+}
+
+
+RUNTIME_FUNCTION(MaybeObject*, UnaryOpIC_Miss) {
HandleScope scope(isolate);
- Handle<Object> operand = args.at<Object>(0);
- Token::Value op = static_cast<Token::Value>(args.smi_at(1));
- UnaryOverwriteMode mode = static_cast<UnaryOverwriteMode>(args.smi_at(2));
- UnaryOpIC::TypeInfo previous_type =
- static_cast<UnaryOpIC::TypeInfo>(args.smi_at(3));
-
- UnaryOpIC::TypeInfo type = UnaryOpIC::GetTypeInfo(operand);
- type = UnaryOpIC::ComputeNewType(type, previous_type);
-
- UnaryOpStub stub(op, mode, type);
- Handle<Code> code = stub.GetCode(isolate);
- if (!code.is_null()) {
- if (FLAG_trace_ic) {
- PrintF("[UnaryOpIC in ");
- JavaScriptFrame::PrintTop(isolate, stdout, false, true);
- PrintF(" %s => %s #%s @ %p]\n",
- UnaryOpIC::GetName(previous_type),
- UnaryOpIC::GetName(type),
- Token::Name(op),
- static_cast<void*>(*code));
- }
- UnaryOpIC ic(isolate);
- ic.patch(*code);
- }
-
- Handle<JSBuiltinsObject> builtins(isolate->js_builtins_object());
- Object* builtin = NULL; // Initialization calms down the compiler.
- switch (op) {
- case Token::SUB:
- builtin = builtins->javascript_builtin(Builtins::UNARY_MINUS);
- break;
- case Token::BIT_NOT:
- builtin = builtins->javascript_builtin(Builtins::BIT_NOT);
- break;
- default:
- UNREACHABLE();
- }
-
- Handle<JSFunction> builtin_function(JSFunction::cast(builtin), isolate);
-
- bool caught_exception;
- Handle<Object> result = Execution::Call(builtin_function, operand, 0, NULL,
- &caught_exception);
- if (caught_exception) {
- return Failure::Exception();
- }
- return *result;
+ Handle<Object> object = args.at<Object>(0);
+ UnaryOpIC ic(isolate);
+ return ic.Transition(object);
}
@@ -3069,9 +2972,7 @@
// types must be supported as a result of the miss.
bool already_monomorphic = stub.IsMonomorphic();
- CompareNilICStub::State old_state = stub.GetState();
- stub.Record(object);
- old_state.TraceTransition(stub.GetState());
+ stub.UpdateStatus(object);
NilValue nil = stub.GetNilValue();
@@ -3108,7 +3009,7 @@
MaybeObject* ToBooleanIC::ToBoolean(Handle<Object> object,
Code::ExtraICState extra_ic_state) {
ToBooleanStub stub(extra_ic_state);
- bool to_boolean_value = stub.Record(object);
+ bool to_boolean_value = stub.UpdateStatus(object);
Handle<Code> code = stub.GetCode(isolate());
set_target(*code);
return Smi::FromInt(to_boolean_value ? 1 : 0);
diff --git a/src/ic.h b/src/ic.h
index 829c6b1..61bf848 100644
--- a/src/ic.h
+++ b/src/ic.h
@@ -57,7 +57,6 @@
ICU(LoadPropertyWithInterceptorForCall) \
ICU(KeyedLoadPropertyWithInterceptor) \
ICU(StoreInterceptorProperty) \
- ICU(UnaryOp_Patch) \
ICU(BinaryOp_Patch) \
ICU(CompareIC_Miss) \
ICU(CompareNilIC_Miss) \
@@ -560,7 +559,8 @@
virtual Handle<Code> ComputeStoreMonomorphic(LookupResult* lookup,
StrictModeFlag strict_mode,
Handle<JSObject> receiver,
- Handle<String> name);
+ Handle<String> name,
+ Handle<Object> value);
private:
void set_target(Code* code) {
@@ -627,7 +627,8 @@
virtual Handle<Code> ComputeStoreMonomorphic(LookupResult* lookup,
StrictModeFlag strict_mode,
Handle<JSObject> receiver,
- Handle<String> name);
+ Handle<String> name,
+ Handle<Object> value);
virtual void UpdateMegamorphicCache(Map* map, Name* name, Code* code) { }
virtual Handle<Code> megamorphic_stub() {
@@ -681,28 +682,9 @@
class UnaryOpIC: public IC {
public:
- // sorted: increasingly more unspecific (ignoring UNINITIALIZED)
- // TODO(svenpanne) Using enums+switch is an antipattern, use a class instead.
- enum TypeInfo {
- UNINITIALIZED,
- SMI,
- NUMBER,
- GENERIC
- };
+ explicit UnaryOpIC(Isolate* isolate) : IC(EXTRA_CALL_FRAME, isolate) { }
- static Handle<Type> TypeInfoToType(TypeInfo info, Isolate* isolate);
-
- explicit UnaryOpIC(Isolate* isolate) : IC(NO_EXTRA_FRAME, isolate) { }
-
- void patch(Code* code);
-
- static const char* GetName(TypeInfo type_info);
-
- static State ToState(TypeInfo type_info);
-
- static TypeInfo GetTypeInfo(Handle<Object> operand);
-
- static TypeInfo ComputeNewType(TypeInfo type, TypeInfo previous);
+ MUST_USE_RESULT MaybeObject* Transition(Handle<Object> object);
};
@@ -838,6 +820,8 @@
DECLARE_RUNTIME_FUNCTION(MaybeObject*, KeyedLoadIC_MissFromStubFailure);
DECLARE_RUNTIME_FUNCTION(MaybeObject*, KeyedStoreIC_MissFromStubFailure);
+DECLARE_RUNTIME_FUNCTION(MaybeObject*, UnaryOpIC_Miss);
+DECLARE_RUNTIME_FUNCTION(MaybeObject*, StoreIC_MissFromStubFailure);
DECLARE_RUNTIME_FUNCTION(MaybeObject*, CompareNilIC_Miss);
DECLARE_RUNTIME_FUNCTION(MaybeObject*, ToBooleanIC_Miss);
diff --git a/src/incremental-marking.cc b/src/incremental-marking.cc
index 80dc8ea..17e79fd 100644
--- a/src/incremental-marking.cc
+++ b/src/incremental-marking.cc
@@ -563,6 +563,7 @@
}
}
+
void IncrementalMarking::UncommitMarkingDeque() {
if (state_ == STOPPED && marking_deque_memory_committed_) {
bool success = marking_deque_memory_->Uncommit(
diff --git a/src/isolate.cc b/src/isolate.cc
index 6a87580..cf0f3b3 100644
--- a/src/isolate.cc
+++ b/src/isolate.cc
@@ -509,6 +509,7 @@
Iterate(v, current_t);
}
+
void Isolate::IterateDeferredHandles(ObjectVisitor* visitor) {
for (DeferredHandles* deferred = deferred_handles_head_;
deferred != NULL;
@@ -1876,6 +1877,10 @@
if (state_ == INITIALIZED) {
TRACE_ISOLATE(deinit);
+#ifdef ENABLE_DEBUGGER_SUPPORT
+ debugger()->UnloadDebugger();
+#endif
+
if (FLAG_parallel_recompilation) optimizing_compiler_thread_.Stop();
if (FLAG_sweeper_threads > 0) {
diff --git a/src/lithium.cc b/src/lithium.cc
index b22fdf6..3df8d6c 100644
--- a/src/lithium.cc
+++ b/src/lithium.cc
@@ -306,6 +306,7 @@
return label->label();
}
+
void LChunk::MarkEmptyBlocks() {
LPhase phase("L_Mark empty blocks", this);
for (int i = 0; i < graph()->blocks()->length(); ++i) {
diff --git a/src/liveedit.cc b/src/liveedit.cc
index 3ec2da3..95f0b00 100644
--- a/src/liveedit.cc
+++ b/src/liveedit.cc
@@ -61,6 +61,7 @@
USE(no_failure);
}
+
// A simple implementation of dynamic programming algorithm. It solves
// the problem of finding the difference of 2 arrays. It uses a table of results
// of subproblems. Each cell contains a number together with 2-bit flag
@@ -1456,6 +1457,7 @@
static const int kMaximalBufferSize = 512*MB;
};
+
// Patch positions in code (changes relocation info section) and possibly
// returns new instance of code.
static Handle<Code> PatchPositionsInCode(
@@ -1829,6 +1831,7 @@
Handle<JSArray> m_result;
};
+
// Drops all call frame matched by target and all frames above them.
template<typename TARGET>
static const char* DropActivationsInActiveThreadImpl(
@@ -1925,6 +1928,7 @@
return NULL;
}
+
// Fills result array with statuses of functions. Modifies the stack
// removing all listed function if possible and if do_drop is true.
static const char* DropActivationsInActiveThread(
diff --git a/src/log.cc b/src/log.cc
index e95b963..a44add6 100644
--- a/src/log.cc
+++ b/src/log.cc
@@ -491,6 +491,7 @@
code_event_handler_(&event);
}
+
void* Logger::IssueStartCodePosInfoEvent() {
JitCodeEvent event;
memset(&event, 0, sizeof(event));
@@ -500,6 +501,7 @@
return event.user_data;
}
+
void Logger::IssueEndCodePosInfoEvent(Code* code, void* jit_handler_data) {
JitCodeEvent event;
memset(&event, 0, sizeof(event));
@@ -828,6 +830,7 @@
ApiEvent("api,%s,\"%s\",%u\n", tag, *class_name, index);
}
+
void Logger::ApiObjectAccess(const char* tag, JSObject* object) {
if (!log_->IsEnabled() || !FLAG_log_api) return;
String* class_name_obj = object->class_name();
@@ -1206,6 +1209,7 @@
}
}
+
void Logger::CodeStartLinePosInfoRecordEvent(PositionsRecorder* pos_recorder) {
if (code_event_handler_ != NULL) {
pos_recorder->AttachJITHandlerData(IssueStartCodePosInfoEvent());
@@ -1219,6 +1223,7 @@
}
}
+
void Logger::SnapshotPositionEvent(Address addr, int pos) {
if (!log_->IsEnabled()) return;
if (FLAG_ll_prof) LowLevelSnapshotPositionEvent(addr, pos);
@@ -1654,15 +1659,15 @@
Handle<String> func_name(shared->DebugName());
if (shared->script()->IsScript()) {
Handle<Script> script(Script::cast(shared->script()));
+ int line_num = GetScriptLineNumber(script, shared->start_position()) + 1;
if (script->name()->IsString()) {
Handle<String> script_name(String::cast(script->name()));
- int line_num = GetScriptLineNumber(script, shared->start_position());
if (line_num > 0) {
PROFILE(isolate_,
CodeCreateEvent(
Logger::ToNativeByScript(Logger::LAZY_COMPILE_TAG, *script),
*code, *shared, NULL,
- *script_name, line_num + 1));
+ *script_name, line_num));
} else {
// Can't distinguish eval and script here, so always use Script.
PROFILE(isolate_,
@@ -1674,7 +1679,8 @@
PROFILE(isolate_,
CodeCreateEvent(
Logger::ToNativeByScript(Logger::LAZY_COMPILE_TAG, *script),
- *code, *shared, NULL, *func_name));
+ *code, *shared, NULL,
+ isolate_->heap()->empty_string(), line_num));
}
} else if (shared->IsApiFunction()) {
// API function.
diff --git a/src/macros.py b/src/macros.py
index e442b44..5174d5f 100644
--- a/src/macros.py
+++ b/src/macros.py
@@ -145,6 +145,7 @@
macro NUMBER_IS_NAN(arg) = (!%_IsSmi(%IS_VAR(arg)) && !(arg == arg));
macro NUMBER_IS_FINITE(arg) = (%_IsSmi(%IS_VAR(arg)) || ((arg == arg) && (arg != 1/0) && (arg != -1/0)));
macro TO_INTEGER(arg) = (%_IsSmi(%IS_VAR(arg)) ? arg : %NumberToInteger(ToNumber(arg)));
+macro TO_INTEGER_FOR_SIDE_EFFECT(arg) = (%_IsSmi(%IS_VAR(arg)) ? arg : ToNumber(arg));
macro TO_INTEGER_MAP_MINUS_ZERO(arg) = (%_IsSmi(%IS_VAR(arg)) ? arg : %NumberToIntegerMapMinusZero(ToNumber(arg)));
macro TO_INT32(arg) = (%_IsSmi(%IS_VAR(arg)) ? arg : (arg >> 0));
macro TO_UINT32(arg) = (arg >>> 0);
diff --git a/src/messages.js b/src/messages.js
index 137d98f..6c9e2d7 100644
--- a/src/messages.js
+++ b/src/messages.js
@@ -73,7 +73,7 @@
invalid_in_operator_use: ["Cannot use 'in' operator to search for '", "%0", "' in ", "%1"],
instanceof_function_expected: ["Expecting a function in instanceof check, but got ", "%0"],
instanceof_nonobject_proto: ["Function has non-object prototype '", "%0", "' in instanceof check"],
- null_to_object: ["Cannot convert null to object"],
+ undefined_or_null_to_object: ["Cannot convert undefined or null to object"],
reduce_no_initial: ["Reduce of empty array with no initial value"],
getter_must_be_callable: ["Getter must be a function: ", "%0"],
setter_must_be_callable: ["Setter must be a function: ", "%0"],
diff --git a/src/mips/assembler-mips.cc b/src/mips/assembler-mips.cc
index c4fefcc..a04d456 100644
--- a/src/mips/assembler-mips.cc
+++ b/src/mips/assembler-mips.cc
@@ -501,11 +501,13 @@
(opcode == COP1 && rs_field == BC1); // Coprocessor branch.
}
+
bool Assembler::IsEmittedConstant(Instr instr) {
uint32_t label_constant = GetLabelConst(instr);
return label_constant == 0; // Emitted label const in reg-exp engine.
}
+
bool Assembler::IsBeq(Instr instr) {
return GetOpcodeField(instr) == BEQ;
}
@@ -539,10 +541,12 @@
return GetOpcodeField(instr) == JAL;
}
+
bool Assembler::IsJr(Instr instr) {
return GetOpcodeField(instr) == SPECIAL && GetFunctionField(instr) == JR;
}
+
bool Assembler::IsJalr(Instr instr) {
return GetOpcodeField(instr) == SPECIAL && GetFunctionField(instr) == JALR;
}
@@ -825,6 +829,7 @@
}
}
+
bool Assembler::is_near(Label* L) {
if (L->is_bound()) {
return ((pc_offset() - L->pos()) < kMaxBranchOffset - 4 * kInstrSize);
@@ -832,6 +837,7 @@
return false;
}
+
// We have to use a temporary register for things that can be relocated even
// if they can be encoded in the MIPS's 16 bits of immediate-offset instruction
// space. There is no guarantee that the relocated location can be similarly
@@ -1669,6 +1675,7 @@
GenInstrRegister(COP1, CFC1, rt, fs);
}
+
void Assembler::DoubleAsTwoUInt32(double d, uint32_t* lo, uint32_t* hi) {
uint64_t i;
OS::MemCopy(&i, &d, 8);
@@ -1677,6 +1684,7 @@
*hi = i >> 32;
}
+
// Arithmetic.
void Assembler::add_d(FPURegister fd, FPURegister fs, FPURegister ft) {
@@ -2257,6 +2265,7 @@
CPU::FlushICache(pc, (patched_jump ? 3 : 2) * sizeof(int32_t));
}
+
void Assembler::JumpLabelToJumpRegister(Address pc) {
// Address pc points to lui/ori instructions.
// Jump to label may follow at pc + 2 * kInstrSize.
diff --git a/src/mips/builtins-mips.cc b/src/mips/builtins-mips.cc
old mode 100755
new mode 100644
diff --git a/src/mips/code-stubs-mips.cc b/src/mips/code-stubs-mips.cc
index 69b957a..727dee5 100644
--- a/src/mips/code-stubs-mips.cc
+++ b/src/mips/code-stubs-mips.cc
@@ -227,8 +227,31 @@
}
+void UnaryOpStub::InitializeInterfaceDescriptor(
+ Isolate* isolate,
+ CodeStubInterfaceDescriptor* descriptor) {
+ static Register registers[] = { a0 };
+ descriptor->register_param_count_ = 1;
+ descriptor->register_params_ = registers;
+ descriptor->deoptimization_handler_ =
+ FUNCTION_ADDR(UnaryOpIC_Miss);
+}
+
+
+void StoreGlobalStub::InitializeInterfaceDescriptor(
+ Isolate* isolate,
+ CodeStubInterfaceDescriptor* descriptor) {
+ static Register registers[] = { a1, a2, a0 };
+ descriptor->register_param_count_ = 3;
+ descriptor->register_params_ = registers;
+ descriptor->deoptimization_handler_ =
+ FUNCTION_ADDR(StoreIC_MissFromStubFailure);
+}
+
+
#define __ ACCESS_MASM(masm)
+
static void EmitIdenticalObjectComparison(MacroAssembler* masm,
Label* slow,
Condition cc);
@@ -1586,294 +1609,6 @@
}
-void UnaryOpStub::PrintName(StringStream* stream) {
- const char* op_name = Token::Name(op_);
- const char* overwrite_name = NULL; // Make g++ happy.
- switch (mode_) {
- case UNARY_NO_OVERWRITE: overwrite_name = "Alloc"; break;
- case UNARY_OVERWRITE: overwrite_name = "Overwrite"; break;
- }
- stream->Add("UnaryOpStub_%s_%s_%s",
- op_name,
- overwrite_name,
- UnaryOpIC::GetName(operand_type_));
-}
-
-
-// TODO(svenpanne): Use virtual functions instead of switch.
-void UnaryOpStub::Generate(MacroAssembler* masm) {
- switch (operand_type_) {
- case UnaryOpIC::UNINITIALIZED:
- GenerateTypeTransition(masm);
- break;
- case UnaryOpIC::SMI:
- GenerateSmiStub(masm);
- break;
- case UnaryOpIC::NUMBER:
- GenerateNumberStub(masm);
- break;
- case UnaryOpIC::GENERIC:
- GenerateGenericStub(masm);
- break;
- }
-}
-
-
-void UnaryOpStub::GenerateTypeTransition(MacroAssembler* masm) {
- // Argument is in a0 and v0 at this point, so we can overwrite a0.
- __ li(a2, Operand(Smi::FromInt(op_)));
- __ li(a1, Operand(Smi::FromInt(mode_)));
- __ li(a0, Operand(Smi::FromInt(operand_type_)));
- __ Push(v0, a2, a1, a0);
-
- __ TailCallExternalReference(
- ExternalReference(IC_Utility(IC::kUnaryOp_Patch), masm->isolate()), 4, 1);
-}
-
-
-// TODO(svenpanne): Use virtual functions instead of switch.
-void UnaryOpStub::GenerateSmiStub(MacroAssembler* masm) {
- switch (op_) {
- case Token::SUB:
- GenerateSmiStubSub(masm);
- break;
- case Token::BIT_NOT:
- GenerateSmiStubBitNot(masm);
- break;
- default:
- UNREACHABLE();
- }
-}
-
-
-void UnaryOpStub::GenerateSmiStubSub(MacroAssembler* masm) {
- Label non_smi, slow;
- GenerateSmiCodeSub(masm, &non_smi, &slow);
- __ bind(&non_smi);
- __ bind(&slow);
- GenerateTypeTransition(masm);
-}
-
-
-void UnaryOpStub::GenerateSmiStubBitNot(MacroAssembler* masm) {
- Label non_smi;
- GenerateSmiCodeBitNot(masm, &non_smi);
- __ bind(&non_smi);
- GenerateTypeTransition(masm);
-}
-
-
-void UnaryOpStub::GenerateSmiCodeSub(MacroAssembler* masm,
- Label* non_smi,
- Label* slow) {
- __ JumpIfNotSmi(a0, non_smi);
-
- // The result of negating zero or the smallest negative smi is not a smi.
- __ And(t0, a0, ~0x80000000);
- __ Branch(slow, eq, t0, Operand(zero_reg));
-
- // Return '0 - value'.
- __ Ret(USE_DELAY_SLOT);
- __ subu(v0, zero_reg, a0);
-}
-
-
-void UnaryOpStub::GenerateSmiCodeBitNot(MacroAssembler* masm,
- Label* non_smi) {
- __ JumpIfNotSmi(a0, non_smi);
-
- // Flip bits and revert inverted smi-tag.
- __ Neg(v0, a0);
- __ And(v0, v0, ~kSmiTagMask);
- __ Ret();
-}
-
-
-// TODO(svenpanne): Use virtual functions instead of switch.
-void UnaryOpStub::GenerateNumberStub(MacroAssembler* masm) {
- switch (op_) {
- case Token::SUB:
- GenerateNumberStubSub(masm);
- break;
- case Token::BIT_NOT:
- GenerateNumberStubBitNot(masm);
- break;
- default:
- UNREACHABLE();
- }
-}
-
-
-void UnaryOpStub::GenerateNumberStubSub(MacroAssembler* masm) {
- Label non_smi, slow, call_builtin;
- GenerateSmiCodeSub(masm, &non_smi, &call_builtin);
- __ bind(&non_smi);
- GenerateHeapNumberCodeSub(masm, &slow);
- __ bind(&slow);
- GenerateTypeTransition(masm);
- __ bind(&call_builtin);
- GenerateGenericCodeFallback(masm);
-}
-
-
-void UnaryOpStub::GenerateNumberStubBitNot(MacroAssembler* masm) {
- Label non_smi, slow;
- GenerateSmiCodeBitNot(masm, &non_smi);
- __ bind(&non_smi);
- GenerateHeapNumberCodeBitNot(masm, &slow);
- __ bind(&slow);
- GenerateTypeTransition(masm);
-}
-
-
-void UnaryOpStub::GenerateHeapNumberCodeSub(MacroAssembler* masm,
- Label* slow) {
- EmitCheckForHeapNumber(masm, a0, a1, t2, slow);
- // a0 is a heap number. Get a new heap number in a1.
- if (mode_ == UNARY_OVERWRITE) {
- __ lw(a2, FieldMemOperand(a0, HeapNumber::kExponentOffset));
- __ Xor(a2, a2, Operand(HeapNumber::kSignMask)); // Flip sign.
- __ Ret(USE_DELAY_SLOT);
- __ sw(a2, FieldMemOperand(a0, HeapNumber::kExponentOffset));
- } else {
- Label slow_allocate_heapnumber, heapnumber_allocated;
- __ AllocateHeapNumber(a1, a2, a3, t2, &slow_allocate_heapnumber);
- __ jmp(&heapnumber_allocated);
-
- __ bind(&slow_allocate_heapnumber);
- {
- FrameScope scope(masm, StackFrame::INTERNAL);
- __ push(a0);
- __ CallRuntime(Runtime::kNumberAlloc, 0);
- __ mov(a1, v0);
- __ pop(a0);
- }
-
- __ bind(&heapnumber_allocated);
- __ lw(a3, FieldMemOperand(a0, HeapNumber::kMantissaOffset));
- __ lw(a2, FieldMemOperand(a0, HeapNumber::kExponentOffset));
- __ sw(a3, FieldMemOperand(a1, HeapNumber::kMantissaOffset));
- __ Xor(a2, a2, Operand(HeapNumber::kSignMask)); // Flip sign.
- __ sw(a2, FieldMemOperand(a1, HeapNumber::kExponentOffset));
- __ Ret(USE_DELAY_SLOT);
- __ mov(v0, a1);
- }
-}
-
-
-void UnaryOpStub::GenerateHeapNumberCodeBitNot(
- MacroAssembler* masm,
- Label* slow) {
- Label impossible;
-
- EmitCheckForHeapNumber(masm, a0, a1, t2, slow);
- // Convert the heap number in a0 to an untagged integer in a1.
- __ ConvertToInt32(a0, a1, a2, a3, f0, slow);
-
- // Do the bitwise operation and check if the result fits in a smi.
- Label try_float;
- __ Neg(a1, a1);
- __ Addu(a2, a1, Operand(0x40000000));
- __ Branch(&try_float, lt, a2, Operand(zero_reg));
-
- // Tag the result as a smi and we're done.
- __ Ret(USE_DELAY_SLOT); // SmiTag emits one instruction in delay slot.
- __ SmiTag(v0, a1);
-
- // Try to store the result in a heap number.
- __ bind(&try_float);
- if (mode_ == UNARY_NO_OVERWRITE) {
- Label slow_allocate_heapnumber, heapnumber_allocated;
- // Allocate a new heap number without zapping v0, which we need if it fails.
- __ AllocateHeapNumber(a2, a3, t0, t2, &slow_allocate_heapnumber);
- __ jmp(&heapnumber_allocated);
-
- __ bind(&slow_allocate_heapnumber);
- {
- FrameScope scope(masm, StackFrame::INTERNAL);
- __ push(v0); // Push the heap number, not the untagged int32.
- __ CallRuntime(Runtime::kNumberAlloc, 0);
- __ mov(a2, v0); // Move the new heap number into a2.
- // Get the heap number into v0, now that the new heap number is in a2.
- __ pop(v0);
- }
-
- // Convert the heap number in v0 to an untagged integer in a1.
- // This can't go slow-case because it's the same number we already
- // converted once again.
- __ ConvertToInt32(v0, a1, a3, t0, f0, &impossible);
- // Negate the result.
- __ Xor(a1, a1, -1);
-
- __ bind(&heapnumber_allocated);
- __ mov(v0, a2); // Move newly allocated heap number to v0.
- }
-
- // Convert the int32 in a1 to the heap number in v0. a2 is corrupted.
- __ mtc1(a1, f0);
- __ cvt_d_w(f0, f0);
- __ sdc1(f0, FieldMemOperand(v0, HeapNumber::kValueOffset));
- __ Ret();
-
- __ bind(&impossible);
- if (FLAG_debug_code) {
- __ stop("Incorrect assumption in bit-not stub");
- }
-}
-
-
-// TODO(svenpanne): Use virtual functions instead of switch.
-void UnaryOpStub::GenerateGenericStub(MacroAssembler* masm) {
- switch (op_) {
- case Token::SUB:
- GenerateGenericStubSub(masm);
- break;
- case Token::BIT_NOT:
- GenerateGenericStubBitNot(masm);
- break;
- default:
- UNREACHABLE();
- }
-}
-
-
-void UnaryOpStub::GenerateGenericStubSub(MacroAssembler* masm) {
- Label non_smi, slow;
- GenerateSmiCodeSub(masm, &non_smi, &slow);
- __ bind(&non_smi);
- GenerateHeapNumberCodeSub(masm, &slow);
- __ bind(&slow);
- GenerateGenericCodeFallback(masm);
-}
-
-
-void UnaryOpStub::GenerateGenericStubBitNot(MacroAssembler* masm) {
- Label non_smi, slow;
- GenerateSmiCodeBitNot(masm, &non_smi);
- __ bind(&non_smi);
- GenerateHeapNumberCodeBitNot(masm, &slow);
- __ bind(&slow);
- GenerateGenericCodeFallback(masm);
-}
-
-
-void UnaryOpStub::GenerateGenericCodeFallback(
- MacroAssembler* masm) {
- // Handle the slow case by jumping to the JavaScript builtin.
- __ push(a0);
- switch (op_) {
- case Token::SUB:
- __ InvokeBuiltin(Builtins::UNARY_MINUS, JUMP_FUNCTION);
- break;
- case Token::BIT_NOT:
- __ InvokeBuiltin(Builtins::BIT_NOT, JUMP_FUNCTION);
- break;
- default:
- UNREACHABLE();
- }
-}
-
-
void BinaryOpStub::Initialize() {
platform_specific_bit_ = true; // FPU is a base requirement for V8.
}
@@ -6815,6 +6550,7 @@
GenerateMiss(masm);
}
+
void ICCompareStub::GenerateMiss(MacroAssembler* masm) {
{
// Call the runtime system in a fresh internal frame.
@@ -7145,6 +6881,7 @@
RememberedSetAction action;
};
+
#define REG(Name) { kRegister_ ## Name ## _Code }
static const AheadOfTimeWriteBarrierStubList kAheadOfTime[] = {
diff --git a/src/mips/code-stubs-mips.h b/src/mips/code-stubs-mips.h
index bf5db10..afef979 100644
--- a/src/mips/code-stubs-mips.h
+++ b/src/mips/code-stubs-mips.h
@@ -81,71 +81,6 @@
};
-class UnaryOpStub: public PlatformCodeStub {
- public:
- UnaryOpStub(Token::Value op,
- UnaryOverwriteMode mode,
- UnaryOpIC::TypeInfo operand_type = UnaryOpIC::UNINITIALIZED)
- : op_(op),
- mode_(mode),
- operand_type_(operand_type) {
- }
-
- private:
- Token::Value op_;
- UnaryOverwriteMode mode_;
-
- // Operand type information determined at runtime.
- UnaryOpIC::TypeInfo operand_type_;
-
- virtual void PrintName(StringStream* stream);
-
- class ModeBits: public BitField<UnaryOverwriteMode, 0, 1> {};
- class OpBits: public BitField<Token::Value, 1, 7> {};
- class OperandTypeInfoBits: public BitField<UnaryOpIC::TypeInfo, 8, 3> {};
-
- Major MajorKey() { return UnaryOp; }
- int MinorKey() {
- return ModeBits::encode(mode_)
- | OpBits::encode(op_)
- | OperandTypeInfoBits::encode(operand_type_);
- }
-
- // Note: A lot of the helper functions below will vanish when we use virtual
- // function instead of switch more often.
- void Generate(MacroAssembler* masm);
-
- void GenerateTypeTransition(MacroAssembler* masm);
-
- void GenerateSmiStub(MacroAssembler* masm);
- void GenerateSmiStubSub(MacroAssembler* masm);
- void GenerateSmiStubBitNot(MacroAssembler* masm);
- void GenerateSmiCodeSub(MacroAssembler* masm, Label* non_smi, Label* slow);
- void GenerateSmiCodeBitNot(MacroAssembler* masm, Label* slow);
-
- void GenerateNumberStub(MacroAssembler* masm);
- void GenerateNumberStubSub(MacroAssembler* masm);
- void GenerateNumberStubBitNot(MacroAssembler* masm);
- void GenerateHeapNumberCodeSub(MacroAssembler* masm, Label* slow);
- void GenerateHeapNumberCodeBitNot(MacroAssembler* masm, Label* slow);
-
- void GenerateGenericStub(MacroAssembler* masm);
- void GenerateGenericStubSub(MacroAssembler* masm);
- void GenerateGenericStubBitNot(MacroAssembler* masm);
- void GenerateGenericCodeFallback(MacroAssembler* masm);
-
- virtual Code::Kind GetCodeKind() const { return Code::UNARY_OP_IC; }
-
- virtual InlineCacheState GetICState() {
- return UnaryOpIC::ToState(operand_type_);
- }
-
- virtual void FinishCode(Handle<Code> code) {
- code->set_unary_op_type(operand_type_);
- }
-};
-
-
class StringHelper : public AllStatic {
public:
// Generate code for copying characters using a simple loop. This should only
diff --git a/src/mips/codegen-mips.cc b/src/mips/codegen-mips.cc
index 7a95bc4..523e87c 100644
--- a/src/mips/codegen-mips.cc
+++ b/src/mips/codegen-mips.cc
@@ -120,6 +120,7 @@
return &sqrt;
}
+
// -------------------------------------------------------------------------
// Platform-specific RuntimeCallHelper functions.
@@ -136,6 +137,7 @@
masm->set_has_frame(false);
}
+
// -------------------------------------------------------------------------
// Code generators
diff --git a/src/mips/constants-mips.cc b/src/mips/constants-mips.cc
index a20ec54..2dd7a31 100644
--- a/src/mips/constants-mips.cc
+++ b/src/mips/constants-mips.cc
@@ -58,6 +58,7 @@
"pc"
};
+
// List of alias names which can be used when referring to MIPS registers.
const Registers::RegisterAlias Registers::aliases_[] = {
{0, "zero"},
@@ -67,6 +68,7 @@
{kInvalidRegister, NULL}
};
+
const char* Registers::Name(int reg) {
const char* result;
if ((0 <= reg) && (reg < kNumSimuRegisters)) {
@@ -106,11 +108,13 @@
"f22", "f23", "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31"
};
+
// List of alias names which can be used when referring to MIPS registers.
const FPURegisters::RegisterAlias FPURegisters::aliases_[] = {
{kInvalidRegister, NULL}
};
+
const char* FPURegisters::Name(int creg) {
const char* result;
if ((0 <= creg) && (creg < kNumFPURegisters)) {
diff --git a/src/mips/full-codegen-mips.cc b/src/mips/full-codegen-mips.cc
index 032c1f5..43325df 100644
--- a/src/mips/full-codegen-mips.cc
+++ b/src/mips/full-codegen-mips.cc
@@ -4400,10 +4400,7 @@
const char* comment) {
// TODO(svenpanne): Allowing format strings in Comment would be nice here...
Comment cmt(masm_, comment);
- bool can_overwrite = expr->expression()->ResultOverwriteAllowed();
- UnaryOverwriteMode overwrite =
- can_overwrite ? UNARY_OVERWRITE : UNARY_NO_OVERWRITE;
- UnaryOpStub stub(expr->op(), overwrite);
+ UnaryOpStub stub(expr->op());
// GenericUnaryOpStub expects the argument to be in a0.
VisitForAccumulatorValue(expr->expression());
SetSourcePosition(expr->position());
diff --git a/src/mips/lithium-codegen-mips.cc b/src/mips/lithium-codegen-mips.cc
index 8109e8a..5dad77e 100644
--- a/src/mips/lithium-codegen-mips.cc
+++ b/src/mips/lithium-codegen-mips.cc
@@ -1971,11 +1971,11 @@
template<class InstrType>
void LCodeGen::EmitBranch(InstrType instr,
Condition cc, Register src1, const Operand& src2) {
- int right_block = instr->FalseDestination(chunk_);
int left_block = instr->TrueDestination(chunk_);
+ int right_block = instr->FalseDestination(chunk_);
int next_block = GetNextEmittedBlock();
- if (right_block == left_block) {
+ if (right_block == left_block || cc == al) {
EmitGoto(left_block);
} else if (left_block == next_block) {
__ Branch(chunk_->GetAssemblyLabel(right_block),
@@ -2015,6 +2015,25 @@
}
+void LCodeGen::DoIsNumberAndBranch(LIsNumberAndBranch* instr) {
+ Representation r = instr->hydrogen()->value()->representation();
+ if (r.IsSmiOrInteger32() || r.IsDouble()) {
+ EmitBranch(instr, al, zero_reg, Operand(zero_reg));
+ } else {
+ ASSERT(r.IsTagged());
+ Register reg = ToRegister(instr->value());
+ HType type = instr->hydrogen()->value()->type();
+ if (type.IsTaggedNumber()) {
+ EmitBranch(instr, al, zero_reg, Operand(zero_reg));
+ }
+ __ JumpIfSmi(reg, instr->TrueLabel(chunk_));
+ __ lw(scratch0(), FieldMemOperand(reg, HeapObject::kMapOffset));
+ __ LoadRoot(at, Heap::kHeapNumberMapRootIndex);
+ EmitBranch(instr, eq, scratch0(), Operand(at));
+ }
+}
+
+
void LCodeGen::DoBranch(LBranch* instr) {
Representation r = instr->hydrogen()->value()->representation();
if (r.IsInteger32() || r.IsSmi()) {
@@ -2183,7 +2202,7 @@
}
-void LCodeGen::DoCmpIDAndBranch(LCmpIDAndBranch* instr) {
+void LCodeGen::DoCompareNumericAndBranch(LCompareNumericAndBranch* instr) {
LOperand* left = instr->left();
LOperand* right = instr->right();
Condition cond = TokenToCondition(instr->op(), false);
@@ -3360,6 +3379,7 @@
__ bind(&receiver_ok);
}
+
void LCodeGen::DoApplyArguments(LApplyArguments* instr) {
Register receiver = ToRegister(instr->receiver());
Register function = ToRegister(instr->function());
@@ -3886,6 +3906,7 @@
__ sub_d(f0, f12, f14);
}
+
void LCodeGen::DoDeferredRandom(LRandom* instr) {
__ PrepareCallCFunction(1, scratch0());
__ CallCFunction(ExternalReference::random_uint32_function(isolate()), 1);
diff --git a/src/mips/lithium-gap-resolver-mips.cc b/src/mips/lithium-gap-resolver-mips.cc
index 23a8f32..9705e1f 100644
--- a/src/mips/lithium-gap-resolver-mips.cc
+++ b/src/mips/lithium-gap-resolver-mips.cc
@@ -222,7 +222,6 @@
ASSERT(destination->IsStackSlot());
__ sw(source_register, cgen_->ToMemOperand(destination));
}
-
} else if (source->IsStackSlot()) {
MemOperand source_operand = cgen_->ToMemOperand(source);
if (destination->IsRegister()) {
@@ -259,6 +258,10 @@
} else {
__ LoadObject(dst, cgen_->ToHandle(constant_source));
}
+ } else if (source->IsDoubleRegister()) {
+ DoubleRegister result = cgen_->ToDoubleRegister(destination);
+ double v = cgen_->ToDouble(constant_source);
+ __ Move(result, v);
} else {
ASSERT(destination->IsStackSlot());
ASSERT(!in_cycle_); // Constant moves happen after all cycles are gone.
diff --git a/src/mips/lithium-mips.cc b/src/mips/lithium-mips.cc
index 638eaa4..0a7fb44 100644
--- a/src/mips/lithium-mips.cc
+++ b/src/mips/lithium-mips.cc
@@ -186,7 +186,8 @@
return new(zone()) LDebugBreak();
}
-void LCmpIDAndBranch::PrintDataTo(StringStream* stream) {
+
+void LCompareNumericAndBranch::PrintDataTo(StringStream* stream) {
stream->Add("if ");
left()->PrintTo(stream);
stream->Add(" %s ", Token::String(op()));
@@ -1605,8 +1606,8 @@
}
-LInstruction* LChunkBuilder::DoCompareIDAndBranch(
- HCompareIDAndBranch* instr) {
+LInstruction* LChunkBuilder::DoCompareNumericAndBranch(
+ HCompareNumericAndBranch* instr) {
Representation r = instr->representation();
if (r.IsSmiOrInteger32()) {
ASSERT(instr->left()->representation().IsSmiOrInteger32());
@@ -1614,14 +1615,14 @@
instr->right()->representation()));
LOperand* left = UseRegisterOrConstantAtStart(instr->left());
LOperand* right = UseRegisterOrConstantAtStart(instr->right());
- return new(zone()) LCmpIDAndBranch(left, right);
+ return new(zone()) LCompareNumericAndBranch(left, right);
} else {
ASSERT(r.IsDouble());
ASSERT(instr->left()->representation().IsDouble());
ASSERT(instr->right()->representation().IsDouble());
LOperand* left = UseRegisterAtStart(instr->left());
LOperand* right = UseRegisterAtStart(instr->right());
- return new(zone()) LCmpIDAndBranch(left, right);
+ return new(zone()) LCompareNumericAndBranch(left, right);
}
}
@@ -1918,6 +1919,18 @@
}
+LInstruction* LChunkBuilder::DoCheckSmi(HCheckSmi* instr) {
+ LOperand* value = UseRegisterAtStart(instr->value());
+ return AssignEnvironment(new(zone()) LCheckSmi(value));
+}
+
+
+LInstruction* LChunkBuilder::DoIsNumberAndBranch(HIsNumberAndBranch* instr) {
+ return new(zone())
+ LIsNumberAndBranch(UseRegisterOrConstantAtStart(instr->value()));
+}
+
+
LInstruction* LChunkBuilder::DoCheckInstanceType(HCheckInstanceType* instr) {
LOperand* value = UseRegisterAtStart(instr->value());
LInstruction* result = new(zone()) LCheckInstanceType(value);
diff --git a/src/mips/lithium-mips.h b/src/mips/lithium-mips.h
index 06d30d0..751cb23 100644
--- a/src/mips/lithium-mips.h
+++ b/src/mips/lithium-mips.h
@@ -81,7 +81,7 @@
V(ClampTToUint8) \
V(ClassOfTestAndBranch) \
V(CmpConstantEqAndBranch) \
- V(CmpIDAndBranch) \
+ V(CompareNumericAndBranch) \
V(CmpObjectEqAndBranch) \
V(CmpMapAndBranch) \
V(CmpT) \
@@ -118,6 +118,7 @@
V(IsConstructCallAndBranch) \
V(IsObjectAndBranch) \
V(IsStringAndBranch) \
+ V(IsNumberAndBranch) \
V(IsSmiAndBranch) \
V(IsUndetectableAndBranch) \
V(Label) \
@@ -711,9 +712,9 @@
};
-class LCmpIDAndBranch: public LControlInstruction<2, 0> {
+class LCompareNumericAndBranch: public LControlInstruction<2, 0> {
public:
- LCmpIDAndBranch(LOperand* left, LOperand* right) {
+ LCompareNumericAndBranch(LOperand* left, LOperand* right) {
inputs_[0] = left;
inputs_[1] = right;
}
@@ -721,8 +722,9 @@
LOperand* left() { return inputs_[0]; }
LOperand* right() { return inputs_[1]; }
- DECLARE_CONCRETE_INSTRUCTION(CmpIDAndBranch, "cmp-id-and-branch")
- DECLARE_HYDROGEN_ACCESSOR(CompareIDAndBranch)
+ DECLARE_CONCRETE_INSTRUCTION(CompareNumericAndBranch,
+ "compare-numeric-and-branch")
+ DECLARE_HYDROGEN_ACCESSOR(CompareNumericAndBranch)
Token::Value op() const { return hydrogen()->token(); }
bool is_double() const {
@@ -919,6 +921,19 @@
};
+class LIsNumberAndBranch: public LControlInstruction<1, 0> {
+ public:
+ explicit LIsNumberAndBranch(LOperand* value) {
+ inputs_[0] = value;
+ }
+
+ LOperand* value() { return inputs_[0]; }
+
+ DECLARE_CONCRETE_INSTRUCTION(IsNumberAndBranch, "is-number-and-branch")
+ DECLARE_HYDROGEN_ACCESSOR(IsNumberAndBranch)
+};
+
+
class LIsStringAndBranch: public LControlInstruction<1, 1> {
public:
LIsStringAndBranch(LOperand* value, LOperand* temp) {
diff --git a/src/mips/macro-assembler-mips.cc b/src/mips/macro-assembler-mips.cc
index 47e6ff9..95eafae 100644
--- a/src/mips/macro-assembler-mips.cc
+++ b/src/mips/macro-assembler-mips.cc
@@ -768,6 +768,7 @@
}
}
+
//------------Pseudo-instructions-------------
void MacroAssembler::li(Register rd, Operand j, LiFlags mode) {
@@ -1021,6 +1022,7 @@
mtc1(t8, fd);
}
+
void MacroAssembler::Trunc_w_d(FPURegister fd, FPURegister fs) {
if (kArchVariant == kLoongson && fd.is(fs)) {
mfc1(t8, FPURegister::from_code(fs.code() + 1));
@@ -1031,6 +1033,7 @@
}
}
+
void MacroAssembler::Round_w_d(FPURegister fd, FPURegister fs) {
if (kArchVariant == kLoongson && fd.is(fs)) {
mfc1(t8, FPURegister::from_code(fs.code() + 1));
@@ -2639,6 +2642,7 @@
nop();
}
+
void MacroAssembler::DropAndRet(int drop) {
Ret(USE_DELAY_SLOT);
addiu(sp, sp, drop * kPointerSize);
diff --git a/src/objects-debug.cc b/src/objects-debug.cc
index c0c0e47..a7189c5 100644
--- a/src/objects-debug.cc
+++ b/src/objects-debug.cc
@@ -755,6 +755,7 @@
VerifyPointer(construct_trap());
}
+
void JSArrayBuffer::JSArrayBufferVerify() {
CHECK(IsJSArrayBuffer());
JSObjectVerify();
@@ -875,6 +876,7 @@
VerifyPointer(property_list());
}
+
void FunctionTemplateInfo::FunctionTemplateInfoVerify() {
CHECK(IsFunctionTemplateInfo());
TemplateInfoVerify();
@@ -1070,6 +1072,7 @@
number_of_slow_unused_elements_ = 0;
}
+
void JSObject::SpillInformation::Print() {
PrintF("\n JSObject Spill Statistics (#%d):\n", number_of_objects_);
diff --git a/src/objects-inl.h b/src/objects-inl.h
index fe054da..61ae90e 100644
--- a/src/objects-inl.h
+++ b/src/objects-inl.h
@@ -3787,6 +3787,7 @@
kind() == BINARY_OP_IC ||
kind() == COMPARE_IC ||
kind() == COMPARE_NIL_IC ||
+ kind() == STORE_IC ||
kind() == LOAD_IC ||
kind() == KEYED_LOAD_IC ||
kind() == TO_BOOLEAN_IC);
diff --git a/src/objects-printer.cc b/src/objects-printer.cc
index f1616da..1fae69b 100644
--- a/src/objects-printer.cc
+++ b/src/objects-printer.cc
@@ -760,6 +760,7 @@
"???", "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
};
+
void JSDate::JSDatePrint(FILE* out) {
HeapObject::PrintHeader(out, "JSDate");
PrintF(out, " - map = 0x%p\n", reinterpret_cast<void*>(map()));
diff --git a/src/objects-visiting-inl.h b/src/objects-visiting-inl.h
index cfb7d44..612f937 100644
--- a/src/objects-visiting-inl.h
+++ b/src/objects-visiting-inl.h
@@ -136,8 +136,8 @@
map->GetHeap(),
HeapObject::RawField(object,
JSTypedArray::kWeakNextOffset + kPointerSize),
- HeapObject::RawField(object, JSTypedArray::kSize));
- return JSTypedArray::kSize;
+ HeapObject::RawField(object, JSTypedArray::kSizeWithInternalFields));
+ return JSTypedArray::kSizeWithInternalFields;
}
@@ -152,8 +152,8 @@
map->GetHeap(),
HeapObject::RawField(object,
JSDataView::kWeakNextOffset + kPointerSize),
- HeapObject::RawField(object, JSDataView::kSize));
- return JSDataView::kSize;
+ HeapObject::RawField(object, JSDataView::kSizeWithInternalFields));
+ return JSDataView::kSizeWithInternalFields;
}
@@ -522,7 +522,7 @@
map->GetHeap(),
HeapObject::RawField(object,
JSTypedArray::kWeakNextOffset + kPointerSize),
- HeapObject::RawField(object, JSTypedArray::kSize));
+ HeapObject::RawField(object, JSTypedArray::kSizeWithInternalFields));
}
@@ -537,7 +537,7 @@
map->GetHeap(),
HeapObject::RawField(object,
JSDataView::kWeakNextOffset + kPointerSize),
- HeapObject::RawField(object, JSDataView::kSize));
+ HeapObject::RawField(object, JSDataView::kSizeWithInternalFields));
}
diff --git a/src/objects.cc b/src/objects.cc
index aa67876..2611b57 100644
--- a/src/objects.cc
+++ b/src/objects.cc
@@ -630,12 +630,23 @@
}
-Object* JSObject::SetNormalizedProperty(LookupResult* result, Object* value) {
+Handle<Object> JSObject::SetNormalizedProperty(Handle<JSObject> object,
+ LookupResult* result,
+ Handle<Object> value) {
+ CALL_HEAP_FUNCTION(object->GetIsolate(),
+ object->SetNormalizedProperty(result, *value),
+ Object);
+}
+
+
+MaybeObject* JSObject::SetNormalizedProperty(LookupResult* result,
+ Object* value) {
ASSERT(!HasFastProperties());
if (IsGlobalObject()) {
PropertyCell* cell = PropertyCell::cast(
property_dictionary()->ValueAt(result->GetDictionaryEntry()));
- cell->set_value(value);
+ MaybeObject* maybe_type = cell->SetValueInferType(value);
+ if (maybe_type->IsFailure()) return maybe_type;
} else {
property_dictionary()->ValueAtPut(result->GetDictionaryEntry(), value);
}
@@ -691,7 +702,8 @@
if (IsGlobalObject()) {
PropertyCell* cell =
PropertyCell::cast(property_dictionary()->ValueAt(entry));
- cell->set_value(value);
+ MaybeObject* maybe_type = cell->SetValueInferType(value);
+ if (maybe_type->IsFailure()) return maybe_type;
// Please note we have to update the property details.
property_dictionary()->DetailsAtPut(entry, details);
} else {
@@ -723,7 +735,9 @@
set_map(new_map);
}
PropertyCell* cell = PropertyCell::cast(dictionary->ValueAt(entry));
- cell->set_value(cell->GetHeap()->the_hole_value());
+ MaybeObject* maybe_type =
+ cell->SetValueInferType(cell->GetHeap()->the_hole_value());
+ if (maybe_type->IsFailure()) return maybe_type;
dictionary->DetailsAtPut(entry, details.AsDeleted());
} else {
Object* deleted = dictionary->DeleteProperty(entry, mode);
@@ -1930,7 +1944,9 @@
int entry = dict->FindEntry(name);
if (entry != NameDictionary::kNotFound) {
store_value = dict->ValueAt(entry);
- PropertyCell::cast(store_value)->set_value(value);
+ MaybeObject* maybe_type =
+ PropertyCell::cast(store_value)->SetValueInferType(value);
+ if (maybe_type->IsFailure()) return maybe_type;
// Assign an enumeration index to the property and update
// SetNextEnumerationIndex.
int index = dict->NextEnumerationIndex();
@@ -1944,7 +1960,9 @@
heap->AllocatePropertyCell(value);
if (!maybe_store_value->ToObject(&store_value)) return maybe_store_value;
}
- PropertyCell::cast(store_value)->set_value(value);
+ MaybeObject* maybe_type =
+ PropertyCell::cast(store_value)->SetValueInferType(value);
+ if (maybe_type->IsFailure()) return maybe_type;
}
PropertyDetails details = PropertyDetails(attributes, NORMAL, 0);
Object* result;
@@ -9961,22 +9979,26 @@
CHECK_EQ(target, old_target); // VisitPointer doesn't change Code* *target.
}
+
void ObjectVisitor::VisitEmbeddedPointer(RelocInfo* rinfo) {
ASSERT(rinfo->rmode() == RelocInfo::EMBEDDED_OBJECT);
VisitPointer(rinfo->target_object_address());
}
+
void ObjectVisitor::VisitExternalReference(RelocInfo* rinfo) {
Address* p = rinfo->target_reference_address();
VisitExternalReferences(p, p + 1);
}
+
byte Code::compare_nil_state() {
ASSERT(is_compare_nil_ic_stub());
return CompareNilICStub::ExtractTypesFromExtraICState(
extended_extra_ic_state());
}
+
byte Code::compare_nil_value() {
ASSERT(is_compare_nil_ic_stub());
return CompareNilICStub::ExtractNilValueFromExtraICState(
@@ -10610,6 +10632,7 @@
void Code::PrintExtraICState(FILE* out, Kind kind, ExtraICState extra) {
+ PrintF(out, "extra_ic_state = ");
const char* name = NULL;
switch (kind) {
case CALL_IC:
@@ -10627,9 +10650,9 @@
break;
}
if (name != NULL) {
- PrintF(out, "extra_ic_state = %s\n", name);
+ PrintF(out, "%s\n", name);
} else {
- PrintF(out, "extra_ic_state = %d\n", extra);
+ PrintF(out, "%d\n", extra);
}
}
@@ -10638,7 +10661,8 @@
PrintF(out, "kind = %s\n", Kind2String(kind()));
if (is_inline_cache_stub()) {
PrintF(out, "ic_state = %s\n", ICState2String(ic_state()));
- PrintExtraICState(out, kind(), extra_ic_state());
+ PrintExtraICState(out, kind(), needs_extended_extra_ic_state(kind()) ?
+ extended_extra_ic_state() : extra_ic_state());
if (ic_state() == MONOMORPHIC) {
PrintF(out, "type = %s\n", StubType2String(type()));
}
@@ -13299,6 +13323,7 @@
Smi* flags_;
};
+
// Utf8StringKey carries a vector of chars as key.
class Utf8StringKey : public HashTableKey {
public:
@@ -13665,6 +13690,7 @@
return entry;
}
+
// Force instantiation of template instances class.
// Please note this list is compiler dependent.
@@ -14027,6 +14053,7 @@
return result_double;
}
+
ExternalArrayType JSTypedArray::type() {
switch (elements()->map()->instance_type()) {
case EXTERNAL_BYTE_ARRAY_TYPE:
@@ -14241,39 +14268,36 @@
}
-Handle<PropertyCell> GlobalObject::EnsurePropertyCell(
- Handle<GlobalObject> global,
- Handle<Name> name) {
- Isolate* isolate = global->GetIsolate();
- CALL_HEAP_FUNCTION(isolate,
- global->EnsurePropertyCell(*name),
- PropertyCell);
+// TODO(mstarzinger): Temporary wrapper until handlified.
+static Handle<NameDictionary> NameDictionaryAdd(Handle<NameDictionary> dict,
+ Handle<Name> name,
+ Handle<Object> value,
+ PropertyDetails details) {
+ CALL_HEAP_FUNCTION(dict->GetIsolate(),
+ dict->Add(*name, *value, details),
+ NameDictionary);
}
-MaybeObject* GlobalObject::EnsurePropertyCell(Name* name) {
- ASSERT(!HasFastProperties());
- int entry = property_dictionary()->FindEntry(name);
+Handle<PropertyCell> GlobalObject::EnsurePropertyCell(
+ Handle<GlobalObject> global,
+ Handle<Name> name) {
+ ASSERT(!global->HasFastProperties());
+ int entry = global->property_dictionary()->FindEntry(*name);
if (entry == NameDictionary::kNotFound) {
- Heap* heap = GetHeap();
- Object* cell;
- { MaybeObject* maybe_cell =
- heap->AllocatePropertyCell(heap->the_hole_value());
- if (!maybe_cell->ToObject(&cell)) return maybe_cell;
- }
+ Isolate* isolate = global->GetIsolate();
+ Handle<PropertyCell> cell = isolate->factory()->NewPropertyCell(
+ isolate->factory()->the_hole_value());
PropertyDetails details(NONE, NORMAL, 0);
details = details.AsDeleted();
- Object* dictionary;
- { MaybeObject* maybe_dictionary =
- property_dictionary()->Add(name, cell, details);
- if (!maybe_dictionary->ToObject(&dictionary)) return maybe_dictionary;
- }
- set_properties(NameDictionary::cast(dictionary));
+ Handle<NameDictionary> dictionary = NameDictionaryAdd(
+ handle(global->property_dictionary()), name, cell, details);
+ global->set_properties(*dictionary);
return cell;
} else {
- Object* value = property_dictionary()->ValueAt(entry);
+ Object* value = global->property_dictionary()->ValueAt(entry);
ASSERT(value->IsPropertyCell());
- return value;
+ return handle(PropertyCell::cast(value));
}
}
@@ -14406,6 +14430,7 @@
return LookupKey(&key, s);
}
+
MaybeObject* StringTable::LookupKey(HashTableKey* key, Object** s) {
int entry = FindEntry(key);
@@ -15802,10 +15827,51 @@
void PropertyCell::set_type(Type* type, WriteBarrierMode ignored) {
+ ASSERT(IsPropertyCell());
set_type_raw(type, ignored);
}
+Type* PropertyCell::UpdateType(Handle<PropertyCell> cell,
+ Handle<Object> value) {
+ Isolate* isolate = cell->GetIsolate();
+ Handle<Type> old_type(cell->type(), isolate);
+ Handle<Type> new_type((value->IsSmi() || value->IsUndefined())
+ ? Type::Constant(value, isolate)
+ : Type::Any(), isolate);
+
+ if (new_type->Is(old_type)) {
+ return *old_type;
+ }
+
+ cell->dependent_code()->DeoptimizeDependentCodeGroup(
+ isolate, DependentCode::kPropertyCellChangedGroup);
+
+ if (old_type->Is(Type::None()) || old_type->Is(Type::Undefined())) {
+ return *new_type;
+ }
+
+ return Type::Any();
+}
+
+
+MaybeObject* PropertyCell::SetValueInferType(Object* value,
+ WriteBarrierMode ignored) {
+ set_value(value, ignored);
+ if (!Type::Any()->Is(type())) {
+ IdempotentPointerToHandleCodeTrampoline trampoline(GetIsolate());
+ MaybeObject* maybe_type = trampoline.CallWithReturnValue(
+ &PropertyCell::UpdateType,
+ Handle<PropertyCell>(this),
+ Handle<Object>(value, GetIsolate()));
+ if (maybe_type->IsFailure()) return maybe_type;
+ Type* new_type = static_cast<Type*>(maybe_type);
+ set_type(new_type);
+ }
+ return value;
+}
+
+
void PropertyCell::AddDependentCompilationInfo(CompilationInfo* info) {
Handle<DependentCode> dep(dependent_code());
Handle<DependentCode> codes =
diff --git a/src/objects.h b/src/objects.h
index 416ed7f..eb6d882 100644
--- a/src/objects.h
+++ b/src/objects.h
@@ -1886,9 +1886,16 @@
// Handles the special representation of JS global objects.
Object* GetNormalizedProperty(LookupResult* result);
+ // Sets the property value in a normalized object given (key, value).
+ // Handles the special representation of JS global objects.
+ static Handle<Object> SetNormalizedProperty(Handle<JSObject> object,
+ LookupResult* result,
+ Handle<Object> value);
+
// Sets the property value in a normalized object given a lookup result.
// Handles the special representation of JS global objects.
- Object* SetNormalizedProperty(LookupResult* result, Object* value);
+ MUST_USE_RESULT MaybeObject* SetNormalizedProperty(LookupResult* result,
+ Object* value);
// Sets the property value in a normalized object given (key, value, details).
// Handles the special representation of JS global objects.
@@ -4567,7 +4574,8 @@
// TODO(danno): This is a bit of a hack right now since there are still
// clients of this API that pass "extra" values in for argc. These clients
// should be retrofitted to used ExtendedExtraICState.
- return kind == COMPARE_NIL_IC || kind == TO_BOOLEAN_IC;
+ return kind == COMPARE_NIL_IC || kind == TO_BOOLEAN_IC ||
+ kind == UNARY_OP_IC;
}
inline StubType type(); // Only valid for monomorphic IC stubs.
@@ -6819,12 +6827,8 @@
}
// Ensure that the global object has a cell for the given property name.
- static Handle<PropertyCell> EnsurePropertyCell(
- Handle<GlobalObject> global,
- Handle<Name> name);
- // TODO(kmillikin): This function can be eliminated once the stub cache is
- // fully handlified (and the static helper can be written directly).
- MUST_USE_RESULT MaybeObject* EnsurePropertyCell(Name* name);
+ static Handle<PropertyCell> EnsurePropertyCell(Handle<GlobalObject> global,
+ Handle<Name> name);
// Casting.
static inline GlobalObject* cast(Object* obj);
@@ -8586,6 +8590,14 @@
// property.
DECL_ACCESSORS(dependent_code, DependentCode)
+ // Sets the value of the cell and updates the type field to be the union
+ // of the cell's current type and the value's type. If the change causes
+ // a change of the type of the cell's contents, code dependent on the cell
+ // will be deoptimized.
+ MUST_USE_RESULT MaybeObject* SetValueInferType(
+ Object* value,
+ WriteBarrierMode mode = UPDATE_WRITE_BARRIER);
+
// Casting.
static inline PropertyCell* cast(Object* obj);
@@ -8613,6 +8625,9 @@
void AddDependentCode(Handle<Code> code);
+ static Type* UpdateType(Handle<PropertyCell> cell,
+ Handle<Object> value);
+
private:
DECL_ACCESSORS(type_raw, Object)
DISALLOW_IMPLICIT_CONSTRUCTORS(PropertyCell);
@@ -8921,6 +8936,9 @@
static const int kLengthOffset = kViewSize + kPointerSize;
static const int kSize = kLengthOffset + kPointerSize;
+ static const int kSizeWithInternalFields =
+ kSize + v8::ArrayBufferView::kInternalFieldCount * kPointerSize;
+
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(JSTypedArray);
};
@@ -8940,6 +8958,9 @@
static const int kSize = kViewSize;
+ static const int kSizeWithInternalFields =
+ kSize + v8::ArrayBufferView::kInternalFieldCount * kPointerSize;
+
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(JSDataView);
};
diff --git a/src/parser.cc b/src/parser.cc
index b320299..ca2d022 100644
--- a/src/parser.cc
+++ b/src/parser.cc
@@ -371,6 +371,7 @@
return result;
}
+
Scanner::Location ScriptDataImpl::MessageLocation() {
int beg_pos = Read(PreparseDataConstants::kMessageStartPos);
int end_pos = Read(PreparseDataConstants::kMessageEndPos);
@@ -3769,6 +3770,7 @@
return isolate()->factory()->uninitialized_value();
}
+
// Validation per 11.1.5 Object Initialiser
class ObjectLiteralPropertyChecker {
public:
@@ -4962,6 +4964,7 @@
return factory()->NewThrow(call_constructor, scanner().location().beg_pos);
}
+
// ----------------------------------------------------------------------------
// Regular expressions
@@ -5032,6 +5035,7 @@
return simple_;
}
+
RegExpTree* RegExpParser::ReportError(Vector<const char> message) {
failed_ = true;
*error_ = isolate()->factory()->NewStringFromAscii(message, NOT_TENURED);
diff --git a/src/platform-cygwin.cc b/src/platform-cygwin.cc
index bda9f92..7c3da1b 100644
--- a/src/platform-cygwin.cc
+++ b/src/platform-cygwin.cc
@@ -67,6 +67,7 @@
POSIXPostSetUp();
}
+
uint64_t OS::CpuFeaturesImpliedByPlatform() {
return 0; // Nothing special about Cygwin.
}
diff --git a/src/platform-macos.cc b/src/platform-macos.cc
index 21e9c7f..f4d8b33 100644
--- a/src/platform-macos.cc
+++ b/src/platform-macos.cc
@@ -596,6 +596,7 @@
Release_Store(&tls_base_offset_initialized, 1);
}
+
static void CheckFastTls(Thread::LocalStorageKey key) {
void* expected = reinterpret_cast<void*>(0x1234CAFE);
Thread::SetThreadLocal(key, expected);
diff --git a/src/platform-openbsd.cc b/src/platform-openbsd.cc
index b722e31..f849d58 100644
--- a/src/platform-openbsd.cc
+++ b/src/platform-openbsd.cc
@@ -720,6 +720,7 @@
}
}
+
Semaphore* OS::CreateSemaphore(int count) {
return new OpenBSDSemaphore(count);
}
diff --git a/src/platform-posix.cc b/src/platform-posix.cc
index e72a5d9..6e83b04 100644
--- a/src/platform-posix.cc
+++ b/src/platform-posix.cc
@@ -326,6 +326,7 @@
memmove(dest, src, size);
}
+
// Initialize to library version so we can call this at any time during startup.
static OS::MemMoveFunction memmove_function = &MemMoveWrapper;
@@ -358,6 +359,7 @@
init_fast_sqrt_function();
}
+
// ----------------------------------------------------------------------------
// POSIX string support.
//
diff --git a/src/platform-win32.cc b/src/platform-win32.cc
index 1913760..80bcaf9 100644
--- a/src/platform-win32.cc
+++ b/src/platform-win32.cc
@@ -152,6 +152,7 @@
memmove(dest, src, size);
}
+
// Initialize to library version so we can call this at any time during startup.
static OS::MemMoveFunction memmove_function = &MemMoveWrapper;
@@ -178,6 +179,7 @@
modulo_function = CreateModuloFunction();
}
+
double modulo(double x, double y) {
// Note: here we rely on dependent reads being ordered. This is true
// on all architectures we currently support.
@@ -321,6 +323,7 @@
TimeStamp time_;
};
+
// Static variables.
bool Time::tz_initialized_ = false;
TIME_ZONE_INFORMATION Time::tzinfo_;
@@ -616,6 +619,7 @@
return t.ToJSTime();
}
+
// Returns the tickcounter based on timeGetTime.
int64_t OS::Ticks() {
return timeGetTime() * 1000; // Convert to microseconds.
@@ -1449,6 +1453,7 @@
return frames_count;
}
+
// Restore warnings to previous settings.
#pragma warning(pop)
@@ -1479,6 +1484,10 @@
int OS::ActivationFrameAlignment() {
#ifdef _WIN64
return 16; // Windows 64-bit ABI requires the stack to be 16-byte aligned.
+#elif defined(__MINGW32__)
+ // With gcc 4.4 the tree vectorization optimizer can generate code
+ // that requires 16 byte alignment such as movdqa on x86.
+ return 16;
#else
return 8; // Floating-point math runs faster with 8-byte alignment.
#endif
diff --git a/src/preparse-data.cc b/src/preparse-data.cc
index 287ad66..8e08848 100644
--- a/src/preparse-data.cc
+++ b/src/preparse-data.cc
@@ -86,6 +86,7 @@
}
}
+
// ----------------------------------------------------------------------------
// PartialParserRecorder - Record both function entries and symbols.
diff --git a/src/preparser.cc b/src/preparser.cc
index 3268e3c..fe37cfa 100644
--- a/src/preparser.cc
+++ b/src/preparser.cc
@@ -1685,6 +1685,7 @@
return result;
}
+
bool PreParser::peek_any_identifier() {
i::Token::Value next = peek();
return next == i::Token::IDENTIFIER ||
@@ -1698,6 +1699,7 @@
return AddSymbol(i::Vector<const byte>::cast(key), true, value);
}
+
int DuplicateFinder::AddUtf16Symbol(i::Vector<const uint16_t> key, int value) {
return AddSymbol(i::Vector<const byte>::cast(key), false, value);
}
diff --git a/src/profile-generator-inl.h b/src/profile-generator-inl.h
index 20c1aec..d92085a 100644
--- a/src/profile-generator-inl.h
+++ b/src/profile-generator-inl.h
@@ -45,7 +45,6 @@
CodeEntry::CodeEntry(Logger::LogEventsAndTags tag,
const char* name,
- int security_token_id,
const char* name_prefix,
const char* resource_name,
int line_number)
@@ -57,7 +56,6 @@
line_number_(line_number),
shared_id_(0),
script_id_(v8::Script::kNoScriptId),
- security_token_id_(security_token_id),
no_frame_ranges_(NULL) {
}
diff --git a/src/profile-generator.cc b/src/profile-generator.cc
index 78b05c5..cc86724 100644
--- a/src/profile-generator.cc
+++ b/src/profile-generator.cc
@@ -41,60 +41,6 @@
namespace internal {
-TokenEnumerator::TokenEnumerator()
- : token_locations_(4),
- token_removed_(4) {
-}
-
-
-TokenEnumerator::~TokenEnumerator() {
- Isolate* isolate = Isolate::Current();
- for (int i = 0; i < token_locations_.length(); ++i) {
- if (!token_removed_[i]) {
- isolate->global_handles()->ClearWeakness(token_locations_[i]);
- isolate->global_handles()->Destroy(token_locations_[i]);
- }
- }
-}
-
-
-int TokenEnumerator::GetTokenId(Object* token) {
- Isolate* isolate = Isolate::Current();
- if (token == NULL) return TokenEnumerator::kNoSecurityToken;
- for (int i = 0; i < token_locations_.length(); ++i) {
- if (*token_locations_[i] == token && !token_removed_[i]) return i;
- }
- Handle<Object> handle = isolate->global_handles()->Create(token);
- // handle.location() points to a memory cell holding a pointer
- // to a token object in the V8's heap.
- isolate->global_handles()->MakeWeak(handle.location(),
- this,
- TokenRemovedCallback);
- token_locations_.Add(handle.location());
- token_removed_.Add(false);
- return token_locations_.length() - 1;
-}
-
-
-void TokenEnumerator::TokenRemovedCallback(v8::Isolate* isolate,
- v8::Persistent<v8::Value>* handle,
- void* parameter) {
- reinterpret_cast<TokenEnumerator*>(parameter)->TokenRemoved(
- Utils::OpenPersistent(handle).location());
- handle->Dispose(isolate);
-}
-
-
-void TokenEnumerator::TokenRemoved(Object** token_location) {
- for (int i = 0; i < token_locations_.length(); ++i) {
- if (token_locations_[i] == token_location && !token_removed_[i]) {
- token_removed_[i] = true;
- return;
- }
- }
-}
-
-
StringsStorage::StringsStorage()
: names_(StringsMatch) {
}
@@ -274,12 +220,11 @@
void ProfileNode::Print(int indent) {
- OS::Print("%5u %5u %*c %s%s [%d] #%d %d",
+ OS::Print("%5u %5u %*c %s%s #%d %d",
total_ticks_, self_ticks_,
indent, ' ',
entry_->name_prefix(),
entry_->name(),
- entry_->security_token_id(),
entry_->script_id(),
id());
if (entry_->resource_name()[0] != '\0')
@@ -353,58 +298,6 @@
};
-class FilteredCloneCallback {
- public:
- FilteredCloneCallback(ProfileNode* dst_root, int security_token_id)
- : stack_(10),
- security_token_id_(security_token_id) {
- stack_.Add(NodesPair(NULL, dst_root));
- }
-
- void BeforeTraversingChild(ProfileNode* parent, ProfileNode* child) {
- if (IsTokenAcceptable(child->entry()->security_token_id(),
- parent->entry()->security_token_id())) {
- ProfileNode* clone = stack_.last().dst->FindOrAddChild(child->entry());
- clone->IncreaseSelfTicks(child->self_ticks());
- stack_.Add(NodesPair(child, clone));
- } else {
- // Attribute ticks to parent node.
- stack_.last().dst->IncreaseSelfTicks(child->self_ticks());
- }
- }
-
- void AfterAllChildrenTraversed(ProfileNode* parent) { }
-
- void AfterChildTraversed(ProfileNode*, ProfileNode* child) {
- if (stack_.last().src == child) {
- stack_.RemoveLast();
- }
- }
-
- private:
- bool IsTokenAcceptable(int token, int parent_token) {
- if (token == TokenEnumerator::kNoSecurityToken
- || token == security_token_id_) return true;
- if (token == TokenEnumerator::kInheritsSecurityToken) {
- ASSERT(parent_token != TokenEnumerator::kInheritsSecurityToken);
- return parent_token == TokenEnumerator::kNoSecurityToken
- || parent_token == security_token_id_;
- }
- return false;
- }
-
- List<NodesPair> stack_;
- int security_token_id_;
-};
-
-void ProfileTree::FilteredClone(ProfileTree* src, int security_token_id) {
- ms_to_ticks_scale_ = src->ms_to_ticks_scale_;
- FilteredCloneCallback cb(root_, security_token_id);
- src->TraverseDepthFirst(&cb);
- CalculateTotalTicks();
-}
-
-
void ProfileTree::SetTickRatePerMs(double ticks_per_ms) {
ms_to_ticks_scale_ = ticks_per_ms > 0 ? 1.0 / ticks_per_ms : 1.0;
}
@@ -495,14 +388,6 @@
}
-CpuProfile* CpuProfile::FilteredClone(int security_token_id) {
- ASSERT(security_token_id != TokenEnumerator::kNoSecurityToken);
- CpuProfile* clone = new CpuProfile(title_, uid_, false);
- clone->top_down_.FilteredClone(&top_down_, security_token_id);
- return clone;
-}
-
-
void CpuProfile::ShortPrint() {
OS::Print("top down ");
top_down_.ShortPrint();
@@ -601,10 +486,7 @@
CpuProfilesCollection::CpuProfilesCollection()
- : profiles_uids_(UidsMatch),
- current_profiles_semaphore_(OS::CreateSemaphore(1)) {
- // Create list of unabridged profiles.
- profiles_by_token_.Add(new List<CpuProfile*>());
+ : current_profiles_semaphore_(OS::CreateSemaphore(1)) {
}
@@ -612,22 +494,16 @@
delete *entry_ptr;
}
+
static void DeleteCpuProfile(CpuProfile** profile_ptr) {
delete *profile_ptr;
}
-static void DeleteProfilesList(List<CpuProfile*>** list_ptr) {
- if (*list_ptr != NULL) {
- (*list_ptr)->Iterate(DeleteCpuProfile);
- delete *list_ptr;
- }
-}
CpuProfilesCollection::~CpuProfilesCollection() {
delete current_profiles_semaphore_;
+ finished_profiles_.Iterate(DeleteCpuProfile);
current_profiles_.Iterate(DeleteCpuProfile);
- detached_profiles_.Iterate(DeleteCpuProfile);
- profiles_by_token_.Iterate(DeleteProfilesList);
code_entries_.Iterate(DeleteCodeEntry);
}
@@ -653,8 +529,7 @@
}
-CpuProfile* CpuProfilesCollection::StopProfiling(int security_token_id,
- const char* title,
+CpuProfile* CpuProfilesCollection::StopProfiling(const char* title,
double actual_sampling_rate) {
const int title_len = StrLength(title);
CpuProfile* profile = NULL;
@@ -667,48 +542,11 @@
}
current_profiles_semaphore_->Signal();
- if (profile != NULL) {
- profile->CalculateTotalTicks();
- profile->SetActualSamplingRate(actual_sampling_rate);
- List<CpuProfile*>* unabridged_list =
- profiles_by_token_[TokenToIndex(TokenEnumerator::kNoSecurityToken)];
- unabridged_list->Add(profile);
- HashMap::Entry* entry =
- profiles_uids_.Lookup(reinterpret_cast<void*>(profile->uid()),
- static_cast<uint32_t>(profile->uid()),
- true);
- ASSERT(entry->value == NULL);
- entry->value = reinterpret_cast<void*>(unabridged_list->length() - 1);
- return GetProfile(security_token_id, profile->uid());
- }
- return NULL;
-}
-
-
-CpuProfile* CpuProfilesCollection::GetProfile(int security_token_id,
- unsigned uid) {
- int index = GetProfileIndex(uid);
- if (index < 0) return NULL;
- List<CpuProfile*>* unabridged_list =
- profiles_by_token_[TokenToIndex(TokenEnumerator::kNoSecurityToken)];
- if (security_token_id == TokenEnumerator::kNoSecurityToken) {
- return unabridged_list->at(index);
- }
- List<CpuProfile*>* list = GetProfilesList(security_token_id);
- if (list->at(index) == NULL) {
- (*list)[index] =
- unabridged_list->at(index)->FilteredClone(security_token_id);
- }
- return list->at(index);
-}
-
-
-int CpuProfilesCollection::GetProfileIndex(unsigned uid) {
- HashMap::Entry* entry = profiles_uids_.Lookup(reinterpret_cast<void*>(uid),
- static_cast<uint32_t>(uid),
- false);
- return entry != NULL ?
- static_cast<int>(reinterpret_cast<intptr_t>(entry->value)) : -1;
+ if (profile == NULL) return NULL;
+ profile->CalculateTotalTicks();
+ profile->SetActualSamplingRate(actual_sampling_rate);
+ finished_profiles_.Add(profile);
+ return profile;
}
@@ -724,74 +562,13 @@
void CpuProfilesCollection::RemoveProfile(CpuProfile* profile) {
// Called from VM thread for a completed profile.
unsigned uid = profile->uid();
- int index = GetProfileIndex(uid);
- if (index < 0) {
- detached_profiles_.RemoveElement(profile);
- return;
- }
- profiles_uids_.Remove(reinterpret_cast<void*>(uid),
- static_cast<uint32_t>(uid));
- // Decrement all indexes above the deleted one.
- for (HashMap::Entry* p = profiles_uids_.Start();
- p != NULL;
- p = profiles_uids_.Next(p)) {
- intptr_t p_index = reinterpret_cast<intptr_t>(p->value);
- if (p_index > index) {
- p->value = reinterpret_cast<void*>(p_index - 1);
+ for (int i = 0; i < finished_profiles_.length(); i++) {
+ if (uid == finished_profiles_[i]->uid()) {
+ finished_profiles_.Remove(i);
+ return;
}
}
- for (int i = 0; i < profiles_by_token_.length(); ++i) {
- List<CpuProfile*>* list = profiles_by_token_[i];
- if (list != NULL && index < list->length()) {
- // Move all filtered clones into detached_profiles_,
- // so we can know that they are still in use.
- CpuProfile* cloned_profile = list->Remove(index);
- if (cloned_profile != NULL && cloned_profile != profile) {
- detached_profiles_.Add(cloned_profile);
- }
- }
- }
-}
-
-
-int CpuProfilesCollection::TokenToIndex(int security_token_id) {
- ASSERT(TokenEnumerator::kNoSecurityToken == -1);
- return security_token_id + 1; // kNoSecurityToken -> 0, 0 -> 1, ...
-}
-
-
-List<CpuProfile*>* CpuProfilesCollection::GetProfilesList(
- int security_token_id) {
- const int index = TokenToIndex(security_token_id);
- const int lists_to_add = index - profiles_by_token_.length() + 1;
- if (lists_to_add > 0) profiles_by_token_.AddBlock(NULL, lists_to_add);
- List<CpuProfile*>* unabridged_list =
- profiles_by_token_[TokenToIndex(TokenEnumerator::kNoSecurityToken)];
- const int current_count = unabridged_list->length();
- if (profiles_by_token_[index] == NULL) {
- profiles_by_token_[index] = new List<CpuProfile*>(current_count);
- }
- List<CpuProfile*>* list = profiles_by_token_[index];
- const int profiles_to_add = current_count - list->length();
- if (profiles_to_add > 0) list->AddBlock(NULL, profiles_to_add);
- return list;
-}
-
-
-List<CpuProfile*>* CpuProfilesCollection::Profiles(int security_token_id) {
- List<CpuProfile*>* unabridged_list =
- profiles_by_token_[TokenToIndex(TokenEnumerator::kNoSecurityToken)];
- if (security_token_id == TokenEnumerator::kNoSecurityToken) {
- return unabridged_list;
- }
- List<CpuProfile*>* list = GetProfilesList(security_token_id);
- const int current_count = unabridged_list->length();
- for (int i = 0; i < current_count; ++i) {
- if (list->at(i) == NULL) {
- (*list)[i] = unabridged_list->at(i)->FilteredClone(security_token_id);
- }
- }
- return list;
+ UNREACHABLE();
}
@@ -811,13 +588,11 @@
CodeEntry* CpuProfilesCollection::NewCodeEntry(
Logger::LogEventsAndTags tag,
const char* name,
- int security_token_id,
const char* name_prefix,
const char* resource_name,
int line_number) {
CodeEntry* code_entry = new CodeEntry(tag,
name,
- security_token_id,
name_prefix,
resource_name,
line_number);
diff --git a/src/profile-generator.h b/src/profile-generator.h
index 411cbdb..6b02368 100644
--- a/src/profile-generator.h
+++ b/src/profile-generator.h
@@ -37,30 +37,6 @@
struct OffsetRange;
-class TokenEnumerator {
- public:
- TokenEnumerator();
- ~TokenEnumerator();
- int GetTokenId(Object* token);
-
- static const int kNoSecurityToken = -1;
- static const int kInheritsSecurityToken = -2;
-
- private:
- static void TokenRemovedCallback(v8::Isolate* isolate,
- v8::Persistent<v8::Value>* handle,
- void* parameter);
- void TokenRemoved(Object** token_location);
-
- List<Object**> token_locations_;
- List<bool> token_removed_;
-
- friend class TokenEnumeratorTester;
-
- DISALLOW_COPY_AND_ASSIGN(TokenEnumerator);
-};
-
-
// Provides a storage of strings allocated in C++ heap, to hold them
// forever, even if they disappear from JS heap or external storage.
class StringsStorage {
@@ -98,7 +74,6 @@
// CodeEntry doesn't own name strings, just references them.
INLINE(CodeEntry(Logger::LogEventsAndTags tag,
const char* name,
- int security_token_id = TokenEnumerator::kNoSecurityToken,
const char* name_prefix = CodeEntry::kEmptyNamePrefix,
const char* resource_name = CodeEntry::kEmptyResourceName,
int line_number = v8::CpuProfileNode::kNoLineNumberInfo));
@@ -113,7 +88,6 @@
INLINE(void set_shared_id(int shared_id)) { shared_id_ = shared_id; }
INLINE(int script_id() const) { return script_id_; }
INLINE(void set_script_id(int script_id)) { script_id_ = script_id; }
- INLINE(int security_token_id() const) { return security_token_id_; }
INLINE(static bool is_js_function_tag(Logger::LogEventsAndTags tag));
@@ -141,7 +115,6 @@
int line_number_;
int shared_id_;
int script_id_;
- int security_token_id_;
List<OffsetRange>* no_frame_ranges_;
DISALLOW_COPY_AND_ASSIGN(CodeEntry);
@@ -201,7 +174,6 @@
ProfileNode* AddPathFromEnd(const Vector<CodeEntry*>& path);
void AddPathFromStart(const Vector<CodeEntry*>& path);
void CalculateTotalTicks();
- void FilteredClone(ProfileTree* src, int security_token_id);
double TicksToMillis(unsigned ticks) const {
return ticks * ms_to_ticks_scale_;
@@ -238,7 +210,6 @@
void AddPath(const Vector<CodeEntry*>& path);
void CalculateTotalTicks();
void SetActualSamplingRate(double actual_sampling_rate);
- CpuProfile* FilteredClone(int security_token_id);
INLINE(const char* title() const) { return title_; }
INLINE(unsigned uid() const) { return uid_; }
@@ -315,10 +286,8 @@
~CpuProfilesCollection();
bool StartProfiling(const char* title, unsigned uid, bool record_samples);
- CpuProfile* StopProfiling(int security_token_id,
- const char* title,
- double actual_sampling_rate);
- List<CpuProfile*>* Profiles(int security_token_id);
+ CpuProfile* StopProfiling(const char* title, double actual_sampling_rate);
+ List<CpuProfile*>* profiles() { return &finished_profiles_; }
const char* GetName(Name* name) {
return function_and_resource_names_.GetName(name);
}
@@ -331,15 +300,12 @@
const char* GetFunctionName(const char* name) {
return function_and_resource_names_.GetFunctionName(name);
}
- CpuProfile* GetProfile(int security_token_id, unsigned uid);
bool IsLastProfile(const char* title);
void RemoveProfile(CpuProfile* profile);
- bool HasDetachedProfiles() { return detached_profiles_.length() > 0; }
CodeEntry* NewCodeEntry(
Logger::LogEventsAndTags tag,
const char* name,
- int security_token_id = TokenEnumerator::kNoSecurityToken,
const char* name_prefix = CodeEntry::kEmptyNamePrefix,
const char* resource_name = CodeEntry::kEmptyResourceName,
int line_number = v8::CpuProfileNode::kNoLineNumberInfo);
@@ -351,21 +317,9 @@
static const int kMaxSimultaneousProfiles = 100;
private:
- int GetProfileIndex(unsigned uid);
- List<CpuProfile*>* GetProfilesList(int security_token_id);
- int TokenToIndex(int security_token_id);
-
- INLINE(static bool UidsMatch(void* key1, void* key2)) {
- return key1 == key2;
- }
-
StringsStorage function_and_resource_names_;
List<CodeEntry*> code_entries_;
- List<List<CpuProfile*>* > profiles_by_token_;
- // Mapping from profiles' uids to indexes in the second nested list
- // of profiles_by_token_.
- HashMap profiles_uids_;
- List<CpuProfile*> detached_profiles_;
+ List<CpuProfile*> finished_profiles_;
// Accessed by VM thread and profile generator thread.
List<CpuProfile*> current_profiles_;
diff --git a/src/property-details.h b/src/property-details.h
index b0d10e1..ac36563 100644
--- a/src/property-details.h
+++ b/src/property-details.h
@@ -55,6 +55,8 @@
namespace internal {
class Smi;
+class Type;
+class TypeInfo;
// Type of properties.
// Order of properties is significant.
@@ -101,6 +103,10 @@
static Representation FromKind(Kind kind) { return Representation(kind); }
+ // TODO(rossberg): this should die eventually.
+ static Representation FromType(TypeInfo info);
+ static Representation FromType(Handle<Type> type);
+
bool Equals(const Representation& other) const {
return kind_ == other.kind_;
}
diff --git a/src/runtime.cc b/src/runtime.cc
index e3ee6d5..81018fe 100644
--- a/src/runtime.cc
+++ b/src/runtime.cc
@@ -467,7 +467,7 @@
constant_properties,
should_have_fast_elements,
has_function_literal);
- if (boilerplate.is_null()) return Failure::Exception();
+ RETURN_IF_EMPTY_HANDLE(isolate, boilerplate);
// Update the functions literal and return the boilerplate.
literals->set(literals_index, *boilerplate);
}
@@ -493,7 +493,7 @@
constant_properties,
should_have_fast_elements,
has_function_literal);
- if (boilerplate.is_null()) return Failure::Exception();
+ RETURN_IF_EMPTY_HANDLE(isolate, boilerplate);
// Update the functions literal and return the boilerplate.
literals->set(literals_index, *boilerplate);
}
@@ -514,7 +514,7 @@
ASSERT(*elements != isolate->heap()->empty_fixed_array());
boilerplate =
Runtime::CreateArrayLiteralBoilerplate(isolate, literals, elements);
- if (boilerplate.is_null()) return Failure::Exception();
+ RETURN_IF_EMPTY_HANDLE(isolate, boilerplate);
// Update the functions literal and return the boilerplate.
literals->set(literals_index, *boilerplate);
}
@@ -535,7 +535,7 @@
ASSERT(*elements != isolate->heap()->empty_fixed_array());
boilerplate =
Runtime::CreateArrayLiteralBoilerplate(isolate, literals, elements);
- if (boilerplate.is_null()) return Failure::Exception();
+ RETURN_IF_EMPTY_HANDLE(isolate, boilerplate);
// Update the functions literal and return the boilerplate.
literals->set(literals_index, *boilerplate);
}
@@ -796,6 +796,12 @@
CONVERT_ARG_HANDLE_CHECKED(Object, byte_offset_object, 3);
CONVERT_ARG_HANDLE_CHECKED(Object, byte_length_object, 4);
+ ASSERT(holder->GetInternalFieldCount() ==
+ v8::ArrayBufferView::kInternalFieldCount);
+ for (int i = 0; i < v8::ArrayBufferView::kInternalFieldCount; i++) {
+ holder->SetInternalField(i, Smi::FromInt(0));
+ }
+
ExternalArrayType arrayType;
size_t elementSize;
switch (arrayId) {
@@ -1012,6 +1018,12 @@
CONVERT_ARG_HANDLE_CHECKED(Object, byte_offset, 2);
CONVERT_ARG_HANDLE_CHECKED(Object, byte_length, 3);
+ ASSERT(holder->GetInternalFieldCount() ==
+ v8::ArrayBufferView::kInternalFieldCount);
+ for (int i = 0; i < v8::ArrayBufferView::kInternalFieldCount; i++) {
+ holder->SetInternalField(i, Smi::FromInt(0));
+ }
+
holder->set_buffer(*buffer);
ASSERT(byte_offset->IsNumber());
ASSERT(
@@ -1460,7 +1472,7 @@
GetPrototypeSkipHiddenPrototypes(isolate, *obj), isolate);
Handle<Object> result = JSObject::SetPrototype(obj, prototype, true);
- if (result.is_null()) return Failure::Exception();
+ RETURN_IF_EMPTY_HANDLE(isolate, result);
Handle<Object> new_value(
GetPrototypeSkipHiddenPrototypes(isolate, *obj), isolate);
@@ -1472,7 +1484,7 @@
return *result;
}
Handle<Object> result = JSObject::SetPrototype(obj, prototype, true);
- if (result.is_null()) return Failure::Exception();
+ RETURN_IF_EMPTY_HANDLE(isolate, result);
return *result;
}
@@ -1635,7 +1647,7 @@
elms->set(WRITABLE_INDEX, heap->ToBoolean((attrs & READ_ONLY) == 0));
// GetProperty does access check.
Handle<Object> value = GetProperty(isolate, obj, name);
- if (value.is_null()) return Failure::Exception();
+ RETURN_IF_EMPTY_HANDLE(isolate, value);
elms->set(VALUE_INDEX, *value);
} else {
// Access checks are performed for both accessors separately.
@@ -1700,7 +1712,7 @@
CONVERT_ARG_HANDLE_CHECKED(String, flags, 2);
Handle<Object> result =
RegExpImpl::Compile(re, pattern, flags);
- if (result.is_null()) return Failure::Exception();
+ RETURN_IF_EMPTY_HANDLE(isolate, result);
return *result;
}
@@ -2109,7 +2121,8 @@
} else if (lookup.IsNormal()) {
if (global->GetNormalizedProperty(&lookup)->IsTheHole() ||
!lookup.IsReadOnly()) {
- global->SetNormalizedProperty(&lookup, *value);
+ HandleScope scope(isolate);
+ JSObject::SetNormalizedProperty(Handle<JSObject>(global), &lookup, value);
}
} else {
// Ignore re-initialization of constants that have already been
@@ -2198,7 +2211,7 @@
}
} else if (lookup.IsNormal()) {
if (object->GetNormalizedProperty(&lookup)->IsTheHole()) {
- object->SetNormalizedProperty(&lookup, *value);
+ JSObject::SetNormalizedProperty(object, &lookup, value);
}
} else {
// We should not reach here. Any real, named property should be
@@ -2250,7 +2263,7 @@
subject,
index,
last_match_info);
- if (result.is_null()) return Failure::Exception();
+ RETURN_IF_EMPTY_HANDLE(isolate, result);
return *result;
}
@@ -4068,6 +4081,7 @@
return -1;
}
+
RUNTIME_FUNCTION(MaybeObject*, Runtime_StringLastIndexOf) {
HandleScope scope(isolate);
ASSERT(args.length() == 3);
@@ -4789,6 +4803,7 @@
return isolate->heap()->undefined_value();
}
+
// Implements part of 8.12.9 DefineOwnProperty.
// There are 3 cases that lead here:
// Step 4a - define a new data property.
@@ -7463,6 +7478,7 @@
return isolate->transcendental_cache()->Get(TranscendentalCache::LOG, x);
}
+
// Slow version of Math.pow. We check for fast paths for special cases.
// Used if SSE2/VFP3 is not available.
RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow) {
@@ -7485,6 +7501,7 @@
return isolate->heap()->AllocateHeapNumber(result);
}
+
// Fast version of Math.pow if we know that y is not an integer and y is not
// -0.5 or 0.5. Used as slow case from full codegen.
RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow_cfunction) {
@@ -8852,6 +8869,7 @@
MaybeObject* y;
};
+
static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
ObjectPair result = {x, y};
// Pointers x and y returned in rax and rdx, in AMD-x64-abi.
@@ -9377,7 +9395,7 @@
? ONLY_SINGLE_FUNCTION_LITERAL : NO_PARSE_RESTRICTION;
Handle<SharedFunctionInfo> shared = Compiler::CompileEval(
source, context, true, CLASSIC_MODE, restriction, RelocInfo::kNoPosition);
- if (shared.is_null()) return Failure::Exception();
+ RETURN_IF_EMPTY_HANDLE(isolate, shared);
Handle<JSFunction> fun =
isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
context,
@@ -9414,7 +9432,8 @@
language_mode,
NO_PARSE_RESTRICTION,
scope_position);
- if (shared.is_null()) return MakePair(Failure::Exception(), NULL);
+ RETURN_IF_EMPTY_HANDLE_VALUE(isolate, shared,
+ MakePair(Failure::Exception(), NULL));
Handle<JSFunction> compiled =
isolate->factory()->NewFunctionFromSharedFunctionInfo(
shared, context, NOT_TENURED);
@@ -10233,6 +10252,7 @@
return string;
}
+
// Moves all own elements of an object, that are below a limit, to positions
// starting at zero. All undefined values are placed after non-undefined values,
// and are followed by non-existing element. Does not change the length
@@ -11850,6 +11870,7 @@
return *isolate->factory()->NewJSArrayWithElements(details);
}
+
// Return an array with scope details
// args[0]: number: break id
// args[1]: number: frame index
@@ -12414,7 +12435,7 @@
CLASSIC_MODE,
NO_PARSE_RESTRICTION,
RelocInfo::kNoPosition);
- if (shared.is_null()) return Failure::Exception();
+ RETURN_IF_EMPTY_HANDLE(isolate, shared);
Handle<JSFunction> eval_fun =
isolate->factory()->NewFunctionFromSharedFunctionInfo(
@@ -12956,6 +12977,7 @@
return counter;
}
+
// For a script finds all SharedFunctionInfo's in the heap that points
// to this script. Returns JSArray of SharedFunctionInfo wrapped
// in OpaqueReferences.
@@ -13001,6 +13023,7 @@
return *result;
}
+
// For a script calculates compilation information about all its functions.
// The script source is explicitly specified by the second argument.
// The source of the actual script is not used, however it is important that
@@ -13027,6 +13050,7 @@
return result;
}
+
// Changes the source of the script to a new_source.
// If old_script_name is provided (i.e. is a String), also creates a copy of
// the script with its original source and sends notification to debugger.
@@ -13074,6 +13098,7 @@
return LiveEdit::ReplaceFunctionCode(new_compile_info, shared_info);
}
+
// Connects SharedFunctionInfo to another script.
RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditFunctionSetScript) {
HandleScope scope(isolate);
@@ -13148,6 +13173,7 @@
return *LiveEdit::CheckAndDropActivations(shared_array, do_drop);
}
+
// Compares 2 strings line-by-line, then token-wise and returns diff in form
// of JSArray of triplets (pos1, pos1_end, pos2_end) describing list
// of diff chunks.
diff --git a/src/runtime.js b/src/runtime.js
index 348fd74..90fb36b 100644
--- a/src/runtime.js
+++ b/src/runtime.js
@@ -587,7 +587,7 @@
if (IS_NUMBER(x)) return new $Number(x);
if (IS_BOOLEAN(x)) return new $Boolean(x);
if (IS_NULL_OR_UNDEFINED(x) && !IS_UNDETECTABLE(x)) {
- throw %MakeTypeError('null_to_object', []);
+ throw %MakeTypeError('undefined_or_null_to_object', []);
}
return x;
}
diff --git a/src/sampler.cc b/src/sampler.cc
index 982f252..e86cb68 100644
--- a/src/sampler.cc
+++ b/src/sampler.cc
@@ -668,6 +668,7 @@
delete data_;
}
+
void Sampler::Start() {
ASSERT(!IsActive());
SetActive(true);
@@ -681,6 +682,7 @@
SetActive(false);
}
+
void Sampler::SampleStack(const RegisterState& state) {
TickSample* sample = isolate_->cpu_profiler()->TickSampleEvent();
TickSample sample_obj;
diff --git a/src/scanner-character-streams.cc b/src/scanner-character-streams.cc
index 56b9f03..fb50345 100644
--- a/src/scanner-character-streams.cc
+++ b/src/scanner-character-streams.cc
@@ -46,6 +46,7 @@
buffer_end_ = buffer_;
}
+
BufferedUtf16CharacterStream::~BufferedUtf16CharacterStream() { }
void BufferedUtf16CharacterStream::PushBack(uc32 character) {
@@ -113,6 +114,7 @@
return BufferSeekForward(delta);
}
+
// ----------------------------------------------------------------------------
// GenericStringUtf16CharacterStream
diff --git a/src/spaces.cc b/src/spaces.cc
index 15381ea..5935c4a 100644
--- a/src/spaces.cc
+++ b/src/spaces.cc
@@ -914,6 +914,7 @@
chunk->IncrementLiveBytes(by);
}
+
// -----------------------------------------------------------------------------
// PagedSpace implementation
@@ -994,6 +995,7 @@
return Failure::Exception();
}
+
bool PagedSpace::CanExpand() {
ASSERT(max_capacity_ % AreaSize() == 0);
@@ -1868,6 +1870,7 @@
}
}
+
// Because the copying collector does not touch garbage objects, we iterate
// the new space before a collection to get a histogram of allocated objects.
// This only happens when --log-gc flag is set.
@@ -1961,6 +1964,7 @@
return size;
}
+
// -----------------------------------------------------------------------------
// Free lists for old object spaces implementation
diff --git a/src/string.js b/src/string.js
index 7e18687..cb82c16 100644
--- a/src/string.js
+++ b/src/string.js
@@ -185,7 +185,8 @@
if (IS_REGEXP(regexp)) {
// Emulate RegExp.prototype.exec's side effect in step 5, even though
// value is discarded.
- ToInteger(regexp.lastIndex);
+ var lastIndex = regexp.lastIndex;
+ TO_INTEGER_FOR_SIDE_EFFECT(lastIndex);
if (!regexp.global) return RegExpExecNoTests(regexp, subject, 0);
%_Log('regexp', 'regexp-match,%0S,%1r', [subject, regexp]);
// lastMatchInfo is defined in regexp.js.
@@ -236,7 +237,8 @@
if (IS_REGEXP(search)) {
// Emulate RegExp.prototype.exec's side effect in step 5, even if
// value is discarded.
- ToInteger(search.lastIndex);
+ var lastIndex = search.lastIndex;
+ TO_INTEGER_FOR_SIDE_EFFECT(lastIndex);
%_Log('regexp', 'regexp-replace,%0r,%1S', [search, subject]);
if (!IS_SPEC_FUNCTION(replace)) {
diff --git a/src/strtod.cc b/src/strtod.cc
index a1774b6..d332fd2 100644
--- a/src/strtod.cc
+++ b/src/strtod.cc
@@ -128,6 +128,7 @@
exponent + (buffer.length() - kMaxSignificantDecimalDigits);
}
+
// Reads digits from the buffer and converts them to a uint64.
// Reads in as many digits as fit into a uint64.
// When the string starts with "1844674407370955161" no further digit is read.
@@ -175,8 +176,7 @@
static bool DoubleStrtod(Vector<const char> trimmed,
int exponent,
double* result) {
-#if (V8_TARGET_ARCH_IA32 || defined(USE_SIMULATOR)) \
- && !defined(_MSC_VER)
+#if (V8_TARGET_ARCH_IA32 || defined(USE_SIMULATOR)) && !defined(_MSC_VER)
// On x86 the floating-point stack can be 64 or 80 bits wide. If it is
// 80 bits wide (as is the case on Linux) then double-rounding occurs and the
// result is not accurate.
diff --git a/src/stub-cache.cc b/src/stub-cache.cc
index 62ac2c8..0ccd5e6 100644
--- a/src/stub-cache.cc
+++ b/src/stub-cache.cc
@@ -499,15 +499,30 @@
Handle<Code> StubCache::ComputeStoreGlobal(Handle<Name> name,
Handle<GlobalObject> receiver,
Handle<PropertyCell> cell,
+ Handle<Object> value,
StrictModeFlag strict_mode) {
- Handle<Code> stub = FindIC(
- name, Handle<JSObject>::cast(receiver),
- Code::STORE_IC, Code::NORMAL, strict_mode);
- if (!stub.is_null()) return stub;
+ Isolate* isolate = cell->GetIsolate();
+ Handle<Type> union_type(PropertyCell::UpdateType(cell, value), isolate);
+ bool is_constant = union_type->IsConstant();
+ StoreGlobalStub stub(strict_mode, is_constant);
- StoreStubCompiler compiler(isolate_, strict_mode);
- Handle<Code> code = compiler.CompileStoreGlobal(receiver, cell, name);
+ Handle<Code> code = FindIC(
+ name, Handle<JSObject>::cast(receiver),
+ Code::STORE_IC, Code::NORMAL, stub.GetExtraICState());
+ if (!code.is_null()) return code;
+
+ if (is_constant) return stub.GetCode(isolate_);
+
+ // Replace the placeholder cell and global object map with the actual global
+ // cell and receiver map.
+ Handle<Map> cell_map(isolate_->heap()->global_property_cell_map());
+ Handle<Map> meta_map(isolate_->heap()->meta_map());
+ Handle<Object> receiver_map(receiver->map(), isolate_);
+ code = stub.GetCodeCopyFromTemplate(isolate_);
+ code->ReplaceNthObject(1, *meta_map, *receiver_map);
+ code->ReplaceNthObject(1, *cell_map, *cell);
JSObject::UpdateMapCodeCache(receiver, name, code);
+
return code;
}
@@ -922,12 +937,8 @@
if (!cached_ic.is_null()) return cached_ic;
}
- Handle<Code> ic = stub.GetCode(isolate_);
-
- // For monomorphic maps, use the code as a template, copying and replacing
- // the monomorphic map that checks the object's type.
- ic = isolate_->factory()->CopyCode(ic);
- ic->ReplaceFirstMap(*receiver_map);
+ Handle<Code> ic = stub.GetCodeCopyFromTemplate(isolate_);
+ ic->ReplaceNthObject(1, isolate_->heap()->meta_map(), *receiver_map);
if (!receiver_map->is_shared()) {
Map::UpdateCodeCache(receiver_map, name, ic);
@@ -2045,6 +2056,7 @@
}
}
+
CallOptimization::CallOptimization(Handle<JSFunction> function) {
Initialize(function);
}
diff --git a/src/stub-cache.h b/src/stub-cache.h
index 6d70d34..5317ce8 100644
--- a/src/stub-cache.h
+++ b/src/stub-cache.h
@@ -184,6 +184,7 @@
Handle<Code> ComputeStoreGlobal(Handle<Name> name,
Handle<GlobalObject> object,
Handle<PropertyCell> cell,
+ Handle<Object> value,
StrictModeFlag strict_mode);
Handle<Code> ComputeStoreCallback(Handle<Name> name,
diff --git a/src/type-info.cc b/src/type-info.cc
index 83eb9c4..e2be3aa 100644
--- a/src/type-info.cc
+++ b/src/type-info.cc
@@ -395,8 +395,7 @@
}
Handle<Code> code = Handle<Code>::cast(object);
ASSERT(code->is_unary_op_stub());
- return UnaryOpIC::TypeInfoToType(
- static_cast<UnaryOpIC::TypeInfo>(code->unary_op_type()), isolate());
+ return UnaryOpStub(code->extra_ic_state()).GetType(isolate());
}
@@ -698,4 +697,16 @@
#endif
}
+
+Representation Representation::FromType(TypeInfo info) {
+ if (info.IsUninitialized()) return Representation::None();
+ // TODO(verwaest): Return Smi rather than Integer32.
+ if (info.IsSmi()) return Representation::Integer32();
+ if (info.IsInteger32()) return Representation::Integer32();
+ if (info.IsDouble()) return Representation::Double();
+ if (info.IsNumber()) return Representation::Double();
+ return Representation::Tagged();
+}
+
+
} } // namespace v8::internal
diff --git a/src/type-info.h b/src/type-info.h
index a1c1f54..aa1f509 100644
--- a/src/type-info.h
+++ b/src/type-info.h
@@ -303,9 +303,9 @@
Maybe<int>* fixed_right_arg);
void CompareType(TypeFeedbackId id,
- Handle<Type>* left_type,
- Handle<Type>* right_type,
- Handle<Type>* combined_type);
+ Handle<Type>* left,
+ Handle<Type>* right,
+ Handle<Type>* combined);
Handle<Type> ClauseType(TypeFeedbackId id);
diff --git a/src/types.cc b/src/types.cc
index 1275dea..ed98480 100644
--- a/src/types.cc
+++ b/src/types.cc
@@ -318,6 +318,7 @@
return false;
}
+
// Get non-bitsets from this which are not subsumed by union, store at unioned,
// starting at index. Returns updated index.
int Type::ExtendUnion(Handle<Unioned> result, int current_size) {
@@ -476,4 +477,13 @@
: Union(type, Undefined()->handle_via_isolate_of(*type));
}
+
+Representation Representation::FromType(Handle<Type> type) {
+ if (type->Is(Type::None())) return Representation::None();
+ if (type->Is(Type::Signed32())) return Representation::Integer32();
+ if (type->Is(Type::Number())) return Representation::Double();
+ return Representation::Tagged();
+}
+
+
} } // namespace v8::internal
diff --git a/src/typing.cc b/src/typing.cc
index 7c11612..3f3ff60 100644
--- a/src/typing.cc
+++ b/src/typing.cc
@@ -432,13 +432,13 @@
CHECK_ALIVE(Visit(expr->right()));
// Collect type feedback.
- Handle<Type> left_type, right_type, result_type;
+ Handle<Type> type, left_type, right_type;
Maybe<int> fixed_right_arg;
oracle()->BinaryType(expr->BinaryOperationFeedbackId(),
- &left_type, &right_type, &result_type, &fixed_right_arg);
+ &left_type, &right_type, &type, &fixed_right_arg);
+ MergeLowerType(expr, type);
MergeLowerType(expr->left(), left_type);
MergeLowerType(expr->right(), right_type);
- expr->set_result_type(result_type);
expr->set_fixed_right_arg(fixed_right_arg);
if (expr->op() == Token::OR || expr->op() == Token::AND) {
expr->left()->RecordToBooleanTypeFeedback(oracle());
diff --git a/src/unicode.cc b/src/unicode.cc
index 04065b0..bd32467 100644
--- a/src/unicode.cc
+++ b/src/unicode.cc
@@ -52,14 +52,17 @@
return table[D * index];
}
+
static inline uchar GetEntry(int32_t entry) {
return entry & (kStartBit - 1);
}
+
static inline bool IsStart(int32_t entry) {
return (entry & kStartBit) != 0;
}
+
/**
* Look up a character in the unicode table using a mix of binary and
* interpolation search. For a uniformly distributed array
@@ -106,6 +109,7 @@
uchar chars[kW];
};
+
// Look up the mapping for the given character in the specified table,
// which is of the specified length and uses the specified special case
// mapping for multi-char mappings. The next parameter is the character
@@ -456,6 +460,7 @@
}
}
+
// Lowercase: point.category == 'Ll'
static const uint16_t kLowercaseTable0Size = 463;
@@ -567,6 +572,7 @@
}
}
+
// Letter: point.category in ['Lu', 'Ll', 'Lt', 'Lm', 'Lo', 'Nl' ]
static const uint16_t kLetterTable0Size = 435;
@@ -703,6 +709,7 @@
}
}
+
// Space: point.category == 'Zs'
static const uint16_t kSpaceTable0Size = 4;
@@ -724,6 +731,7 @@
}
}
+
// Number: point.category == 'Nd'
static const uint16_t kNumberTable0Size = 56;
@@ -758,6 +766,7 @@
}
}
+
// WhiteSpace: 'Ws' in point.properties
static const uint16_t kWhiteSpaceTable0Size = 7;
@@ -779,6 +788,7 @@
}
}
+
// LineTerminator: 'Lt' in point.properties
static const uint16_t kLineTerminatorTable0Size = 2;
@@ -800,6 +810,7 @@
}
}
+
// CombiningMark: point.category in ['Mn', 'Mc']
static const uint16_t kCombiningMarkTable0Size = 258;
@@ -871,6 +882,7 @@
}
}
+
// ConnectorPunctuation: point.category == 'Pc'
static const uint16_t kConnectorPunctuationTable0Size = 1;
diff --git a/src/v8-counters.cc b/src/v8-counters.cc
index ca83e38..b3e15bb 100644
--- a/src/v8-counters.cc
+++ b/src/v8-counters.cc
@@ -78,6 +78,7 @@
#undef SC
}
+
void Counters::ResetHistograms() {
#define HT(name, caption) name##_.Reset();
HISTOGRAM_TIMER_LIST(HT)
diff --git a/src/v8.cc b/src/v8.cc
index cb67105..cfec0c0 100644
--- a/src/v8.cc
+++ b/src/v8.cc
@@ -263,6 +263,7 @@
return heap_number;
}
+
void V8::InitializeOncePerProcessImpl() {
FlagList::EnforceFlagImplications();
if (FLAG_stress_compaction) {
@@ -323,6 +324,7 @@
Bootstrapper::InitializeOncePerProcess();
}
+
void V8::InitializeOncePerProcess() {
CallOnce(&init_once, &InitializeOncePerProcessImpl);
}
diff --git a/src/v8threads.cc b/src/v8threads.cc
index 925e198..2df187a 100644
--- a/src/v8threads.cc
+++ b/src/v8threads.cc
@@ -388,6 +388,7 @@
return data != NULL && data->thread_state() != NULL;
}
+
void ThreadManager::Iterate(ObjectVisitor* v) {
// Expecting no threads during serialization/deserialization
for (ThreadState* state = FirstThreadStateInUse();
diff --git a/src/version.cc b/src/version.cc
index 0041c67..4ded5d2 100644
--- a/src/version.cc
+++ b/src/version.cc
@@ -34,7 +34,7 @@
// system so their names cannot be changed without changing the scripts.
#define MAJOR_VERSION 3
#define MINOR_VERSION 20
-#define BUILD_NUMBER 2
+#define BUILD_NUMBER 3
#define PATCH_LEVEL 0
// Use 1 for candidates and 0 otherwise.
// (Boolean macro values are not supported by all preprocessors.)
diff --git a/src/x64/assembler-x64.cc b/src/x64/assembler-x64.cc
index 3a3ee9c..aaab839 100644
--- a/src/x64/assembler-x64.cc
+++ b/src/x64/assembler-x64.cc
@@ -902,11 +902,13 @@
emit(0xF8);
}
+
void Assembler::cld() {
EnsureSpace ensure_space(this);
emit(0xFC);
}
+
void Assembler::cdq() {
EnsureSpace ensure_space(this);
emit(0x99);
@@ -2522,6 +2524,7 @@
emit(b2 + i);
}
+
// SSE 2 operations.
void Assembler::movd(XMMRegister dst, Register src) {
@@ -2582,6 +2585,7 @@
}
}
+
void Assembler::movdqa(const Operand& dst, XMMRegister src) {
EnsureSpace ensure_space(this);
emit(0x66);
@@ -3035,10 +3039,12 @@
emit(0xC0 | (dst.low_bits() << 3) | src.low_bits());
}
+
void Assembler::emit_sse_operand(XMMRegister dst, Register src) {
emit(0xC0 | (dst.low_bits() << 3) | src.low_bits());
}
+
void Assembler::emit_sse_operand(Register dst, XMMRegister src) {
emit(0xC0 | (dst.low_bits() << 3) | src.low_bits());
}
@@ -3075,6 +3081,7 @@
reloc_info_writer.Write(&rinfo);
}
+
void Assembler::RecordJSReturn() {
positions_recorder()->WriteRecordedPositions();
EnsureSpace ensure_space(this);
diff --git a/src/x64/builtins-x64.cc b/src/x64/builtins-x64.cc
index 2b44a77..c1a2ed7 100644
--- a/src/x64/builtins-x64.cc
+++ b/src/x64/builtins-x64.cc
@@ -726,6 +726,7 @@
__ Abort("no cases left");
}
+
void Builtins::Generate_NotifyDeoptimized(MacroAssembler* masm) {
Generate_NotifyDeoptimizedHelper(masm, Deoptimizer::EAGER);
}
diff --git a/src/x64/code-stubs-x64.cc b/src/x64/code-stubs-x64.cc
index 9233848..e4136ba 100644
--- a/src/x64/code-stubs-x64.cc
+++ b/src/x64/code-stubs-x64.cc
@@ -1,4 +1,4 @@
-// Copyright 2012 the V8 project authors. All rights reserved.
+// Copyright 2013 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
@@ -222,7 +222,29 @@
descriptor->deoptimization_handler_ =
FUNCTION_ADDR(ToBooleanIC_Miss);
descriptor->SetMissHandler(
- ExternalReference(IC_Utility(IC::kToBooleanIC_Miss), isolate));
+ ExternalReference(IC_Utility(IC::kToBooleanIC_Miss), isolate));
+}
+
+
+void UnaryOpStub::InitializeInterfaceDescriptor(
+ Isolate* isolate,
+ CodeStubInterfaceDescriptor* descriptor) {
+ static Register registers[] = { rax };
+ descriptor->register_param_count_ = 1;
+ descriptor->register_params_ = registers;
+ descriptor->deoptimization_handler_ =
+ FUNCTION_ADDR(UnaryOpIC_Miss);
+}
+
+
+void StoreGlobalStub::InitializeInterfaceDescriptor(
+ Isolate* isolate,
+ CodeStubInterfaceDescriptor* descriptor) {
+ static Register registers[] = { rdx, rcx, rax };
+ descriptor->register_param_count_ = 3;
+ descriptor->register_params_ = registers;
+ descriptor->deoptimization_handler_ =
+ FUNCTION_ADDR(StoreIC_MissFromStubFailure);
}
@@ -643,259 +665,6 @@
}
-void UnaryOpStub::Generate(MacroAssembler* masm) {
- switch (operand_type_) {
- case UnaryOpIC::UNINITIALIZED:
- GenerateTypeTransition(masm);
- break;
- case UnaryOpIC::SMI:
- GenerateSmiStub(masm);
- break;
- case UnaryOpIC::NUMBER:
- GenerateNumberStub(masm);
- break;
- case UnaryOpIC::GENERIC:
- GenerateGenericStub(masm);
- break;
- }
-}
-
-
-void UnaryOpStub::GenerateTypeTransition(MacroAssembler* masm) {
- __ pop(rcx); // Save return address.
-
- __ push(rax); // the operand
- __ Push(Smi::FromInt(op_));
- __ Push(Smi::FromInt(mode_));
- __ Push(Smi::FromInt(operand_type_));
-
- __ push(rcx); // Push return address.
-
- // Patch the caller to an appropriate specialized stub and return the
- // operation result to the caller of the stub.
- __ TailCallExternalReference(
- ExternalReference(IC_Utility(IC::kUnaryOp_Patch), masm->isolate()), 4, 1);
-}
-
-
-// TODO(svenpanne): Use virtual functions instead of switch.
-void UnaryOpStub::GenerateSmiStub(MacroAssembler* masm) {
- switch (op_) {
- case Token::SUB:
- GenerateSmiStubSub(masm);
- break;
- case Token::BIT_NOT:
- GenerateSmiStubBitNot(masm);
- break;
- default:
- UNREACHABLE();
- }
-}
-
-
-void UnaryOpStub::GenerateSmiStubSub(MacroAssembler* masm) {
- Label slow;
- GenerateSmiCodeSub(masm, &slow, &slow, Label::kNear, Label::kNear);
- __ bind(&slow);
- GenerateTypeTransition(masm);
-}
-
-
-void UnaryOpStub::GenerateSmiStubBitNot(MacroAssembler* masm) {
- Label non_smi;
- GenerateSmiCodeBitNot(masm, &non_smi, Label::kNear);
- __ bind(&non_smi);
- GenerateTypeTransition(masm);
-}
-
-
-void UnaryOpStub::GenerateSmiCodeSub(MacroAssembler* masm,
- Label* non_smi,
- Label* slow,
- Label::Distance non_smi_near,
- Label::Distance slow_near) {
- Label done;
- __ JumpIfNotSmi(rax, non_smi, non_smi_near);
- __ SmiNeg(rax, rax, &done, Label::kNear);
- __ jmp(slow, slow_near);
- __ bind(&done);
- __ ret(0);
-}
-
-
-void UnaryOpStub::GenerateSmiCodeBitNot(MacroAssembler* masm,
- Label* non_smi,
- Label::Distance non_smi_near) {
- __ JumpIfNotSmi(rax, non_smi, non_smi_near);
- __ SmiNot(rax, rax);
- __ ret(0);
-}
-
-
-// TODO(svenpanne): Use virtual functions instead of switch.
-void UnaryOpStub::GenerateNumberStub(MacroAssembler* masm) {
- switch (op_) {
- case Token::SUB:
- GenerateNumberStubSub(masm);
- break;
- case Token::BIT_NOT:
- GenerateNumberStubBitNot(masm);
- break;
- default:
- UNREACHABLE();
- }
-}
-
-
-void UnaryOpStub::GenerateNumberStubSub(MacroAssembler* masm) {
- Label non_smi, slow, call_builtin;
- GenerateSmiCodeSub(masm, &non_smi, &call_builtin, Label::kNear);
- __ bind(&non_smi);
- GenerateHeapNumberCodeSub(masm, &slow);
- __ bind(&slow);
- GenerateTypeTransition(masm);
- __ bind(&call_builtin);
- GenerateGenericCodeFallback(masm);
-}
-
-
-void UnaryOpStub::GenerateNumberStubBitNot(
- MacroAssembler* masm) {
- Label non_smi, slow;
- GenerateSmiCodeBitNot(masm, &non_smi, Label::kNear);
- __ bind(&non_smi);
- GenerateHeapNumberCodeBitNot(masm, &slow);
- __ bind(&slow);
- GenerateTypeTransition(masm);
-}
-
-
-void UnaryOpStub::GenerateHeapNumberCodeSub(MacroAssembler* masm,
- Label* slow) {
- // Check if the operand is a heap number.
- __ CompareRoot(FieldOperand(rax, HeapObject::kMapOffset),
- Heap::kHeapNumberMapRootIndex);
- __ j(not_equal, slow);
-
- // Operand is a float, negate its value by flipping the sign bit.
- if (mode_ == UNARY_OVERWRITE) {
- __ Set(kScratchRegister, 0x01);
- __ shl(kScratchRegister, Immediate(63));
- __ xor_(FieldOperand(rax, HeapNumber::kValueOffset), kScratchRegister);
- } else {
- // Allocate a heap number before calculating the answer,
- // so we don't have an untagged double around during GC.
- Label slow_allocate_heapnumber, heapnumber_allocated;
- __ AllocateHeapNumber(rcx, rbx, &slow_allocate_heapnumber);
- __ jmp(&heapnumber_allocated);
-
- __ bind(&slow_allocate_heapnumber);
- {
- FrameScope scope(masm, StackFrame::INTERNAL);
- __ push(rax);
- __ CallRuntime(Runtime::kNumberAlloc, 0);
- __ movq(rcx, rax);
- __ pop(rax);
- }
- __ bind(&heapnumber_allocated);
- // rcx: allocated 'empty' number
-
- // Copy the double value to the new heap number, flipping the sign.
- __ movq(rdx, FieldOperand(rax, HeapNumber::kValueOffset));
- __ Set(kScratchRegister, 0x01);
- __ shl(kScratchRegister, Immediate(63));
- __ xor_(rdx, kScratchRegister); // Flip sign.
- __ movq(FieldOperand(rcx, HeapNumber::kValueOffset), rdx);
- __ movq(rax, rcx);
- }
- __ ret(0);
-}
-
-
-void UnaryOpStub::GenerateHeapNumberCodeBitNot(MacroAssembler* masm,
- Label* slow) {
- // Check if the operand is a heap number.
- __ CompareRoot(FieldOperand(rax, HeapObject::kMapOffset),
- Heap::kHeapNumberMapRootIndex);
- __ j(not_equal, slow);
-
- // Convert the heap number in rax to an untagged integer in rcx.
- IntegerConvert(masm, rax, rax);
-
- // Do the bitwise operation and smi tag the result.
- __ notl(rax);
- __ Integer32ToSmi(rax, rax);
- __ ret(0);
-}
-
-
-// TODO(svenpanne): Use virtual functions instead of switch.
-void UnaryOpStub::GenerateGenericStub(MacroAssembler* masm) {
- switch (op_) {
- case Token::SUB:
- GenerateGenericStubSub(masm);
- break;
- case Token::BIT_NOT:
- GenerateGenericStubBitNot(masm);
- break;
- default:
- UNREACHABLE();
- }
-}
-
-
-void UnaryOpStub::GenerateGenericStubSub(MacroAssembler* masm) {
- Label non_smi, slow;
- GenerateSmiCodeSub(masm, &non_smi, &slow, Label::kNear);
- __ bind(&non_smi);
- GenerateHeapNumberCodeSub(masm, &slow);
- __ bind(&slow);
- GenerateGenericCodeFallback(masm);
-}
-
-
-void UnaryOpStub::GenerateGenericStubBitNot(MacroAssembler* masm) {
- Label non_smi, slow;
- GenerateSmiCodeBitNot(masm, &non_smi, Label::kNear);
- __ bind(&non_smi);
- GenerateHeapNumberCodeBitNot(masm, &slow);
- __ bind(&slow);
- GenerateGenericCodeFallback(masm);
-}
-
-
-void UnaryOpStub::GenerateGenericCodeFallback(MacroAssembler* masm) {
- // Handle the slow case by jumping to the JavaScript builtin.
- __ pop(rcx); // pop return address
- __ push(rax);
- __ push(rcx); // push return address
- switch (op_) {
- case Token::SUB:
- __ InvokeBuiltin(Builtins::UNARY_MINUS, JUMP_FUNCTION);
- break;
- case Token::BIT_NOT:
- __ InvokeBuiltin(Builtins::BIT_NOT, JUMP_FUNCTION);
- break;
- default:
- UNREACHABLE();
- }
-}
-
-
-void UnaryOpStub::PrintName(StringStream* stream) {
- const char* op_name = Token::Name(op_);
- const char* overwrite_name = NULL; // Make g++ happy.
- switch (mode_) {
- case UNARY_NO_OVERWRITE: overwrite_name = "Alloc"; break;
- case UNARY_OVERWRITE: overwrite_name = "Overwrite"; break;
- }
- stream->Add("UnaryOpStub_%s_%s_%s",
- op_name,
- overwrite_name,
- UnaryOpIC::GetName(operand_type_));
-}
-
-
void BinaryOpStub::Initialize() {}
@@ -5328,6 +5097,7 @@
__ bind(&hash_not_zero);
}
+
void SubStringStub::Generate(MacroAssembler* masm) {
Label runtime;
diff --git a/src/x64/code-stubs-x64.h b/src/x64/code-stubs-x64.h
index f6cfad0..228a82a 100644
--- a/src/x64/code-stubs-x64.h
+++ b/src/x64/code-stubs-x64.h
@@ -81,77 +81,6 @@
};
-class UnaryOpStub: public PlatformCodeStub {
- public:
- UnaryOpStub(Token::Value op,
- UnaryOverwriteMode mode,
- UnaryOpIC::TypeInfo operand_type = UnaryOpIC::UNINITIALIZED)
- : op_(op),
- mode_(mode),
- operand_type_(operand_type) {
- }
-
- private:
- Token::Value op_;
- UnaryOverwriteMode mode_;
-
- // Operand type information determined at runtime.
- UnaryOpIC::TypeInfo operand_type_;
-
- virtual void PrintName(StringStream* stream);
-
- class ModeBits: public BitField<UnaryOverwriteMode, 0, 1> {};
- class OpBits: public BitField<Token::Value, 1, 7> {};
- class OperandTypeInfoBits: public BitField<UnaryOpIC::TypeInfo, 8, 3> {};
-
- Major MajorKey() { return UnaryOp; }
- int MinorKey() {
- return ModeBits::encode(mode_)
- | OpBits::encode(op_)
- | OperandTypeInfoBits::encode(operand_type_);
- }
-
- // Note: A lot of the helper functions below will vanish when we use virtual
- // function instead of switch more often.
- void Generate(MacroAssembler* masm);
-
- void GenerateTypeTransition(MacroAssembler* masm);
-
- void GenerateSmiStub(MacroAssembler* masm);
- void GenerateSmiStubSub(MacroAssembler* masm);
- void GenerateSmiStubBitNot(MacroAssembler* masm);
- void GenerateSmiCodeSub(MacroAssembler* masm,
- Label* non_smi,
- Label* slow,
- Label::Distance non_smi_near = Label::kFar,
- Label::Distance slow_near = Label::kFar);
- void GenerateSmiCodeBitNot(MacroAssembler* masm,
- Label* non_smi,
- Label::Distance non_smi_near);
-
- void GenerateNumberStub(MacroAssembler* masm);
- void GenerateNumberStubSub(MacroAssembler* masm);
- void GenerateNumberStubBitNot(MacroAssembler* masm);
- void GenerateHeapNumberCodeSub(MacroAssembler* masm, Label* slow);
- void GenerateHeapNumberCodeBitNot(MacroAssembler* masm, Label* slow);
-
- void GenerateGenericStub(MacroAssembler* masm);
- void GenerateGenericStubSub(MacroAssembler* masm);
- void GenerateGenericStubBitNot(MacroAssembler* masm);
- void GenerateGenericCodeFallback(MacroAssembler* masm);
-
- virtual Code::Kind GetCodeKind() const { return Code::UNARY_OP_IC; }
-
- virtual InlineCacheState GetICState() {
- return UnaryOpIC::ToState(operand_type_);
- }
-
- virtual void FinishCode(Handle<Code> code) {
- code->set_unary_op_type(operand_type_);
- }
-};
-
-
class StringHelper : public AllStatic {
public:
// Generate code for copying characters using a simple loop. This should only
diff --git a/src/x64/disasm-x64.cc b/src/x64/disasm-x64.cc
index d787775..eefa703 100644
--- a/src/x64/disasm-x64.cc
+++ b/src/x64/disasm-x64.cc
@@ -49,6 +49,7 @@
BYTE_OPER_REG_OP_ORDER = OPER_REG_OP_ORDER | BYTE_SIZE_OPERAND_FLAG
};
+
//------------------------------------------------------------------
// Tables
//------------------------------------------------------------------
@@ -293,6 +294,7 @@
{"cmovg", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false}
};
+
//------------------------------------------------------------------------------
// DisassemblerX64 implementation.
@@ -301,6 +303,7 @@
ABORT_ON_UNIMPLEMENTED_OPCODE
};
+
// A new DisassemblerX64 object is created to disassemble each instruction.
// The object can only disassemble a single instruction.
class DisassemblerX64 {
@@ -1763,6 +1766,7 @@
return instr_len;
}
+
//------------------------------------------------------------------------------
@@ -1822,6 +1826,7 @@
return "";
}
+
//------------------------------------------------------------------------------
Disassembler::Disassembler(const NameConverter& converter)
diff --git a/src/x64/full-codegen-x64.cc b/src/x64/full-codegen-x64.cc
index 9ad7f58..66bc38b 100644
--- a/src/x64/full-codegen-x64.cc
+++ b/src/x64/full-codegen-x64.cc
@@ -4353,10 +4353,7 @@
const char* comment) {
// TODO(svenpanne): Allowing format strings in Comment would be nice here...
Comment cmt(masm_, comment);
- bool can_overwrite = expr->expression()->ResultOverwriteAllowed();
- UnaryOverwriteMode overwrite =
- can_overwrite ? UNARY_OVERWRITE : UNARY_NO_OVERWRITE;
- UnaryOpStub stub(expr->op(), overwrite);
+ UnaryOpStub stub(expr->op());
// UnaryOpStub expects the argument to be in the
// accumulator register rax.
VisitForAccumulatorValue(expr->expression());
diff --git a/src/x64/lithium-codegen-x64.cc b/src/x64/lithium-codegen-x64.cc
index de43f86..8a2a086 100644
--- a/src/x64/lithium-codegen-x64.cc
+++ b/src/x64/lithium-codegen-x64.cc
@@ -1834,12 +1834,12 @@
template<class InstrType>
void LCodeGen::EmitBranch(InstrType instr, Condition cc) {
- int right_block = instr->FalseDestination(chunk_);
int left_block = instr->TrueDestination(chunk_);
+ int right_block = instr->FalseDestination(chunk_);
int next_block = GetNextEmittedBlock();
- if (right_block == left_block) {
+ if (right_block == left_block || cc == no_condition) {
EmitGoto(left_block);
} else if (left_block == next_block) {
__ j(NegateCondition(cc), chunk_->GetAssemblyLabel(right_block));
@@ -1859,6 +1859,25 @@
}
+void LCodeGen::DoIsNumberAndBranch(LIsNumberAndBranch* instr) {
+ Representation r = instr->hydrogen()->value()->representation();
+ if (r.IsSmiOrInteger32() || r.IsDouble()) {
+ EmitBranch(instr, no_condition);
+ } else {
+ ASSERT(r.IsTagged());
+ Register reg = ToRegister(instr->value());
+ HType type = instr->hydrogen()->value()->type();
+ if (type.IsTaggedNumber()) {
+ EmitBranch(instr, no_condition);
+ }
+ __ JumpIfSmi(reg, instr->TrueLabel(chunk_));
+ __ CompareRoot(FieldOperand(reg, HeapObject::kMapOffset),
+ Heap::kHeapNumberMapRootIndex);
+ EmitBranch(instr, equal);
+ }
+}
+
+
void LCodeGen::DoBranch(LBranch* instr) {
Representation r = instr->hydrogen()->value()->representation();
if (r.IsInteger32()) {
@@ -2027,7 +2046,7 @@
}
-void LCodeGen::DoCmpIDAndBranch(LCmpIDAndBranch* instr) {
+void LCodeGen::DoCompareNumericAndBranch(LCompareNumericAndBranch* instr) {
LOperand* left = instr->left();
LOperand* right = instr->right();
Condition cc = TokenToCondition(instr->op(), instr->is_double());
diff --git a/src/x64/lithium-gap-resolver-x64.cc b/src/x64/lithium-gap-resolver-x64.cc
index aed4f36..adb1afa 100644
--- a/src/x64/lithium-gap-resolver-x64.cc
+++ b/src/x64/lithium-gap-resolver-x64.cc
@@ -202,6 +202,20 @@
} else {
__ LoadObject(dst, cgen_->ToHandle(constant_source));
}
+ } else if (destination->IsDoubleRegister()) {
+ double v = cgen_->ToDouble(constant_source);
+ uint64_t int_val = BitCast<uint64_t, double>(v);
+ int32_t lower = static_cast<int32_t>(int_val);
+ int32_t upper = static_cast<int32_t>(int_val >> (kBitsPerInt));
+ XMMRegister dst = cgen_->ToDoubleRegister(destination);
+ if (int_val == 0) {
+ __ xorps(dst, dst);
+ } else {
+ __ push(Immediate(upper));
+ __ push(Immediate(lower));
+ __ movsd(dst, Operand(rsp, 0));
+ __ addq(rsp, Immediate(kDoubleSize));
+ }
} else {
ASSERT(destination->IsStackSlot());
Operand dst = cgen_->ToOperand(destination);
diff --git a/src/x64/lithium-x64.cc b/src/x64/lithium-x64.cc
index 95a44f0..950bf4d 100644
--- a/src/x64/lithium-x64.cc
+++ b/src/x64/lithium-x64.cc
@@ -185,7 +185,7 @@
}
-void LCmpIDAndBranch::PrintDataTo(StringStream* stream) {
+void LCompareNumericAndBranch::PrintDataTo(StringStream* stream) {
stream->Add("if ");
left()->PrintTo(stream);
stream->Add(" %s ", Token::String(op()));
@@ -1168,6 +1168,7 @@
return AssignEnvironment(DefineAsRegister(result));
}
+
LInstruction* LChunkBuilder::DoMathAbs(HUnaryMathOperation* instr) {
LOperand* input = UseRegisterAtStart(instr->value());
LMathAbs* result = new(zone()) LMathAbs(input);
@@ -1598,8 +1599,8 @@
}
-LInstruction* LChunkBuilder::DoCompareIDAndBranch(
- HCompareIDAndBranch* instr) {
+LInstruction* LChunkBuilder::DoCompareNumericAndBranch(
+ HCompareNumericAndBranch* instr) {
Representation r = instr->representation();
if (r.IsSmiOrInteger32()) {
ASSERT(instr->left()->representation().IsSmiOrInteger32());
@@ -1607,7 +1608,7 @@
instr->right()->representation()));
LOperand* left = UseRegisterOrConstantAtStart(instr->left());
LOperand* right = UseOrConstantAtStart(instr->right());
- return new(zone()) LCmpIDAndBranch(left, right);
+ return new(zone()) LCompareNumericAndBranch(left, right);
} else {
ASSERT(r.IsDouble());
ASSERT(instr->left()->representation().IsDouble());
@@ -1621,7 +1622,7 @@
left = UseRegisterAtStart(instr->left());
right = UseRegisterAtStart(instr->right());
}
- return new(zone()) LCmpIDAndBranch(left, right);
+ return new(zone()) LCompareNumericAndBranch(left, right);
}
}
@@ -1911,6 +1912,18 @@
}
+LInstruction* LChunkBuilder::DoCheckSmi(HCheckSmi* instr) {
+ LOperand* value = UseRegisterAtStart(instr->value());
+ return AssignEnvironment(new(zone()) LCheckSmi(value));
+}
+
+
+LInstruction* LChunkBuilder::DoIsNumberAndBranch(HIsNumberAndBranch* instr) {
+ return new(zone()) LIsNumberAndBranch(
+ UseRegisterOrConstantAtStart(instr->value()));
+}
+
+
LInstruction* LChunkBuilder::DoCheckInstanceType(HCheckInstanceType* instr) {
LOperand* value = UseRegisterAtStart(instr->value());
LCheckInstanceType* result = new(zone()) LCheckInstanceType(value);
diff --git a/src/x64/lithium-x64.h b/src/x64/lithium-x64.h
index a7530be..6efa9d3 100644
--- a/src/x64/lithium-x64.h
+++ b/src/x64/lithium-x64.h
@@ -81,7 +81,7 @@
V(ClampTToUint8) \
V(ClassOfTestAndBranch) \
V(CmpConstantEqAndBranch) \
- V(CmpIDAndBranch) \
+ V(CompareNumericAndBranch) \
V(CmpObjectEqAndBranch) \
V(CmpMapAndBranch) \
V(CmpT) \
@@ -120,6 +120,7 @@
V(IsObjectAndBranch) \
V(IsStringAndBranch) \
V(IsSmiAndBranch) \
+ V(IsNumberAndBranch) \
V(IsUndetectableAndBranch) \
V(Label) \
V(LazyBailout) \
@@ -672,9 +673,9 @@
};
-class LCmpIDAndBranch: public LControlInstruction<2, 0> {
+class LCompareNumericAndBranch: public LControlInstruction<2, 0> {
public:
- LCmpIDAndBranch(LOperand* left, LOperand* right) {
+ LCompareNumericAndBranch(LOperand* left, LOperand* right) {
inputs_[0] = left;
inputs_[1] = right;
}
@@ -682,8 +683,9 @@
LOperand* left() { return inputs_[0]; }
LOperand* right() { return inputs_[1]; }
- DECLARE_CONCRETE_INSTRUCTION(CmpIDAndBranch, "cmp-id-and-branch")
- DECLARE_HYDROGEN_ACCESSOR(CompareIDAndBranch)
+ DECLARE_CONCRETE_INSTRUCTION(CompareNumericAndBranch,
+ "compare-numeric-and-branch")
+ DECLARE_HYDROGEN_ACCESSOR(CompareNumericAndBranch)
Token::Value op() const { return hydrogen()->token(); }
bool is_double() const {
@@ -866,6 +868,19 @@
};
+class LIsNumberAndBranch: public LControlInstruction<1, 0> {
+ public:
+ explicit LIsNumberAndBranch(LOperand* value) {
+ inputs_[0] = value;
+ }
+
+ LOperand* value() { return inputs_[0]; }
+
+ DECLARE_CONCRETE_INSTRUCTION(IsNumberAndBranch, "is-number-and-branch")
+ DECLARE_HYDROGEN_ACCESSOR(IsNumberAndBranch)
+};
+
+
class LIsStringAndBranch: public LControlInstruction<1, 1> {
public:
explicit LIsStringAndBranch(LOperand* value, LOperand* temp) {
diff --git a/src/x64/macro-assembler-x64.cc b/src/x64/macro-assembler-x64.cc
index e5bee67..d2db523 100644
--- a/src/x64/macro-assembler-x64.cc
+++ b/src/x64/macro-assembler-x64.cc
@@ -972,6 +972,7 @@
}
}
+
void MacroAssembler::Set(const Operand& dst, int64_t x) {
if (is_int32(x)) {
movq(dst, Immediate(static_cast<int32_t>(x)));
@@ -1029,6 +1030,7 @@
return kScratchRegister;
}
+
void MacroAssembler::LoadSmiConstant(Register dst, Smi* source) {
if (emit_debug_code()) {
movq(dst,
@@ -3897,52 +3899,8 @@
Label* gc_required,
AllocationFlags flags) {
ASSERT((flags & SIZE_IN_WORDS) == 0);
- if (!FLAG_inline_new) {
- if (emit_debug_code()) {
- // Trash the registers to simulate an allocation failure.
- movl(result, Immediate(0x7091));
- movl(result_end, Immediate(0x7191));
- if (scratch.is_valid()) {
- movl(scratch, Immediate(0x7291));
- }
- // Register element_count is not modified by the function.
- }
- jmp(gc_required);
- return;
- }
- ASSERT(!result.is(result_end));
-
- // Load address of new object into result.
- LoadAllocationTopHelper(result, scratch, flags);
-
- // Align the next allocation. Storing the filler map without checking top is
- // always safe because the limit of the heap is always aligned.
- if (((flags & DOUBLE_ALIGNMENT) != 0) && FLAG_debug_code) {
- testq(result, Immediate(kDoubleAlignmentMask));
- Check(zero, "Allocation is not double aligned");
- }
-
- // Calculate new top and bail out if new space is exhausted.
- ExternalReference allocation_limit =
- AllocationUtils::GetAllocationLimitReference(isolate(), flags);
-
- // We assume that element_count*element_size + header_size does not
- // overflow.
lea(result_end, Operand(element_count, element_size, header_size));
- addq(result_end, result);
- j(carry, gc_required);
- Operand limit_operand = ExternalOperand(allocation_limit);
- cmpq(result_end, limit_operand);
- j(above, gc_required);
-
- // Update allocation top.
- UpdateAllocationTopHelper(result_end, scratch, flags);
-
- // Tag the result if requested.
- if ((flags & TAG_OBJECT) != 0) {
- ASSERT(kHeapObjectTag == 1);
- incq(result);
- }
+ Allocate(result_end, result, result_end, scratch, gc_required, flags);
}
@@ -3952,7 +3910,7 @@
Register scratch,
Label* gc_required,
AllocationFlags flags) {
- ASSERT((flags & (RESULT_CONTAINS_TOP | SIZE_IN_WORDS)) == 0);
+ ASSERT((flags & SIZE_IN_WORDS) == 0);
if (!FLAG_inline_new) {
if (emit_debug_code()) {
// Trash the registers to simulate an allocation failure.
@@ -3971,6 +3929,13 @@
// Load address of new object into result.
LoadAllocationTopHelper(result, scratch, flags);
+ // Align the next allocation. Storing the filler map without checking top is
+ // always safe because the limit of the heap is always aligned.
+ if (((flags & DOUBLE_ALIGNMENT) != 0) && FLAG_debug_code) {
+ testq(result, Immediate(kDoubleAlignmentMask));
+ Check(zero, "Allocation is not double aligned");
+ }
+
// Calculate new top and bail out if new space is exhausted.
ExternalReference allocation_limit =
AllocationUtils::GetAllocationLimitReference(isolate(), flags);
@@ -3986,13 +3951,6 @@
// Update allocation top.
UpdateAllocationTopHelper(result_end, scratch, flags);
- // Align the next allocation. Storing the filler map without checking top is
- // always safe because the limit of the heap is always aligned.
- if (((flags & DOUBLE_ALIGNMENT) != 0) && FLAG_debug_code) {
- testq(result, Immediate(kDoubleAlignmentMask));
- Check(zero, "Allocation is not double aligned");
- }
-
// Tag the result if requested.
if ((flags & TAG_OBJECT) != 0) {
addq(result, Immediate(kHeapObjectTag));
diff --git a/src/zone.cc b/src/zone.cc
index 2a0a0e2..9ee00ed 100644
--- a/src/zone.cc
+++ b/src/zone.cc
@@ -92,18 +92,15 @@
#endif
// Find a segment with a suitable size to keep around.
- Segment* keep = segment_head_;
- while (keep != NULL && keep->size() > kMaximumKeptSegmentSize) {
- keep = keep->next();
- }
-
+ Segment* keep = NULL;
// Traverse the chained list of segments, zapping (in debug mode)
// and freeing every segment except the one we wish to keep.
for (Segment* current = segment_head_; current != NULL; ) {
Segment* next = current->next();
- if (current == keep) {
+ if (keep == NULL && current->size() <= kMaximumKeptSegmentSize) {
// Unlink the segment we wish to keep from the list.
- current->clear_next();
+ keep = current;
+ keep->clear_next();
} else {
int size = current->size();
#ifdef DEBUG
diff --git a/test/cctest/test-accessors.cc b/test/cctest/test-accessors.cc
index 87d8d66..7d96ea6 100644
--- a/test/cctest/test-accessors.cc
+++ b/test/cctest/test-accessors.cc
@@ -258,6 +258,7 @@
info.GetReturnValue().Set(17);
}
+
THREADED_TEST(DirectCall) {
LocalContext context;
v8::HandleScope scope(context->GetIsolate());
@@ -284,6 +285,7 @@
info.GetReturnValue().Set(v8::Handle<v8::Value>());
}
+
THREADED_TEST(EmptyResult) {
LocalContext context;
v8::HandleScope scope(context->GetIsolate());
diff --git a/test/cctest/test-api.cc b/test/cctest/test-api.cc
index 34432e3..f8f1930 100644
--- a/test/cctest/test-api.cc
+++ b/test/cctest/test-api.cc
@@ -102,12 +102,14 @@
CHECK_EQ(expected, *utf8);
}
+
static void ExpectInt32(const char* code, int expected) {
Local<Value> result = CompileRun(code);
CHECK(result->IsInt32());
CHECK_EQ(expected, result->Int32Value());
}
+
static void ExpectBoolean(const char* code, bool expected) {
Local<Value> result = CompileRun(code);
CHECK(result->IsBoolean());
@@ -860,10 +862,12 @@
info.GetReturnValue().Set(v8_num(102));
}
+
static void handle_callback(const v8::FunctionCallbackInfo<Value>& info) {
return handle_callback_impl(info, FUNCTION_ADDR(handle_callback));
}
+
static void handle_callback_2(const v8::FunctionCallbackInfo<Value>& info) {
return handle_callback_impl(info, FUNCTION_ADDR(handle_callback_2));
}
@@ -1077,6 +1081,7 @@
return scope.Close(CompileRun("callback_object.callback()"));
}
+
THREADED_PROFILED_TEST(FastReturnValues) {
LocalContext env;
v8::HandleScope scope(v8::Isolate::GetCurrent());
@@ -1693,6 +1698,7 @@
info.GetReturnValue().Set(name);
}
+
// Helper functions for Interceptor/Accessor interaction tests
void SimpleAccessorGetter(Local<String> name,
@@ -1755,6 +1761,7 @@
templ->InstanceTemplate()->SetNamedPropertyHandler(getter, setter);
}
+
THREADED_TEST(EmptyInterceptorDoesNotShadowAccessors) {
v8::HandleScope scope(v8::Isolate::GetCurrent());
Handle<FunctionTemplate> parent = FunctionTemplate::New();
@@ -1772,6 +1779,7 @@
ExpectInt32("child.accessor_age", 10);
}
+
THREADED_TEST(EmptyInterceptorDoesNotShadowJSAccessors) {
v8::HandleScope scope(v8::Isolate::GetCurrent());
Handle<FunctionTemplate> parent = FunctionTemplate::New();
@@ -1792,6 +1800,7 @@
ExpectInt32("child.accessor_age", 10);
}
+
THREADED_TEST(EmptyInterceptorDoesNotAffectJSProperties) {
v8::HandleScope scope(v8::Isolate::GetCurrent());
Handle<FunctionTemplate> parent = FunctionTemplate::New();
@@ -1811,6 +1820,7 @@
ExpectString("parent.name", "Alice");
}
+
THREADED_TEST(SwitchFromInterceptorToAccessor) {
v8::HandleScope scope(v8::Isolate::GetCurrent());
Handle<FunctionTemplate> templ = FunctionTemplate::New();
@@ -1828,6 +1838,7 @@
ExpectInt32("obj.accessor_age", 10000);
}
+
THREADED_TEST(SwitchFromAccessorToInterceptor) {
v8::HandleScope scope(v8::Isolate::GetCurrent());
Handle<FunctionTemplate> templ = FunctionTemplate::New();
@@ -1845,6 +1856,7 @@
ExpectInt32("obj.interceptor_age", 9999);
}
+
THREADED_TEST(SwitchFromInterceptorToAccessorWithInheritance) {
v8::HandleScope scope(v8::Isolate::GetCurrent());
Handle<FunctionTemplate> parent = FunctionTemplate::New();
@@ -1864,6 +1876,7 @@
ExpectInt32("child.accessor_age", 10000);
}
+
THREADED_TEST(SwitchFromAccessorToInterceptorWithInheritance) {
v8::HandleScope scope(v8::Isolate::GetCurrent());
Handle<FunctionTemplate> parent = FunctionTemplate::New();
@@ -1883,6 +1896,7 @@
ExpectInt32("child.interceptor_age", 9999);
}
+
THREADED_TEST(SwitchFromInterceptorToJSAccessor) {
v8::HandleScope scope(v8::Isolate::GetCurrent());
Handle<FunctionTemplate> templ = FunctionTemplate::New();
@@ -1907,6 +1921,7 @@
ExpectUndefined("Object.getOwnPropertyDescriptor(obj, 'age').value");
}
+
THREADED_TEST(SwitchFromJSAccessorToInterceptor) {
v8::HandleScope scope(v8::Isolate::GetCurrent());
Handle<FunctionTemplate> templ = FunctionTemplate::New();
@@ -1931,6 +1946,7 @@
ExpectUndefined("Object.getOwnPropertyDescriptor(obj, 'age').value");
}
+
THREADED_TEST(SwitchFromInterceptorToProperty) {
v8::HandleScope scope(v8::Isolate::GetCurrent());
Handle<FunctionTemplate> parent = FunctionTemplate::New();
@@ -1948,6 +1964,7 @@
ExpectInt32("child.age", 10000);
}
+
THREADED_TEST(SwitchFromPropertyToInterceptor) {
v8::HandleScope scope(v8::Isolate::GetCurrent());
Handle<FunctionTemplate> parent = FunctionTemplate::New();
@@ -1965,6 +1982,7 @@
ExpectInt32("child.interceptor_age", 9999);
}
+
THREADED_TEST(NamedPropertyHandlerGetter) {
echo_named_call_count = 0;
v8::HandleScope scope(v8::Isolate::GetCurrent());
@@ -2404,6 +2422,7 @@
CHECK((*env)->GetEmbedderData(index)->StrictEquals(data));
}
+
THREADED_TEST(EmbedderData) {
LocalContext env;
v8::HandleScope scope(env->GetIsolate());
@@ -2553,6 +2572,14 @@
const v8::ArrayBuffer::Contents contents_;
};
+template <typename T>
+static void CheckInternalFieldsAreZero(v8::Handle<T> value) {
+ CHECK_EQ(T::kInternalFieldCount, value->InternalFieldCount());
+ for (int i = 0; i < value->InternalFieldCount(); i++) {
+ CHECK_EQ(0, value->GetInternalField(i)->Int32Value());
+ }
+}
+
THREADED_TEST(ArrayBuffer_ApiInternalToExternal) {
i::FLAG_harmony_array_buffer = true;
@@ -2563,6 +2590,7 @@
v8::HandleScope handle_scope(isolate);
Local<v8::ArrayBuffer> ab = v8::ArrayBuffer::New(1024);
+ CheckInternalFieldsAreZero(ab);
CHECK_EQ(1024, static_cast<int>(ab->ByteLength()));
CHECK(!ab->IsExternal());
HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
@@ -2607,6 +2635,7 @@
"u8_a[0] = 0xAA;"
"u8_a[1] = 0xFF; u8_a.buffer");
Local<v8::ArrayBuffer> ab1 = Local<v8::ArrayBuffer>::Cast(result);
+ CheckInternalFieldsAreZero(ab1);
CHECK_EQ(2, static_cast<int>(ab1->ByteLength()));
CHECK(!ab1->IsExternal());
ScopedArrayBufferContents ab1_contents(ab1->Externalize());
@@ -2647,6 +2676,7 @@
i::ScopedVector<uint8_t> my_data(100);
memset(my_data.start(), 0, 100);
Local<v8::ArrayBuffer> ab3 = v8::ArrayBuffer::New(my_data.start(), 100);
+ CheckInternalFieldsAreZero(ab3);
CHECK_EQ(100, static_cast<int>(ab3->ByteLength()));
CHECK(ab3->IsExternal());
@@ -2699,6 +2729,7 @@
int byteOffset,
int length) {
v8::Handle<TypedArray> ta = TypedArray::New(ab, byteOffset, length);
+ CheckInternalFieldsAreZero<v8::ArrayBufferView>(ta);
CHECK_EQ(byteOffset, static_cast<int>(ta->ByteOffset()));
CHECK_EQ(length, static_cast<int>(ta->Length()));
CHECK_EQ(length * kElementSize, static_cast<int>(ta->ByteLength()));
@@ -2736,6 +2767,7 @@
CreateAndCheck<v8::Float64Array, 8>(buffer, 8, 127);
v8::Handle<v8::DataView> dv = v8::DataView::New(buffer, 1, 1023);
+ CheckInternalFieldsAreZero<v8::ArrayBufferView>(dv);
CHECK_EQ(1, static_cast<int>(dv->ByteOffset()));
CHECK_EQ(1023, static_cast<int>(dv->ByteLength()));
@@ -2754,6 +2786,7 @@
CheckDataViewIsNeutered(dv);
}
+
THREADED_TEST(ArrayBuffer_NeuteringScript) {
LocalContext env;
v8::Isolate* isolate = env->GetIsolate();
@@ -4386,6 +4419,7 @@
fun->Call(fun, argc, a5);
}
+
void ThrowValue(const v8::FunctionCallbackInfo<v8::Value>& args) {
ApiTestFuzzer::Fuzz();
CHECK_EQ(1, args.Length());
@@ -4608,6 +4642,7 @@
}
}
+
THREADED_TEST(DefinePropertyOnAPIAccessor) {
LocalContext context;
v8::HandleScope scope(context->GetIsolate());
@@ -4655,6 +4690,7 @@
CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
}
+
THREADED_TEST(DefinePropertyOnDefineGetterSetter) {
v8::HandleScope scope(v8::Isolate::GetCurrent());
Local<ObjectTemplate> templ = ObjectTemplate::New();
@@ -6318,6 +6354,7 @@
info.GetReturnValue().Set(whammy->getScript()->Run());
}
+
THREADED_TEST(WeakReference) {
v8::HandleScope handle_scope(v8::Isolate::GetCurrent());
v8::Handle<v8::ObjectTemplate> templ= v8::ObjectTemplate::New();
@@ -7453,6 +7490,7 @@
CHECK_EQ(" new o.foo();", *source_line);
}
+
TEST(ExceptionInNativeScript) {
LocalContext env;
v8::HandleScope scope(env->GetIsolate());
@@ -10713,6 +10751,7 @@
args.GetReturnValue().Set(args[0]->Int32Value() + 1);
}
+
// Helper to maximize the odds of object moving.
static void GenerateSomeGarbage() {
CompileRun(
@@ -10814,6 +10853,7 @@
CHECK_EQ(31, p_getter_count);
}
+
THREADED_PROFILED_TEST(LoadICFastApi_DirectCall_GCMoveStub) {
LoadICFastApi_DirectCall_GCMoveStub(DirectGetterCallback);
}
@@ -10869,6 +10909,7 @@
CHECK_EQ(100, interceptor_call_count);
}
+
THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature) {
int interceptor_call_count = 0;
v8::HandleScope scope(v8::Isolate::GetCurrent());
@@ -10900,6 +10941,7 @@
CHECK_EQ(100, interceptor_call_count);
}
+
THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss1) {
int interceptor_call_count = 0;
v8::HandleScope scope(v8::Isolate::GetCurrent());
@@ -10937,6 +10979,7 @@
CHECK_GE(interceptor_call_count, 50);
}
+
THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss2) {
int interceptor_call_count = 0;
v8::HandleScope scope(v8::Isolate::GetCurrent());
@@ -10974,6 +11017,7 @@
CHECK_GE(interceptor_call_count, 50);
}
+
THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss3) {
int interceptor_call_count = 0;
v8::HandleScope scope(v8::Isolate::GetCurrent());
@@ -11014,6 +11058,7 @@
CHECK_GE(interceptor_call_count, 50);
}
+
THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_TypeError) {
int interceptor_call_count = 0;
v8::HandleScope scope(v8::Isolate::GetCurrent());
@@ -11054,6 +11099,7 @@
CHECK_GE(interceptor_call_count, 50);
}
+
THREADED_PROFILED_TEST(CallICFastApi_TrivialSignature) {
v8::HandleScope scope(v8::Isolate::GetCurrent());
v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
@@ -11078,6 +11124,7 @@
CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
}
+
THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature) {
v8::HandleScope scope(v8::Isolate::GetCurrent());
v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
@@ -11106,6 +11153,7 @@
CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
}
+
THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature_Miss1) {
v8::HandleScope scope(v8::Isolate::GetCurrent());
v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
@@ -11139,6 +11187,7 @@
CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
}
+
THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature_Miss2) {
v8::HandleScope scope(v8::Isolate::GetCurrent());
v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
@@ -11175,6 +11224,7 @@
CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
}
+
THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature_TypeError) {
v8::HandleScope scope(v8::Isolate::GetCurrent());
v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
@@ -11325,6 +11375,7 @@
CHECK_EQ(239, context->Global()->Get(v8_str("saved_result"))->Int32Value());
}
+
// Test the map transition before the interceptor.
THREADED_TEST(InterceptorKeyedCallICMapChangeBefore) {
v8::HandleScope scope(v8::Isolate::GetCurrent());
@@ -11427,6 +11478,7 @@
}
}
+
// Test interceptor load/call IC where the interceptor throws an
// exception once in a while.
THREADED_TEST(InterceptorICGetterExceptions) {
@@ -11470,6 +11522,7 @@
}
}
+
// Test interceptor store IC where the interceptor throws an exception
// once in a while.
THREADED_TEST(InterceptorICSetterExceptions) {
@@ -11633,6 +11686,7 @@
message->GetScriptResourceName();
}
+
THREADED_TEST(ExceptionsDoNotPropagatePastTryCatch) {
LocalContext context;
HandleScope scope(context->GetIsolate());
@@ -11951,24 +12005,28 @@
ApiTestFuzzer::TearDown();
}
+
TEST(Threading2) {
ApiTestFuzzer::SetUp(ApiTestFuzzer::SECOND_PART);
ApiTestFuzzer::RunAllTests();
ApiTestFuzzer::TearDown();
}
+
TEST(Threading3) {
ApiTestFuzzer::SetUp(ApiTestFuzzer::THIRD_PART);
ApiTestFuzzer::RunAllTests();
ApiTestFuzzer::TearDown();
}
+
TEST(Threading4) {
ApiTestFuzzer::SetUp(ApiTestFuzzer::FOURTH_PART);
ApiTestFuzzer::RunAllTests();
ApiTestFuzzer::TearDown();
}
+
void ApiTestFuzzer::CallTest() {
if (kLogThreading)
printf("Start test %d\n", test_number_);
@@ -12583,6 +12641,7 @@
env->Exit();
}
+
void SetFunctionEntryHookTest::RunTest() {
// Work in a new isolate throughout.
v8::Isolate* isolate = v8::Isolate::New();
@@ -12671,13 +12730,18 @@
const char* tail = event->name.str + kPreambleLen;
size_t tail_len = event->name.len - kPreambleLen;
size_t expected_len = strlen(expected);
- if (tail_len == expected_len + 1) {
- if (*tail == '*' || *tail == '~') {
- --tail_len;
- ++tail;
- } else {
- return false;
- }
+ if (tail_len > 1 && (*tail == '*' || *tail == '~')) {
+ --tail_len;
+ ++tail;
+ }
+
+ // Check for tails like 'bar :1'.
+ if (tail_len > expected_len + 2 &&
+ tail[expected_len] == ' ' &&
+ tail[expected_len + 1] == ':' &&
+ tail[expected_len + 2] &&
+ !strncmp(tail, expected, expected_len)) {
+ return true;
}
if (tail_len != expected_len)
@@ -13126,6 +13190,7 @@
CheckOwnProperties(elms->Get(v8::Integer::New(3)), elmc4, elmv4);
}
+
THREADED_TEST(PropertyEnumeration2) {
LocalContext context;
v8::HandleScope scope(context->GetIsolate());
@@ -14234,6 +14299,7 @@
info.GetReturnValue().SetUndefined();
}
+
TEST(ForceSet) {
force_set_get_count = 0;
force_set_set_count = 0;
@@ -14275,6 +14341,7 @@
CHECK_EQ(2, force_set_get_count);
}
+
TEST(ForceSetWithInterceptor) {
force_set_get_count = 0;
force_set_set_count = 0;
@@ -15734,6 +15801,7 @@
backing_store.start(), (kElementCount+2)*sizeof(ElementType));
Local<TypedArray> ta =
TypedArray::New(ab, 2*sizeof(ElementType), kElementCount);
+ CheckInternalFieldsAreZero<v8::ArrayBufferView>(ta);
CHECK_EQ(kElementCount, static_cast<int>(ta->Length()));
CHECK_EQ(2*sizeof(ElementType), static_cast<int>(ta->ByteOffset()));
CHECK_EQ(kElementCount*sizeof(ElementType),
@@ -15819,6 +15887,7 @@
backing_store.start(), 2 + kSize);
Local<v8::DataView> dv =
v8::DataView::New(ab, 2, kSize);
+ CheckInternalFieldsAreZero<v8::ArrayBufferView>(dv);
CHECK_EQ(2, static_cast<int>(dv->ByteOffset()));
CHECK_EQ(kSize, static_cast<int>(dv->ByteLength()));
CHECK_EQ(ab, dv->Buffer());
@@ -15838,6 +15907,7 @@
"new " #View "(ab)"); \
CHECK(result->IsArrayBufferView()); \
CHECK(result->Is##View()); \
+ CheckInternalFieldsAreZero<v8::ArrayBufferView>(result.As<v8::View>()); \
}
IS_ARRAY_BUFFER_VIEW_TEST(Uint8Array)
@@ -16019,6 +16089,7 @@
stack_trace->GetFrame(1));
}
+
TEST(CaptureStackTraceForUncaughtException) {
report_count = 0;
LocalContext env;
@@ -16326,6 +16397,7 @@
CHECK(CompileRunWithOrigin(code.start(), "url", 0, 0)->IsUndefined());
}
+
static void CreateGarbageInOldSpace() {
i::Factory* factory = i::Isolate::Current()->factory();
v8::HandleScope scope(v8::Isolate::GetCurrent());
@@ -16335,6 +16407,7 @@
}
}
+
// Test that idle notification can be handled and eventually returns true.
TEST(IdleNotification) {
const intptr_t MB = 1024 * 1024;
@@ -16552,6 +16625,7 @@
bool found_resource_[4];
};
+
TEST(VisitExternalStrings) {
LocalContext env;
v8::HandleScope scope(env->GetIsolate());
@@ -16611,6 +16685,7 @@
return (input < 0) ? -(floor(-input)) : floor(input);
}
+
// We don't have a consistent way to write 64-bit constants syntactically, so we
// split them into two 32-bit constants and combine them programmatically.
static double DoubleFromBits(uint32_t high_bits, uint32_t low_bits) {
@@ -16850,6 +16925,7 @@
CHECK_EQ(0, script_origin_g.ResourceLineOffset()->Int32Value());
}
+
THREADED_TEST(FunctionGetInferredName) {
LocalContext env;
v8::HandleScope scope(env->GetIsolate());
@@ -16862,6 +16938,7 @@
CHECK_EQ("foo.bar.baz", *v8::String::Utf8Value(f->GetInferredName()));
}
+
THREADED_TEST(ScriptLineNumber) {
LocalContext env;
v8::HandleScope scope(env->GetIsolate());
@@ -17092,18 +17169,22 @@
++prologue_call_count;
}
+
void EpilogueCallback(v8::GCType, v8::GCCallbackFlags) {
++epilogue_call_count;
}
+
void PrologueCallbackSecond(v8::GCType, v8::GCCallbackFlags) {
++prologue_call_count_second;
}
+
void EpilogueCallbackSecond(v8::GCType, v8::GCCallbackFlags) {
++epilogue_call_count_second;
}
+
TEST(GCCallbacks) {
LocalContext context;
@@ -17494,6 +17575,7 @@
v8::V8::SetFailedAccessCheckCallbackFunction(NULL);
}
+
TEST(DefaultIsolateGetCurrent) {
CHECK(v8::Isolate::GetCurrent() != NULL);
v8::Isolate* isolate = v8::Isolate::GetCurrent();
@@ -17501,6 +17583,7 @@
printf("*** %s\n", "DefaultIsolateGetCurrent success");
}
+
TEST(IsolateNewDispose) {
v8::Isolate* current_isolate = v8::Isolate::GetCurrent();
v8::Isolate* isolate = v8::Isolate::New();
@@ -17516,6 +17599,7 @@
CHECK_EQ(last_message, NULL);
}
+
TEST(IsolateEnterExitDefault) {
v8::Isolate* current_isolate = v8::Isolate::GetCurrent();
CHECK(current_isolate != NULL); // Default isolate.
@@ -17534,6 +17618,7 @@
ExpectString("'still working 3'", "still working 3");
}
+
TEST(DisposeDefaultIsolate) {
v8::V8::SetFatalErrorHandler(StoringErrorCallback);
@@ -17551,6 +17636,7 @@
CHECK_NE(last_message, NULL);
}
+
TEST(RunDefaultAndAnotherIsolate) {
v8::HandleScope scope(v8::Isolate::GetCurrent());
LocalContext context;
@@ -17593,6 +17679,7 @@
ExpectTrue("function f() { return bar == 371; }; f()");
}
+
TEST(DisposeIsolateWhenInUse) {
v8::Isolate* isolate = v8::Isolate::New();
CHECK(isolate);
@@ -17609,6 +17696,7 @@
CHECK_NE(last_message, NULL);
}
+
TEST(RunTwoIsolatesOnSingleThread) {
// Run isolate 1.
v8::Isolate* isolate1 = v8::Isolate::New();
@@ -17733,6 +17821,7 @@
}
}
+
static int CalcFibonacci(v8::Isolate* isolate, int limit) {
v8::Isolate::Scope isolate_scope(isolate);
v8::HandleScope scope(isolate);
@@ -17768,6 +17857,7 @@
int result_;
};
+
TEST(MultipleIsolatesOnIndividualThreads) {
v8::Isolate* isolate1 = v8::Isolate::New();
v8::Isolate* isolate2 = v8::Isolate::New();
@@ -17796,6 +17886,7 @@
isolate2->Dispose();
}
+
TEST(IsolateDifferentContexts) {
v8::Isolate* isolate = v8::Isolate::New();
Local<v8::Context> context;
@@ -17884,26 +17975,32 @@
CHECK_EQ(thread.result(), true);
}
+
TEST(InitializeDefaultIsolateOnSecondaryThread1) {
InitializeTestHelper(InitDefaultIsolateThread::IgnoreOOM);
}
+
TEST(InitializeDefaultIsolateOnSecondaryThread2) {
InitializeTestHelper(InitDefaultIsolateThread::SetResourceConstraints);
}
+
TEST(InitializeDefaultIsolateOnSecondaryThread3) {
InitializeTestHelper(InitDefaultIsolateThread::SetFatalHandler);
}
+
TEST(InitializeDefaultIsolateOnSecondaryThread4) {
InitializeTestHelper(InitDefaultIsolateThread::SetCounterFunction);
}
+
TEST(InitializeDefaultIsolateOnSecondaryThread5) {
InitializeTestHelper(InitDefaultIsolateThread::SetCreateHistogramFunction);
}
+
TEST(InitializeDefaultIsolateOnSecondaryThread6) {
InitializeTestHelper(InitDefaultIsolateThread::SetAddHistogramSampleFunction);
}
diff --git a/test/cctest/test-assembler-arm.cc b/test/cctest/test-assembler-arm.cc
index 232f846..cb44ddc 100644
--- a/test/cctest/test-assembler-arm.cc
+++ b/test/cctest/test-assembler-arm.cc
@@ -619,6 +619,7 @@
TestRoundingMode(u32_f64, RN, (kMaxUInt + 1.0), kMaxUInt, true);
}
+
TEST(8) {
// Test VFP multi load/store with ia_w.
CcTest::InitializeVM();
diff --git a/test/cctest/test-assembler-ia32.cc b/test/cctest/test-assembler-ia32.cc
index 880370f..76eecc0 100644
--- a/test/cctest/test-assembler-ia32.cc
+++ b/test/cctest/test-assembler-ia32.cc
@@ -473,6 +473,95 @@
}
+#ifdef __GNUC__
+#define ELEMENT_COUNT 4
+
+void DoSSE2(const v8::FunctionCallbackInfo<v8::Value>& args) {
+ Isolate* isolate = reinterpret_cast<Isolate*>(CcTest::isolate());
+ HandleScope scope(isolate);
+
+ CHECK(args[0]->IsArray());
+ v8::Local<v8::Array> vec = v8::Local<v8::Array>::Cast(args[0]);
+ CHECK_EQ(ELEMENT_COUNT, vec->Length());
+
+ v8::internal::byte buffer[256];
+ Assembler assm(isolate, buffer, sizeof buffer);
+
+ ASSERT(CpuFeatures::IsSupported(SSE2));
+ CpuFeatureScope fscope(&assm, SSE2);
+
+ // Remove return address from the stack for fix stack frame alignment.
+ __ pop(ecx);
+
+ // Store input vector on the stack.
+ for (int i = 0; i < ELEMENT_COUNT; ++i) {
+ __ push(Immediate(vec->Get(i)->Int32Value()));
+ }
+
+ // Read vector into a xmm register.
+ __ pxor(xmm0, xmm0);
+ __ movdqa(xmm0, Operand(esp, 0));
+ // Create mask and store it in the return register.
+ __ movmskps(eax, xmm0);
+
+ // Remove unused data from the stack.
+ __ add(esp, Immediate(ELEMENT_COUNT * sizeof(int32_t)));
+ // Restore return address.
+ __ push(ecx);
+
+ __ ret(0);
+
+ CodeDesc desc;
+ assm.GetCode(&desc);
+
+ Object* code = isolate->heap()->CreateCode(
+ desc,
+ Code::ComputeFlags(Code::STUB),
+ Handle<Code>())->ToObjectChecked();
+ CHECK(code->IsCode());
+
+ F0 f = FUNCTION_CAST<F0>(Code::cast(code)->entry());
+ int res = f();
+ args.GetReturnValue().Set(v8::Integer::New(res));
+}
+
+
+TEST(StackAlignmentForSSE2) {
+ CcTest::InitializeVM();
+ if (!CpuFeatures::IsSupported(SSE2)) return;
+
+ CHECK_EQ(0, OS::ActivationFrameAlignment() % 16);
+
+ v8::Isolate* isolate = v8::Isolate::GetCurrent();
+ v8::HandleScope handle_scope(isolate);
+ v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
+ global_template->Set(v8_str("do_sse2"), v8::FunctionTemplate::New(DoSSE2));
+
+ LocalContext env(NULL, global_template);
+ CompileRun(
+ "function foo(vec) {"
+ " return do_sse2(vec);"
+ "}");
+
+ v8::Local<v8::Object> global_object = env->Global();
+ v8::Local<v8::Function> foo =
+ v8::Local<v8::Function>::Cast(global_object->Get(v8_str("foo")));
+
+ int32_t vec[ELEMENT_COUNT] = { -1, 1, 1, 1 };
+ v8::Local<v8::Array> v8_vec = v8::Array::New(ELEMENT_COUNT);
+ for (int i = 0; i < ELEMENT_COUNT; i++) {
+ v8_vec->Set(i, v8_num(vec[i]));
+ }
+
+ v8::Local<v8::Value> args[] = { v8_vec };
+ v8::Local<v8::Value> result = foo->Call(global_object, 1, args);
+
+ // The mask should be 0b1000.
+ CHECK_EQ(8, result->Int32Value());
+}
+
+#undef ELEMENT_COUNT
+#endif // __GNUC__
#undef __
diff --git a/test/cctest/test-assembler-x64.cc b/test/cctest/test-assembler-x64.cc
index 669475a..d5aaf4f 100644
--- a/test/cctest/test-assembler-x64.cc
+++ b/test/cctest/test-assembler-x64.cc
@@ -62,6 +62,7 @@
using v8::internal::rsi;
using v8::internal::rsp;
using v8::internal::times_1;
+using v8::internal::xmm0;
// Test the x64 assembler by compiling some simple functions into
// a buffer and executing them. These tests do not initialize the
@@ -110,6 +111,7 @@
CHECK_EQ(2, result);
}
+
TEST(AssemblerX64StackOperations) {
OS::SetUp();
// Allocate an executable page of memory.
@@ -142,6 +144,7 @@
CHECK_EQ(2, result);
}
+
TEST(AssemblerX64ArithmeticOperations) {
OS::SetUp();
// Allocate an executable page of memory.
@@ -164,6 +167,7 @@
CHECK_EQ(5, result);
}
+
TEST(AssemblerX64ImulOperation) {
OS::SetUp();
// Allocate an executable page of memory.
@@ -192,6 +196,7 @@
CHECK_EQ(-1, result);
}
+
TEST(AssemblerX64MemoryOperands) {
OS::SetUp();
// Allocate an executable page of memory.
@@ -226,6 +231,7 @@
CHECK_EQ(3, result);
}
+
TEST(AssemblerX64ControlFlow) {
OS::SetUp();
// Allocate an executable page of memory.
@@ -255,6 +261,7 @@
CHECK_EQ(3, result);
}
+
TEST(AssemblerX64LoopImmediates) {
OS::SetUp();
// Allocate an executable page of memory.
@@ -429,6 +436,92 @@
}
+#ifdef __GNUC__
+#define ELEMENT_COUNT 4
+
+void DoSSE2(const v8::FunctionCallbackInfo<v8::Value>& args) {
+ CcTest::InitializeVM();
+ v8::HandleScope scope(CcTest::isolate());
+ v8::internal::byte buffer[1024];
+
+ CHECK(args[0]->IsArray());
+ v8::Local<v8::Array> vec = v8::Local<v8::Array>::Cast(args[0]);
+ CHECK_EQ(ELEMENT_COUNT, vec->Length());
+
+ Isolate* isolate = Isolate::Current();
+ Assembler assm(isolate, buffer, sizeof(buffer));
+
+ // Remove return address from the stack for fix stack frame alignment.
+ __ pop(rcx);
+
+ // Store input vector on the stack.
+ for (int i = 0; i < ELEMENT_COUNT; i++) {
+ __ movl(rax, Immediate(vec->Get(i)->Int32Value()));
+ __ shl(rax, Immediate(0x20));
+ __ or_(rax, Immediate(vec->Get(++i)->Int32Value()));
+ __ push(rax);
+ }
+
+ // Read vector into a xmm register.
+ __ xorps(xmm0, xmm0);
+ __ movdqa(xmm0, Operand(rsp, 0));
+ // Create mask and store it in the return register.
+ __ movmskps(rax, xmm0);
+
+ // Remove unused data from the stack.
+ __ addq(rsp, Immediate(ELEMENT_COUNT * sizeof(int32_t)));
+ // Restore return address.
+ __ push(rcx);
+
+ __ ret(0);
+
+ CodeDesc desc;
+ assm.GetCode(&desc);
+ Code* code = Code::cast(isolate->heap()->CreateCode(
+ desc,
+ Code::ComputeFlags(Code::STUB),
+ v8::internal::Handle<Code>())->ToObjectChecked());
+ CHECK(code->IsCode());
+
+ F0 f = FUNCTION_CAST<F0>(code->entry());
+ int res = f();
+ args.GetReturnValue().Set(v8::Integer::New(res));
+}
+
+
+TEST(StackAlignmentForSSE2) {
+ CHECK_EQ(0, OS::ActivationFrameAlignment() % 16);
+
+ v8::Isolate* isolate = v8::Isolate::GetCurrent();
+ v8::HandleScope handle_scope(isolate);
+ v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
+ global_template->Set(v8_str("do_sse2"), v8::FunctionTemplate::New(DoSSE2));
+
+ LocalContext env(NULL, global_template);
+ CompileRun(
+ "function foo(vec) {"
+ " return do_sse2(vec);"
+ "}");
+
+ v8::Local<v8::Object> global_object = env->Global();
+ v8::Local<v8::Function> foo =
+ v8::Local<v8::Function>::Cast(global_object->Get(v8_str("foo")));
+
+ int32_t vec[ELEMENT_COUNT] = { -1, 1, 1, 1 };
+ v8::Local<v8::Array> v8_vec = v8::Array::New(ELEMENT_COUNT);
+ for (int i = 0; i < ELEMENT_COUNT; i++) {
+ v8_vec->Set(i, v8_num(vec[i]));
+ }
+
+ v8::Local<v8::Value> args[] = { v8_vec };
+ v8::Local<v8::Value> result = foo->Call(global_object, 1, args);
+
+ // The mask should be 0b1000.
+ CHECK_EQ(8, result->Int32Value());
+}
+
+#undef ELEMENT_COUNT
+#endif // __GNUC__
#undef __
diff --git a/test/cctest/test-compare-nil-ic-stub.cc b/test/cctest/test-compare-nil-ic-stub.cc
index 258ab01..78bb6fd 100644
--- a/test/cctest/test-compare-nil-ic-stub.cc
+++ b/test/cctest/test-compare-nil-ic-stub.cc
@@ -43,6 +43,7 @@
CHECK_EQ(state.ToIntegral(), state2.ToIntegral());
}
+
TEST(ExternalICStateParsing) {
State state;
state.Add(CompareNilICStub::UNDEFINED);
@@ -52,6 +53,7 @@
CHECK_EQ(stub.GetState().ToIntegral(), stub2.GetState().ToIntegral());
}
+
TEST(SettingState) {
State state;
CHECK(state.IsEmpty());
@@ -66,6 +68,7 @@
CHECK(!state.Contains(CompareNilICStub::UNDETECTABLE));
}
+
TEST(ClearState) {
State state;
state.Add(CompareNilICStub::NULL_TYPE);
@@ -73,6 +76,7 @@
CHECK(state.IsEmpty());
}
+
TEST(Generic) {
State state;
CHECK(State::Generic() != state);
diff --git a/test/cctest/test-conversions.cc b/test/cctest/test-conversions.cc
index cf2092e..3253d83 100644
--- a/test/cctest/test-conversions.cc
+++ b/test/cctest/test-conversions.cc
@@ -130,6 +130,7 @@
CHECK_EQ(0.0, StringToDouble(&uc, " ", NO_FLAGS));
}
+
TEST(IntegerStrLiteral) {
UnicodeCache uc;
CHECK_EQ(0.0, StringToDouble(&uc, "0.0", NO_FLAGS));
@@ -151,6 +152,7 @@
CHECK_EQ(0.0, StringToDouble(&uc, "0.", ALLOW_HEX | ALLOW_OCTALS));
}
+
TEST(LongNumberStr) {
UnicodeCache uc;
CHECK_EQ(1e10, StringToDouble(&uc, "1" "0000000000", NO_FLAGS));
@@ -204,6 +206,7 @@
CHECK_EQ(4.4501477170144022721148e-308, StringToDouble(&uc, num, NO_FLAGS));
}
+
TEST(MinimumExponent) {
UnicodeCache uc;
// Same test but with different point-position.
diff --git a/test/cctest/test-cpu-profiler.cc b/test/cctest/test-cpu-profiler.cc
index e59687b..e880d17 100644
--- a/test/cctest/test-cpu-profiler.cc
+++ b/test/cctest/test-cpu-profiler.cc
@@ -44,7 +44,6 @@
using i::ProfileNode;
using i::ProfilerEventsProcessor;
using i::ScopedVector;
-using i::TokenEnumerator;
using i::Vector;
@@ -53,10 +52,11 @@
ProfileGenerator generator(&profiles);
ProfilerEventsProcessor processor(&generator);
processor.Start();
- processor.Stop();
+ processor.StopSynchronously();
processor.Join();
}
+
static inline i::Address ToAddress(int n) {
return reinterpret_cast<i::Address>(n);
}
@@ -160,7 +160,7 @@
// Enqueue a tick event to enable code events processing.
EnqueueTickSampleEvent(&processor, aaa_code->address());
- processor.Stop();
+ processor.StopSynchronously();
processor.Join();
// Check the state of profile generator.
@@ -189,6 +189,7 @@
return strcmp((*p1)->entry()->name(), (*p2)->entry()->name());
}
+
TEST(TickEvents) {
TestSetup test_setup;
LocalContext env;
@@ -221,10 +222,9 @@
frame2_code->instruction_end() - 1,
frame1_code->instruction_end() - 1);
- processor.Stop();
+ processor.StopSynchronously();
processor.Join();
- CpuProfile* profile =
- profiles->StopProfiling(TokenEnumerator::kNoSecurityToken, "", 1);
+ CpuProfile* profile = profiles->StopProfiling("", 1);
CHECK_NE(NULL, profile);
// Check call trees.
@@ -286,10 +286,9 @@
sample->stack[i] = code->address();
}
- processor.Stop();
+ processor.StopSynchronously();
processor.Join();
- CpuProfile* profile =
- profiles->StopProfiling(TokenEnumerator::kNoSecurityToken, "", 1);
+ CpuProfile* profile = profiles->StopProfiling("", 1);
CHECK_NE(NULL, profile);
int actual_depth = 0;
@@ -393,63 +392,6 @@
}
-TEST(DeleteCpuProfileDifferentTokens) {
- LocalContext env;
- v8::HandleScope scope(env->GetIsolate());
- v8::CpuProfiler* cpu_profiler = env->GetIsolate()->GetCpuProfiler();
-
- CHECK_EQ(0, cpu_profiler->GetProfileCount());
- v8::Local<v8::String> name1 = v8::String::New("1");
- cpu_profiler->StartCpuProfiling(name1);
- const v8::CpuProfile* p1 = cpu_profiler->StopCpuProfiling(name1);
- CHECK_NE(NULL, p1);
- CHECK_EQ(1, cpu_profiler->GetProfileCount());
- unsigned uid1 = p1->GetUid();
- CHECK_EQ(p1, cpu_profiler->FindCpuProfile(uid1));
- v8::Local<v8::String> token1 = v8::String::New("token1");
- const v8::CpuProfile* p1_t1 = cpu_profiler->FindCpuProfile(uid1, token1);
- CHECK_NE(NULL, p1_t1);
- CHECK_NE(p1, p1_t1);
- CHECK_EQ(1, cpu_profiler->GetProfileCount());
- const_cast<v8::CpuProfile*>(p1)->Delete();
- CHECK_EQ(0, cpu_profiler->GetProfileCount());
- CHECK_EQ(NULL, cpu_profiler->FindCpuProfile(uid1));
- CHECK_EQ(NULL, cpu_profiler->FindCpuProfile(uid1, token1));
- const_cast<v8::CpuProfile*>(p1_t1)->Delete();
- CHECK_EQ(0, cpu_profiler->GetProfileCount());
-
- v8::Local<v8::String> name2 = v8::String::New("2");
- cpu_profiler->StartCpuProfiling(name2);
- v8::Local<v8::String> token2 = v8::String::New("token2");
- const v8::CpuProfile* p2_t2 = cpu_profiler->StopCpuProfiling(name2, token2);
- CHECK_NE(NULL, p2_t2);
- CHECK_EQ(1, cpu_profiler->GetProfileCount());
- unsigned uid2 = p2_t2->GetUid();
- CHECK_NE(static_cast<int>(uid1), static_cast<int>(uid2));
- const v8::CpuProfile* p2 = cpu_profiler->FindCpuProfile(uid2);
- CHECK_NE(p2_t2, p2);
- v8::Local<v8::String> name3 = v8::String::New("3");
- cpu_profiler->StartCpuProfiling(name3);
- const v8::CpuProfile* p3 = cpu_profiler->StopCpuProfiling(name3);
- CHECK_NE(NULL, p3);
- CHECK_EQ(2, cpu_profiler->GetProfileCount());
- unsigned uid3 = p3->GetUid();
- CHECK_NE(static_cast<int>(uid1), static_cast<int>(uid3));
- CHECK_EQ(p3, cpu_profiler->FindCpuProfile(uid3));
- const_cast<v8::CpuProfile*>(p2_t2)->Delete();
- CHECK_EQ(1, cpu_profiler->GetProfileCount());
- CHECK_EQ(NULL, cpu_profiler->FindCpuProfile(uid2));
- CHECK_EQ(p3, cpu_profiler->FindCpuProfile(uid3));
- const_cast<v8::CpuProfile*>(p2)->Delete();
- CHECK_EQ(1, cpu_profiler->GetProfileCount());
- CHECK_EQ(NULL, cpu_profiler->FindCpuProfile(uid2));
- CHECK_EQ(p3, cpu_profiler->FindCpuProfile(uid3));
- const_cast<v8::CpuProfile*>(p3)->Delete();
- CHECK_EQ(0, cpu_profiler->GetProfileCount());
- CHECK_EQ(NULL, cpu_profiler->FindCpuProfile(uid3));
-}
-
-
TEST(GetProfilerWhenIsolateIsNotInitialized) {
v8::Isolate* isolate = v8::Isolate::GetCurrent();
CHECK(i::Isolate::Current()->IsDefaultIsolate());
diff --git a/test/cctest/test-date.cc b/test/cctest/test-date.cc
index 0152bb7..6336481 100644
--- a/test/cctest/test-date.cc
+++ b/test/cctest/test-date.cc
@@ -107,6 +107,7 @@
return (result + day - 1) * DateCache::kMsPerDay;
}
+
static void CheckDST(int64_t time) {
Isolate* isolate = Isolate::Current();
DateCache* date_cache = isolate->date_cache();
diff --git a/test/cctest/test-debug.cc b/test/cctest/test-debug.cc
index 788f7af..0f31c14 100644
--- a/test/cctest/test-debug.cc
+++ b/test/cctest/test-debug.cc
@@ -820,6 +820,8 @@
const char* expr; // An expression to evaluate when a break point is hit.
v8::Handle<v8::Value> expected; // The expected result.
};
+
+
// Array of checks to do.
struct EvaluateCheck* checks = NULL;
// Source for The JavaScript function which can do the evaluation when a break
@@ -1393,6 +1395,7 @@
}
}
+
// Test GC during break point processing.
TEST(GCDuringBreakPointProcessing) {
break_point_hit_count = 0;
@@ -2526,6 +2529,7 @@
if (eventDetails.GetEvent() == v8::Break) ++debugEventCount;
}
+
// Test that the conditional breakpoints work event if code generation from
// strings is prohibited in the debugee context.
TEST(ConditionalBreakpointWithCodeGenerationDisallowed) {
@@ -2571,6 +2575,7 @@
}
}
+
// Test that the evaluation of expressions when a break point is hit generates
// the correct results in case code generation from strings is disallowed in the
// debugee context.
@@ -2625,6 +2630,7 @@
return i;
}
+
// Copies a 16-bit string to a C string by dropping the high byte of
// each character. Does not check for buffer overflow.
// Can be used in any thread. Requires string length as an input.
@@ -2712,6 +2718,7 @@
}
}
+
// Test that the evaluation of expressions works even from ProcessDebugMessages
// i.e. with empty stack.
TEST(DebugEvaluateWithoutStack) {
@@ -4265,6 +4272,7 @@
CheckDebuggerUnloaded();
}
+
static void NamedEnum(const v8::PropertyCallbackInfo<v8::Array>& info) {
v8::Handle<v8::Array> result = v8::Array::New(3);
result->Set(v8::Integer::New(0), v8::String::New("a"));
@@ -4709,6 +4717,7 @@
invalid_ = false; // A barrier may only be used once. Then it is invalid.
}
+
// Do not call, due to race condition with Wait().
// Could be resolved with Pthread condition variables.
ThreadBarrier::~ThreadBarrier() {
@@ -4717,6 +4726,7 @@
delete sem_;
}
+
void ThreadBarrier::Wait() {
lock_->Lock();
CHECK(!invalid_);
@@ -4736,6 +4746,7 @@
}
}
+
// A set containing enough barriers and semaphores for any of the tests.
class Barriers {
public:
@@ -4845,6 +4856,7 @@
return res;
}
+
/* Test MessageQueues */
/* Tests the message queues that hold debugger commands and
* response messages to the debugger. Fills queues and makes
@@ -4876,6 +4888,7 @@
message_queue_barriers.semaphore_1->Wait();
}
+
void MessageQueueDebuggerThread::Run() {
const int kBufferSize = 1000;
uint16_t buffer_1[kBufferSize];
@@ -5175,6 +5188,7 @@
CompileRun(source);
}
+
void DebuggerThread::Run() {
const int kBufSize = 1000;
uint16_t buffer[kBufSize];
@@ -5209,6 +5223,7 @@
debugger_thread.Join();
}
+
/* Test RecursiveBreakpoints */
/* In this test, the debugger evaluates a function with a breakpoint, after
* hitting a breakpoint in another function. We do this with both values
@@ -5400,6 +5415,7 @@
v8::Debug::SendCommand(buffer, AsciiToUtf16(command_8, buffer));
}
+
void TestRecursiveBreakpointsGeneric(bool global_evaluate) {
i::FLAG_debugger_auto_break = true;
@@ -5418,10 +5434,12 @@
breakpoints_debugger_thread.Join();
}
+
TEST(RecursiveBreakpoints) {
TestRecursiveBreakpointsGeneric(false);
}
+
TEST(RecursiveBreakpointsGlobal) {
TestRecursiveBreakpointsGeneric(true);
}
@@ -6270,8 +6288,6 @@
v8::Isolate* isolate = v8::Isolate::GetCurrent();
v8::HandleScope scope(isolate);
- v8::Debug::SetMessageHandler2(ContextCheckMessageHandler);
-
// Create two contexts.
v8::Handle<v8::Context> context_1;
v8::Handle<v8::Context> context_2;
@@ -6281,6 +6297,8 @@
context_1 = v8::Context::New(isolate, NULL, global_template, global_object);
context_2 = v8::Context::New(isolate, NULL, global_template, global_object);
+ v8::Debug::SetMessageHandler2(ContextCheckMessageHandler);
+
// Default data value is undefined.
CHECK(context_1->GetEmbedderData(0)->IsUndefined());
CHECK(context_2->GetEmbedderData(0)->IsUndefined());
@@ -6438,7 +6456,8 @@
// Common part of EvalContextData and NestedBreakEventContextData tests.
-static void ExecuteScriptForContextCheck() {
+static void ExecuteScriptForContextCheck(
+ v8::Debug::MessageHandler2 message_handler) {
// Create a context.
v8::Handle<v8::Context> context_1;
v8::Handle<v8::ObjectTemplate> global_template =
@@ -6446,6 +6465,8 @@
context_1 =
v8::Context::New(v8::Isolate::GetCurrent(), NULL, global_template);
+ v8::Debug::SetMessageHandler2(message_handler);
+
// Default data value is undefined.
CHECK(context_1->GetEmbedderData(0)->IsUndefined());
@@ -6465,6 +6486,8 @@
v8::Local<v8::Function> f = CompileFunction(source, "f");
f->Call(context_1->Global(), 0, NULL);
}
+
+ v8::Debug::SetMessageHandler2(NULL);
}
@@ -6474,13 +6497,11 @@
// Message.GetEventContext.
TEST(EvalContextData) {
v8::HandleScope scope(v8::Isolate::GetCurrent());
- v8::Debug::SetMessageHandler2(ContextCheckMessageHandler);
- ExecuteScriptForContextCheck();
+ ExecuteScriptForContextCheck(ContextCheckMessageHandler);
// One time compile event and one time break event.
CHECK_GT(message_handler_hit_count, 2);
- v8::Debug::SetMessageHandler2(NULL);
CheckDebuggerUnloaded();
}
@@ -6539,16 +6560,14 @@
v8::HandleScope scope(v8::Isolate::GetCurrent());
break_count = 0;
message_handler_hit_count = 0;
- v8::Debug::SetMessageHandler2(DebugEvalContextCheckMessageHandler);
- ExecuteScriptForContextCheck();
+ ExecuteScriptForContextCheck(DebugEvalContextCheckMessageHandler);
// One time compile event and two times break event.
CHECK_GT(message_handler_hit_count, 3);
// One break from the source and another from the evaluate request.
CHECK_EQ(break_count, 2);
- v8::Debug::SetMessageHandler2(NULL);
CheckDebuggerUnloaded();
}
@@ -6873,6 +6892,7 @@
counting_message_handler_counter++;
}
+
// Test that debug messages get processed when ProcessDebugMessages is called.
TEST(ProcessDebugMessages) {
DebugLocalContext env;
@@ -7112,14 +7132,15 @@
CHECK_EQ(expected_callback_data, details.GetCallbackData());
}
+
// Check that event details contain context where debug event occured.
TEST(DebugEventContext) {
v8::Isolate* isolate = v8::Isolate::GetCurrent();
v8::HandleScope scope(isolate);
expected_callback_data = v8::Int32::New(2010);
+ expected_context = v8::Context::New(isolate);
v8::Debug::SetDebugEventListener2(DebugEventContextChecker,
expected_callback_data);
- expected_context = v8::Context::New(isolate);
v8::Context::Scope context_scope(expected_context);
v8::Script::Compile(v8::String::New("(function(){debugger;})();"))->Run();
expected_context.Clear();
diff --git a/test/cctest/test-double.cc b/test/cctest/test-double.cc
index 0e50bdc..2c9f0c2 100644
--- a/test/cctest/test-double.cc
+++ b/test/cctest/test-double.cc
@@ -50,6 +50,7 @@
CHECK_EQ(1.7976931348623157e308, Double(max_double64).value());
}
+
TEST(AsDiyFp) {
uint64_t ordered = V8_2PART_UINT64_C(0x01234567, 89ABCDEF);
DiyFp diy_fp = Double(ordered).AsDiyFp();
diff --git a/test/cctest/test-heap-profiler.cc b/test/cctest/test-heap-profiler.cc
index 5973941..ba6a97a 100644
--- a/test/cctest/test-heap-profiler.cc
+++ b/test/cctest/test-heap-profiler.cc
@@ -340,6 +340,7 @@
CHECK_EQ(v8::HeapGraphNode::kHeapNumber, b->GetType());
}
+
TEST(HeapSnapshotSlicedString) {
LocalContext env;
v8::HandleScope scope(env->GetIsolate());
@@ -364,6 +365,7 @@
CHECK_EQ(parent_string, parent);
}
+
TEST(HeapSnapshotInternalReferences) {
v8::Isolate* isolate = v8::Isolate::GetCurrent();
v8::HandleScope scope(isolate);
@@ -481,6 +483,7 @@
CHECK_EQ_SNAPSHOT_OBJECT_ID(k1->GetId(), k2->GetId());
}
+
TEST(HeapEntryIdsAndGC) {
LocalContext env;
v8::HandleScope scope(env->GetIsolate());
@@ -1017,6 +1020,7 @@
};
}
+
TEST(TakeHeapSnapshotAborting) {
LocalContext env;
v8::HandleScope scope(env->GetIsolate());
@@ -1340,6 +1344,7 @@
}
};
+
TEST(GlobalObjectName) {
LocalContext env;
v8::HandleScope scope(env->GetIsolate());
@@ -1606,6 +1611,7 @@
CHECK_NE(NULL, hidden_props);
}
+
bool HasWeakEdge(const v8::HeapGraphNode* node) {
for (int i = 0; i < node->GetChildrenCount(); ++i) {
const v8::HeapGraphEdge* handle_edge = node->GetChild(i);
diff --git a/test/cctest/test-list.cc b/test/cctest/test-list.cc
index 740b432..a29972b 100644
--- a/test/cctest/test-list.cc
+++ b/test/cctest/test-list.cc
@@ -51,6 +51,7 @@
}
};
+
// Check that we can add (a reference to) an element of the list
// itself.
TEST(ListAdd) {
@@ -66,6 +67,7 @@
CHECK_EQ(1, list[4]);
}
+
// Test that we can add all elements from a list to another list.
TEST(ListAddAll) {
List<int, ZeroingAllocationPolicy> list(4);
diff --git a/test/cctest/test-lockers.cc b/test/cctest/test-lockers.cc
index 072bbff..a8e870e 100644
--- a/test/cctest/test-lockers.cc
+++ b/test/cctest/test-lockers.cc
@@ -96,6 +96,7 @@
Persistent<v8::Context> context_;
};
+
// Migrates an isolate from one thread to another
TEST(KangarooIsolates) {
v8::Isolate* isolate = v8::Isolate::New();
@@ -114,6 +115,7 @@
thread1->Join();
}
+
static void CalcFibAndCheck() {
Local<Value> v = CompileRun("function fib(n) {"
" if (n <= 2) return 1;"
@@ -192,6 +194,7 @@
v8::Isolate* isolate_;
};
+
static void StartJoinAndDeleteThreads(const i::List<JoinableThread*>& threads) {
for (int i = 0; i < threads.length(); i++) {
threads[i]->Start();
@@ -242,6 +245,7 @@
private:
};
+
// Run many threads each accessing its own isolate without locking
TEST(MultithreadedParallelIsolates) {
#if V8_TARGET_ARCH_ARM || V8_TARGET_ARCH_MIPS
@@ -280,6 +284,7 @@
v8::Isolate* isolate_;
};
+
// Run many threads with nested locks
TEST(IsolateNestedLocking) {
#if V8_TARGET_ARCH_MIPS
@@ -321,6 +326,7 @@
v8::Isolate* isolate2_;
};
+
// Run parallel threads that lock and access different isolates in parallel
TEST(SeparateIsolatesLocksNonexclusive) {
#if V8_TARGET_ARCH_ARM || V8_TARGET_ARCH_MIPS
@@ -397,6 +403,7 @@
v8::Isolate* isolate_;
};
+
// Use unlocker inside of a Locker, multiple threads.
TEST(LockerUnlocker) {
#if V8_TARGET_ARCH_ARM || V8_TARGET_ARCH_MIPS
@@ -450,6 +457,7 @@
v8::Isolate* isolate_;
};
+
// Use Unlocker inside two Lockers.
TEST(LockTwiceAndUnlock) {
#if V8_TARGET_ARCH_ARM || V8_TARGET_ARCH_MIPS
@@ -517,6 +525,7 @@
v8::Isolate* isolate2_;
};
+
// Lock two isolates and unlock one of them.
TEST(LockAndUnlockDifferentIsolates) {
v8::Isolate* isolate1 = v8::Isolate::New();
@@ -571,6 +580,7 @@
v8::Persistent<v8::Context> context_;
};
+
// Locker inside an Unlocker inside a Locker.
TEST(LockUnlockLockMultithreaded) {
#if V8_TARGET_ARCH_MIPS
@@ -626,6 +636,7 @@
v8::Persistent<v8::Context> context_;
};
+
// Locker inside an Unlocker inside a Locker for default isolate.
TEST(LockUnlockLockDefaultIsolateMultithreaded) {
#if V8_TARGET_ARCH_MIPS
@@ -696,6 +707,7 @@
const char** extension_names_;
};
+
// Test installing extensions in separate isolates concurrently.
// http://code.google.com/p/v8/issues/detail?id=1821
TEST(ExtensionsRegistration) {
diff --git a/test/cctest/test-log-stack-tracer.cc b/test/cctest/test-log-stack-tracer.cc
index 20f135d..7c3567c 100644
--- a/test/cctest/test-log-stack-tracer.cc
+++ b/test/cctest/test-log-stack-tracer.cc
@@ -186,6 +186,7 @@
return code->contains(addr);
}
+
static bool IsAddressWithinFuncCode(const char* func_name, Address addr) {
v8::Local<v8::Value> func = CcTest::env()->Global()->Get(v8_str(func_name));
CHECK(func->IsFunction());
diff --git a/test/cctest/test-log.cc b/test/cctest/test-log.cc
index 6ccf58e..58657ed 100644
--- a/test/cctest/test-log.cc
+++ b/test/cctest/test-log.cc
@@ -395,6 +395,7 @@
static void ObjMethod1(const v8::FunctionCallbackInfo<v8::Value>& args) {
}
+
TEST(LogCallbacks) {
ScopedLoggerInitializer initialize_logger(false);
Logger* logger = initialize_logger.logger();
@@ -443,6 +444,7 @@
const v8::PropertyCallbackInfo<v8::Value>& info) {
}
+
TEST(LogAccessorCallbacks) {
ScopedLoggerInitializer initialize_logger(false);
Logger* logger = initialize_logger.logger();
diff --git a/test/cctest/test-macro-assembler-x64.cc b/test/cctest/test-macro-assembler-x64.cc
old mode 100755
new mode 100644
index 3945f1b..a2070a5
--- a/test/cctest/test-macro-assembler-x64.cc
+++ b/test/cctest/test-macro-assembler-x64.cc
@@ -801,6 +801,7 @@
__ j(not_equal, exit);
}
+
TEST(SmiAdd) {
v8::internal::V8::Initialize(NULL);
// Allocate an executable page of memory.
@@ -1397,6 +1398,7 @@
}
}
+
TEST(SmiIndex) {
v8::internal::V8::Initialize(NULL);
// Allocate an executable page of memory.
diff --git a/test/cctest/test-mark-compact.cc b/test/cctest/test-mark-compact.cc
index 8be72d3..626df16 100644
--- a/test/cctest/test-mark-compact.cc
+++ b/test/cctest/test-mark-compact.cc
@@ -310,6 +310,7 @@
handle->Dispose(isolate);
}
+
TEST(ObjectGroups) {
FLAG_incremental_marking = false;
CcTest::InitializeVM();
@@ -560,7 +561,7 @@
if (v8::internal::Snapshot::IsEnabled()) {
CHECK_LE(delta, 3100 * 1024);
} else {
- CHECK_LE(delta, 3400 * 1024);
+ CHECK_LE(delta, 3450 * 1024);
}
}
}
diff --git a/test/cctest/test-object-observe.cc b/test/cctest/test-object-observe.cc
index 3778fed..2bbcaad 100644
--- a/test/cctest/test-object-observe.cc
+++ b/test/cctest/test-object-observe.cc
@@ -54,6 +54,7 @@
};
}
+
TEST(PerIsolateState) {
HarmonyIsolate isolate;
HandleScope scope(isolate.GetIsolate());
@@ -94,6 +95,7 @@
CHECK_EQ(3, CompileRun("count")->Int32Value());
}
+
TEST(EndOfMicrotaskDelivery) {
HarmonyIsolate isolate;
HandleScope scope(isolate.GetIsolate());
@@ -107,6 +109,7 @@
CHECK_EQ(1, CompileRun("count")->Int32Value());
}
+
TEST(DeliveryOrdering) {
HarmonyIsolate isolate;
HandleScope scope(isolate.GetIsolate());
@@ -138,6 +141,7 @@
CHECK_EQ(3, CompileRun("ordering[2]")->Int32Value());
}
+
TEST(DeliveryOrderingReentrant) {
HarmonyIsolate isolate;
HandleScope scope(isolate.GetIsolate());
@@ -169,6 +173,7 @@
CHECK_EQ(2, CompileRun("ordering[1]")->Int32Value());
}
+
TEST(DeliveryOrderingDeliverChangeRecords) {
HarmonyIsolate isolate;
HandleScope scope(isolate.GetIsolate());
@@ -193,6 +198,7 @@
CHECK_EQ(2, CompileRun("ordering[3]")->Int32Value());
}
+
TEST(ObjectHashTableGrowth) {
HarmonyIsolate isolate;
HandleScope scope(isolate.GetIsolate());
@@ -222,6 +228,7 @@
CHECK(CompileRun("ran")->BooleanValue());
}
+
TEST(GlobalObjectObservation) {
HarmonyIsolate isolate;
LocalContext context;
@@ -290,6 +297,7 @@
Handle<Value> old_value;
};
+
// TODO(adamk): Use this helper elsewhere in this file.
static void ExpectRecords(Handle<Value> records,
const RecordExpectation expectations[],
@@ -360,6 +368,7 @@
EXPECT_RECORDS(CompileRun("records"), expected_records);
}
+
TEST(HiddenPrototypeObservation) {
HarmonyIsolate isolate;
HandleScope scope(isolate.GetIsolate());
diff --git a/test/cctest/test-parsing.cc b/test/cctest/test-parsing.cc
index 9879886..ee628c3 100644
--- a/test/cctest/test-parsing.cc
+++ b/test/cctest/test-parsing.cc
@@ -633,6 +633,7 @@
} while (expected_tokens[i] != i::Token::ILLEGAL);
}
+
TEST(StreamScanner) {
v8::V8::Initialize();
diff --git a/test/cctest/test-platform-tls.cc b/test/cctest/test-platform-tls.cc
index cc9ffeb..31501d9 100644
--- a/test/cctest/test-platform-tls.cc
+++ b/test/cctest/test-platform-tls.cc
@@ -43,6 +43,7 @@
return reinterpret_cast<void*>(static_cast<intptr_t>(num + 1));
}
+
static void DoTest() {
for (int i = 0; i < kValueCount; i++) {
CHECK(!Thread::HasThreadLocal(keys[i]));
@@ -80,6 +81,7 @@
}
};
+
TEST(FastTLS) {
for (int i = 0; i < kValueCount; i++) {
keys[i] = Thread::CreateThreadLocalKey();
diff --git a/test/cctest/test-platform.cc b/test/cctest/test-platform.cc
index 6c20b85..2d8eb20 100644
--- a/test/cctest/test-platform.cc
+++ b/test/cctest/test-platform.cc
@@ -35,3 +35,66 @@
TEST(NumberOfCores) {
CHECK_GT(OS::NumberOfCores(), 0);
}
+
+
+#ifdef __GNUC__
+#define ASM __asm__ __volatile__
+
+#if defined(_M_X64) || defined(__x86_64__)
+#define GET_STACK_POINTER() \
+ static int sp_addr = 0; \
+ do { \
+ ASM("mov %%rsp, %0" : "=g" (sp_addr)); \
+ } while (0)
+#elif defined(_M_IX86) || defined(__i386__)
+#define GET_STACK_POINTER() \
+ static int sp_addr = 0; \
+ do { \
+ ASM("mov %%esp, %0" : "=g" (sp_addr)); \
+ } while (0)
+#elif defined(__ARMEL__)
+#define GET_STACK_POINTER() \
+ static int sp_addr = 0; \
+ do { \
+ ASM("str %%sp, %0" : "=g" (sp_addr)); \
+ } while (0)
+#elif defined(__MIPSEL__)
+#define GET_STACK_POINTER() \
+ static int sp_addr = 0; \
+ do { \
+ ASM("sw $sp, %0" : "=g" (sp_addr)); \
+ } while (0)
+#else
+#error Host architecture was not detected as supported by v8
+#endif
+
+void GetStackPointer(const v8::FunctionCallbackInfo<v8::Value>& args) {
+ GET_STACK_POINTER();
+ args.GetReturnValue().Set(v8_num(sp_addr));
+}
+
+
+TEST(StackAlignment) {
+ v8::Isolate* isolate = v8::Isolate::GetCurrent();
+ v8::HandleScope handle_scope(isolate);
+ v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
+ global_template->Set(v8_str("get_stack_pointer"),
+ v8::FunctionTemplate::New(GetStackPointer));
+
+ LocalContext env(NULL, global_template);
+ CompileRun(
+ "function foo() {"
+ " return get_stack_pointer();"
+ "}");
+
+ v8::Local<v8::Object> global_object = env->Global();
+ v8::Local<v8::Function> foo =
+ v8::Local<v8::Function>::Cast(global_object->Get(v8_str("foo")));
+
+ v8::Local<v8::Value> result = foo->Call(global_object, 0, NULL);
+ CHECK_EQ(0, result->Int32Value() % OS::ActivationFrameAlignment());
+}
+
+#undef GET_STACK_POINTERS
+#undef ASM
+#endif // __GNUC__
diff --git a/test/cctest/test-profile-generator.cc b/test/cctest/test-profile-generator.cc
index 7472669..7b8278b 100644
--- a/test/cctest/test-profile-generator.cc
+++ b/test/cctest/test-profile-generator.cc
@@ -43,48 +43,9 @@
using i::ProfileGenerator;
using i::SampleRateCalculator;
using i::TickSample;
-using i::TokenEnumerator;
using i::Vector;
-namespace v8 {
-namespace internal {
-
-class TokenEnumeratorTester {
- public:
- static i::List<bool>* token_removed(TokenEnumerator* te) {
- return &te->token_removed_;
- }
-};
-
-} } // namespace v8::internal
-
-TEST(TokenEnumerator) {
- TokenEnumerator te;
- CHECK_EQ(TokenEnumerator::kNoSecurityToken, te.GetTokenId(NULL));
- v8::HandleScope hs(v8::Isolate::GetCurrent());
- v8::Local<v8::String> token1(v8::String::New("1x"));
- CHECK_EQ(0, te.GetTokenId(*v8::Utils::OpenHandle(*token1)));
- CHECK_EQ(0, te.GetTokenId(*v8::Utils::OpenHandle(*token1)));
- v8::Local<v8::String> token2(v8::String::New("2x"));
- CHECK_EQ(1, te.GetTokenId(*v8::Utils::OpenHandle(*token2)));
- CHECK_EQ(1, te.GetTokenId(*v8::Utils::OpenHandle(*token2)));
- CHECK_EQ(0, te.GetTokenId(*v8::Utils::OpenHandle(*token1)));
- {
- v8::HandleScope hs(v8::Isolate::GetCurrent());
- v8::Local<v8::String> token3(v8::String::New("3x"));
- CHECK_EQ(2, te.GetTokenId(*v8::Utils::OpenHandle(*token3)));
- CHECK_EQ(1, te.GetTokenId(*v8::Utils::OpenHandle(*token2)));
- CHECK_EQ(0, te.GetTokenId(*v8::Utils::OpenHandle(*token1)));
- }
- CHECK(!i::TokenEnumeratorTester::token_removed(&te)->at(2));
- HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
- CHECK(i::TokenEnumeratorTester::token_removed(&te)->at(2));
- CHECK_EQ(1, te.GetTokenId(*v8::Utils::OpenHandle(*token2)));
- CHECK_EQ(0, te.GetTokenId(*v8::Utils::OpenHandle(*token1)));
-}
-
-
TEST(ProfileNodeFindOrAddChild) {
ProfileTree tree;
ProfileNode node(&tree, NULL);
@@ -121,8 +82,7 @@
CodeEntry entry2(i::Logger::FUNCTION_TAG, aaa);
CHECK_EQ(childNode1, node.FindOrAddChild(&entry2));
// Now with a different security token.
- CodeEntry entry3(i::Logger::FUNCTION_TAG, aaa,
- TokenEnumerator::kNoSecurityToken + 1);
+ CodeEntry entry3(i::Logger::FUNCTION_TAG, aaa);
CHECK_EQ(childNode1, node.FindOrAddChild(&entry3));
}
@@ -415,108 +375,11 @@
}
-TEST(ProfileTreeFilteredClone) {
- ProfileTree source_tree;
- const int token0 = 0, token1 = 1, token2 = 2;
- CodeEntry entry1(i::Logger::FUNCTION_TAG, "aaa", token0);
- CodeEntry entry2(i::Logger::FUNCTION_TAG, "bbb", token1);
- CodeEntry entry3(i::Logger::FUNCTION_TAG, "ccc", token0);
- CodeEntry entry4(i::Logger::FUNCTION_TAG, "ddd",
- TokenEnumerator::kInheritsSecurityToken);
-
- {
- CodeEntry* e1_e2_path[] = {&entry1, &entry2};
- Vector<CodeEntry*> e1_e2_path_vec(
- e1_e2_path, sizeof(e1_e2_path) / sizeof(e1_e2_path[0]));
- source_tree.AddPathFromStart(e1_e2_path_vec);
- CodeEntry* e2_e4_path[] = {&entry2, &entry4};
- Vector<CodeEntry*> e2_e4_path_vec(
- e2_e4_path, sizeof(e2_e4_path) / sizeof(e2_e4_path[0]));
- source_tree.AddPathFromStart(e2_e4_path_vec);
- CodeEntry* e3_e1_path[] = {&entry3, &entry1};
- Vector<CodeEntry*> e3_e1_path_vec(
- e3_e1_path, sizeof(e3_e1_path) / sizeof(e3_e1_path[0]));
- source_tree.AddPathFromStart(e3_e1_path_vec);
- CodeEntry* e3_e2_path[] = {&entry3, &entry2};
- Vector<CodeEntry*> e3_e2_path_vec(
- e3_e2_path, sizeof(e3_e2_path) / sizeof(e3_e2_path[0]));
- source_tree.AddPathFromStart(e3_e2_path_vec);
- source_tree.CalculateTotalTicks();
- // Results in -> {entry1,0,1,0} -> {entry2,1,1,1}
- // {root,0,4,-1} -> {entry2,0,1,1} -> {entry4,1,1,inherits}
- // -> {entry3,0,2,0} -> {entry1,1,1,0}
- // -> {entry2,1,1,1}
- CHECK_EQ(4, source_tree.root()->total_ticks());
- CHECK_EQ(0, source_tree.root()->self_ticks());
- }
-
- {
- ProfileTree token0_tree;
- token0_tree.FilteredClone(&source_tree, token0);
- // Should be -> {entry1,1,1,0}
- // {root,1,4,-1} -> {entry3,1,2,0} -> {entry1,1,1,0}
- // [self ticks from filtered nodes are attributed to their parents]
- CHECK_EQ(4, token0_tree.root()->total_ticks());
- CHECK_EQ(1, token0_tree.root()->self_ticks());
- ProfileTreeTestHelper token0_helper(&token0_tree);
- ProfileNode* node1 = token0_helper.Walk(&entry1);
- CHECK_NE(NULL, node1);
- CHECK_EQ(1, node1->total_ticks());
- CHECK_EQ(1, node1->self_ticks());
- CHECK_EQ(NULL, token0_helper.Walk(&entry2));
- ProfileNode* node3 = token0_helper.Walk(&entry3);
- CHECK_NE(NULL, node3);
- CHECK_EQ(2, node3->total_ticks());
- CHECK_EQ(1, node3->self_ticks());
- ProfileNode* node3_1 = token0_helper.Walk(&entry3, &entry1);
- CHECK_NE(NULL, node3_1);
- CHECK_EQ(1, node3_1->total_ticks());
- CHECK_EQ(1, node3_1->self_ticks());
- CHECK_EQ(NULL, token0_helper.Walk(&entry3, &entry2));
- }
-
- {
- ProfileTree token1_tree;
- token1_tree.FilteredClone(&source_tree, token1);
- // Should be
- // {root,1,4,-1} -> {entry2,2,3,1} -> {entry4,1,1,inherits}
- // [child nodes referring to the same entry get merged and
- // their self times summed up]
- CHECK_EQ(4, token1_tree.root()->total_ticks());
- CHECK_EQ(1, token1_tree.root()->self_ticks());
- ProfileTreeTestHelper token1_helper(&token1_tree);
- CHECK_EQ(NULL, token1_helper.Walk(&entry1));
- CHECK_EQ(NULL, token1_helper.Walk(&entry3));
- ProfileNode* node2 = token1_helper.Walk(&entry2);
- CHECK_NE(NULL, node2);
- CHECK_EQ(3, node2->total_ticks());
- CHECK_EQ(2, node2->self_ticks());
- ProfileNode* node2_4 = token1_helper.Walk(&entry2, &entry4);
- CHECK_NE(NULL, node2_4);
- CHECK_EQ(1, node2_4->total_ticks());
- CHECK_EQ(1, node2_4->self_ticks());
- }
-
- {
- ProfileTree token2_tree;
- token2_tree.FilteredClone(&source_tree, token2);
- // Should be
- // {root,4,4,-1}
- // [no nodes, all ticks get migrated into root node]
- CHECK_EQ(4, token2_tree.root()->total_ticks());
- CHECK_EQ(4, token2_tree.root()->self_ticks());
- ProfileTreeTestHelper token2_helper(&token2_tree);
- CHECK_EQ(NULL, token2_helper.Walk(&entry1));
- CHECK_EQ(NULL, token2_helper.Walk(&entry2));
- CHECK_EQ(NULL, token2_helper.Walk(&entry3));
- }
-}
-
-
static inline i::Address ToAddress(int n) {
return reinterpret_cast<i::Address>(n);
}
+
TEST(CodeMapAddCode) {
CodeMap code_map;
CodeEntry entry1(i::Logger::FUNCTION_TAG, "aaa");
@@ -622,8 +485,7 @@
sample3.frames_count = 2;
generator.RecordTickSample(sample3);
- CpuProfile* profile =
- profiles.StopProfiling(TokenEnumerator::kNoSecurityToken, "", 1);
+ CpuProfile* profile = profiles.StopProfiling("", 1);
CHECK_NE(NULL, profile);
ProfileTreeTestHelper top_down_test_helper(profile->top_down());
CHECK_EQ(NULL, top_down_test_helper.Walk(entry2));
@@ -700,6 +562,7 @@
}
}
+
TEST(SampleIds) {
TestSetup test_setup;
CpuProfilesCollection profiles;
@@ -735,8 +598,7 @@
sample3.frames_count = 2;
generator.RecordTickSample(sample3);
- CpuProfile* profile =
- profiles.StopProfiling(TokenEnumerator::kNoSecurityToken, "", 1);
+ CpuProfile* profile = profiles.StopProfiling("", 1);
int nodeId = 1;
CheckNodeIds(profile->top_down()->root(), &nodeId);
CHECK_EQ(7, nodeId - 1);
@@ -765,8 +627,7 @@
sample1.frames_count = 1;
generator.RecordTickSample(sample1);
- CpuProfile* profile =
- profiles.StopProfiling(TokenEnumerator::kNoSecurityToken, "", 1);
+ CpuProfile* profile = profiles.StopProfiling("", 1);
int nodeId = 1;
CheckNodeIds(profile->top_down()->root(), &nodeId);
CHECK_EQ(3, nodeId - 1);
@@ -860,7 +721,7 @@
"a();\n"
"stopProfiling();");
CHECK_EQ(1, profiler->GetProfilesCount());
- CpuProfile* profile = profiler->GetProfile(NULL, 0);
+ CpuProfile* profile = profiler->GetProfile(0);
const ProfileTree* topDown = profile->top_down();
const ProfileNode* current = topDown->root();
const_cast<ProfileNode*>(current)->Print(0);
@@ -965,3 +826,59 @@
}
+
+
+static const char* line_number_test_source_existing_functions =
+"function foo_at_the_first_line() {\n"
+"}\n"
+"foo_at_the_first_line();\n"
+"function lazy_func_at_forth_line() {}\n";
+
+
+static const char* line_number_test_source_profile_time_functions =
+"// Empty first line\n"
+"function bar_at_the_second_line() {\n"
+" foo_at_the_first_line();\n"
+"}\n"
+"bar_at_the_second_line();\n"
+"function lazy_func_at_6th_line() {}";
+
+int GetFunctionLineNumber(LocalContext* env, const char* name) {
+ CpuProfiler* profiler = i::Isolate::Current()->cpu_profiler();
+ CodeMap* code_map = profiler->generator()->code_map();
+ i::Handle<i::JSFunction> func = v8::Utils::OpenHandle(
+ *v8::Local<v8::Function>::Cast(
+ (*(*env))->Global()->Get(v8_str(name))));
+ CodeEntry* func_entry = code_map->FindEntry(func->code()->address());
+ if (!func_entry)
+ FATAL(name);
+ return func_entry->line_number();
+}
+
+
+TEST(LineNumber) {
+ i::FLAG_use_inlining = false;
+
+ CcTest::InitializeVM();
+ LocalContext env;
+ i::Isolate* isolate = i::Isolate::Current();
+ TestSetup test_setup;
+
+ i::HandleScope scope(isolate);
+
+ CompileRun(line_number_test_source_existing_functions);
+
+ CpuProfiler* profiler = isolate->cpu_profiler();
+ profiler->StartProfiling("LineNumber");
+
+ CompileRun(line_number_test_source_profile_time_functions);
+
+ profiler->processor()->StopSynchronously();
+
+ CHECK_EQ(1, GetFunctionLineNumber(&env, "foo_at_the_first_line"));
+ CHECK_EQ(0, GetFunctionLineNumber(&env, "lazy_func_at_forth_line"));
+ CHECK_EQ(2, GetFunctionLineNumber(&env, "bar_at_the_second_line"));
+ CHECK_EQ(0, GetFunctionLineNumber(&env, "lazy_func_at_6th_line"));
+
+ profiler->StopProfiling("LineNumber");
+}
diff --git a/test/cctest/test-regexp.cc b/test/cctest/test-regexp.cc
index f9eed1f..14989ee 100644
--- a/test/cctest/test-regexp.cc
+++ b/test/cctest/test-regexp.cc
@@ -94,6 +94,7 @@
return output;
}
+
static bool CheckSimple(const char* input) {
V8::Initialize(NULL);
v8::HandleScope scope(v8::Isolate::GetCurrent());
@@ -112,6 +113,7 @@
int max_match;
};
+
static MinMaxPair CheckMinMaxMatch(const char* input) {
V8::Initialize(NULL);
v8::HandleScope scope(v8::Isolate::GetCurrent());
@@ -377,6 +379,7 @@
CHECK_MIN_MAX("a(?!bbb|bb)c", 2, 2);
}
+
TEST(ParserRegression) {
CHECK_PARSE_EQ("[A-Z$-][x]", "(! [A-Z $ -] [x])");
CHECK_PARSE_EQ("a{3,4*}", "(: 'a{3,' (# 0 - g '4') '}')");
@@ -659,6 +662,7 @@
}
}
+
// Test of debug-only syntax.
#ifdef DEBUG
diff --git a/test/cctest/test-thread-termination.cc b/test/cctest/test-thread-termination.cc
index 50be501..b29b1dc 100644
--- a/test/cctest/test-thread-termination.cc
+++ b/test/cctest/test-thread-termination.cc
@@ -322,6 +322,7 @@
v8::Script::Compile(source)->Run();
}
+
void ReenterAfterTermination(const v8::FunctionCallbackInfo<v8::Value>& args) {
v8::TryCatch try_catch;
CHECK(!v8::V8::IsExecutionTerminating());
@@ -346,6 +347,7 @@
v8::Script::Compile(v8::String::New("function f() { fail(); } f()"))->Run();
}
+
// Test that reentry into V8 while the termination exception is still pending
// (has not yet unwound the 0-level JS frame) does not crash.
TEST(TerminateAndReenterFromThreadItself) {
@@ -365,6 +367,7 @@
"f()"))->Run()->IsTrue());
}
+
void DoLoopCancelTerminate(const v8::FunctionCallbackInfo<v8::Value>& args) {
v8::TryCatch try_catch;
CHECK(!v8::V8::IsExecutionTerminating());
@@ -384,6 +387,7 @@
CHECK(!v8::V8::IsExecutionTerminating());
}
+
// Test that a single thread of JavaScript execution can terminate
// itself and then resume execution.
TEST(TerminateCancelTerminateFromThreadItself) {
diff --git a/test/cctest/test-threads.cc b/test/cctest/test-threads.cc
index 3b9c1ad..a35a88d 100644
--- a/test/cctest/test-threads.cc
+++ b/test/cctest/test-threads.cc
@@ -175,6 +175,7 @@
i::Semaphore* semaphore_;
};
+
TEST(ThreadIdValidation) {
const int kNThreads = 100;
i::List<ThreadIdValidationThread*> threads(kNThreads);
diff --git a/test/cctest/test-types.cc b/test/cctest/test-types.cc
index 78abeba..b5f6595 100644
--- a/test/cctest/test-types.cc
+++ b/test/cctest/test-types.cc
@@ -62,6 +62,7 @@
CHECK(type2->Is(type1));
}
+
static void CheckSub(Handle<Type> type1, Handle<Type> type2) {
CHECK(type1->Is(type2));
CHECK(!type2->Is(type1));
@@ -70,6 +71,7 @@
}
}
+
static void CheckUnordered(Handle<Type> type1, Handle<Type> type2) {
CHECK(!type1->Is(type2));
CHECK(!type2->Is(type1));
@@ -78,6 +80,7 @@
}
}
+
static void CheckOverlap(Handle<Type> type1, Handle<Type> type2) {
CHECK(type1->Maybe(type2));
CHECK(type2->Maybe(type1));
@@ -86,6 +89,7 @@
}
}
+
static void CheckDisjoint(Handle<Type> type1, Handle<Type> type2) {
CHECK(!type1->Is(type2));
CHECK(!type2->Is(type1));
diff --git a/test/mjsunit/bugs/bug-2758.js b/test/mjsunit/bugs/bug-2758.js
new file mode 100644
index 0000000..ee78844
--- /dev/null
+++ b/test/mjsunit/bugs/bug-2758.js
@@ -0,0 +1,49 @@
+// Copyright 2013 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Flags: --allow-natives-syntax
+
+var functions = [
+ function() { var f = [].concat; f() },
+ function() { var f = [].push; f() },
+ function() { var f = [].shift; f() },
+ function() { (0, [].concat)() },
+ function() { (0, [].push)() },
+ function() { (0, [].shift)() }
+]
+
+for (var i = 0; i < 5; ++i) {
+ for (var j in functions) {
+ print(functions[i])
+ assertThrows(functions[j], TypeError)
+ }
+
+ if (i === 3) {
+ for (var j in functions)
+ %OptimizeFunctionOnNextCall(functions[j]);
+ }
+}
diff --git a/test/mjsunit/function-call.js b/test/mjsunit/function-call.js
index 38be10c..88df353 100644
--- a/test/mjsunit/function-call.js
+++ b/test/mjsunit/function-call.js
@@ -151,8 +151,8 @@
function checkExpectedMessage(e) {
assertTrue(e.message.indexOf("called on null or undefined") >= 0 ||
- e.message.indexOf("invoked on undefined or null value") >= 0 ||
- e.message.indexOf("Cannot convert null to object") >= 0);
+ e.message.indexOf("invoked on undefined or null value") >= 0 ||
+ e.message.indexOf("Cannot convert undefined or null to object") >= 0);
}
// Test that all natives using the ToObject call throw the right exception.
diff --git a/test/mjsunit/regress/regress-2537.js b/test/mjsunit/regress/regress-2537.js
index c6b5af9..1a86000 100644
--- a/test/mjsunit/regress/regress-2537.js
+++ b/test/mjsunit/regress/regress-2537.js
@@ -31,7 +31,8 @@
function foo(x, expected) {
assertEquals(expected, x); // This succeeds.
- x += 0; // Force int32 representation so that CompareIDAndBranch is used.
+ x += 0; // Force int32 representation so that
+ // CompareNumericAndBranch is used.
if (3 != x) {
x += 0; // Poor man's "iDef".
// Fails due to Smi-tagging without overflow check.
diff --git a/test/mjsunit/regress/regress-2618.js b/test/mjsunit/regress/regress-2618.js
index 638b71e..99f05ca 100644
--- a/test/mjsunit/regress/regress-2618.js
+++ b/test/mjsunit/regress/regress-2618.js
@@ -30,7 +30,7 @@
function f() {
do {
do {
- for (i = 0; i < 10000000; i++) {
+ for (var i = 0; i < 10000000; i++) {
// This should run long enough to trigger OSR.
}
} while (false);
@@ -46,7 +46,7 @@
do {
do {
- for (i = 0; i < 1; i++) { }
+ for (var i = 0; i < 1; i++) { }
} while (false);
} while (false);
@@ -58,7 +58,7 @@
do {
do {
do {
- for (i = 0; i < 10000000; i++) { }
+ for (var i = 0; i < 10000000; i++) { }
} while (false);
} while (false);
} while (false);
diff --git a/tools/gyp/v8.gyp b/tools/gyp/v8.gyp
index 892e437..e251a73 100644
--- a/tools/gyp/v8.gyp
+++ b/tools/gyp/v8.gyp
@@ -335,6 +335,8 @@
'../../src/heap-snapshot-generator.h',
'../../src/heap.cc',
'../../src/heap.h',
+ '../../src/hydrogen-dce.cc',
+ '../../src/hydrogen-dce.h',
'../../src/hydrogen-environment-liveness.cc',
'../../src/hydrogen-environment-liveness.h',
'../../src/hydrogen-escape-analysis.cc',
@@ -347,8 +349,14 @@
'../../src/hydrogen-gvn.h',
'../../src/hydrogen-infer-representation.cc',
'../../src/hydrogen-infer-representation.h',
+ '../../src/hydrogen-infer-types.cc',
+ '../../src/hydrogen-infer-types.h',
'../../src/hydrogen-range-analysis.cc',
'../../src/hydrogen-range-analysis.h',
+ '../../src/hydrogen-redundant-phi.cc',
+ '../../src/hydrogen-redundant-phi.h',
+ '../../src/hydrogen-sce.cc',
+ '../../src/hydrogen-sce.h',
'../../src/hydrogen-uint32-analysis.cc',
'../../src/hydrogen-uint32-analysis.h',
'../../src/hydrogen-osr.cc',
diff --git a/tools/oom_dump/oom_dump.cc b/tools/oom_dump/oom_dump.cc
index 1bf5ac1..5dfb5df 100644
--- a/tools/oom_dump/oom_dump.cc
+++ b/tools/oom_dump/oom_dump.cc
@@ -108,6 +108,7 @@
int* a_;
};
+
void DumpHeapStats(const char *minidump_file) {
Minidump minidump(minidump_file);
CHECK(minidump.Read());
diff --git a/tools/presubmit.py b/tools/presubmit.py
index c717ee8..12475b3 100755
--- a/tools/presubmit.py
+++ b/tools/presubmit.py
@@ -331,6 +331,14 @@
'gnuplot-4.6.3-emscripten.js']
IGNORE_TABS = IGNORE_COPYRIGHTS + ['unicode-test.js', 'html-comments.js']
+ def EndOfDeclaration(self, line):
+ return line == "}" or line == "};"
+
+ def StartOfDeclaration(self, line):
+ return line.find("//") == 0 or \
+ line.find("/*") == 0 or \
+ line.find(") {") != -1
+
def ProcessContents(self, name, contents):
result = True
base = basename(name)
@@ -342,7 +350,6 @@
if not COPYRIGHT_HEADER_PATTERN.search(contents):
print "%s is missing a correct copyright header." % name
result = False
- ext = base.split('.').pop()
if ' \n' in contents or contents.endswith(' '):
line = 0
lines = []
@@ -358,6 +365,30 @@
else:
print "%s has trailing whitespaces in line %s." % (name, linenumbers)
result = False
+ # Check two empty lines between declarations.
+ if name.endswith(".cc"):
+ line = 0
+ lines = []
+ parts = contents.split('\n')
+ while line < len(parts) - 2:
+ if self.EndOfDeclaration(parts[line]):
+ if self.StartOfDeclaration(parts[line + 1]):
+ lines.append(str(line + 1))
+ line += 1
+ elif parts[line + 1] == "" and \
+ self.StartOfDeclaration(parts[line + 2]):
+ lines.append(str(line + 1))
+ line += 2
+ line += 1
+ if len(lines) >= 1:
+ linenumbers = ', '.join(lines)
+ if len(lines) > 1:
+ print "%s does not have two empty lines between declarations " \
+ "in lines %s." % (name, linenumbers)
+ else:
+ print "%s does not have two empty lines between declarations " \
+ "in line %s." % (name, linenumbers)
+ result = False
return result
def ProcessFiles(self, files, path):
@@ -391,7 +422,8 @@
print "Running C++ lint check..."
if not options.no_lint:
success = CppLintProcessor().Run(workspace) and success
- print "Running copyright header and trailing whitespaces check..."
+ print "Running copyright header, trailing whitespaces and " \
+ "two empty lines between declarations check..."
success = SourceProcessor().Run(workspace) and success
if success:
return 0