Version 3.25.12 (based on bleeding_edge revision r19944)
PromiseCoerce should deal with an error during accessing "then" (Chromium issue 347095).
Propagate updated offsets in BoundsCheckBbData (Chromium issue 350863).
Add regression test for range analysis bug (issue 3204).
Continued fix for 351257. Reusing the feedback vector is too complex (Chromium issue 351257).
StopCpuProfiling should return non-const CpuProfile (issue 3213).
Allow for compiling with xcode 5.1 (which doesn't have gcc anymore).
Performance and stability improvements on all platforms.
git-svn-id: http://v8.googlecode.com/svn/trunk@19945 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
diff --git a/src/a64/assembler-a64.cc b/src/a64/assembler-a64.cc
index 5843c2e..51542b2 100644
--- a/src/a64/assembler-a64.cc
+++ b/src/a64/assembler-a64.cc
@@ -2548,7 +2548,7 @@
// Emit veneers for branches that would go out of range during emission of the
// constant pool.
- CheckVeneerPool(require_jump, kVeneerDistanceMargin - pool_size);
+ CheckVeneerPool(require_jump, kVeneerDistanceMargin + pool_size);
Label size_check;
bind(&size_check);
diff --git a/src/a64/assembler-a64.h b/src/a64/assembler-a64.h
index c07c638..31d7f17 100644
--- a/src/a64/assembler-a64.h
+++ b/src/a64/assembler-a64.h
@@ -2175,20 +2175,19 @@
: Assembler(NULL,
reinterpret_cast<byte*>(start),
count * kInstructionSize + kGap) {
- // Block constant pool emission.
- StartBlockConstPool();
+ StartBlockPools();
}
PatchingAssembler(byte* start, unsigned count)
: Assembler(NULL, start, count * kInstructionSize + kGap) {
// Block constant pool emission.
- StartBlockConstPool();
+ StartBlockPools();
}
~PatchingAssembler() {
// Const pool should still be blocked.
ASSERT(is_const_pool_blocked());
- EndBlockConstPool();
+ EndBlockPools();
// Verify we have generated the number of instruction we expected.
ASSERT((pc_offset() + kGap) == buffer_size_);
// Verify no relocation information has been emitted.
diff --git a/src/a64/constants-a64.h b/src/a64/constants-a64.h
index 140e4dd..4b216aa 100644
--- a/src/a64/constants-a64.h
+++ b/src/a64/constants-a64.h
@@ -85,12 +85,18 @@
const int64_t kDRegMask = 0xffffffffffffffffL;
// TODO(all) check if the expression below works on all compilers or if it
// triggers an overflow error.
-const int64_t kDSignMask = 0x1L << 63;
const int64_t kDSignBit = 63;
-const int64_t kXSignMask = 0x1L << 63;
+const int64_t kDSignMask = 0x1L << kDSignBit;
+const int64_t kSSignBit = 31;
+const int64_t kSSignMask = 0x1L << kSSignBit;
const int64_t kXSignBit = 63;
-const int64_t kWSignMask = 0x1L << 31;
+const int64_t kXSignMask = 0x1L << kXSignBit;
const int64_t kWSignBit = 31;
+const int64_t kWSignMask = 0x1L << kWSignBit;
+const int64_t kDQuietNanBit = 51;
+const int64_t kDQuietNanMask = 0x1L << kDQuietNanBit;
+const int64_t kSQuietNanBit = 22;
+const int64_t kSQuietNanMask = 0x1L << kSQuietNanBit;
const int64_t kByteMask = 0xffL;
const int64_t kHalfWordMask = 0xffffL;
const int64_t kWordMask = 0xffffffffL;
diff --git a/src/a64/deoptimizer-a64.cc b/src/a64/deoptimizer-a64.cc
index 3fa1ddd..f3a5fcd 100644
--- a/src/a64/deoptimizer-a64.cc
+++ b/src/a64/deoptimizer-a64.cc
@@ -377,6 +377,12 @@
}
+void FrameDescription::SetCallerConstantPool(unsigned offset, intptr_t value) {
+ // No out-of-line constant pool support.
+ UNREACHABLE();
+}
+
+
#undef __
} } // namespace v8::internal
diff --git a/src/a64/frames-a64.cc b/src/a64/frames-a64.cc
index 56d2e26..ca5be3a 100644
--- a/src/a64/frames-a64.cc
+++ b/src/a64/frames-a64.cc
@@ -40,10 +40,18 @@
Register JavaScriptFrame::fp_register() { return v8::internal::fp; }
Register JavaScriptFrame::context_register() { return cp; }
+Register JavaScriptFrame::constant_pool_pointer_register() {
+ UNREACHABLE();
+ return no_reg;
+}
Register StubFailureTrampolineFrame::fp_register() { return v8::internal::fp; }
Register StubFailureTrampolineFrame::context_register() { return cp; }
+Register StubFailureTrampolineFrame::constant_pool_pointer_register() {
+ UNREACHABLE();
+ return no_reg;
+}
Object*& ExitFrame::constant_pool_slot() const {
diff --git a/src/a64/full-codegen-a64.cc b/src/a64/full-codegen-a64.cc
index dcab182..a5f7311 100644
--- a/src/a64/full-codegen-a64.cc
+++ b/src/a64/full-codegen-a64.cc
@@ -129,8 +129,6 @@
handler_table_ =
isolate()->factory()->NewFixedArray(function()->handler_count(), TENURED);
- InitializeFeedbackVector();
-
profiling_counter_ = isolate()->factory()->NewCell(
Handle<Smi>(Smi::FromInt(FLAG_interrupt_budget), isolate()));
SetFunctionPosition(function());
@@ -1162,12 +1160,8 @@
// We got a fixed array in register x0. Iterate through that.
__ Bind(&fixed_array);
- Handle<Object> feedback = Handle<Object>(
- Smi::FromInt(TypeFeedbackInfo::kForInFastCaseMarker),
- isolate());
- StoreFeedbackVectorSlot(slot, feedback);
__ LoadObject(x1, FeedbackVector());
- __ Mov(x10, Operand(Smi::FromInt(TypeFeedbackInfo::kForInSlowCaseMarker)));
+ __ Mov(x10, Operand(TypeFeedbackInfo::MegamorphicSentinel(isolate())));
__ Str(x10, FieldMemOperand(x1, FixedArray::OffsetOfElementAt(slot)));
__ Mov(x1, Operand(Smi::FromInt(1))); // Smi indicates slow check.
@@ -2414,9 +2408,6 @@
// Record source position for debugger.
SetSourcePosition(expr->position());
- Handle<Object> uninitialized =
- TypeFeedbackInfo::UninitializedSentinel(isolate());
- StoreFeedbackVectorSlot(expr->CallFeedbackSlot(), uninitialized);
__ LoadObject(x2, FeedbackVector());
__ Mov(x3, Operand(Smi::FromInt(expr->CallFeedbackSlot())));
@@ -2613,9 +2604,6 @@
__ Peek(x1, arg_count * kXRegSize);
// Record call targets in unoptimized code.
- Handle<Object> uninitialized =
- TypeFeedbackInfo::UninitializedSentinel(isolate());
- StoreFeedbackVectorSlot(expr->CallNewFeedbackSlot(), uninitialized);
__ LoadObject(x2, FeedbackVector());
__ Mov(x3, Operand(Smi::FromInt(expr->CallNewFeedbackSlot())));
diff --git a/src/a64/instructions-a64.h b/src/a64/instructions-a64.h
index 472d4bf..ccab39e 100644
--- a/src/a64/instructions-a64.h
+++ b/src/a64/instructions-a64.h
@@ -67,6 +67,10 @@
DEFINE_DOUBLE(kFP64QuietNaN, 0x7ff800007fc00001);
DEFINE_FLOAT(kFP32QuietNaN, 0x7fc00001);
+// The default NaN values (for FPCR.DN=1).
+DEFINE_DOUBLE(kFP64DefaultNaN, 0x7ff8000000000000UL);
+DEFINE_FLOAT(kFP32DefaultNaN, 0x7fc00000);
+
#undef DEFINE_FLOAT
#undef DEFINE_DOUBLE
@@ -115,14 +119,12 @@
class Instruction {
public:
- Instr InstructionBits() const {
- Instr bits;
- memcpy(&bits, this, sizeof(bits));
- return bits;
+ V8_INLINE Instr InstructionBits() const {
+ return *reinterpret_cast<const Instr*>(this);
}
- void SetInstructionBits(Instr new_instr) {
- memcpy(this, &new_instr, sizeof(new_instr));
+ V8_INLINE void SetInstructionBits(Instr new_instr) {
+ *reinterpret_cast<Instr*>(this) = new_instr;
}
int Bit(int pos) const {
@@ -365,28 +367,6 @@
return reinterpret_cast<uint8_t*>(this) + offset;
}
- uint32_t Literal32() {
- uint32_t literal;
- memcpy(&literal, LiteralAddress(), sizeof(literal));
-
- return literal;
- }
-
- uint64_t Literal64() {
- uint64_t literal;
- memcpy(&literal, LiteralAddress(), sizeof(literal));
-
- return literal;
- }
-
- float LiteralFP32() {
- return rawbits_to_float(Literal32());
- }
-
- double LiteralFP64() {
- return rawbits_to_double(Literal64());
- }
-
Instruction* NextInstruction() {
return this + kInstructionSize;
}
diff --git a/src/a64/lithium-codegen-a64.cc b/src/a64/lithium-codegen-a64.cc
index 982cd8f..6e48ce4 100644
--- a/src/a64/lithium-codegen-a64.cc
+++ b/src/a64/lithium-codegen-a64.cc
@@ -841,16 +841,16 @@
__ bind(&table_start);
Label needs_frame;
for (int i = 0; i < deopt_jump_table_.length(); i++) {
- __ Bind(&deopt_jump_table_[i].label);
- Address entry = deopt_jump_table_[i].address;
- Deoptimizer::BailoutType type = deopt_jump_table_[i].bailout_type;
+ __ Bind(&deopt_jump_table_[i]->label);
+ Address entry = deopt_jump_table_[i]->address;
+ Deoptimizer::BailoutType type = deopt_jump_table_[i]->bailout_type;
int id = Deoptimizer::GetDeoptimizationId(isolate(), entry, type);
if (id == Deoptimizer::kNotDeoptimizationEntry) {
Comment(";;; jump table entry %d.", i);
} else {
Comment(";;; jump table entry %d: deoptimization bailout %d.", i, id);
}
- if (deopt_jump_table_[i].needs_frame) {
+ if (deopt_jump_table_[i]->needs_frame) {
ASSERT(!info()->saves_caller_doubles());
UseScratchRegisterScope temps(masm());
@@ -1030,24 +1030,23 @@
ASSERT(info()->IsStub() || frame_is_built_);
// Go through jump table if we need to build frame, or restore caller doubles.
- if (frame_is_built_ && !info()->saves_caller_doubles()) {
- Label dont_deopt;
- __ B(&dont_deopt, InvertBranchType(branch_type), reg, bit);
+ if (branch_type == always &&
+ frame_is_built_ && !info()->saves_caller_doubles()) {
__ Call(entry, RelocInfo::RUNTIME_ENTRY);
- __ Bind(&dont_deopt);
} else {
// We often have several deopts to the same entry, reuse the last
// jump entry if this is the case.
if (deopt_jump_table_.is_empty() ||
- (deopt_jump_table_.last().address != entry) ||
- (deopt_jump_table_.last().bailout_type != bailout_type) ||
- (deopt_jump_table_.last().needs_frame != !frame_is_built_)) {
- Deoptimizer::JumpTableEntry table_entry(entry,
- bailout_type,
- !frame_is_built_);
+ (deopt_jump_table_.last()->address != entry) ||
+ (deopt_jump_table_.last()->bailout_type != bailout_type) ||
+ (deopt_jump_table_.last()->needs_frame != !frame_is_built_)) {
+ Deoptimizer::JumpTableEntry* table_entry =
+ new(zone()) Deoptimizer::JumpTableEntry(entry,
+ bailout_type,
+ !frame_is_built_);
deopt_jump_table_.Add(table_entry, zone());
}
- __ B(&deopt_jump_table_.last().label,
+ __ B(&deopt_jump_table_.last()->label,
branch_type, reg, bit);
}
}
@@ -1507,7 +1506,11 @@
if (instr->size()->IsConstantOperand()) {
int32_t size = ToInteger32(LConstantOperand::cast(instr->size()));
- __ Allocate(size, result, temp1, temp2, deferred->entry(), flags);
+ if (size <= Page::kMaxRegularHeapObjectSize) {
+ __ Allocate(size, result, temp1, temp2, deferred->entry(), flags);
+ } else {
+ __ B(deferred->entry());
+ }
} else {
Register size = ToRegister32(instr->size());
__ Sxtw(size.X(), size);
@@ -4139,7 +4142,7 @@
// Note that this is correct even for kMinInt operands.
__ Neg(dividend, dividend);
__ And(dividend, dividend, Operand(mask));
- __ Neg(dividend, dividend);
+ __ Negs(dividend, dividend);
if (hmod->CheckFlag(HValue::kBailoutOnMinusZero)) {
DeoptimizeIf(eq, instr->environment());
}
diff --git a/src/a64/lithium-codegen-a64.h b/src/a64/lithium-codegen-a64.h
index fb1ca94..cca8772 100644
--- a/src/a64/lithium-codegen-a64.h
+++ b/src/a64/lithium-codegen-a64.h
@@ -347,7 +347,7 @@
void EnsureSpaceForLazyDeopt(int space_needed) V8_OVERRIDE;
ZoneList<LEnvironment*> deoptimizations_;
- ZoneList<Deoptimizer::JumpTableEntry> deopt_jump_table_;
+ ZoneList<Deoptimizer::JumpTableEntry*> deopt_jump_table_;
ZoneList<Handle<Object> > deoptimization_literals_;
int inlined_function_count_;
Scope* const scope_;
diff --git a/src/a64/simulator-a64.cc b/src/a64/simulator-a64.cc
index c80266b..ca17105 100644
--- a/src/a64/simulator-a64.cc
+++ b/src/a64/simulator-a64.cc
@@ -731,6 +731,16 @@
}
+template<> double Simulator::FPDefaultNaN<double>() const {
+ return kFP64DefaultNaN;
+}
+
+
+template<> float Simulator::FPDefaultNaN<float>() const {
+ return kFP32DefaultNaN;
+}
+
+
void Simulator::FPCompare(double val0, double val1) {
AssertSupportedFPCR();
@@ -2100,8 +2110,8 @@
void Simulator::VisitFPCompare(Instruction* instr) {
AssertSupportedFPCR();
- unsigned reg_size = instr->FPType() == FP32 ? kSRegSizeInBits
- : kDRegSizeInBits;
+ unsigned reg_size = (instr->Mask(FP64) == FP64) ? kDRegSizeInBits
+ : kSRegSizeInBits;
double fn_val = fpreg(reg_size, instr->Rn());
switch (instr->Mask(FPCompareMask)) {
@@ -2123,8 +2133,8 @@
if (ConditionPassed(static_cast<Condition>(instr->Condition()))) {
// If the condition passes, set the status flags to the result of
// comparing the operands.
- unsigned reg_size = instr->FPType() == FP32 ? kSRegSizeInBits
- : kDRegSizeInBits;
+ unsigned reg_size = (instr->Mask(FP64) == FP64) ? kDRegSizeInBits
+ : kSRegSizeInBits;
FPCompare(fpreg(reg_size, instr->Rn()), fpreg(reg_size, instr->Rm()));
} else {
// If the condition fails, set the status flags to the nzcv immediate.
@@ -2168,8 +2178,8 @@
case FABS_d: set_dreg(fd, std::fabs(dreg(fn))); break;
case FNEG_s: set_sreg(fd, -sreg(fn)); break;
case FNEG_d: set_dreg(fd, -dreg(fn)); break;
- case FSQRT_s: set_sreg(fd, std::sqrt(sreg(fn))); break;
- case FSQRT_d: set_dreg(fd, std::sqrt(dreg(fn))); break;
+ case FSQRT_s: set_sreg(fd, FPSqrt(sreg(fn))); break;
+ case FSQRT_d: set_dreg(fd, FPSqrt(dreg(fn))); break;
case FRINTA_s: set_sreg(fd, FPRoundInt(sreg(fn), FPTieAway)); break;
case FRINTA_d: set_dreg(fd, FPRoundInt(dreg(fn), FPTieAway)); break;
case FRINTN_s: set_sreg(fd, FPRoundInt(sreg(fn), FPTieEven)); break;
@@ -2428,8 +2438,10 @@
double Simulator::FPRoundInt(double value, FPRounding round_mode) {
if ((value == 0.0) || (value == kFP64PositiveInfinity) ||
- (value == kFP64NegativeInfinity) || std::isnan(value)) {
+ (value == kFP64NegativeInfinity)) {
return value;
+ } else if (std::isnan(value)) {
+ return FPProcessNaN(value);
}
double int_result = floor(value);
@@ -2473,8 +2485,9 @@
double Simulator::FPToDouble(float value) {
switch (std::fpclassify(value)) {
case FP_NAN: {
- // Convert NaNs as the processor would, assuming that FPCR.DN (default
- // NaN) is not set:
+ if (DN()) return kFP64DefaultNaN;
+
+ // Convert NaNs as the processor would:
// - The sign is propagated.
// - The payload (mantissa) is transferred entirely, except that the top
// bit is forced to '1', making the result a quiet NaN. The unused
@@ -2513,8 +2526,9 @@
switch (std::fpclassify(value)) {
case FP_NAN: {
- // Convert NaNs as the processor would, assuming that FPCR.DN (default
- // NaN) is not set:
+ if (DN()) return kFP32DefaultNaN;
+
+ // Convert NaNs as the processor would:
// - The sign is propagated.
// - The payload (mantissa) is transferred as much as possible, except
// that the top bit is forced to '1', making the result a quiet NaN.
@@ -2565,23 +2579,37 @@
unsigned fn = instr->Rn();
unsigned fm = instr->Rm();
+ // Fmaxnm and Fminnm have special NaN handling.
switch (instr->Mask(FPDataProcessing2SourceMask)) {
- case FADD_s: set_sreg(fd, sreg(fn) + sreg(fm)); break;
- case FADD_d: set_dreg(fd, dreg(fn) + dreg(fm)); break;
- case FSUB_s: set_sreg(fd, sreg(fn) - sreg(fm)); break;
- case FSUB_d: set_dreg(fd, dreg(fn) - dreg(fm)); break;
- case FMUL_s: set_sreg(fd, sreg(fn) * sreg(fm)); break;
- case FMUL_d: set_dreg(fd, dreg(fn) * dreg(fm)); break;
- case FDIV_s: set_sreg(fd, sreg(fn) / sreg(fm)); break;
- case FDIV_d: set_dreg(fd, dreg(fn) / dreg(fm)); break;
+ case FMAXNM_s: set_sreg(fd, FPMaxNM(sreg(fn), sreg(fm))); return;
+ case FMAXNM_d: set_dreg(fd, FPMaxNM(dreg(fn), dreg(fm))); return;
+ case FMINNM_s: set_sreg(fd, FPMinNM(sreg(fn), sreg(fm))); return;
+ case FMINNM_d: set_dreg(fd, FPMinNM(dreg(fn), dreg(fm))); return;
+ default:
+ break; // Fall through.
+ }
+
+ if (FPProcessNaNs(instr)) return;
+
+ switch (instr->Mask(FPDataProcessing2SourceMask)) {
+ case FADD_s: set_sreg(fd, FPAdd(sreg(fn), sreg(fm))); break;
+ case FADD_d: set_dreg(fd, FPAdd(dreg(fn), dreg(fm))); break;
+ case FSUB_s: set_sreg(fd, FPSub(sreg(fn), sreg(fm))); break;
+ case FSUB_d: set_dreg(fd, FPSub(dreg(fn), dreg(fm))); break;
+ case FMUL_s: set_sreg(fd, FPMul(sreg(fn), sreg(fm))); break;
+ case FMUL_d: set_dreg(fd, FPMul(dreg(fn), dreg(fm))); break;
+ case FDIV_s: set_sreg(fd, FPDiv(sreg(fn), sreg(fm))); break;
+ case FDIV_d: set_dreg(fd, FPDiv(dreg(fn), dreg(fm))); break;
case FMAX_s: set_sreg(fd, FPMax(sreg(fn), sreg(fm))); break;
case FMAX_d: set_dreg(fd, FPMax(dreg(fn), dreg(fm))); break;
case FMIN_s: set_sreg(fd, FPMin(sreg(fn), sreg(fm))); break;
case FMIN_d: set_dreg(fd, FPMin(dreg(fn), dreg(fm))); break;
- case FMAXNM_s: set_sreg(fd, FPMaxNM(sreg(fn), sreg(fm))); break;
- case FMAXNM_d: set_dreg(fd, FPMaxNM(dreg(fn), dreg(fm))); break;
- case FMINNM_s: set_sreg(fd, FPMinNM(sreg(fn), sreg(fm))); break;
- case FMINNM_d: set_dreg(fd, FPMinNM(dreg(fn), dreg(fm))); break;
+ case FMAXNM_s:
+ case FMAXNM_d:
+ case FMINNM_s:
+ case FMINNM_d:
+ // These were handled before the standard FPProcessNaNs() stage.
+ UNREACHABLE();
default: UNIMPLEMENTED();
}
}
@@ -2598,33 +2626,62 @@
// The C99 (and C++11) fma function performs a fused multiply-accumulate.
switch (instr->Mask(FPDataProcessing3SourceMask)) {
// fd = fa +/- (fn * fm)
- case FMADD_s: set_sreg(fd, fmaf(sreg(fn), sreg(fm), sreg(fa))); break;
- case FMSUB_s: set_sreg(fd, fmaf(-sreg(fn), sreg(fm), sreg(fa))); break;
- case FMADD_d: set_dreg(fd, fma(dreg(fn), dreg(fm), dreg(fa))); break;
- case FMSUB_d: set_dreg(fd, fma(-dreg(fn), dreg(fm), dreg(fa))); break;
- // Variants of the above where the result is negated.
- case FNMADD_s: set_sreg(fd, -fmaf(sreg(fn), sreg(fm), sreg(fa))); break;
- case FNMSUB_s: set_sreg(fd, -fmaf(-sreg(fn), sreg(fm), sreg(fa))); break;
- case FNMADD_d: set_dreg(fd, -fma(dreg(fn), dreg(fm), dreg(fa))); break;
- case FNMSUB_d: set_dreg(fd, -fma(-dreg(fn), dreg(fm), dreg(fa))); break;
+ case FMADD_s: set_sreg(fd, FPMulAdd(sreg(fa), sreg(fn), sreg(fm))); break;
+ case FMSUB_s: set_sreg(fd, FPMulAdd(sreg(fa), -sreg(fn), sreg(fm))); break;
+ case FMADD_d: set_dreg(fd, FPMulAdd(dreg(fa), dreg(fn), dreg(fm))); break;
+ case FMSUB_d: set_dreg(fd, FPMulAdd(dreg(fa), -dreg(fn), dreg(fm))); break;
+ // Negated variants of the above.
+ case FNMADD_s:
+ set_sreg(fd, FPMulAdd(-sreg(fa), -sreg(fn), sreg(fm)));
+ break;
+ case FNMSUB_s:
+ set_sreg(fd, FPMulAdd(-sreg(fa), sreg(fn), sreg(fm)));
+ break;
+ case FNMADD_d:
+ set_dreg(fd, FPMulAdd(-dreg(fa), -dreg(fn), dreg(fm)));
+ break;
+ case FNMSUB_d:
+ set_dreg(fd, FPMulAdd(-dreg(fa), dreg(fn), dreg(fm)));
+ break;
default: UNIMPLEMENTED();
}
}
template <typename T>
-T Simulator::FPMax(T a, T b) {
- if (IsSignallingNaN(a)) {
- return a;
- } else if (IsSignallingNaN(b)) {
- return b;
- } else if (std::isnan(a)) {
- ASSERT(IsQuietNaN(a));
- return a;
- } else if (std::isnan(b)) {
- ASSERT(IsQuietNaN(b));
- return b;
+T Simulator::FPAdd(T op1, T op2) {
+ // NaNs should be handled elsewhere.
+ ASSERT(!std::isnan(op1) && !std::isnan(op2));
+
+ if (isinf(op1) && isinf(op2) && (op1 != op2)) {
+ // inf + -inf returns the default NaN.
+ return FPDefaultNaN<T>();
+ } else {
+ // Other cases should be handled by standard arithmetic.
+ return op1 + op2;
}
+}
+
+
+template <typename T>
+T Simulator::FPDiv(T op1, T op2) {
+ // NaNs should be handled elsewhere.
+ ASSERT(!std::isnan(op1) && !std::isnan(op2));
+
+ if ((isinf(op1) && isinf(op2)) || ((op1 == 0.0) && (op2 == 0.0))) {
+ // inf / inf and 0.0 / 0.0 return the default NaN.
+ return FPDefaultNaN<T>();
+ } else {
+ // Other cases should be handled by standard arithmetic.
+ return op1 / op2;
+ }
+}
+
+
+template <typename T>
+T Simulator::FPMax(T a, T b) {
+ // NaNs should be handled elsewhere.
+ ASSERT(!std::isnan(a) && !std::isnan(b));
if ((a == 0.0) && (b == 0.0) &&
(copysign(1.0, a) != copysign(1.0, b))) {
@@ -2643,22 +2700,15 @@
} else if (!IsQuietNaN(a) && IsQuietNaN(b)) {
b = kFP64NegativeInfinity;
}
- return FPMax(a, b);
+
+ T result = FPProcessNaNs(a, b);
+ return std::isnan(result) ? result : FPMax(a, b);
}
template <typename T>
T Simulator::FPMin(T a, T b) {
- if (IsSignallingNaN(a)) {
- return a;
- } else if (IsSignallingNaN(b)) {
- return b;
- } else if (std::isnan(a)) {
- ASSERT(IsQuietNaN(a));
- return a;
- } else if (std::isnan(b)) {
- ASSERT(IsQuietNaN(b));
- return b;
- }
+ // NaNs should be handled elsewhere.
+ ASSERT(!isnan(a) && !isnan(b));
if ((a == 0.0) && (b == 0.0) &&
(copysign(1.0, a) != copysign(1.0, b))) {
@@ -2677,7 +2727,168 @@
} else if (!IsQuietNaN(a) && IsQuietNaN(b)) {
b = kFP64PositiveInfinity;
}
- return FPMin(a, b);
+
+ T result = FPProcessNaNs(a, b);
+ return isnan(result) ? result : FPMin(a, b);
+}
+
+
+template <typename T>
+T Simulator::FPMul(T op1, T op2) {
+ // NaNs should be handled elsewhere.
+ ASSERT(!std::isnan(op1) && !std::isnan(op2));
+
+ if ((isinf(op1) && (op2 == 0.0)) || (isinf(op2) && (op1 == 0.0))) {
+ // inf * 0.0 returns the default NaN.
+ return FPDefaultNaN<T>();
+ } else {
+ // Other cases should be handled by standard arithmetic.
+ return op1 * op2;
+ }
+}
+
+
+template<typename T>
+T Simulator::FPMulAdd(T a, T op1, T op2) {
+ T result = FPProcessNaNs3(a, op1, op2);
+
+ T sign_a = copysign(1.0, a);
+ T sign_prod = copysign(1.0, op1) * copysign(1.0, op2);
+ bool isinf_prod = std::isinf(op1) || std::isinf(op2);
+ bool operation_generates_nan =
+ (std::isinf(op1) && (op2 == 0.0)) || // inf * 0.0
+ (std::isinf(op2) && (op1 == 0.0)) || // 0.0 * inf
+ (std::isinf(a) && isinf_prod && (sign_a != sign_prod)); // inf - inf
+
+ if (std::isnan(result)) {
+ // Generated NaNs override quiet NaNs propagated from a.
+ if (operation_generates_nan && IsQuietNaN(a)) {
+ return FPDefaultNaN<T>();
+ } else {
+ return result;
+ }
+ }
+
+ // If the operation would produce a NaN, return the default NaN.
+ if (operation_generates_nan) {
+ return FPDefaultNaN<T>();
+ }
+
+ // Work around broken fma implementations for exact zero results: The sign of
+ // exact 0.0 results is positive unless both a and op1 * op2 are negative.
+ if (((op1 == 0.0) || (op2 == 0.0)) && (a == 0.0)) {
+ return ((sign_a < 0) && (sign_prod < 0)) ? -0.0 : 0.0;
+ }
+
+ result = FusedMultiplyAdd(op1, op2, a);
+ ASSERT(!std::isnan(result));
+
+ // Work around broken fma implementations for rounded zero results: If a is
+ // 0.0, the sign of the result is the sign of op1 * op2 before rounding.
+ if ((a == 0.0) && (result == 0.0)) {
+ return copysign(0.0, sign_prod);
+ }
+
+ return result;
+}
+
+
+template <typename T>
+T Simulator::FPSqrt(T op) {
+ if (std::isnan(op)) {
+ return FPProcessNaN(op);
+ } else if (op < 0.0) {
+ return FPDefaultNaN<T>();
+ } else {
+ return std::sqrt(op);
+ }
+}
+
+
+template <typename T>
+T Simulator::FPSub(T op1, T op2) {
+ // NaNs should be handled elsewhere.
+ ASSERT(!std::isnan(op1) && !std::isnan(op2));
+
+ if (isinf(op1) && isinf(op2) && (op1 == op2)) {
+ // inf - inf returns the default NaN.
+ return FPDefaultNaN<T>();
+ } else {
+ // Other cases should be handled by standard arithmetic.
+ return op1 - op2;
+ }
+}
+
+
+template <typename T>
+T Simulator::FPProcessNaN(T op) {
+ ASSERT(std::isnan(op));
+ return DN() ? FPDefaultNaN<T>() : ToQuietNaN(op);
+}
+
+
+template <typename T>
+T Simulator::FPProcessNaNs(T op1, T op2) {
+ if (IsSignallingNaN(op1)) {
+ return FPProcessNaN(op1);
+ } else if (IsSignallingNaN(op2)) {
+ return FPProcessNaN(op2);
+ } else if (std::isnan(op1)) {
+ ASSERT(IsQuietNaN(op1));
+ return FPProcessNaN(op1);
+ } else if (std::isnan(op2)) {
+ ASSERT(IsQuietNaN(op2));
+ return FPProcessNaN(op2);
+ } else {
+ return 0.0;
+ }
+}
+
+
+template <typename T>
+T Simulator::FPProcessNaNs3(T op1, T op2, T op3) {
+ if (IsSignallingNaN(op1)) {
+ return FPProcessNaN(op1);
+ } else if (IsSignallingNaN(op2)) {
+ return FPProcessNaN(op2);
+ } else if (IsSignallingNaN(op3)) {
+ return FPProcessNaN(op3);
+ } else if (std::isnan(op1)) {
+ ASSERT(IsQuietNaN(op1));
+ return FPProcessNaN(op1);
+ } else if (std::isnan(op2)) {
+ ASSERT(IsQuietNaN(op2));
+ return FPProcessNaN(op2);
+ } else if (std::isnan(op3)) {
+ ASSERT(IsQuietNaN(op3));
+ return FPProcessNaN(op3);
+ } else {
+ return 0.0;
+ }
+}
+
+
+bool Simulator::FPProcessNaNs(Instruction* instr) {
+ unsigned fd = instr->Rd();
+ unsigned fn = instr->Rn();
+ unsigned fm = instr->Rm();
+ bool done = false;
+
+ if (instr->Mask(FP64) == FP64) {
+ double result = FPProcessNaNs(dreg(fn), dreg(fm));
+ if (std::isnan(result)) {
+ set_dreg(fd, result);
+ done = true;
+ }
+ } else {
+ float result = FPProcessNaNs(sreg(fn), sreg(fm));
+ if (std::isnan(result)) {
+ set_sreg(fd, result);
+ done = true;
+ }
+ }
+
+ return done;
}
diff --git a/src/a64/simulator-a64.h b/src/a64/simulator-a64.h
index 602d723..de7330b 100644
--- a/src/a64/simulator-a64.h
+++ b/src/a64/simulator-a64.h
@@ -537,8 +537,9 @@
SimSystemRegister& nzcv() { return nzcv_; }
// TODO(jbramley): Find a way to make the fpcr_ members return the proper
- // types, so this accessor is not necessary.
+ // types, so these accessors are not necessary.
FPRounding RMode() { return static_cast<FPRounding>(fpcr_.RMode()); }
+ bool DN() { return fpcr_.DN() != 0; }
SimSystemRegister& fpcr() { return fpcr_; }
// Debug helpers
@@ -707,6 +708,9 @@
uint64_t ReverseBits(uint64_t value, unsigned num_bits);
uint64_t ReverseBytes(uint64_t value, ReverseByteMode mode);
+ template <typename T>
+ T FPDefaultNaN() const;
+
void FPCompare(double val0, double val1);
double FPRoundInt(double value, FPRounding round_mode);
double FPToDouble(float value);
@@ -721,17 +725,47 @@
uint64_t FPToUInt64(double value, FPRounding rmode);
template <typename T>
- T FPMax(T a, T b);
+ T FPAdd(T op1, T op2);
template <typename T>
- T FPMin(T a, T b);
+ T FPDiv(T op1, T op2);
+
+ template <typename T>
+ T FPMax(T a, T b);
template <typename T>
T FPMaxNM(T a, T b);
template <typename T>
+ T FPMin(T a, T b);
+
+ template <typename T>
T FPMinNM(T a, T b);
+ template <typename T>
+ T FPMul(T op1, T op2);
+
+ template <typename T>
+ T FPMulAdd(T a, T op1, T op2);
+
+ template <typename T>
+ T FPSqrt(T op);
+
+ template <typename T>
+ T FPSub(T op1, T op2);
+
+ // Standard NaN processing.
+ template <typename T>
+ T FPProcessNaN(T op);
+
+ bool FPProcessNaNs(Instruction* instr);
+
+ template <typename T>
+ T FPProcessNaNs(T op1, T op2);
+
+ template <typename T>
+ T FPProcessNaNs3(T op1, T op2, T op3);
+
void CheckStackAlignment();
inline void CheckPCSComplianceAndRun();
@@ -784,7 +818,6 @@
// functions, or to save and restore it when entering and leaving generated
// code.
void AssertSupportedFPCR() {
- ASSERT(fpcr().DN() == 0); // No default-NaN support.
ASSERT(fpcr().FZ() == 0); // No flush-to-zero support.
ASSERT(fpcr().RMode() == FPTieEven); // Ties-to-even rounding only.
diff --git a/src/a64/utils-a64.h b/src/a64/utils-a64.h
index 16c51a9..c14ea95 100644
--- a/src/a64/utils-a64.h
+++ b/src/a64/utils-a64.h
@@ -70,7 +70,7 @@
}
-// Bits counting.
+// Bit counting.
int CountLeadingZeros(uint64_t value, int width);
int CountLeadingSignBits(int64_t value, int width);
int CountTrailingZeros(uint64_t value, int width);
@@ -80,9 +80,8 @@
// NaN tests.
inline bool IsSignallingNaN(double num) {
- const uint64_t kFP64QuietNaNMask = 0x0008000000000000UL;
uint64_t raw = double_to_rawbits(num);
- if (std::isnan(num) && ((raw & kFP64QuietNaNMask) == 0)) {
+ if (std::isnan(num) && ((raw & kDQuietNanMask) == 0)) {
return true;
}
return false;
@@ -90,9 +89,8 @@
inline bool IsSignallingNaN(float num) {
- const uint64_t kFP32QuietNaNMask = 0x00400000UL;
uint32_t raw = float_to_rawbits(num);
- if (std::isnan(num) && ((raw & kFP32QuietNaNMask) == 0)) {
+ if (std::isnan(num) && ((raw & kSQuietNanMask) == 0)) {
return true;
}
return false;
@@ -104,6 +102,30 @@
return std::isnan(num) && !IsSignallingNaN(num);
}
+
+// Convert the NaN in 'num' to a quiet NaN.
+inline double ToQuietNaN(double num) {
+ ASSERT(isnan(num));
+ return rawbits_to_double(double_to_rawbits(num) | kDQuietNanMask);
+}
+
+
+inline float ToQuietNaN(float num) {
+ ASSERT(isnan(num));
+ return rawbits_to_float(float_to_rawbits(num) | kSQuietNanMask);
+}
+
+
+// Fused multiply-add.
+inline double FusedMultiplyAdd(double op1, double op2, double a) {
+ return fma(op1, op2, a);
+}
+
+
+inline float FusedMultiplyAdd(float op1, float op2, float a) {
+ return fmaf(op1, op2, a);
+}
+
} } // namespace v8::internal
#endif // V8_A64_UTILS_A64_H_
diff --git a/src/api.cc b/src/api.cc
index fe43c4d..0418506 100644
--- a/src/api.cc
+++ b/src/api.cc
@@ -1611,107 +1611,89 @@
}
-// --- S c r i p t ---
+// --- S c r i p t s ---
-Local<Script> Script::New(v8::Handle<String> source,
- v8::ScriptOrigin* origin,
- v8::ScriptData* pre_data) {
- i::Handle<i::String> str = Utils::OpenHandle(*source);
- i::Isolate* isolate = str->GetIsolate();
- ON_BAILOUT(isolate, "v8::Script::New()", return Local<Script>());
- LOG_API(isolate, "Script::New");
- ENTER_V8(isolate);
- i::SharedFunctionInfo* raw_result = NULL;
- { i::HandleScope scope(isolate);
- i::Handle<i::Object> name_obj;
- int line_offset = 0;
- int column_offset = 0;
- bool is_shared_cross_origin = false;
- if (origin != NULL) {
- if (!origin->ResourceName().IsEmpty()) {
- name_obj = Utils::OpenHandle(*origin->ResourceName());
- }
- if (!origin->ResourceLineOffset().IsEmpty()) {
- line_offset = static_cast<int>(origin->ResourceLineOffset()->Value());
- }
- if (!origin->ResourceColumnOffset().IsEmpty()) {
- column_offset =
- static_cast<int>(origin->ResourceColumnOffset()->Value());
- }
- if (!origin->ResourceIsSharedCrossOrigin().IsEmpty()) {
- v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate);
- is_shared_cross_origin =
- origin->ResourceIsSharedCrossOrigin() == v8::True(v8_isolate);
- }
- }
- EXCEPTION_PREAMBLE(isolate);
- i::ScriptDataImpl* pre_data_impl =
- static_cast<i::ScriptDataImpl*>(pre_data);
- // We assert that the pre-data is sane, even though we can actually
- // handle it if it turns out not to be in release mode.
- ASSERT(pre_data_impl == NULL || pre_data_impl->SanityCheck());
- // If the pre-data isn't sane we simply ignore it
- if (pre_data_impl != NULL && !pre_data_impl->SanityCheck()) {
- pre_data_impl = NULL;
- }
- i::Handle<i::SharedFunctionInfo> result =
- i::Compiler::CompileScript(str,
- name_obj,
- line_offset,
- column_offset,
- is_shared_cross_origin,
- isolate->global_context(),
- NULL,
- pre_data_impl,
- i::NOT_NATIVES_CODE);
- has_pending_exception = result.is_null();
- EXCEPTION_BAILOUT_CHECK(isolate, Local<Script>());
- raw_result = *result;
+// Internally, UnboundScript is a SharedFunctionInfo, and Script is a
+// JSFunction.
+
+ScriptCompiler::Source::Source(Local<String> string, const ScriptOrigin& origin,
+ const CachedData& data)
+ : source_string(string),
+ resource_name(origin.ResourceName()),
+ resource_line_offset(origin.ResourceLineOffset()),
+ resource_column_offset(origin.ResourceColumnOffset()),
+ resource_is_shared_cross_origin(origin.ResourceIsSharedCrossOrigin()),
+ cached_data(data) {}
+
+
+ScriptCompiler::Source::Source(Local<String> string,
+ const CachedData& data)
+ : source_string(string), cached_data(data) {}
+
+
+Local<Script> UnboundScript::BindToCurrentContext() {
+ i::Handle<i::HeapObject> obj =
+ i::Handle<i::HeapObject>::cast(Utils::OpenHandle(this));
+ i::Handle<i::SharedFunctionInfo>
+ function_info(i::SharedFunctionInfo::cast(*obj), obj->GetIsolate());
+ i::Handle<i::JSFunction> function =
+ obj->GetIsolate()->factory()->NewFunctionFromSharedFunctionInfo(
+ function_info, obj->GetIsolate()->global_context());
+ return ToApiHandle<Script>(function);
+}
+
+
+int UnboundScript::GetId() {
+ i::Handle<i::HeapObject> obj =
+ i::Handle<i::HeapObject>::cast(Utils::OpenHandle(this));
+ i::Isolate* isolate = obj->GetIsolate();
+ ON_BAILOUT(isolate, "v8::UnboundScript::GetId()", return -1);
+ LOG_API(isolate, "v8::UnboundScript::GetId");
+ {
+ i::HandleScope scope(isolate);
+ i::Handle<i::SharedFunctionInfo> function_info(
+ i::SharedFunctionInfo::cast(*obj));
+ i::Handle<i::Script> script(i::Script::cast(function_info->script()));
+ return script->id()->value();
}
- i::Handle<i::SharedFunctionInfo> result(raw_result, isolate);
- return ToApiHandle<Script>(result);
}
-Local<Script> Script::New(v8::Handle<String> source,
- v8::Handle<Value> file_name) {
- ScriptOrigin origin(file_name);
- return New(source, &origin);
+int UnboundScript::GetLineNumber(int code_pos) {
+ i::Handle<i::HeapObject> obj =
+ i::Handle<i::HeapObject>::cast(Utils::OpenHandle(this));
+ i::Isolate* isolate = obj->GetIsolate();
+ ON_BAILOUT(isolate, "v8::UnboundScript::GetLineNumber()", return -1);
+ LOG_API(isolate, "UnboundScript::GetLineNumber");
+ if (obj->IsScript()) {
+ i::Handle<i::Script> script(i::Script::cast(*obj));
+ return i::GetScriptLineNumber(script, code_pos);
+ } else {
+ return -1;
+ }
}
-Local<Script> Script::Compile(v8::Handle<String> source,
- v8::ScriptOrigin* origin,
- v8::ScriptData* pre_data) {
- i::Handle<i::String> str = Utils::OpenHandle(*source);
- i::Isolate* isolate = str->GetIsolate();
- ON_BAILOUT(isolate, "v8::Script::Compile()", return Local<Script>());
- LOG_API(isolate, "Script::Compile");
- ENTER_V8(isolate);
- Local<Script> generic = New(source, origin, pre_data);
- if (generic.IsEmpty())
- return generic;
- i::Handle<i::Object> obj = Utils::OpenHandle(*generic);
- i::Handle<i::SharedFunctionInfo> function =
- i::Handle<i::SharedFunctionInfo>(i::SharedFunctionInfo::cast(*obj));
- i::Handle<i::JSFunction> result =
- isolate->factory()->NewFunctionFromSharedFunctionInfo(
- function,
- isolate->global_context());
- return ToApiHandle<Script>(result);
-}
-
-
-Local<Script> Script::Compile(v8::Handle<String> source,
- v8::Handle<Value> file_name) {
- ScriptOrigin origin(file_name);
- return Compile(source, &origin);
+Handle<Value> UnboundScript::GetScriptName() {
+ i::Handle<i::HeapObject> obj =
+ i::Handle<i::HeapObject>::cast(Utils::OpenHandle(this));
+ i::Isolate* isolate = obj->GetIsolate();
+ ON_BAILOUT(isolate, "v8::UnboundScript::GetName()",
+ return Handle<String>());
+ LOG_API(isolate, "UnboundScript::GetName");
+ if (obj->IsScript()) {
+ i::Object* name = i::Script::cast(*obj)->name();
+ return Utils::ToLocal(i::Handle<i::Object>(name, isolate));
+ } else {
+ return Handle<String>();
+ }
}
Local<Value> Script::Run() {
- // If execution is terminating, Compile(script)->Run() requires this check.
+ // If execution is terminating, Compile(..)->Run() requires this
+ // check.
if (this == NULL) return Local<Value>();
i::Handle<i::HeapObject> obj =
i::Handle<i::HeapObject>::cast(Utils::OpenHandle(this));
@@ -1724,15 +1706,8 @@
i::Object* raw_result = NULL;
{
i::HandleScope scope(isolate);
- i::Handle<i::JSFunction> fun;
- if (obj->IsSharedFunctionInfo()) {
- i::Handle<i::SharedFunctionInfo>
- function_info(i::SharedFunctionInfo::cast(*obj), isolate);
- fun = isolate->factory()->NewFunctionFromSharedFunctionInfo(
- function_info, isolate->global_context());
- } else {
- fun = i::Handle<i::JSFunction>(i::JSFunction::cast(*obj), isolate);
- }
+ i::Handle<i::JSFunction> fun =
+ i::Handle<i::JSFunction>(i::JSFunction::cast(*obj), isolate);
EXCEPTION_PREAMBLE(isolate);
i::Handle<i::Object> receiver(
isolate->context()->global_proxy(), isolate);
@@ -1746,62 +1721,124 @@
}
-static i::Handle<i::SharedFunctionInfo> OpenScript(Script* script) {
- i::Handle<i::Object> obj = Utils::OpenHandle(script);
- i::Handle<i::SharedFunctionInfo> result;
- if (obj->IsSharedFunctionInfo()) {
- result =
- i::Handle<i::SharedFunctionInfo>(i::SharedFunctionInfo::cast(*obj));
- } else {
- result =
- i::Handle<i::SharedFunctionInfo>(i::JSFunction::cast(*obj)->shared());
- }
- return result;
+Local<UnboundScript> Script::GetUnboundScript() {
+ i::Handle<i::Object> obj = Utils::OpenHandle(this);
+ return ToApiHandle<UnboundScript>(
+ i::Handle<i::SharedFunctionInfo>(i::JSFunction::cast(*obj)->shared()));
}
-int Script::GetId() {
- i::Handle<i::HeapObject> obj =
- i::Handle<i::HeapObject>::cast(Utils::OpenHandle(this));
- i::Isolate* isolate = obj->GetIsolate();
- ON_BAILOUT(isolate, "v8::Script::Id()", return -1);
- LOG_API(isolate, "Script::Id");
- {
- i::HandleScope scope(isolate);
- i::Handle<i::SharedFunctionInfo> function_info = OpenScript(this);
- i::Handle<i::Script> script(i::Script::cast(function_info->script()));
- return script->id()->value();
+Local<UnboundScript> ScriptCompiler::CompileUnbound(
+ Isolate* v8_isolate,
+ const Source& source,
+ CompileOptions options) {
+ // FIXME(marja): This function cannot yet create cached data (if options |
+ // produce_data_to_cache is true), but the PreCompile function is still there
+ // for doing it.
+ i::Handle<i::String> str = Utils::OpenHandle(*(source.source_string));
+ i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8_isolate);
+ ON_BAILOUT(isolate, "v8::ScriptCompiler::CompileUnbound()",
+ return Local<UnboundScript>());
+ LOG_API(isolate, "ScriptCompiler::CompileUnbound");
+ ENTER_V8(isolate);
+ i::SharedFunctionInfo* raw_result = NULL;
+ { i::HandleScope scope(isolate);
+ i::Handle<i::Object> name_obj;
+ int line_offset = 0;
+ int column_offset = 0;
+ bool is_shared_cross_origin = false;
+ if (!source.resource_name.IsEmpty()) {
+ name_obj = Utils::OpenHandle(*source.resource_name);
+ }
+ if (!source.resource_line_offset.IsEmpty()) {
+ line_offset = static_cast<int>(source.resource_line_offset->Value());
+ }
+ if (!source.resource_column_offset.IsEmpty()) {
+ column_offset =
+ static_cast<int>(source.resource_column_offset->Value());
+ }
+ if (!source.resource_is_shared_cross_origin.IsEmpty()) {
+ v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate);
+ is_shared_cross_origin =
+ source.resource_is_shared_cross_origin == v8::True(v8_isolate);
+ }
+ EXCEPTION_PREAMBLE(isolate);
+ i::ScriptDataImpl* pre_data_impl = NULL;
+ if (source.cached_data.data) {
+ // FIXME(marja): Make compiler use CachedData directly.
+ pre_data_impl = static_cast<i::ScriptDataImpl*>(ScriptData::New(
+ reinterpret_cast<const char*>(source.cached_data.data),
+ source.cached_data.length));
+ }
+ // We assert that the pre-data is sane, even though we can actually
+ // handle it if it turns out not to be in release mode.
+ ASSERT(pre_data_impl == NULL || pre_data_impl->SanityCheck());
+ // If the pre-data isn't sane we simply ignore it
+ if (pre_data_impl != NULL && !pre_data_impl->SanityCheck()) {
+ delete pre_data_impl;
+ pre_data_impl = NULL;
+ }
+ i::Handle<i::SharedFunctionInfo> result =
+ i::Compiler::CompileScript(str,
+ name_obj,
+ line_offset,
+ column_offset,
+ is_shared_cross_origin,
+ isolate->global_context(),
+ NULL,
+ pre_data_impl,
+ i::NOT_NATIVES_CODE);
+ has_pending_exception = result.is_null();
+ EXCEPTION_BAILOUT_CHECK(isolate, Local<UnboundScript>());
+ raw_result = *result;
+ delete pre_data_impl;
}
+ i::Handle<i::SharedFunctionInfo> result(raw_result, isolate);
+ return ToApiHandle<UnboundScript>(result);
}
-int Script::GetLineNumber(int code_pos) {
- i::Handle<i::HeapObject> obj =
- i::Handle<i::HeapObject>::cast(Utils::OpenHandle(this));
- i::Isolate* isolate = obj->GetIsolate();
- ON_BAILOUT(isolate, "v8::Script::GetLineNumber()", return -1);
- LOG_API(isolate, "Script::GetLineNumber");
- if (obj->IsScript()) {
- i::Handle<i::Script> script = i::Handle<i::Script>(i::Script::cast(*obj));
- return i::GetScriptLineNumber(script, code_pos);
- } else {
- return -1;
- }
+Local<Script> ScriptCompiler::Compile(
+ Isolate* v8_isolate,
+ const Source& source,
+ CompileOptions options) {
+ i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8_isolate);
+ ON_BAILOUT(isolate, "v8::ScriptCompiler::Compile()",
+ return Local<Script>());
+ LOG_API(isolate, "ScriptCompiler::CompiletBound()");
+ ENTER_V8(isolate);
+ Local<UnboundScript> generic =
+ CompileUnbound(v8_isolate, source, options);
+ if (generic.IsEmpty()) return Local<Script>();
+ return generic->BindToCurrentContext();
}
-Handle<Value> Script::GetScriptName() {
- i::Handle<i::HeapObject> obj =
- i::Handle<i::HeapObject>::cast(Utils::OpenHandle(this));
- i::Isolate* isolate = obj->GetIsolate();
- ON_BAILOUT(isolate, "v8::Script::GetName()", return Handle<String>());
- LOG_API(isolate, "Script::GetName");
- if (obj->IsScript()) {
- i::Object* name = i::Script::cast(*obj)->name();
- return Utils::ToLocal(i::Handle<i::Object>(name, isolate));
- } else {
- return Handle<String>();
+Local<Script> Script::Compile(v8::Handle<String> source,
+ v8::ScriptOrigin* origin,
+ ScriptData* script_data) {
+ i::Handle<i::String> str = Utils::OpenHandle(*source);
+ ScriptCompiler::CachedData cached_data;
+ if (script_data) {
+ cached_data = ScriptCompiler::CachedData(
+ reinterpret_cast<const uint8_t*>(script_data->Data()),
+ script_data->Length());
}
+ if (origin) {
+ return ScriptCompiler::Compile(
+ reinterpret_cast<v8::Isolate*>(str->GetIsolate()),
+ ScriptCompiler::Source(source, *origin, cached_data));
+ }
+ return ScriptCompiler::Compile(
+ reinterpret_cast<v8::Isolate*>(str->GetIsolate()),
+ ScriptCompiler::Source(source, cached_data));
+}
+
+
+Local<Script> Script::Compile(v8::Handle<String> source,
+ v8::Handle<String> file_name) {
+ ScriptOrigin origin(file_name);
+ return Compile(source, &origin);
}
@@ -4029,7 +4066,9 @@
int Function::ScriptId() const {
i::Handle<i::JSFunction> func = Utils::OpenHandle(this);
- if (!func->shared()->script()->IsScript()) return v8::Script::kNoScriptId;
+ if (!func->shared()->script()->IsScript()) {
+ return v8::UnboundScript::kNoScriptId;
+ }
i::Handle<i::Script> script(i::Script::cast(func->shared()->script()));
return script->id()->value();
}
@@ -6956,19 +6995,29 @@
}
-void CpuProfiler::StartCpuProfiling(Handle<String> title, bool record_samples) {
+void CpuProfiler::StartProfiling(Handle<String> title, bool record_samples) {
reinterpret_cast<i::CpuProfiler*>(this)->StartProfiling(
*Utils::OpenHandle(*title), record_samples);
}
-const CpuProfile* CpuProfiler::StopCpuProfiling(Handle<String> title) {
- return reinterpret_cast<const CpuProfile*>(
+void CpuProfiler::StartCpuProfiling(Handle<String> title, bool record_samples) {
+ StartProfiling(title, record_samples);
+}
+
+
+CpuProfile* CpuProfiler::StopProfiling(Handle<String> title) {
+ return reinterpret_cast<CpuProfile*>(
reinterpret_cast<i::CpuProfiler*>(this)->StopProfiling(
*Utils::OpenHandle(*title)));
}
+const CpuProfile* CpuProfiler::StopCpuProfiling(Handle<String> title) {
+ return StopProfiling(title);
+}
+
+
void CpuProfiler::SetIdle(bool is_idle) {
i::Isolate* isolate = reinterpret_cast<i::CpuProfiler*>(this)->isolate();
i::StateTag state = isolate->current_vm_state();
diff --git a/src/api.h b/src/api.h
index 9fc99d9..128087c 100644
--- a/src/api.h
+++ b/src/api.h
@@ -183,7 +183,8 @@
V(DataView, JSDataView) \
V(String, String) \
V(Symbol, Symbol) \
- V(Script, Object) \
+ V(Script, JSFunction) \
+ V(UnboundScript, SharedFunctionInfo) \
V(Function, JSFunction) \
V(Message, JSObject) \
V(Context, Context) \
diff --git a/src/arm/builtins-arm.cc b/src/arm/builtins-arm.cc
index daca96d..f53f293 100644
--- a/src/arm/builtins-arm.cc
+++ b/src/arm/builtins-arm.cc
@@ -1353,8 +1353,14 @@
// then tear down the parameters.
__ ldr(r1, MemOperand(fp, -(StandardFrameConstants::kFixedFrameSizeFromFp +
kPointerSize)));
- __ mov(sp, fp);
- __ ldm(ia_w, sp, fp.bit() | lr.bit());
+
+ if (FLAG_enable_ool_constant_pool) {
+ __ add(sp, fp, Operand(StandardFrameConstants::kConstantPoolOffset));
+ __ ldm(ia_w, sp, pp.bit() | fp.bit() | lr.bit());
+ } else {
+ __ mov(sp, fp);;
+ __ ldm(ia_w, sp, fp.bit() | lr.bit());
+ }
__ add(sp, sp, Operand::PointerOffsetFromSmiKey(r1));
__ add(sp, sp, Operand(kPointerSize)); // adjust for receiver
}
diff --git a/src/arm/deoptimizer-arm.cc b/src/arm/deoptimizer-arm.cc
index 59e6e95..ef3ea27 100644
--- a/src/arm/deoptimizer-arm.cc
+++ b/src/arm/deoptimizer-arm.cc
@@ -373,6 +373,12 @@
}
+void FrameDescription::SetCallerConstantPool(unsigned offset, intptr_t value) {
+ ASSERT(FLAG_enable_ool_constant_pool);
+ SetFrameSlot(offset, value);
+}
+
+
#undef __
} } // namespace v8::internal
diff --git a/src/arm/full-codegen-arm.cc b/src/arm/full-codegen-arm.cc
index 8672ccb..bad1003 100644
--- a/src/arm/full-codegen-arm.cc
+++ b/src/arm/full-codegen-arm.cc
@@ -131,8 +131,6 @@
handler_table_ =
isolate()->factory()->NewFixedArray(function()->handler_count(), TENURED);
- InitializeFeedbackVector();
-
profiling_counter_ = isolate()->factory()->NewCell(
Handle<Smi>(Smi::FromInt(FLAG_interrupt_budget), isolate()));
SetFunctionPosition(function());
@@ -1166,12 +1164,8 @@
Label non_proxy;
__ bind(&fixed_array);
- Handle<Object> feedback = Handle<Object>(
- Smi::FromInt(TypeFeedbackInfo::kForInFastCaseMarker),
- isolate());
- StoreFeedbackVectorSlot(slot, feedback);
__ Move(r1, FeedbackVector());
- __ mov(r2, Operand(Smi::FromInt(TypeFeedbackInfo::kForInSlowCaseMarker)));
+ __ mov(r2, Operand(TypeFeedbackInfo::MegamorphicSentinel(isolate())));
__ str(r2, FieldMemOperand(r1, FixedArray::OffsetOfElementAt(slot)));
__ mov(r1, Operand(Smi::FromInt(1))); // Smi indicates slow check
@@ -2711,9 +2705,6 @@
// Record source position for debugger.
SetSourcePosition(expr->position());
- Handle<Object> uninitialized =
- TypeFeedbackInfo::UninitializedSentinel(isolate());
- StoreFeedbackVectorSlot(expr->CallFeedbackSlot(), uninitialized);
__ Move(r2, FeedbackVector());
__ mov(r3, Operand(Smi::FromInt(expr->CallFeedbackSlot())));
@@ -2900,9 +2891,6 @@
__ ldr(r1, MemOperand(sp, arg_count * kPointerSize));
// Record call targets in unoptimized code.
- Handle<Object> uninitialized =
- TypeFeedbackInfo::UninitializedSentinel(isolate());
- StoreFeedbackVectorSlot(expr->CallNewFeedbackSlot(), uninitialized);
__ Move(r2, FeedbackVector());
__ mov(r3, Operand(Smi::FromInt(expr->CallNewFeedbackSlot())));
diff --git a/src/arm/lithium-codegen-arm.cc b/src/arm/lithium-codegen-arm.cc
index 49b7a33..2a15258 100644
--- a/src/arm/lithium-codegen-arm.cc
+++ b/src/arm/lithium-codegen-arm.cc
@@ -5220,7 +5220,11 @@
if (instr->size()->IsConstantOperand()) {
int32_t size = ToInteger32(LConstantOperand::cast(instr->size()));
- __ Allocate(size, result, scratch, scratch2, deferred->entry(), flags);
+ if (size <= Page::kMaxRegularHeapObjectSize) {
+ __ Allocate(size, result, scratch, scratch2, deferred->entry(), flags);
+ } else {
+ __ jmp(deferred->entry());
+ }
} else {
Register size = ToRegister(instr->size());
__ Allocate(size,
diff --git a/src/assembler.h b/src/assembler.h
index cbbe03c..cfd9914 100644
--- a/src/assembler.h
+++ b/src/assembler.h
@@ -210,6 +210,12 @@
friend class Assembler;
friend class Displacement;
friend class RegExpMacroAssemblerIrregexp;
+
+#if V8_TARGET_ARCH_A64
+ // On A64, the Assembler keeps track of pointers to Labels to resolve branches
+ // to distant targets. Copying labels would confuse the Assembler.
+ DISALLOW_COPY_AND_ASSIGN(Label); // NOLINT
+#endif
};
diff --git a/src/compiler.cc b/src/compiler.cc
index fdee097..69b794d 100644
--- a/src/compiler.cc
+++ b/src/compiler.cc
@@ -249,6 +249,17 @@
ASSERT(scope_ == NULL);
scope_ = scope;
function()->ProcessFeedbackSlots(isolate_);
+ int length = function()->slot_count();
+ // Allocate the feedback vector too.
+ feedback_vector_ = isolate()->factory()->NewFixedArray(length, TENURED);
+ // Ensure we can skip the write barrier
+ ASSERT_EQ(isolate()->heap()->uninitialized_symbol(),
+ *TypeFeedbackInfo::UninitializedSentinel(isolate()));
+ for (int i = 0; i < length; i++) {
+ feedback_vector_->set(i,
+ *TypeFeedbackInfo::UninitializedSentinel(isolate()),
+ SKIP_WRITE_BARRIER);
+ }
}
@@ -570,6 +581,8 @@
shared->ReplaceCode(*code);
if (shared->optimization_disabled()) code->set_optimizable(false);
+ shared->set_feedback_vector(*info->feedback_vector());
+
// Set the expected number of properties for instances.
FunctionLiteral* lit = info->function();
int expected = lit->expected_property_count();
@@ -823,7 +836,8 @@
lit->materialized_literal_count(),
lit->is_generator(),
info->code(),
- ScopeInfo::Create(info->scope(), info->zone()));
+ ScopeInfo::Create(info->scope(), info->zone()),
+ info->feedback_vector());
ASSERT_EQ(RelocInfo::kNoPosition, lit->function_token_position());
SetFunctionInfo(result, lit, true, script);
@@ -1022,7 +1036,8 @@
literal->materialized_literal_count(),
literal->is_generator(),
info.code(),
- scope_info);
+ scope_info,
+ info.feedback_vector());
SetFunctionInfo(result, literal, false, script);
RecordFunctionCompilation(Logger::FUNCTION_TAG, &info, result);
result->set_allows_lazy_compilation(allow_lazy);
diff --git a/src/compiler.h b/src/compiler.h
index f63475c..e4ade7b 100644
--- a/src/compiler.h
+++ b/src/compiler.h
@@ -175,6 +175,9 @@
ASSERT(global_scope_ == NULL);
global_scope_ = global_scope;
}
+ Handle<FixedArray> feedback_vector() const {
+ return feedback_vector_;
+ }
void SetCode(Handle<Code> code) { code_ = code; }
void SetExtension(v8::Extension* extension) {
ASSERT(!is_lazy());
@@ -403,6 +406,9 @@
// global script. Will be a null handle otherwise.
Handle<Context> context_;
+ // Used by codegen, ultimately kept rooted by the SharedFunctionInfo.
+ Handle<FixedArray> feedback_vector_;
+
// Compilation mode flag and whether deoptimization is allowed.
Mode mode_;
BailoutId osr_ast_id_;
diff --git a/src/d8.cc b/src/d8.cc
index 564aafe..539ebaa 100644
--- a/src/d8.cc
+++ b/src/d8.cc
@@ -205,7 +205,9 @@
// When debugging make exceptions appear to be uncaught.
try_catch.SetVerbose(true);
}
- Handle<Script> script = Script::New(source, name);
+ ScriptOrigin origin(name);
+ Handle<UnboundScript> script = ScriptCompiler::CompileUnbound(
+ isolate, ScriptCompiler::Source(source, origin));
if (script.IsEmpty()) {
// Print errors that happened during compilation.
if (report_exceptions && !FLAG_debugger)
@@ -216,7 +218,7 @@
Local<Context> realm =
Local<Context>::New(isolate, data->realms_[data->realm_current_]);
realm->Enter();
- Handle<Value> result = script->Run();
+ Handle<Value> result = script->BindToCurrentContext()->Run();
realm->Exit();
data->realm_current_ = data->realm_switch_;
if (result.IsEmpty()) {
@@ -405,11 +407,12 @@
Throw(args.GetIsolate(), "Invalid argument");
return;
}
- Handle<Script> script = Script::New(args[1]->ToString());
+ Handle<UnboundScript> script = ScriptCompiler::CompileUnbound(
+ isolate, ScriptCompiler::Source(args[1]->ToString()));
if (script.IsEmpty()) return;
Local<Context> realm = Local<Context>::New(isolate, data->realms_[index]);
realm->Enter();
- Handle<Value> result = script->Run();
+ Handle<Value> result = script->BindToCurrentContext()->Run();
realm->Exit();
args.GetReturnValue().Set(result);
}
@@ -806,7 +809,8 @@
Handle<String> name =
String::NewFromUtf8(isolate, shell_source_name.start(),
String::kNormalString, shell_source_name.length());
- Handle<Script> script = Script::Compile(source, name);
+ ScriptOrigin origin(name);
+ Handle<Script> script = Script::Compile(source, &origin);
script->Run();
// Mark the d8 shell script as native to avoid it showing up as normal source
// in the debugger.
diff --git a/src/date.cc b/src/date.cc
index 4d9cf22..70d6be9 100644
--- a/src/date.cc
+++ b/src/date.cc
@@ -62,7 +62,7 @@
after_ = &dst_[1];
local_offset_ms_ = kInvalidLocalOffsetInMs;
ymd_valid_ = false;
- OS::TimeZoneChanged();
+ OS::ClearTimezoneCache(tz_cache_);
}
diff --git a/src/date.h b/src/date.h
index fcd61db..e9c9d9c 100644
--- a/src/date.h
+++ b/src/date.h
@@ -62,11 +62,14 @@
// It is an invariant of DateCache that cache stamp is non-negative.
static const int kInvalidStamp = -1;
- DateCache() : stamp_(0) {
+ DateCache() : stamp_(0), tz_cache_(OS::CreateTimezoneCache()) {
ResetDateCache();
}
- virtual ~DateCache() {}
+ virtual ~DateCache() {
+ OS::DisposeTimezoneCache(tz_cache_);
+ tz_cache_ = NULL;
+ }
// Clears cached timezone information and increments the cache stamp.
@@ -113,7 +116,7 @@
if (time_ms < 0 || time_ms > kMaxEpochTimeInMs) {
time_ms = EquivalentTime(time_ms);
}
- return OS::LocalTimezone(static_cast<double>(time_ms));
+ return OS::LocalTimezone(static_cast<double>(time_ms), tz_cache_);
}
// ECMA 262 - 15.9.5.26
@@ -182,11 +185,11 @@
// These functions are virtual so that we can override them when testing.
virtual int GetDaylightSavingsOffsetFromOS(int64_t time_sec) {
double time_ms = static_cast<double>(time_sec * 1000);
- return static_cast<int>(OS::DaylightSavingsOffset(time_ms));
+ return static_cast<int>(OS::DaylightSavingsOffset(time_ms, tz_cache_));
}
virtual int GetLocalOffsetFromOS() {
- double offset = OS::LocalTimeOffset();
+ double offset = OS::LocalTimeOffset(tz_cache_);
ASSERT(offset < kInvalidLocalOffsetInMs);
return static_cast<int>(offset);
}
@@ -253,6 +256,8 @@
int ymd_year_;
int ymd_month_;
int ymd_day_;
+
+ TimezoneCache* tz_cache_;
};
} } // namespace v8::internal
diff --git a/src/deoptimizer.cc b/src/deoptimizer.cc
index 8728a09..9503f47 100644
--- a/src/deoptimizer.cc
+++ b/src/deoptimizer.cc
@@ -992,24 +992,19 @@
if (FLAG_enable_ool_constant_pool) {
// For the bottommost output frame the constant pool pointer can be gotten
- // from the input frame. For subsequent output frames, it can be gotten from
- // the function's code.
- Register constant_pool_reg =
- JavaScriptFrame::constant_pool_pointer_register();
+ // from the input frame. For subsequent output frames, it can be read from
+ // the previous frame.
output_offset -= kPointerSize;
input_offset -= kPointerSize;
if (is_bottommost) {
value = input_->GetFrameSlot(input_offset);
} else {
- value = reinterpret_cast<intptr_t>(
- function->shared()->code()->constant_pool());
+ value = output_[frame_index - 1]->GetConstantPool();
}
- output_frame->SetFrameSlot(output_offset, value);
- output_frame->SetConstantPool(value);
- if (is_topmost) output_frame->SetRegister(constant_pool_reg.code(), value);
+ output_frame->SetCallerConstantPool(output_offset, value);
if (trace_scope_) {
PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
- V8PRIxPTR "; constant_pool\n",
+ V8PRIxPTR "; caller's constant_pool\n",
top_address + output_offset, output_offset, value);
}
}
@@ -1067,6 +1062,18 @@
intptr_t pc_value = reinterpret_cast<intptr_t>(start + pc_offset);
output_frame->SetPc(pc_value);
+ // Update constant pool.
+ if (FLAG_enable_ool_constant_pool) {
+ intptr_t constant_pool_value =
+ reinterpret_cast<intptr_t>(non_optimized_code->constant_pool());
+ output_frame->SetConstantPool(constant_pool_value);
+ if (is_topmost) {
+ Register constant_pool_reg =
+ JavaScriptFrame::constant_pool_pointer_register();
+ output_frame->SetRegister(constant_pool_reg.code(), constant_pool_value);
+ }
+ }
+
FullCodeGenerator::State state =
FullCodeGenerator::StateField::decode(pc_and_state);
output_frame->SetState(Smi::FromInt(state));
@@ -1150,15 +1157,14 @@
}
if (FLAG_enable_ool_constant_pool) {
- // A marker value is used in place of the constant pool.
+ // Read the caller's constant pool from the previous frame.
output_offset -= kPointerSize;
- intptr_t constant_pool = reinterpret_cast<intptr_t>(
- Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR));
- output_frame->SetFrameSlot(output_offset, constant_pool);
+ value = output_[frame_index - 1]->GetConstantPool();
+ output_frame->SetCallerConstantPool(output_offset, value);
if (trace_scope_) {
PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
- V8PRIxPTR " ; constant_pool (adaptor sentinel)\n",
- top_address + output_offset, output_offset, constant_pool);
+ V8PRIxPTR "; caller's constant_pool\n",
+ top_address + output_offset, output_offset, value);
}
}
@@ -1205,6 +1211,11 @@
adaptor_trampoline->instruction_start() +
isolate_->heap()->arguments_adaptor_deopt_pc_offset()->value());
output_frame->SetPc(pc_value);
+ if (FLAG_enable_ool_constant_pool) {
+ intptr_t constant_pool_value =
+ reinterpret_cast<intptr_t>(adaptor_trampoline->constant_pool());
+ output_frame->SetConstantPool(constant_pool_value);
+ }
}
@@ -1280,13 +1291,13 @@
}
if (FLAG_enable_ool_constant_pool) {
- // The constant pool pointer can be gotten from the previous frame.
+ // Read the caller's constant pool from the previous frame.
output_offset -= kPointerSize;
value = output_[frame_index - 1]->GetConstantPool();
- output_frame->SetFrameSlot(output_offset, value);
+ output_frame->SetCallerConstantPool(output_offset, value);
if (trace_scope_) {
PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
- V8PRIxPTR " ; constant pool\n",
+ V8PRIxPTR " ; caller's constant pool\n",
top_address + output_offset, output_offset, value);
}
}
@@ -1367,6 +1378,11 @@
construct_stub->instruction_start() +
isolate_->heap()->construct_stub_deopt_pc_offset()->value());
output_frame->SetPc(pc);
+ if (FLAG_enable_ool_constant_pool) {
+ intptr_t constant_pool_value =
+ reinterpret_cast<intptr_t>(construct_stub->constant_pool());
+ output_frame->SetConstantPool(constant_pool_value);
+ }
}
@@ -1438,13 +1454,13 @@
}
if (FLAG_enable_ool_constant_pool) {
- // The constant pool pointer can be gotten from the previous frame.
+ // Read the caller's constant pool from the previous frame.
output_offset -= kPointerSize;
value = output_[frame_index - 1]->GetConstantPool();
- output_frame->SetFrameSlot(output_offset, value);
+ output_frame->SetCallerConstantPool(output_offset, value);
if (trace_scope_) {
PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
- V8PRIxPTR " ; constant pool\n",
+ V8PRIxPTR " ; caller's constant pool\n",
top_address + output_offset, output_offset, value);
}
}
@@ -1506,6 +1522,11 @@
intptr_t pc = reinterpret_cast<intptr_t>(
accessor_stub->instruction_start() + offset->value());
output_frame->SetPc(pc);
+ if (FLAG_enable_ool_constant_pool) {
+ intptr_t constant_pool_value =
+ reinterpret_cast<intptr_t>(accessor_stub->constant_pool());
+ output_frame->SetConstantPool(constant_pool_value);
+ }
}
@@ -1609,17 +1630,14 @@
}
if (FLAG_enable_ool_constant_pool) {
- // The constant pool pointer can be gotten from the input frame.
- Register constant_pool_pointer_register =
- StubFailureTrampolineFrame::constant_pool_pointer_register();
+ // Read the caller's constant pool from the input frame.
input_frame_offset -= kPointerSize;
value = input_->GetFrameSlot(input_frame_offset);
- output_frame->SetRegister(constant_pool_pointer_register.code(), value);
output_frame_offset -= kPointerSize;
- output_frame->SetFrameSlot(output_frame_offset, value);
+ output_frame->SetCallerConstantPool(output_frame_offset, value);
if (trace_scope_) {
PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
- V8PRIxPTR " ; constant_pool_pointer\n",
+ V8PRIxPTR " ; caller's constant_pool\n",
top_address + output_frame_offset, output_frame_offset, value);
}
}
@@ -1753,6 +1771,14 @@
ASSERT(trampoline != NULL);
output_frame->SetPc(reinterpret_cast<intptr_t>(
trampoline->instruction_start()));
+ if (FLAG_enable_ool_constant_pool) {
+ Register constant_pool_reg =
+ StubFailureTrampolineFrame::constant_pool_pointer_register();
+ intptr_t constant_pool_value =
+ reinterpret_cast<intptr_t>(trampoline->constant_pool());
+ output_frame->SetConstantPool(constant_pool_value);
+ output_frame->SetRegister(constant_pool_reg.code(), constant_pool_value);
+ }
output_frame->SetState(Smi::FromInt(FullCodeGenerator::NO_REGISTERS));
Code* notify_failure = NotifyStubFailureBuiltin();
output_frame->SetContinuation(
diff --git a/src/deoptimizer.h b/src/deoptimizer.h
index 67690de..a36362f 100644
--- a/src/deoptimizer.h
+++ b/src/deoptimizer.h
@@ -134,7 +134,7 @@
static const int kBailoutTypesWithCodeEntry = SOFT + 1;
- struct JumpTableEntry {
+ struct JumpTableEntry : public ZoneObject {
inline JumpTableEntry(Address entry,
Deoptimizer::BailoutType type,
bool frame)
@@ -508,6 +508,8 @@
void SetCallerFp(unsigned offset, intptr_t value);
+ void SetCallerConstantPool(unsigned offset, intptr_t value);
+
intptr_t GetRegister(unsigned n) const {
#if DEBUG
// This convoluted ASSERT is needed to work around a gcc problem that
diff --git a/src/factory.cc b/src/factory.cc
index 4dd7f77..6f86647 100644
--- a/src/factory.cc
+++ b/src/factory.cc
@@ -1542,10 +1542,12 @@
int number_of_literals,
bool is_generator,
Handle<Code> code,
- Handle<ScopeInfo> scope_info) {
+ Handle<ScopeInfo> scope_info,
+ Handle<FixedArray> feedback_vector) {
Handle<SharedFunctionInfo> shared = NewSharedFunctionInfo(name);
shared->set_code(*code);
shared->set_scope_info(*scope_info);
+ shared->set_feedback_vector(*feedback_vector);
int literals_array_size = number_of_literals;
// If the function contains object, regexp or array literals,
// allocate extra space for a literals array prefix containing the
diff --git a/src/factory.h b/src/factory.h
index a87af1d..558ff85 100644
--- a/src/factory.h
+++ b/src/factory.h
@@ -517,7 +517,8 @@
int number_of_literals,
bool is_generator,
Handle<Code> code,
- Handle<ScopeInfo> scope_info);
+ Handle<ScopeInfo> scope_info,
+ Handle<FixedArray> feedback_vector);
Handle<SharedFunctionInfo> NewSharedFunctionInfo(Handle<String> name);
Handle<JSMessageObject> NewJSMessageObject(
diff --git a/src/frames-inl.h b/src/frames-inl.h
index 2973bad..e4dc91f 100644
--- a/src/frames-inl.h
+++ b/src/frames-inl.h
@@ -201,6 +201,11 @@
}
+inline Address StandardFrame::ComputeConstantPoolAddress(Address fp) {
+ return fp + StandardFrameConstants::kConstantPoolOffset;
+}
+
+
inline bool StandardFrame::IsArgumentsAdaptorFrame(Address fp) {
Object* marker =
Memory::Object_at(fp + StandardFrameConstants::kContextOffset);
diff --git a/src/frames.cc b/src/frames.cc
index 3b55c27..0c47de9 100644
--- a/src/frames.cc
+++ b/src/frames.cc
@@ -531,6 +531,10 @@
state->fp = Memory::Address_at(fp() + ExitFrameConstants::kCallerFPOffset);
state->pc_address = ResolveReturnAddressLocation(
reinterpret_cast<Address*>(fp() + ExitFrameConstants::kCallerPCOffset));
+ if (FLAG_enable_ool_constant_pool) {
+ state->constant_pool_address = reinterpret_cast<Address*>(
+ fp() + ExitFrameConstants::kConstantPoolOffset);
+ }
}
@@ -574,6 +578,8 @@
state->fp = fp;
state->pc_address = ResolveReturnAddressLocation(
reinterpret_cast<Address*>(sp - 1 * kPCOnStackSize));
+ state->constant_pool_address =
+ reinterpret_cast<Address*>(fp + ExitFrameConstants::kConstantPoolOffset);
}
@@ -610,6 +616,8 @@
state->fp = caller_fp();
state->pc_address = ResolveReturnAddressLocation(
reinterpret_cast<Address*>(ComputePCAddress(fp())));
+ state->constant_pool_address =
+ reinterpret_cast<Address*>(ComputeConstantPoolAddress(fp()));
}
diff --git a/src/frames.h b/src/frames.h
index af2b55a..aef86bf 100644
--- a/src/frames.h
+++ b/src/frames.h
@@ -225,10 +225,12 @@
};
struct State {
- State() : sp(NULL), fp(NULL), pc_address(NULL) { }
+ State() : sp(NULL), fp(NULL), pc_address(NULL),
+ constant_pool_address(NULL) { }
Address sp;
Address fp;
Address* pc_address;
+ Address* constant_pool_address;
};
// Copy constructor; it breaks the connection to host iterator
@@ -270,6 +272,11 @@
Address pc() const { return *pc_address(); }
void set_pc(Address pc) { *pc_address() = pc; }
+ Address constant_pool() const { return *constant_pool_address(); }
+ void set_constant_pool(ConstantPoolArray* constant_pool) {
+ *constant_pool_address() = reinterpret_cast<Address>(constant_pool);
+ }
+
virtual void SetCallerFp(Address caller_fp) = 0;
// Manually changes value of fp in this object.
@@ -277,6 +284,10 @@
Address* pc_address() const { return state_.pc_address; }
+ Address* constant_pool_address() const {
+ return state_.constant_pool_address;
+ }
+
// Get the id of this stack frame.
Id id() const { return static_cast<Id>(OffsetFrom(caller_sp())); }
@@ -496,6 +507,10 @@
// by the provided frame pointer.
static inline Address ComputePCAddress(Address fp);
+ // Computes the address of the constant pool field in the standard
+ // frame given by the provided frame pointer.
+ static inline Address ComputeConstantPoolAddress(Address fp);
+
// Iterate over expression stack including stack handlers, locals,
// and parts of the fixed part including context and code fields.
void IterateExpressions(ObjectVisitor* v) const;
diff --git a/src/full-codegen.cc b/src/full-codegen.cc
index 2170b84..165d007 100644
--- a/src/full-codegen.cc
+++ b/src/full-codegen.cc
@@ -386,18 +386,6 @@
}
-void FullCodeGenerator::InitializeFeedbackVector() {
- int length = info_->function()->slot_count();
- feedback_vector_ = isolate()->factory()->NewFixedArray(length, TENURED);
- Handle<Object> sentinel = TypeFeedbackInfo::UninitializedSentinel(isolate());
- // Ensure that it's safe to set without using a write barrier.
- ASSERT_EQ(isolate()->heap()->uninitialized_symbol(), *sentinel);
- for (int i = 0; i < length; i++) {
- feedback_vector_->set(i, *sentinel, SKIP_WRITE_BARRIER);
- }
-}
-
-
void FullCodeGenerator::PopulateDeoptimizationData(Handle<Code> code) {
// Fill in the deoptimization information.
ASSERT(info_->HasDeoptimizationSupport() || bailout_entries_.is_empty());
@@ -416,7 +404,6 @@
void FullCodeGenerator::PopulateTypeFeedbackInfo(Handle<Code> code) {
Handle<TypeFeedbackInfo> info = isolate()->factory()->NewTypeFeedbackInfo();
info->set_ic_total_count(ic_total_count_);
- info->set_feedback_vector(*FeedbackVector());
ASSERT(!isolate()->heap()->InNewSpace(*info));
code->set_type_feedback_info(*info);
}
@@ -1618,7 +1605,8 @@
bool is_generator = false;
Handle<SharedFunctionInfo> shared =
isolate()->factory()->NewSharedFunctionInfo(name, literals, is_generator,
- code, Handle<ScopeInfo>(fun->shared()->scope_info()));
+ code, Handle<ScopeInfo>(fun->shared()->scope_info()),
+ Handle<FixedArray>(fun->shared()->feedback_vector()));
shared->set_construct_stub(*construct_stub);
// Copy the function data to the shared function info.
diff --git a/src/full-codegen.h b/src/full-codegen.h
index 7d03527..f2e39de 100644
--- a/src/full-codegen.h
+++ b/src/full-codegen.h
@@ -437,12 +437,8 @@
// Feedback slot support. The feedback vector will be cleared during gc and
// collected by the type-feedback oracle.
Handle<FixedArray> FeedbackVector() {
- return feedback_vector_;
+ return info_->feedback_vector();
}
- void StoreFeedbackVectorSlot(int slot, Handle<Object> object) {
- feedback_vector_->set(slot, *object);
- }
- void InitializeFeedbackVector();
// Record a call's return site offset, used to rebuild the frame if the
// called function was inlined at the site.
@@ -844,7 +840,6 @@
ZoneList<BackEdgeEntry> back_edges_;
int ic_total_count_;
Handle<FixedArray> handler_table_;
- Handle<FixedArray> feedback_vector_;
Handle<Cell> profiling_counter_;
bool generate_debug_code_;
diff --git a/src/heap-snapshot-generator.cc b/src/heap-snapshot-generator.cc
index 10e177d..a7c1c2e 100644
--- a/src/heap-snapshot-generator.cc
+++ b/src/heap-snapshot-generator.cc
@@ -1398,6 +1398,9 @@
SetInternalReference(obj, entry,
"optimized_code_map", shared->optimized_code_map(),
SharedFunctionInfo::kOptimizedCodeMapOffset);
+ SetInternalReference(obj, entry,
+ "feedback_vector", shared->feedback_vector(),
+ SharedFunctionInfo::kFeedbackVectorOffset);
SetWeakReference(obj, entry,
"initial_map", shared->initial_map(),
SharedFunctionInfo::kInitialMapOffset);
diff --git a/src/heap.cc b/src/heap.cc
index 90173a7..aa5c3a9 100644
--- a/src/heap.cc
+++ b/src/heap.cc
@@ -2687,7 +2687,6 @@
if (!maybe_info->To(&info)) return maybe_info;
}
info->initialize_storage();
- info->set_feedback_vector(empty_fixed_array(), SKIP_WRITE_BARRIER);
return info;
}
@@ -3348,7 +3347,7 @@
set_materialized_objects(FixedArray::cast(obj));
// Handling of script id generation is in Factory::NewScript.
- set_last_script_id(Smi::FromInt(v8::Script::kNoScriptId));
+ set_last_script_id(Smi::FromInt(v8::UnboundScript::kNoScriptId));
{ MaybeObject* maybe_obj = AllocateAllocationSitesScratchpad();
if (!maybe_obj->ToObject(&obj)) return false;
@@ -3809,6 +3808,7 @@
share->set_script(undefined_value(), SKIP_WRITE_BARRIER);
share->set_debug_info(undefined_value(), SKIP_WRITE_BARRIER);
share->set_inferred_name(empty_string(), SKIP_WRITE_BARRIER);
+ share->set_feedback_vector(empty_fixed_array(), SKIP_WRITE_BARRIER);
share->set_initial_map(undefined_value(), SKIP_WRITE_BARRIER);
share->set_ast_node_count(0);
share->set_counters(0);
diff --git a/src/hydrogen-bce.cc b/src/hydrogen-bce.cc
index e1a2847..cef1e0f 100644
--- a/src/hydrogen-bce.cc
+++ b/src/hydrogen-bce.cc
@@ -132,6 +132,24 @@
bool HasSingleCheck() { return lower_check_ == upper_check_; }
+ void UpdateUpperOffsets(HBoundsCheck* check, int32_t offset) {
+ BoundsCheckBbData* data = FatherInDominatorTree();
+ while (data != NULL && data->UpperCheck() == check) {
+ ASSERT(data->upper_offset_ <= offset);
+ data->upper_offset_ = offset;
+ data = data->FatherInDominatorTree();
+ }
+ }
+
+ void UpdateLowerOffsets(HBoundsCheck* check, int32_t offset) {
+ BoundsCheckBbData* data = FatherInDominatorTree();
+ while (data != NULL && data->LowerCheck() == check) {
+ ASSERT(data->lower_offset_ > offset);
+ data->lower_offset_ = offset;
+ data = data->FatherInDominatorTree();
+ }
+ }
+
// The goal of this method is to modify either upper_offset_ or
// lower_offset_ so that also new_offset is covered (the covered
// range grows).
@@ -156,6 +174,7 @@
upper_check_ = new_check;
} else {
TightenCheck(upper_check_, new_check);
+ UpdateUpperOffsets(upper_check_, upper_offset_);
}
} else if (new_offset < lower_offset_) {
lower_offset_ = new_offset;
@@ -164,6 +183,7 @@
lower_check_ = new_check;
} else {
TightenCheck(lower_check_, new_check);
+ UpdateLowerOffsets(upper_check_, upper_offset_);
}
} else {
// Should never have called CoverCheck() in this case.
diff --git a/src/hydrogen-gvn.cc b/src/hydrogen-gvn.cc
index 827ad27..4c98015 100644
--- a/src/hydrogen-gvn.cc
+++ b/src/hydrogen-gvn.cc
@@ -592,9 +592,7 @@
graph()->use_optimistic_licm() ? "yes" : "no");
for (int i = graph()->blocks()->length() - 1; i >= 0; --i) {
HBasicBlock* block = graph()->blocks()->at(i);
- if (block->IsLoopHeader() &&
- block->IsReachable() &&
- !block->IsDeoptimizing()) {
+ if (block->IsLoopHeader()) {
SideEffects side_effects = loop_side_effects_[block->block_id()];
if (FLAG_trace_gvn) {
HeapStringAllocator allocator;
@@ -618,7 +616,6 @@
HBasicBlock* block,
HBasicBlock* loop_header,
SideEffects loop_kills) {
- if (!block->IsReachable() || block->IsDeoptimizing()) return;
HBasicBlock* pre_header = loop_header->predecessors()->at(0);
if (FLAG_trace_gvn) {
HeapStringAllocator allocator;
@@ -683,8 +680,10 @@
bool HGlobalValueNumberingPhase::ShouldMove(HInstruction* instr,
HBasicBlock* loop_header) {
- // If we've disabled code motion, don't move any instructions.
- return AllowCodeMotion();
+ // If we've disabled code motion or we're in a block that unconditionally
+ // deoptimizes, don't move any instructions.
+ return AllowCodeMotion() && !instr->block()->IsDeoptimizing() &&
+ instr->block()->IsReachable();
}
@@ -777,18 +776,20 @@
}
GvnBasicBlockState* next_dominated(Zone* zone) {
- while (++dominated_index_ < length_) {
- HBasicBlock* block = block_->dominated_blocks()->at(dominated_index_);
- if (block->IsReachable()) {
- if (dominated_index_ == length_ - 1) {
- // No need to copy the map for the last child in the dominator tree.
- Initialize(block, map(), dominators(), false, zone);
- return this;
- }
- return push(zone, block);
- }
+ dominated_index_++;
+ if (dominated_index_ == length_ - 1) {
+ // No need to copy the map for the last child in the dominator tree.
+ Initialize(block_->dominated_blocks()->at(dominated_index_),
+ map(),
+ dominators(),
+ false,
+ zone);
+ return this;
+ } else if (dominated_index_ < length_) {
+ return push(zone, block_->dominated_blocks()->at(dominated_index_));
+ } else {
+ return NULL;
}
- return NULL;
}
GvnBasicBlockState* push(Zone* zone, HBasicBlock* block) {
diff --git a/src/hydrogen.cc b/src/hydrogen.cc
index 04a045b..2881e90 100644
--- a/src/hydrogen.cc
+++ b/src/hydrogen.cc
@@ -7206,6 +7206,7 @@
target_shared->set_scope_info(*target_scope_info);
}
target_shared->EnableDeoptimizationSupport(*target_info.code());
+ target_shared->set_feedback_vector(*target_info.feedback_vector());
Compiler::RecordFunctionCompilation(Logger::FUNCTION_TAG,
&target_info,
target_shared);
diff --git a/src/ia32/deoptimizer-ia32.cc b/src/ia32/deoptimizer-ia32.cc
index 546781e..711cdf8 100644
--- a/src/ia32/deoptimizer-ia32.cc
+++ b/src/ia32/deoptimizer-ia32.cc
@@ -463,6 +463,12 @@
}
+void FrameDescription::SetCallerConstantPool(unsigned offset, intptr_t value) {
+ // No out-of-line constant pool support.
+ UNREACHABLE();
+}
+
+
#undef __
diff --git a/src/ia32/full-codegen-ia32.cc b/src/ia32/full-codegen-ia32.cc
index 096e2ed..06da7ba 100644
--- a/src/ia32/full-codegen-ia32.cc
+++ b/src/ia32/full-codegen-ia32.cc
@@ -119,8 +119,6 @@
handler_table_ =
isolate()->factory()->NewFixedArray(function()->handler_count(), TENURED);
- InitializeFeedbackVector();
-
profiling_counter_ = isolate()->factory()->NewCell(
Handle<Smi>(Smi::FromInt(FLAG_interrupt_budget), isolate()));
SetFunctionPosition(function());
@@ -1104,15 +1102,10 @@
Label non_proxy;
__ bind(&fixed_array);
- Handle<Object> feedback = Handle<Object>(
- Smi::FromInt(TypeFeedbackInfo::kForInFastCaseMarker),
- isolate());
- StoreFeedbackVectorSlot(slot, feedback);
-
// No need for a write barrier, we are storing a Smi in the feedback vector.
__ LoadHeapObject(ebx, FeedbackVector());
__ mov(FieldOperand(ebx, FixedArray::OffsetOfElementAt(slot)),
- Immediate(Smi::FromInt(TypeFeedbackInfo::kForInSlowCaseMarker)));
+ Immediate(TypeFeedbackInfo::MegamorphicSentinel(isolate())));
__ mov(ebx, Immediate(Smi::FromInt(1))); // Smi indicates slow check
__ mov(ecx, Operand(esp, 0 * kPointerSize)); // Get enumerated object
@@ -2665,9 +2658,6 @@
// Record source position for debugger.
SetSourcePosition(expr->position());
- Handle<Object> uninitialized =
- TypeFeedbackInfo::UninitializedSentinel(isolate());
- StoreFeedbackVectorSlot(expr->CallFeedbackSlot(), uninitialized);
__ LoadHeapObject(ebx, FeedbackVector());
__ mov(edx, Immediate(Smi::FromInt(expr->CallFeedbackSlot())));
@@ -2845,9 +2835,6 @@
__ mov(edi, Operand(esp, arg_count * kPointerSize));
// Record call targets in unoptimized code.
- Handle<Object> uninitialized =
- TypeFeedbackInfo::UninitializedSentinel(isolate());
- StoreFeedbackVectorSlot(expr->CallNewFeedbackSlot(), uninitialized);
__ LoadHeapObject(ebx, FeedbackVector());
__ mov(edx, Immediate(Smi::FromInt(expr->CallNewFeedbackSlot())));
diff --git a/src/ia32/lithium-codegen-ia32.cc b/src/ia32/lithium-codegen-ia32.cc
index f85ab3d..36e876d 100644
--- a/src/ia32/lithium-codegen-ia32.cc
+++ b/src/ia32/lithium-codegen-ia32.cc
@@ -5845,7 +5845,11 @@
if (instr->size()->IsConstantOperand()) {
int32_t size = ToInteger32(LConstantOperand::cast(instr->size()));
- __ Allocate(size, result, temp, no_reg, deferred->entry(), flags);
+ if (size <= Page::kMaxRegularHeapObjectSize) {
+ __ Allocate(size, result, temp, no_reg, deferred->entry(), flags);
+ } else {
+ __ jmp(deferred->entry());
+ }
} else {
Register size = ToRegister(instr->size());
__ Allocate(size, result, temp, no_reg, deferred->entry(), flags);
diff --git a/src/ic.cc b/src/ic.cc
index 7f4d1cd..f1e3c55 100644
--- a/src/ic.cc
+++ b/src/ic.cc
@@ -1599,7 +1599,10 @@
key->ToSmi()->To(&smi_key);
int index = smi_key->value();
bool oob_access = IsOutOfBoundsAccess(receiver, index);
- bool allow_growth = receiver->IsJSArray() && oob_access;
+ // Don't consider this a growing store if the store would send the receiver to
+ // dictionary mode.
+ bool allow_growth = receiver->IsJSArray() && oob_access &&
+ !receiver->WouldConvertToSlowElements(key);
if (allow_growth) {
// Handle growing array in stub if necessary.
if (receiver->HasFastSmiElements()) {
@@ -1724,12 +1727,7 @@
if (!(receiver->map()->DictionaryElementsInPrototypeChainOnly())) {
KeyedAccessStoreMode store_mode =
GetStoreMode(receiver, key, value);
- // Use the generic stub if the store would send the receiver to
- // dictionary mode.
- if (!IsGrowStoreMode(store_mode) ||
- !receiver->WouldConvertToSlowElements(key)) {
- stub = StoreElementStub(receiver, store_mode);
- }
+ stub = StoreElementStub(receiver, store_mode);
}
}
}
diff --git a/src/interpreter-irregexp.cc b/src/interpreter-irregexp.cc
index 2fc9fd3..ccabfd1 100644
--- a/src/interpreter-irregexp.cc
+++ b/src/interpreter-irregexp.cc
@@ -159,24 +159,11 @@
class BacktrackStack {
public:
explicit BacktrackStack(Isolate* isolate) : isolate_(isolate) {
- if (isolate->irregexp_interpreter_backtrack_stack_cache() != NULL) {
- // If the cache is not empty reuse the previously allocated stack.
- data_ = isolate->irregexp_interpreter_backtrack_stack_cache();
- isolate->set_irregexp_interpreter_backtrack_stack_cache(NULL);
- } else {
- // Cache was empty. Allocate a new backtrack stack.
- data_ = NewArray<int>(kBacktrackStackSize);
- }
+ data_ = NewArray<int>(kBacktrackStackSize);
}
~BacktrackStack() {
- if (isolate_->irregexp_interpreter_backtrack_stack_cache() == NULL) {
- // The cache is empty. Keep this backtrack stack around.
- isolate_->set_irregexp_interpreter_backtrack_stack_cache(data_);
- } else {
- // A backtrack stack was already cached, just release this one.
- DeleteArray(data_);
- }
+ DeleteArray(data_);
}
int* data() const { return data_; }
diff --git a/src/isolate.cc b/src/isolate.cc
index bb97c93..c48e2d3 100644
--- a/src/isolate.cc
+++ b/src/isolate.cc
@@ -1550,7 +1550,6 @@
global_handles_(NULL),
eternal_handles_(NULL),
thread_manager_(NULL),
- fp_stubs_generated_(false),
has_installed_extensions_(false),
string_tracker_(NULL),
regexp_stack_(NULL),
@@ -1570,7 +1569,6 @@
optimizing_compiler_thread_(NULL),
sweeper_thread_(NULL),
num_sweeper_threads_(0),
- max_available_threads_(0),
stress_deopt_count_(0),
next_optimization_id_(0) {
id_ = NoBarrier_AtomicIncrement(&isolate_counter_, 1);
@@ -1587,19 +1585,9 @@
thread_manager_ = new ThreadManager();
thread_manager_->isolate_ = this;
-#if V8_TARGET_ARCH_ARM && !defined(__arm__) || \
- V8_TARGET_ARCH_A64 && !defined(__aarch64__) || \
- V8_TARGET_ARCH_MIPS && !defined(__mips__)
- simulator_initialized_ = false;
- simulator_i_cache_ = NULL;
- simulator_redirection_ = NULL;
-#endif
-
#ifdef DEBUG
// heap_histograms_ initializes itself.
memset(&js_spill_information_, 0, sizeof(js_spill_information_));
- memset(code_kind_statistics_, 0,
- sizeof(code_kind_statistics_[0]) * Code::NUMBER_OF_KINDS);
#endif
#ifdef ENABLE_DEBUGGER_SUPPORT
diff --git a/src/isolate.h b/src/isolate.h
index 5df84a2..69e1e4c 100644
--- a/src/isolate.h
+++ b/src/isolate.h
@@ -309,11 +309,28 @@
#endif
+
+#if V8_TARGET_ARCH_ARM && !defined(__arm__) || \
+ V8_TARGET_ARCH_A64 && !defined(__aarch64__) || \
+ V8_TARGET_ARCH_MIPS && !defined(__mips__)
+
+#define ISOLATE_INIT_SIMULATOR_LIST(V) \
+ V(bool, simulator_initialized, false) \
+ V(HashMap*, simulator_i_cache, NULL) \
+ V(Redirection*, simulator_redirection, NULL)
+#else
+
+#define ISOLATE_INIT_SIMULATOR_LIST(V)
+
+#endif
+
+
#ifdef DEBUG
#define ISOLATE_INIT_DEBUG_ARRAY_LIST(V) \
V(CommentStatistic, paged_space_comments_statistics, \
- CommentStatistic::kMaxComments + 1)
+ CommentStatistic::kMaxComments + 1) \
+ V(int, code_kind_statistics, Code::NUMBER_OF_KINDS)
#else
#define ISOLATE_INIT_DEBUG_ARRAY_LIST(V)
@@ -346,15 +363,12 @@
/* function cache of the native context. */ \
V(int, next_serial_number, 0) \
V(ExternalReferenceRedirectorPointer*, external_reference_redirector, NULL) \
- V(bool, always_allow_natives_syntax, false) \
/* Part of the state of liveedit. */ \
V(FunctionInfoListener*, active_function_info_listener, NULL) \
/* State for Relocatable. */ \
V(Relocatable*, relocatable_top, NULL) \
V(DebugObjectCache*, string_stream_debug_object_cache, NULL) \
V(Object*, string_stream_current_security_token, NULL) \
- /* TODO(isolates): Release this on destruction? */ \
- V(int*, irregexp_interpreter_backtrack_stack_cache, NULL) \
/* Serializer state. */ \
V(ExternalReferenceTable*, external_reference_table, NULL) \
/* AstNode state. */ \
@@ -365,6 +379,9 @@
V(HStatistics*, hstatistics, NULL) \
V(HTracer*, htracer, NULL) \
V(CodeTracer*, code_tracer, NULL) \
+ V(bool, fp_stubs_generated, false) \
+ V(int, max_available_threads, 0) \
+ ISOLATE_INIT_SIMULATOR_LIST(V) \
ISOLATE_DEBUGGER_INIT_LIST(V)
#define THREAD_LOCAL_TOP_ACCESSOR(type, name) \
@@ -937,8 +954,6 @@
RuntimeState* runtime_state() { return &runtime_state_; }
- FIELD_ACCESSOR(bool, fp_stubs_generated);
-
Builtins* builtins() { return &builtins_; }
void NotifyExtensionInstalled() {
@@ -984,16 +999,6 @@
JSObject::SpillInformation* js_spill_information() {
return &js_spill_information_;
}
-
- int* code_kind_statistics() { return code_kind_statistics_; }
-#endif
-
-#if V8_TARGET_ARCH_ARM && !defined(__arm__) || \
- V8_TARGET_ARCH_A64 && !defined(__aarch64__) || \
- V8_TARGET_ARCH_MIPS && !defined(__mips__)
- FIELD_ACCESSOR(bool, simulator_initialized)
- FIELD_ACCESSOR(HashMap*, simulator_i_cache)
- FIELD_ACCESSOR(Redirection*, simulator_redirection)
#endif
Factory* factory() { return reinterpret_cast<Factory*>(this); }
@@ -1063,8 +1068,6 @@
bool IsDeferredHandle(Object** location);
#endif // DEBUG
- FIELD_ACCESSOR(int, max_available_threads);
-
bool concurrent_recompilation_enabled() {
// Thread is only available with flag enabled.
ASSERT(optimizing_compiler_thread_ == NULL ||
@@ -1268,7 +1271,6 @@
EternalHandles* eternal_handles_;
ThreadManager* thread_manager_;
RuntimeState runtime_state_;
- bool fp_stubs_generated_;
Builtins builtins_;
bool has_installed_extensions_;
StringTracker* string_tracker_;
@@ -1298,19 +1300,10 @@
// Time stamp at initialization.
double time_millis_at_init_;
-#if V8_TARGET_ARCH_ARM && !defined(__arm__) || \
- V8_TARGET_ARCH_A64 && !defined(__aarch64__) || \
- V8_TARGET_ARCH_MIPS && !defined(__mips__)
- bool simulator_initialized_;
- HashMap* simulator_i_cache_;
- Redirection* simulator_redirection_;
-#endif
-
#ifdef DEBUG
// A static array of histogram info for each type.
HistogramInfo heap_histograms_[LAST_TYPE + 1];
JSObject::SpillInformation js_spill_information_;
- int code_kind_statistics_[Code::NUMBER_OF_KINDS];
#endif
#ifdef ENABLE_DEBUGGER_SUPPORT
@@ -1347,10 +1340,6 @@
SweeperThread** sweeper_thread_;
int num_sweeper_threads_;
- // TODO(yangguo): This will become obsolete once ResourceConstraints
- // becomes an argument to Isolate constructor.
- int max_available_threads_;
-
// Counts deopt points if deopt_every_n_times is enabled.
unsigned int stress_deopt_count_;
diff --git a/src/mips/full-codegen-mips.cc b/src/mips/full-codegen-mips.cc
index 02a890a..8250ce0 100644
--- a/src/mips/full-codegen-mips.cc
+++ b/src/mips/full-codegen-mips.cc
@@ -139,8 +139,6 @@
handler_table_ =
isolate()->factory()->NewFixedArray(function()->handler_count(), TENURED);
- InitializeFeedbackVector();
-
profiling_counter_ = isolate()->factory()->NewCell(
Handle<Smi>(Smi::FromInt(FLAG_interrupt_budget), isolate()));
SetFunctionPosition(function());
@@ -1176,12 +1174,8 @@
Label non_proxy;
__ bind(&fixed_array);
- Handle<Object> feedback = Handle<Object>(
- Smi::FromInt(TypeFeedbackInfo::kForInFastCaseMarker),
- isolate());
- StoreFeedbackVectorSlot(slot, feedback);
__ li(a1, FeedbackVector());
- __ li(a2, Operand(Smi::FromInt(TypeFeedbackInfo::kForInSlowCaseMarker)));
+ __ li(a2, Operand(TypeFeedbackInfo::MegamorphicSentinel(isolate())));
__ sw(a2, FieldMemOperand(a1, FixedArray::OffsetOfElementAt(slot)));
__ li(a1, Operand(Smi::FromInt(1))); // Smi indicates slow check
@@ -2735,9 +2729,6 @@
// Record source position for debugger.
SetSourcePosition(expr->position());
- Handle<Object> uninitialized =
- TypeFeedbackInfo::UninitializedSentinel(isolate());
- StoreFeedbackVectorSlot(expr->CallFeedbackSlot(), uninitialized);
__ li(a2, FeedbackVector());
__ li(a3, Operand(Smi::FromInt(expr->CallFeedbackSlot())));
@@ -2922,9 +2913,6 @@
__ lw(a1, MemOperand(sp, arg_count * kPointerSize));
// Record call targets in unoptimized code.
- Handle<Object> uninitialized =
- TypeFeedbackInfo::UninitializedSentinel(isolate());
- StoreFeedbackVectorSlot(expr->CallNewFeedbackSlot(), uninitialized);
__ li(a2, FeedbackVector());
__ li(a3, Operand(Smi::FromInt(expr->CallNewFeedbackSlot())));
diff --git a/src/mips/lithium-codegen-mips.cc b/src/mips/lithium-codegen-mips.cc
index d9619ed..0f19ce2 100644
--- a/src/mips/lithium-codegen-mips.cc
+++ b/src/mips/lithium-codegen-mips.cc
@@ -5184,7 +5184,11 @@
}
if (instr->size()->IsConstantOperand()) {
int32_t size = ToInteger32(LConstantOperand::cast(instr->size()));
- __ Allocate(size, result, scratch, scratch2, deferred->entry(), flags);
+ if (size <= Page::kMaxRegularHeapObjectSize) {
+ __ Allocate(size, result, scratch, scratch2, deferred->entry(), flags);
+ } else {
+ __ jmp(deferred->entry());
+ }
} else {
Register size = ToRegister(instr->size());
__ Allocate(size,
diff --git a/src/mirror-debugger.js b/src/mirror-debugger.js
index 27c2c9c..f288123 100644
--- a/src/mirror-debugger.js
+++ b/src/mirror-debugger.js
@@ -1543,6 +1543,11 @@
inherits(FrameMirror, Mirror);
+FrameMirror.prototype.details = function() {
+ return this.details_;
+};
+
+
FrameMirror.prototype.index = function() {
return this.index_;
};
@@ -1964,6 +1969,11 @@
inherits(ScopeMirror, Mirror);
+ScopeMirror.prototype.details = function() {
+ return this.details_;
+};
+
+
ScopeMirror.prototype.frameIndex = function() {
return this.frame_index_;
};
diff --git a/src/objects-debug.cc b/src/objects-debug.cc
index 5ca07d5..4fafc15 100644
--- a/src/objects-debug.cc
+++ b/src/objects-debug.cc
@@ -368,7 +368,6 @@
void TypeFeedbackInfo::TypeFeedbackInfoVerify() {
VerifyObjectField(kStorage1Offset);
VerifyObjectField(kStorage2Offset);
- VerifyHeapPointer(feedback_vector());
}
@@ -552,6 +551,7 @@
VerifyObjectField(kNameOffset);
VerifyObjectField(kCodeOffset);
VerifyObjectField(kOptimizedCodeMapOffset);
+ VerifyObjectField(kFeedbackVectorOffset);
VerifyObjectField(kScopeInfoOffset);
VerifyObjectField(kInstanceClassNameOffset);
VerifyObjectField(kFunctionDataOffset);
diff --git a/src/objects-inl.h b/src/objects-inl.h
index 75ff839..49fd9d4 100644
--- a/src/objects-inl.h
+++ b/src/objects-inl.h
@@ -1481,7 +1481,7 @@
AllocationSiteMode AllocationSite::GetMode(ElementsKind from,
ElementsKind to) {
if (IsFastSmiElementsKind(from) &&
- IsMoreGeneralElementsKindTransition(from, to)) {
+ IsMoreGeneralElementsKindTransition(from, to)) {
return TRACK_ALLOCATION_SITE;
}
@@ -4980,6 +4980,8 @@
ACCESSORS(SharedFunctionInfo, optimized_code_map, Object,
kOptimizedCodeMapOffset)
ACCESSORS(SharedFunctionInfo, construct_stub, Code, kConstructStubOffset)
+ACCESSORS(SharedFunctionInfo, feedback_vector, FixedArray,
+ kFeedbackVectorOffset)
ACCESSORS(SharedFunctionInfo, initial_map, Object, kInitialMapOffset)
ACCESSORS(SharedFunctionInfo, instance_class_name, Object,
kInstanceClassNameOffset)
@@ -6652,10 +6654,6 @@
}
-ACCESSORS(TypeFeedbackInfo, feedback_vector, FixedArray,
- kFeedbackVectorOffset)
-
-
SMI_ACCESSORS(AliasedArgumentsEntry, aliased_context_slot, kAliasedContextSlot)
diff --git a/src/objects-printer.cc b/src/objects-printer.cc
index 518167c..e287691 100644
--- a/src/objects-printer.cc
+++ b/src/objects-printer.cc
@@ -566,8 +566,6 @@
HeapObject::PrintHeader(out, "TypeFeedbackInfo");
PrintF(out, " - ic_total_count: %d, ic_with_type_info_count: %d\n",
ic_total_count(), ic_with_type_info_count());
- PrintF(out, " - feedback_vector: ");
- feedback_vector()->FixedArrayPrint(out);
}
@@ -881,6 +879,8 @@
PrintF(out, "\n - length = %d", length());
PrintF(out, "\n - optimized_code_map = ");
optimized_code_map()->ShortPrint(out);
+ PrintF(out, "\n - feedback_vector = ");
+ feedback_vector()->FixedArrayPrint(out);
PrintF(out, "\n");
}
diff --git a/src/objects-visiting-inl.h b/src/objects-visiting-inl.h
index 4f14988..db84664 100644
--- a/src/objects-visiting-inl.h
+++ b/src/objects-visiting-inl.h
@@ -427,9 +427,6 @@
Map* map, HeapObject* object) {
Heap* heap = map->GetHeap();
Code* code = Code::cast(object);
- if (FLAG_cleanup_code_caches_at_gc) {
- code->ClearTypeFeedbackInfo(heap);
- }
if (FLAG_age_code && !Serializer::enabled()) {
code->MakeOlder(heap->mark_compact_collector()->marking_parity());
}
@@ -445,6 +442,9 @@
if (shared->ic_age() != heap->global_ic_age()) {
shared->ResetForNewContext(heap->global_ic_age());
}
+ if (FLAG_cleanup_code_caches_at_gc) {
+ shared->ClearTypeFeedbackInfo(heap);
+ }
if (FLAG_cache_optimized_code &&
FLAG_flush_optimized_code_cache &&
!shared->optimized_code_map()->IsSmi()) {
diff --git a/src/objects.cc b/src/objects.cc
index f1ab81f..92e4dc4 100644
--- a/src/objects.cc
+++ b/src/objects.cc
@@ -2620,6 +2620,8 @@
current->instance_descriptors()->GetValue(i)) {
return NULL;
}
+ } else if (target_details.type() == CALLBACKS) {
+ return NULL;
}
}
@@ -10640,19 +10642,16 @@
}
-void Code::ClearTypeFeedbackInfo(Heap* heap) {
- if (kind() != FUNCTION) return;
- Object* raw_info = type_feedback_info();
- if (raw_info->IsTypeFeedbackInfo()) {
- FixedArray* feedback_vector =
- TypeFeedbackInfo::cast(raw_info)->feedback_vector();
- for (int i = 0; i < feedback_vector->length(); i++) {
- Object* obj = feedback_vector->get(i);
- if (!obj->IsAllocationSite()) {
- // TODO(mvstanton): Can't I avoid a write barrier for this sentinel?
- feedback_vector->set(i,
- TypeFeedbackInfo::RawUninitializedSentinel(heap));
- }
+void SharedFunctionInfo::ClearTypeFeedbackInfo(Heap* heap) {
+ FixedArray* vector = feedback_vector();
+ for (int i = 0; i < vector->length(); i++) {
+ Object* obj = vector->get(i);
+ if (!obj->IsAllocationSite()) {
+ // The assert verifies we can skip the write barrier.
+ ASSERT(heap->uninitialized_symbol() ==
+ TypeFeedbackInfo::RawUninitializedSentinel(heap));
+ vector->set(i, TypeFeedbackInfo::RawUninitializedSentinel(heap),
+ SKIP_WRITE_BARRIER);
}
}
}
diff --git a/src/objects.h b/src/objects.h
index 7a1ae26..c772578 100644
--- a/src/objects.h
+++ b/src/objects.h
@@ -5497,8 +5497,6 @@
void ClearInlineCaches();
void ClearInlineCaches(Kind kind);
- void ClearTypeFeedbackInfo(Heap* heap);
-
BailoutId TranslatePcOffsetToAstId(uint32_t pc_offset);
uint32_t TranslateAstIdToPcOffset(BailoutId ast_id);
@@ -6694,6 +6692,8 @@
// Removed a specific optimized code object from the optimized code map.
void EvictFromOptimizedCodeMap(Code* optimized_code, const char* reason);
+ void ClearTypeFeedbackInfo(Heap* heap);
+
// Trims the optimized code map after entries have been removed.
void TrimOptimizedCodeMap(int shrink_by);
@@ -6802,6 +6802,12 @@
inline int construction_count();
inline void set_construction_count(int value);
+ // [feedback_vector] - accumulates ast node feedback from full-codegen and
+ // (increasingly) from crankshafted code where sufficient feedback isn't
+ // available. Currently the field is duplicated in
+ // TypeFeedbackInfo::feedback_vector, but the allocation is done here.
+ DECL_ACCESSORS(feedback_vector, FixedArray)
+
// [initial_map]: initial map of the first function called as a constructor.
// Saved for the duration of the tracking phase.
// This is a weak link (GC resets it to undefined_value if no other live
@@ -7082,8 +7088,10 @@
static const int kScriptOffset = kFunctionDataOffset + kPointerSize;
static const int kDebugInfoOffset = kScriptOffset + kPointerSize;
static const int kInferredNameOffset = kDebugInfoOffset + kPointerSize;
- static const int kInitialMapOffset =
+ static const int kFeedbackVectorOffset =
kInferredNameOffset + kPointerSize;
+ static const int kInitialMapOffset =
+ kFeedbackVectorOffset + kPointerSize;
// ast_node_count is a Smi field. It could be grouped with another Smi field
// into a PSEUDO_SMI_ACCESSORS pair (on x64), if one becomes available.
static const int kAstNodeCountOffset =
@@ -8169,8 +8177,6 @@
inline void set_inlined_type_change_checksum(int checksum);
inline bool matches_inlined_type_change_checksum(int checksum);
- DECL_ACCESSORS(feedback_vector, FixedArray)
-
static inline TypeFeedbackInfo* cast(Object* obj);
// Dispatched behavior.
@@ -8179,10 +8185,9 @@
static const int kStorage1Offset = HeapObject::kHeaderSize;
static const int kStorage2Offset = kStorage1Offset + kPointerSize;
- static const int kFeedbackVectorOffset =
- kStorage2Offset + kPointerSize;
- static const int kSize = kFeedbackVectorOffset + kPointerSize;
+ static const int kSize = kStorage2Offset + kPointerSize;
+ // TODO(mvstanton): move these sentinel declarations to shared function info.
// The object that indicates an uninitialized cache.
static inline Handle<Object> UninitializedSentinel(Isolate* isolate);
@@ -8198,9 +8203,6 @@
// garbage collection (e.g., for patching the cache).
static inline Object* RawUninitializedSentinel(Heap* heap);
- static const int kForInFastCaseMarker = 0;
- static const int kForInSlowCaseMarker = 1;
-
private:
static const int kTypeChangeChecksumBits = 7;
diff --git a/src/parser.cc b/src/parser.cc
index bdd9348..3627baf 100644
--- a/src/parser.cc
+++ b/src/parser.cc
@@ -437,6 +437,59 @@
}
+bool ParserTraits::IsThisProperty(Expression* expression) {
+ ASSERT(expression != NULL);
+ Property* property = expression->AsProperty();
+ return property != NULL &&
+ property->obj()->AsVariableProxy() != NULL &&
+ property->obj()->AsVariableProxy()->is_this();
+}
+
+
+void ParserTraits::CheckAssigningFunctionLiteralToProperty(Expression* left,
+ Expression* right) {
+ ASSERT(left != NULL);
+ if (left->AsProperty() != NULL &&
+ right->AsFunctionLiteral() != NULL) {
+ right->AsFunctionLiteral()->set_pretenure();
+ }
+}
+
+
+Expression* ParserTraits::ValidateAssignmentLeftHandSide(
+ Expression* expression) const {
+ ASSERT(expression != NULL);
+ if (!expression->IsValidLeftHandSide()) {
+ Handle<String> message =
+ parser_->isolate()->factory()->invalid_lhs_in_assignment_string();
+ expression = parser_->NewThrowReferenceError(message);
+ }
+ return expression;
+}
+
+
+Expression* ParserTraits::MarkExpressionAsLValue(Expression* expression) {
+ VariableProxy* proxy = expression != NULL
+ ? expression->AsVariableProxy()
+ : NULL;
+ if (proxy != NULL) proxy->MarkAsLValue();
+ return expression;
+}
+
+
+void ParserTraits::CheckStrictModeLValue(Expression* expression,
+ bool* ok) {
+ VariableProxy* lhs = expression != NULL
+ ? expression->AsVariableProxy()
+ : NULL;
+ if (lhs != NULL && !lhs->is_this() && IsEvalOrArguments(lhs->name())) {
+ parser_->ReportMessage("strict_eval_arguments",
+ Vector<const char*>::empty());
+ *ok = false;
+ }
+}
+
+
void ParserTraits::ReportMessageAt(Scanner::Location source_location,
const char* message,
Vector<const char*> args) {
@@ -566,11 +619,6 @@
}
-Expression* ParserTraits::ParseAssignmentExpression(bool accept_IN, bool* ok) {
- return parser_->ParseAssignmentExpression(accept_IN, ok);
-}
-
-
Expression* ParserTraits::ParseV8Intrinsic(bool* ok) {
return parser_->ParseV8Intrinsic(ok);
}
@@ -590,6 +638,11 @@
}
+Expression* ParserTraits::ParseConditionalExpression(bool accept_IN, bool* ok) {
+ return parser_->ParseConditionalExpression(accept_IN, ok);
+}
+
+
Parser::Parser(CompilationInfo* info)
: ParserBase<ParserTraits>(&scanner_,
info->isolate()->stack_guard()->real_climit(),
@@ -2877,103 +2930,6 @@
}
-// Precedence = 2
-Expression* Parser::ParseAssignmentExpression(bool accept_IN, bool* ok) {
- // AssignmentExpression ::
- // ConditionalExpression
- // YieldExpression
- // LeftHandSideExpression AssignmentOperator AssignmentExpression
-
- if (peek() == Token::YIELD && is_generator()) {
- return ParseYieldExpression(ok);
- }
-
- if (fni_ != NULL) fni_->Enter();
- Expression* expression = ParseConditionalExpression(accept_IN, CHECK_OK);
-
- if (!Token::IsAssignmentOp(peek())) {
- if (fni_ != NULL) fni_->Leave();
- // Parsed conditional expression only (no assignment).
- return expression;
- }
-
- // Signal a reference error if the expression is an invalid left-hand
- // side expression. We could report this as a syntax error here but
- // for compatibility with JSC we choose to report the error at
- // runtime.
- // TODO(ES5): Should change parsing for spec conformance.
- if (expression == NULL || !expression->IsValidLeftHandSide()) {
- Handle<String> message =
- isolate()->factory()->invalid_lhs_in_assignment_string();
- expression = NewThrowReferenceError(message);
- }
-
- if (strict_mode() == STRICT) {
- // Assignment to eval or arguments is disallowed in strict mode.
- CheckStrictModeLValue(expression, CHECK_OK);
- }
- MarkAsLValue(expression);
-
- Token::Value op = Next(); // Get assignment operator.
- int pos = position();
- Expression* right = ParseAssignmentExpression(accept_IN, CHECK_OK);
-
- // TODO(1231235): We try to estimate the set of properties set by
- // constructors. We define a new property whenever there is an
- // assignment to a property of 'this'. We should probably only add
- // properties if we haven't seen them before. Otherwise we'll
- // probably overestimate the number of properties.
- Property* property = expression ? expression->AsProperty() : NULL;
- if (op == Token::ASSIGN &&
- property != NULL &&
- property->obj()->AsVariableProxy() != NULL &&
- property->obj()->AsVariableProxy()->is_this()) {
- function_state_->AddProperty();
- }
-
- // If we assign a function literal to a property we pretenure the
- // literal so it can be added as a constant function property.
- if (property != NULL && right->AsFunctionLiteral() != NULL) {
- right->AsFunctionLiteral()->set_pretenure();
- }
-
- if (fni_ != NULL) {
- // Check if the right hand side is a call to avoid inferring a
- // name if we're dealing with "a = function(){...}();"-like
- // expression.
- if ((op == Token::INIT_VAR
- || op == Token::INIT_CONST_LEGACY
- || op == Token::ASSIGN)
- && (right->AsCall() == NULL && right->AsCallNew() == NULL)) {
- fni_->Infer();
- } else {
- fni_->RemoveLastFunction();
- }
- fni_->Leave();
- }
-
- return factory()->NewAssignment(op, expression, right, pos);
-}
-
-
-Expression* Parser::ParseYieldExpression(bool* ok) {
- // YieldExpression ::
- // 'yield' '*'? AssignmentExpression
- int pos = peek_position();
- Expect(Token::YIELD, CHECK_OK);
- Yield::Kind kind =
- Check(Token::MUL) ? Yield::DELEGATING : Yield::SUSPEND;
- Expression* generator_object = factory()->NewVariableProxy(
- function_state_->generator_object_variable());
- Expression* expression = ParseAssignmentExpression(false, CHECK_OK);
- Yield* yield = factory()->NewYield(generator_object, expression, kind, pos);
- if (kind == Yield::DELEGATING) {
- yield->set_index(function_state_->NextHandlerIndex());
- }
- return yield;
-}
-
-
// Precedence = 3
Expression* Parser::ParseConditionalExpression(bool accept_IN, bool* ok) {
// ConditionalExpression ::
@@ -3184,7 +3140,7 @@
// Prefix expression operand in strict mode may not be eval or arguments.
CheckStrictModeLValue(expression, CHECK_OK);
}
- MarkAsLValue(expression);
+ MarkExpressionAsLValue(expression);
return factory()->NewCountOperation(op,
true /* prefix */,
@@ -3218,7 +3174,7 @@
// Postfix expression operand in strict mode may not be eval or arguments.
CheckStrictModeLValue(expression, CHECK_OK);
}
- MarkAsLValue(expression);
+ MarkExpressionAsLValue(expression);
Token::Value next = Next();
expression =
@@ -3974,31 +3930,6 @@
}
-void Parser::MarkAsLValue(Expression* expression) {
- VariableProxy* proxy = expression != NULL
- ? expression->AsVariableProxy()
- : NULL;
-
- if (proxy != NULL) proxy->MarkAsLValue();
-}
-
-
-// Checks LHS expression for assignment and prefix/postfix increment/decrement
-// in strict mode.
-void Parser::CheckStrictModeLValue(Expression* expression,
- bool* ok) {
- ASSERT(strict_mode() == STRICT);
- VariableProxy* lhs = expression != NULL
- ? expression->AsVariableProxy()
- : NULL;
-
- if (lhs != NULL && !lhs->is_this() && IsEvalOrArguments(lhs->name())) {
- ReportMessage("strict_eval_arguments", Vector<const char*>::empty());
- *ok = false;
- }
-}
-
-
void Parser::CheckConflictingVarDeclarations(Scope* scope, bool* ok) {
Declaration* decl = scope->CheckConflictingVarDeclarations();
if (decl != NULL) {
diff --git a/src/parser.h b/src/parser.h
index 073d64b..9fd636c 100644
--- a/src/parser.h
+++ b/src/parser.h
@@ -420,6 +420,7 @@
// Return types for traversing functions.
typedef Handle<String> Identifier;
typedef v8::internal::Expression* Expression;
+ typedef Yield* YieldExpression;
typedef v8::internal::FunctionLiteral* FunctionLiteral;
typedef v8::internal::Literal* Literal;
typedef ObjectLiteral::Property* ObjectLiteralProperty;
@@ -452,6 +453,9 @@
// Helper functions for recursive descent.
bool IsEvalOrArguments(Handle<String> identifier) const;
+ // Returns true if the expression is of type "this.foo".
+ static bool IsThisProperty(Expression* expression);
+
static bool IsBoilerplateProperty(ObjectLiteral::Property* property) {
return ObjectLiteral::IsBoilerplateProperty(property);
}
@@ -460,6 +464,8 @@
return !string.is_null() && string->AsArrayIndex(index);
}
+ // Functions for encapsulating the differences between parsing and preparsing;
+ // operations interleaved with the recursive descent.
static void PushLiteralName(FuncNameInferrer* fni, Handle<String> id) {
fni->PushLiteralName(id);
}
@@ -473,6 +479,25 @@
}
}
+ // If we assign a function literal to a property we pretenure the
+ // literal so it can be added as a constant function property.
+ static void CheckAssigningFunctionLiteralToProperty(Expression* left,
+ Expression* right);
+
+ // Signal a reference error if the expression is an invalid left-hand side
+ // expression. We could report this as a syntax error but for compatibility
+ // with JSC we choose to report the error at runtime.
+ Expression* ValidateAssignmentLeftHandSide(Expression* expression) const;
+
+ // Determine if the expression is a variable proxy and mark it as being used
+ // in an assignment or with a increment/decrement operator. This is currently
+ // used on for the statically checking assignments to harmony const bindings.
+ static Expression* MarkExpressionAsLValue(Expression* expression);
+
+ // Checks LHS expression for assignment and prefix/postfix increment/decrement
+ // in strict mode.
+ void CheckStrictModeLValue(Expression*expression, bool* ok);
+
// Reporting errors.
void ReportMessageAt(Scanner::Location source_location,
const char* message,
@@ -523,7 +548,6 @@
}
// Temporary glue; these functions will move to ParserBase.
- Expression* ParseAssignmentExpression(bool accept_IN, bool* ok);
Expression* ParseV8Intrinsic(bool* ok);
FunctionLiteral* ParseFunctionLiteral(
Handle<String> name,
@@ -533,6 +557,7 @@
int function_token_position,
FunctionLiteral::FunctionType type,
bool* ok);
+ Expression* ParseConditionalExpression(bool accept_IN, bool* ok);
private:
Parser* parser_;
@@ -675,8 +700,6 @@
// Support for hamony block scoped bindings.
Block* ParseScopedBlock(ZoneStringList* labels, bool* ok);
- Expression* ParseAssignmentExpression(bool accept_IN, bool* ok);
- Expression* ParseYieldExpression(bool* ok);
Expression* ParseConditionalExpression(bool accept_IN, bool* ok);
Expression* ParseBinaryExpression(int prec, bool accept_IN, bool* ok);
Expression* ParseUnaryExpression(bool* ok);
@@ -711,15 +734,6 @@
// Get odd-ball literals.
Literal* GetLiteralUndefined(int position);
- // Determine if the expression is a variable proxy and mark it as being used
- // in an assignment or with a increment/decrement operator. This is currently
- // used on for the statically checking assignments to harmony const bindings.
- void MarkAsLValue(Expression* expression);
-
- // Strict mode validation of LValue expressions
- void CheckStrictModeLValue(Expression* expression,
- bool* ok);
-
// For harmony block scoping mode: Check if the scope has conflicting var/let
// declarations from different scopes. It covers for example
//
diff --git a/src/platform-cygwin.cc b/src/platform-cygwin.cc
index ac80439..4ae9bec 100644
--- a/src/platform-cygwin.cc
+++ b/src/platform-cygwin.cc
@@ -51,7 +51,7 @@
namespace internal {
-const char* OS::LocalTimezone(double time) {
+const char* OS::LocalTimezone(double time, TimezoneCache* cache) {
if (std::isnan(time)) return "";
time_t tv = static_cast<time_t>(std::floor(time/msPerSecond));
struct tm* t = localtime(&tv);
@@ -60,7 +60,7 @@
}
-double OS::LocalTimeOffset() {
+double OS::LocalTimeOffset(TimezoneCache* cache) {
// On Cygwin, struct tm does not contain a tm_gmtoff field.
time_t utc = time(NULL);
ASSERT(utc != -1);
diff --git a/src/platform-freebsd.cc b/src/platform-freebsd.cc
index 9ab6583..7d15cef 100644
--- a/src/platform-freebsd.cc
+++ b/src/platform-freebsd.cc
@@ -61,7 +61,7 @@
namespace internal {
-const char* OS::LocalTimezone(double time) {
+const char* OS::LocalTimezone(double time, TimezoneCache* cache) {
if (std::isnan(time)) return "";
time_t tv = static_cast<time_t>(std::floor(time/msPerSecond));
struct tm* t = localtime(&tv);
@@ -70,7 +70,7 @@
}
-double OS::LocalTimeOffset() {
+double OS::LocalTimeOffset(TimezoneCache* cache) {
time_t tv = time(NULL);
struct tm* t = localtime(&tv);
// tm_gmtoff includes any daylight savings offset, so subtract it.
diff --git a/src/platform-linux.cc b/src/platform-linux.cc
index b35cd28..527b9f6 100644
--- a/src/platform-linux.cc
+++ b/src/platform-linux.cc
@@ -118,7 +118,7 @@
#endif // def __arm__
-const char* OS::LocalTimezone(double time) {
+const char* OS::LocalTimezone(double time, TimezoneCache* cache) {
if (std::isnan(time)) return "";
time_t tv = static_cast<time_t>(std::floor(time/msPerSecond));
struct tm* t = localtime(&tv);
@@ -127,7 +127,7 @@
}
-double OS::LocalTimeOffset() {
+double OS::LocalTimeOffset(TimezoneCache* cache) {
time_t tv = time(NULL);
struct tm* t = localtime(&tv);
// tm_gmtoff includes any daylight savings offset, so subtract it.
diff --git a/src/platform-macos.cc b/src/platform-macos.cc
index 683a04d..25ba0da 100644
--- a/src/platform-macos.cc
+++ b/src/platform-macos.cc
@@ -182,7 +182,7 @@
}
-const char* OS::LocalTimezone(double time) {
+const char* OS::LocalTimezone(double time, TimezoneCache* cache) {
if (std::isnan(time)) return "";
time_t tv = static_cast<time_t>(std::floor(time/msPerSecond));
struct tm* t = localtime(&tv);
@@ -191,7 +191,7 @@
}
-double OS::LocalTimeOffset() {
+double OS::LocalTimeOffset(TimezoneCache* cache) {
time_t tv = time(NULL);
struct tm* t = localtime(&tv);
// tm_gmtoff includes any daylight savings offset, so subtract it.
diff --git a/src/platform-openbsd.cc b/src/platform-openbsd.cc
index c881d47..a5d477d 100644
--- a/src/platform-openbsd.cc
+++ b/src/platform-openbsd.cc
@@ -59,7 +59,7 @@
namespace internal {
-const char* OS::LocalTimezone(double time) {
+const char* OS::LocalTimezone(double time, TimezoneCache* cache) {
if (std::isnan(time)) return "";
time_t tv = static_cast<time_t>(std::floor(time/msPerSecond));
struct tm* t = localtime(&tv);
@@ -68,7 +68,7 @@
}
-double OS::LocalTimeOffset() {
+double OS::LocalTimeOffset(TimezoneCache* cache) {
time_t tv = time(NULL);
struct tm* t = localtime(&tv);
// tm_gmtoff includes any daylight savings offset, so subtract it.
diff --git a/src/platform-posix.cc b/src/platform-posix.cc
index 94aabe8..c301eae 100644
--- a/src/platform-posix.cc
+++ b/src/platform-posix.cc
@@ -354,7 +354,25 @@
}
-double OS::DaylightSavingsOffset(double time) {
+class TimezoneCache {};
+
+
+TimezoneCache* OS::CreateTimezoneCache() {
+ return NULL;
+}
+
+
+void OS::DisposeTimezoneCache(TimezoneCache* cache) {
+ ASSERT(cache == NULL);
+}
+
+
+void OS::ClearTimezoneCache(TimezoneCache* cache) {
+ ASSERT(cache == NULL);
+}
+
+
+double OS::DaylightSavingsOffset(double time, TimezoneCache*) {
if (std::isnan(time)) return nan_value();
time_t tv = static_cast<time_t>(std::floor(time/msPerSecond));
struct tm* t = localtime(&tv);
@@ -363,9 +381,6 @@
}
-void OS::TimeZoneChanged() {}
-
-
int OS::GetLastError() {
return errno;
}
@@ -565,6 +580,8 @@
public:
PlatformData() : thread_(kNoThread) {}
pthread_t thread_; // Thread handle for pthread.
+ // Synchronizes thread creation
+ Mutex thread_creation_mutex_;
};
Thread::Thread(const Options& options)
@@ -612,10 +629,10 @@
static void* ThreadEntry(void* arg) {
Thread* thread = reinterpret_cast<Thread*>(arg);
- // This is also initialized by the first argument to pthread_create() but we
- // don't know which thread will run first (the original thread or the new
- // one) so we initialize it here too.
- thread->data()->thread_ = pthread_self();
+ // We take the lock here to make sure that pthread_create finished first since
+ // we don't know which thread will run first (the original thread or the new
+ // one).
+ { LockGuard<Mutex> lock_guard(&thread->data()->thread_creation_mutex_); }
SetThreadName(thread->name());
ASSERT(thread->data()->thread_ != kNoThread);
thread->NotifyStartedAndRun();
@@ -642,7 +659,10 @@
ASSERT_EQ(0, result);
}
#endif
- result = pthread_create(&data_->thread_, &attr, ThreadEntry, this);
+ {
+ LockGuard<Mutex> lock_guard(&data_->thread_creation_mutex_);
+ result = pthread_create(&data_->thread_, &attr, ThreadEntry, this);
+ }
ASSERT_EQ(0, result);
result = pthread_attr_destroy(&attr);
ASSERT_EQ(0, result);
diff --git a/src/platform-qnx.cc b/src/platform-qnx.cc
index cd031e7..ef0998f 100644
--- a/src/platform-qnx.cc
+++ b/src/platform-qnx.cc
@@ -110,7 +110,7 @@
#endif // __arm__
-const char* OS::LocalTimezone(double time) {
+const char* OS::LocalTimezone(double time, TimezoneCache* cache) {
if (std::isnan(time)) return "";
time_t tv = static_cast<time_t>(std::floor(time/msPerSecond));
struct tm* t = localtime(&tv);
@@ -119,7 +119,7 @@
}
-double OS::LocalTimeOffset() {
+double OS::LocalTimeOffset(TimezoneCache* cache) {
time_t tv = time(NULL);
struct tm* t = localtime(&tv);
// tm_gmtoff includes any daylight savings offset, so subtract it.
diff --git a/src/platform-solaris.cc b/src/platform-solaris.cc
index 4d910d4..f23ae08 100644
--- a/src/platform-solaris.cc
+++ b/src/platform-solaris.cc
@@ -80,7 +80,7 @@
namespace internal {
-const char* OS::LocalTimezone(double time) {
+const char* OS::LocalTimezone(double time, TimezoneCache* cache) {
if (std::isnan(time)) return "";
time_t tv = static_cast<time_t>(std::floor(time/msPerSecond));
struct tm* t = localtime(&tv);
@@ -89,7 +89,7 @@
}
-double OS::LocalTimeOffset() {
+double OS::LocalTimeOffset(TimezoneCache* cache) {
tzset();
return -static_cast<double>(timezone * msPerSecond);
}
diff --git a/src/platform-win32.cc b/src/platform-win32.cc
index afcd82b..fe84bcd 100644
--- a/src/platform-win32.cc
+++ b/src/platform-win32.cc
@@ -218,6 +218,97 @@
}
+class TimezoneCache {
+ public:
+ TimezoneCache() : initialized_(false) { }
+
+ void Clear() {
+ initialized_ = false;
+ }
+
+ // Initialize timezone information. The timezone information is obtained from
+ // windows. If we cannot get the timezone information we fall back to CET.
+ void InitializeIfNeeded() {
+ // Just return if timezone information has already been initialized.
+ if (initialized_) return;
+
+ // Initialize POSIX time zone data.
+ _tzset();
+ // Obtain timezone information from operating system.
+ memset(&tzinfo_, 0, sizeof(tzinfo_));
+ if (GetTimeZoneInformation(&tzinfo_) == TIME_ZONE_ID_INVALID) {
+ // If we cannot get timezone information we fall back to CET.
+ tzinfo_.Bias = -60;
+ tzinfo_.StandardDate.wMonth = 10;
+ tzinfo_.StandardDate.wDay = 5;
+ tzinfo_.StandardDate.wHour = 3;
+ tzinfo_.StandardBias = 0;
+ tzinfo_.DaylightDate.wMonth = 3;
+ tzinfo_.DaylightDate.wDay = 5;
+ tzinfo_.DaylightDate.wHour = 2;
+ tzinfo_.DaylightBias = -60;
+ }
+
+ // Make standard and DST timezone names.
+ WideCharToMultiByte(CP_UTF8, 0, tzinfo_.StandardName, -1,
+ std_tz_name_, kTzNameSize, NULL, NULL);
+ std_tz_name_[kTzNameSize - 1] = '\0';
+ WideCharToMultiByte(CP_UTF8, 0, tzinfo_.DaylightName, -1,
+ dst_tz_name_, kTzNameSize, NULL, NULL);
+ dst_tz_name_[kTzNameSize - 1] = '\0';
+
+ // If OS returned empty string or resource id (like "@tzres.dll,-211")
+ // simply guess the name from the UTC bias of the timezone.
+ // To properly resolve the resource identifier requires a library load,
+ // which is not possible in a sandbox.
+ if (std_tz_name_[0] == '\0' || std_tz_name_[0] == '@') {
+ OS::SNPrintF(Vector<char>(std_tz_name_, kTzNameSize - 1),
+ "%s Standard Time",
+ GuessTimezoneNameFromBias(tzinfo_.Bias));
+ }
+ if (dst_tz_name_[0] == '\0' || dst_tz_name_[0] == '@') {
+ OS::SNPrintF(Vector<char>(dst_tz_name_, kTzNameSize - 1),
+ "%s Daylight Time",
+ GuessTimezoneNameFromBias(tzinfo_.Bias));
+ }
+ // Timezone information initialized.
+ initialized_ = true;
+ }
+
+ // Guess the name of the timezone from the bias.
+ // The guess is very biased towards the northern hemisphere.
+ const char* GuessTimezoneNameFromBias(int bias) {
+ static const int kHour = 60;
+ switch (-bias) {
+ case -9*kHour: return "Alaska";
+ case -8*kHour: return "Pacific";
+ case -7*kHour: return "Mountain";
+ case -6*kHour: return "Central";
+ case -5*kHour: return "Eastern";
+ case -4*kHour: return "Atlantic";
+ case 0*kHour: return "GMT";
+ case +1*kHour: return "Central Europe";
+ case +2*kHour: return "Eastern Europe";
+ case +3*kHour: return "Russia";
+ case +5*kHour + 30: return "India";
+ case +8*kHour: return "China";
+ case +9*kHour: return "Japan";
+ case +12*kHour: return "New Zealand";
+ default: return "Local";
+ }
+ }
+
+
+ private:
+ static const int kTzNameSize = 128;
+ bool initialized_;
+ char std_tz_name_[kTzNameSize];
+ char dst_tz_name_[kTzNameSize];
+ TIME_ZONE_INFORMATION tzinfo_;
+ friend class Win32Time;
+};
+
+
// ----------------------------------------------------------------------------
// The Time class represents time on win32. A timestamp is represented as
// a 64-bit integer in 100 nanoseconds since January 1, 1601 (UTC). JavaScript
@@ -242,16 +333,14 @@
// LocalOffset(CET) = 3600000 and LocalOffset(PST) = -28800000. This
// routine also takes into account whether daylight saving is effect
// at the time.
- int64_t LocalOffset();
+ int64_t LocalOffset(TimezoneCache* cache);
// Returns the daylight savings time offset for the time in milliseconds.
- int64_t DaylightSavingsOffset();
+ int64_t DaylightSavingsOffset(TimezoneCache* cache);
// Returns a string identifying the current timezone for the
// timestamp taking into account daylight saving.
- char* LocalTimezone();
-
- static void TimeZoneChanged() { tz_initialized_ = false; }
+ char* LocalTimezone(TimezoneCache* cache);
private:
// Constants for time conversion.
@@ -260,25 +349,10 @@
static const int64_t kMsPerMinute = 60000;
// Constants for timezone information.
- static const int kTzNameSize = 128;
static const bool kShortTzNames = false;
- // Timezone information. We need to have static buffers for the
- // timezone names because we return pointers to these in
- // LocalTimezone().
- static bool tz_initialized_;
- static TIME_ZONE_INFORMATION tzinfo_;
- static char std_tz_name_[kTzNameSize];
- static char dst_tz_name_[kTzNameSize];
-
- // Initialize the timezone information (if not already done).
- static void TzSet();
-
- // Guess the name of the timezone from the bias.
- static const char* GuessTimezoneNameFromBias(int bias);
-
// Return whether or not daylight savings time is in effect at this time.
- bool InDST();
+ bool InDST(TimezoneCache* cache);
// Accessor for FILETIME representation.
FILETIME& ft() { return time_.ft_; }
@@ -300,13 +374,6 @@
};
-// Static variables.
-bool Win32Time::tz_initialized_ = false;
-TIME_ZONE_INFORMATION Win32Time::tzinfo_;
-char Win32Time::std_tz_name_[kTzNameSize];
-char Win32Time::dst_tz_name_[kTzNameSize];
-
-
// Initialize timestamp to start of epoc.
Win32Time::Win32Time() {
t() = 0;
@@ -395,90 +462,13 @@
}
-// Guess the name of the timezone from the bias.
-// The guess is very biased towards the northern hemisphere.
-const char* Win32Time::GuessTimezoneNameFromBias(int bias) {
- static const int kHour = 60;
- switch (-bias) {
- case -9*kHour: return "Alaska";
- case -8*kHour: return "Pacific";
- case -7*kHour: return "Mountain";
- case -6*kHour: return "Central";
- case -5*kHour: return "Eastern";
- case -4*kHour: return "Atlantic";
- case 0*kHour: return "GMT";
- case +1*kHour: return "Central Europe";
- case +2*kHour: return "Eastern Europe";
- case +3*kHour: return "Russia";
- case +5*kHour + 30: return "India";
- case +8*kHour: return "China";
- case +9*kHour: return "Japan";
- case +12*kHour: return "New Zealand";
- default: return "Local";
- }
-}
-
-
-// Initialize timezone information. The timezone information is obtained from
-// windows. If we cannot get the timezone information we fall back to CET.
-// Please notice that this code is not thread-safe.
-void Win32Time::TzSet() {
- // Just return if timezone information has already been initialized.
- if (tz_initialized_) return;
-
- // Initialize POSIX time zone data.
- _tzset();
- // Obtain timezone information from operating system.
- memset(&tzinfo_, 0, sizeof(tzinfo_));
- if (GetTimeZoneInformation(&tzinfo_) == TIME_ZONE_ID_INVALID) {
- // If we cannot get timezone information we fall back to CET.
- tzinfo_.Bias = -60;
- tzinfo_.StandardDate.wMonth = 10;
- tzinfo_.StandardDate.wDay = 5;
- tzinfo_.StandardDate.wHour = 3;
- tzinfo_.StandardBias = 0;
- tzinfo_.DaylightDate.wMonth = 3;
- tzinfo_.DaylightDate.wDay = 5;
- tzinfo_.DaylightDate.wHour = 2;
- tzinfo_.DaylightBias = -60;
- }
-
- // Make standard and DST timezone names.
- WideCharToMultiByte(CP_UTF8, 0, tzinfo_.StandardName, -1,
- std_tz_name_, kTzNameSize, NULL, NULL);
- std_tz_name_[kTzNameSize - 1] = '\0';
- WideCharToMultiByte(CP_UTF8, 0, tzinfo_.DaylightName, -1,
- dst_tz_name_, kTzNameSize, NULL, NULL);
- dst_tz_name_[kTzNameSize - 1] = '\0';
-
- // If OS returned empty string or resource id (like "@tzres.dll,-211")
- // simply guess the name from the UTC bias of the timezone.
- // To properly resolve the resource identifier requires a library load,
- // which is not possible in a sandbox.
- if (std_tz_name_[0] == '\0' || std_tz_name_[0] == '@') {
- OS::SNPrintF(Vector<char>(std_tz_name_, kTzNameSize - 1),
- "%s Standard Time",
- GuessTimezoneNameFromBias(tzinfo_.Bias));
- }
- if (dst_tz_name_[0] == '\0' || dst_tz_name_[0] == '@') {
- OS::SNPrintF(Vector<char>(dst_tz_name_, kTzNameSize - 1),
- "%s Daylight Time",
- GuessTimezoneNameFromBias(tzinfo_.Bias));
- }
-
- // Timezone information initialized.
- tz_initialized_ = true;
-}
-
-
// Return the local timezone offset in milliseconds east of UTC. This
// takes into account whether daylight saving is in effect at the time.
// Only times in the 32-bit Unix range may be passed to this function.
// Also, adding the time-zone offset to the input must not overflow.
// The function EquivalentTime() in date.js guarantees this.
-int64_t Win32Time::LocalOffset() {
- // Initialize timezone information, if needed.
- TzSet();
+int64_t Win32Time::LocalOffset(TimezoneCache* cache) {
+ cache->InitializeIfNeeded();
Win32Time rounded_to_second(*this);
rounded_to_second.t() = rounded_to_second.t() / 1000 / kTimeScaler *
@@ -501,29 +491,30 @@
if (localtime_s(&posix_local_time_struct, &posix_time)) return 0;
if (posix_local_time_struct.tm_isdst > 0) {
- return (tzinfo_.Bias + tzinfo_.DaylightBias) * -kMsPerMinute;
+ return (cache->tzinfo_.Bias + cache->tzinfo_.DaylightBias) * -kMsPerMinute;
} else if (posix_local_time_struct.tm_isdst == 0) {
- return (tzinfo_.Bias + tzinfo_.StandardBias) * -kMsPerMinute;
+ return (cache->tzinfo_.Bias + cache->tzinfo_.StandardBias) * -kMsPerMinute;
} else {
- return tzinfo_.Bias * -kMsPerMinute;
+ return cache->tzinfo_.Bias * -kMsPerMinute;
}
}
// Return whether or not daylight savings time is in effect at this time.
-bool Win32Time::InDST() {
- // Initialize timezone information, if needed.
- TzSet();
+bool Win32Time::InDST(TimezoneCache* cache) {
+ cache->InitializeIfNeeded();
// Determine if DST is in effect at the specified time.
bool in_dst = false;
- if (tzinfo_.StandardDate.wMonth != 0 || tzinfo_.DaylightDate.wMonth != 0) {
+ if (cache->tzinfo_.StandardDate.wMonth != 0 ||
+ cache->tzinfo_.DaylightDate.wMonth != 0) {
// Get the local timezone offset for the timestamp in milliseconds.
- int64_t offset = LocalOffset();
+ int64_t offset = LocalOffset(cache);
// Compute the offset for DST. The bias parameters in the timezone info
// are specified in minutes. These must be converted to milliseconds.
- int64_t dstofs = -(tzinfo_.Bias + tzinfo_.DaylightBias) * kMsPerMinute;
+ int64_t dstofs =
+ -(cache->tzinfo_.Bias + cache->tzinfo_.DaylightBias) * kMsPerMinute;
// If the local time offset equals the timezone bias plus the daylight
// bias then DST is in effect.
@@ -535,17 +526,17 @@
// Return the daylight savings time offset for this time.
-int64_t Win32Time::DaylightSavingsOffset() {
- return InDST() ? 60 * kMsPerMinute : 0;
+int64_t Win32Time::DaylightSavingsOffset(TimezoneCache* cache) {
+ return InDST(cache) ? 60 * kMsPerMinute : 0;
}
// Returns a string identifying the current timezone for the
// timestamp taking into account daylight saving.
-char* Win32Time::LocalTimezone() {
+char* Win32Time::LocalTimezone(TimezoneCache* cache) {
// Return the standard or DST time zone name based on whether daylight
// saving is in effect at the given time.
- return InDST() ? dst_tz_name_ : std_tz_name_;
+ return InDST(cache) ? cache->dst_tz_name_ : cache->std_tz_name_;
}
@@ -588,36 +579,47 @@
}
+TimezoneCache* OS::CreateTimezoneCache() {
+ return new TimezoneCache();
+}
+
+
+void OS::DisposeTimezoneCache(TimezoneCache* cache) {
+ delete cache;
+}
+
+
+void OS::ClearTimezoneCache(TimezoneCache* cache) {
+ cache->Clear();
+}
+
+
// Returns a string identifying the current timezone taking into
// account daylight saving.
-const char* OS::LocalTimezone(double time) {
- return Win32Time(time).LocalTimezone();
+const char* OS::LocalTimezone(double time, TimezoneCache* cache) {
+ return Win32Time(time).LocalTimezone(cache);
}
// Returns the local time offset in milliseconds east of UTC without
// taking daylight savings time into account.
-double OS::LocalTimeOffset() {
+double OS::LocalTimeOffset(TimezoneCache* cache) {
// Use current time, rounded to the millisecond.
Win32Time t(TimeCurrentMillis());
// Time::LocalOffset inlcudes any daylight savings offset, so subtract it.
- return static_cast<double>(t.LocalOffset() - t.DaylightSavingsOffset());
+ return static_cast<double>(t.LocalOffset(cache) -
+ t.DaylightSavingsOffset(cache));
}
// Returns the daylight savings offset in milliseconds for the given
// time.
-double OS::DaylightSavingsOffset(double time) {
- int64_t offset = Win32Time(time).DaylightSavingsOffset();
+double OS::DaylightSavingsOffset(double time, TimezoneCache* cache) {
+ int64_t offset = Win32Time(time).DaylightSavingsOffset(cache);
return static_cast<double>(offset);
}
-void OS::TimeZoneChanged() {
- Win32Time::TimeZoneChanged();
-}
-
-
int OS::GetLastError() {
return ::GetLastError();
}
diff --git a/src/platform.h b/src/platform.h
index d424666..d087d23 100644
--- a/src/platform.h
+++ b/src/platform.h
@@ -159,6 +159,9 @@
#endif // V8_NO_FAST_TLS
+class TimezoneCache;
+
+
// ----------------------------------------------------------------------------
// OS
//
@@ -182,18 +185,20 @@
// 00:00:00 UTC, January 1, 1970.
static double TimeCurrentMillis();
+ static TimezoneCache* CreateTimezoneCache();
+ static void DisposeTimezoneCache(TimezoneCache* cache);
+ static void ClearTimezoneCache(TimezoneCache* cache);
+
// Returns a string identifying the current time zone. The
// timestamp is used for determining if DST is in effect.
- static const char* LocalTimezone(double time);
+ static const char* LocalTimezone(double time, TimezoneCache* cache);
// Returns the local time offset in milliseconds east of UTC without
// taking daylight savings time into account.
- static double LocalTimeOffset();
+ static double LocalTimeOffset(TimezoneCache* cache);
// Returns the daylight savings offset for the given time.
- static double DaylightSavingsOffset(double time);
-
- static void TimeZoneChanged();
+ static double DaylightSavingsOffset(double time, TimezoneCache* cache);
// Returns last OS error.
static int GetLastError();
diff --git a/src/preparser.cc b/src/preparser.cc
index 652c1ba..a64a359 100644
--- a/src/preparser.cc
+++ b/src/preparser.cc
@@ -55,6 +55,18 @@
namespace v8 {
namespace internal {
+
+void PreParserTraits::CheckStrictModeLValue(PreParserExpression expression,
+ bool* ok) {
+ if (expression.IsIdentifier() &&
+ expression.AsIdentifier().IsEvalOrArguments()) {
+ pre_parser_->ReportMessage("strict_eval_arguments",
+ Vector<const char*>::empty());
+ *ok = false;
+ }
+}
+
+
void PreParserTraits::ReportMessageAt(Scanner::Location location,
const char* message,
Vector<const char*> args) {
@@ -111,12 +123,6 @@
}
-PreParserExpression PreParserTraits::ParseAssignmentExpression(bool accept_IN,
- bool* ok) {
- return pre_parser_->ParseAssignmentExpression(accept_IN, ok);
-}
-
-
PreParserExpression PreParserTraits::ParseV8Intrinsic(bool* ok) {
return pre_parser_->ParseV8Intrinsic(ok);
}
@@ -136,6 +142,12 @@
}
+PreParserExpression PreParserTraits::ParseConditionalExpression(bool accept_IN,
+ bool* ok) {
+ return pre_parser_->ParseConditionalExpression(accept_IN, ok);
+}
+
+
PreParser::PreParseResult PreParser::PreParseLazyFunction(
StrictMode strict_mode, bool is_generator, ParserRecorder* log) {
log_ = log;
@@ -827,60 +839,6 @@
#undef DUMMY
-// Precedence = 2
-PreParser::Expression PreParser::ParseAssignmentExpression(bool accept_IN,
- bool* ok) {
- // AssignmentExpression ::
- // ConditionalExpression
- // YieldExpression
- // LeftHandSideExpression AssignmentOperator AssignmentExpression
-
- if (function_state_->is_generator() && peek() == Token::YIELD) {
- return ParseYieldExpression(ok);
- }
-
- Scanner::Location before = scanner()->peek_location();
- Expression expression = ParseConditionalExpression(accept_IN, CHECK_OK);
-
- if (!Token::IsAssignmentOp(peek())) {
- // Parsed conditional expression only (no assignment).
- return expression;
- }
-
- if (strict_mode() == STRICT &&
- expression.IsIdentifier() &&
- expression.AsIdentifier().IsEvalOrArguments()) {
- Scanner::Location after = scanner()->location();
- PreParserTraits::ReportMessageAt(before.beg_pos, after.end_pos,
- "strict_eval_arguments", NULL);
- *ok = false;
- return Expression::Default();
- }
-
- Token::Value op = Next(); // Get assignment operator.
- ParseAssignmentExpression(accept_IN, CHECK_OK);
-
- if ((op == Token::ASSIGN) && expression.IsThisProperty()) {
- function_state_->AddProperty();
- }
-
- return Expression::Default();
-}
-
-
-// Precedence = 3
-PreParser::Expression PreParser::ParseYieldExpression(bool* ok) {
- // YieldExpression ::
- // 'yield' '*'? AssignmentExpression
- Consume(Token::YIELD);
- Check(Token::MUL);
-
- ParseAssignmentExpression(false, CHECK_OK);
-
- return Expression::Default();
-}
-
-
// Precedence = 3
PreParser::Expression PreParser::ParseConditionalExpression(bool accept_IN,
bool* ok) {
@@ -939,15 +897,9 @@
return Expression::Default();
} else if (Token::IsCountOp(op)) {
op = Next();
- Scanner::Location before = scanner()->peek_location();
Expression expression = ParseUnaryExpression(CHECK_OK);
- if (strict_mode() == STRICT &&
- expression.IsIdentifier() &&
- expression.AsIdentifier().IsEvalOrArguments()) {
- Scanner::Location after = scanner()->location();
- PreParserTraits::ReportMessageAt(before.beg_pos, after.end_pos,
- "strict_eval_arguments", NULL);
- *ok = false;
+ if (strict_mode() == STRICT) {
+ CheckStrictModeLValue(expression, CHECK_OK);
}
return Expression::Default();
} else {
@@ -960,18 +912,11 @@
// PostfixExpression ::
// LeftHandSideExpression ('++' | '--')?
- Scanner::Location before = scanner()->peek_location();
Expression expression = ParseLeftHandSideExpression(CHECK_OK);
if (!scanner()->HasAnyLineTerminatorBeforeNext() &&
Token::IsCountOp(peek())) {
- if (strict_mode() == STRICT &&
- expression.IsIdentifier() &&
- expression.AsIdentifier().IsEvalOrArguments()) {
- Scanner::Location after = scanner()->location();
- PreParserTraits::ReportMessageAt(before.beg_pos, after.end_pos,
- "strict_eval_arguments", NULL);
- *ok = false;
- return Expression::Default();
+ if (strict_mode() == STRICT) {
+ CheckStrictModeLValue(expression, CHECK_OK);
}
Next();
return Expression::Default();
diff --git a/src/preparser.h b/src/preparser.h
index 06880d5..8c0e067 100644
--- a/src/preparser.h
+++ b/src/preparser.h
@@ -382,6 +382,9 @@
typename Traits::Type::Expression ParseArrayLiteral(bool* ok);
typename Traits::Type::Expression ParseObjectLiteral(bool* ok);
typename Traits::Type::ExpressionList ParseArguments(bool* ok);
+ typename Traits::Type::Expression ParseAssignmentExpression(bool accept_IN,
+ bool* ok);
+ typename Traits::Type::Expression ParseYieldExpression(bool* ok);
// Used to detect duplicates in object literals. Each of the values
// kGetterProperty, kSetterProperty and kValueProperty represents
@@ -564,6 +567,17 @@
bool IsStrictFunction() { return code_ == kStrictFunctionExpression; }
+ // Dummy implementation for making expression->AsCall() work (see below).
+ PreParserExpression* operator->() { return this; }
+
+ // These are only used when doing function name inferring, and PreParser
+ // doesn't do function name inferring.
+ void* AsCall() const { return NULL; }
+ void* AsCallNew() const { return NULL; }
+
+ // More dummy implementations of things PreParser doesn't need to track:
+ void set_index(int index) {} // For YieldExpressions
+
private:
// First two/three bits are used as flags.
// Bit 0 and 1 represent identifiers or strings literals, and are
@@ -683,6 +697,24 @@
int pos) {
return PreParserExpression::Default();
}
+
+ PreParserExpression NewAssignment(Token::Value op,
+ PreParserExpression left,
+ PreParserExpression right,
+ int pos) {
+ return PreParserExpression::Default();
+ }
+
+ PreParserExpression NewVariableProxy(void* generator_variable) {
+ return PreParserExpression::Default();
+ }
+
+ PreParserExpression NewYield(PreParserExpression generator_object,
+ PreParserExpression expression,
+ Yield::Kind yield_kind,
+ int pos) {
+ return PreParserExpression::Default();
+ }
};
@@ -705,6 +737,7 @@
// Return types for traversing functions.
typedef PreParserIdentifier Identifier;
typedef PreParserExpression Expression;
+ typedef PreParserExpression YieldExpression;
typedef PreParserExpression FunctionLiteral;
typedef PreParserExpression ObjectLiteralProperty;
typedef PreParserExpression Literal;
@@ -729,6 +762,11 @@
return identifier.IsEvalOrArguments();
}
+ // Returns true if the expression is of type "this.foo".
+ static bool IsThisProperty(PreParserExpression expression) {
+ return expression.IsThisProperty();
+ }
+
static bool IsBoilerplateProperty(PreParserExpression property) {
// PreParser doesn't count boilerplate properties.
return false;
@@ -738,6 +776,8 @@
return false;
}
+ // Functions for encapsulating the differences between parsing and preparsing;
+ // operations interleaved with the recursive descent.
static void PushLiteralName(FuncNameInferrer* fni, PreParserIdentifier id) {
// PreParser should not use FuncNameInferrer.
ASSERT(false);
@@ -746,6 +786,29 @@
static void CheckFunctionLiteralInsideTopLevelObjectLiteral(
PreParserScope* scope, PreParserExpression value, bool* has_function) {}
+ static void CheckAssigningFunctionLiteralToProperty(
+ PreParserExpression left, PreParserExpression right) {}
+
+
+ static PreParserExpression ValidateAssignmentLeftHandSide(
+ PreParserExpression expression) {
+ // Parser generates a runtime error here if the left hand side is not valid.
+ // PreParser doesn't have to.
+ return expression;
+ }
+
+ static PreParserExpression MarkExpressionAsLValue(
+ PreParserExpression expression) {
+ // TODO(marja): To be able to produce the same errors, the preparser needs
+ // to start tracking which expressions are variables and which are lvalues.
+ return expression;
+ }
+
+ // Checks LHS expression for assignment and prefix/postfix increment/decrement
+ // in strict mode.
+ void CheckStrictModeLValue(PreParserExpression expression, bool* ok);
+
+
// Reporting errors.
void ReportMessageAt(Scanner::Location location,
const char* message,
@@ -815,7 +878,6 @@
}
// Temporary glue; these functions will move to ParserBase.
- PreParserExpression ParseAssignmentExpression(bool accept_IN, bool* ok);
PreParserExpression ParseV8Intrinsic(bool* ok);
PreParserExpression ParseFunctionLiteral(
PreParserIdentifier name,
@@ -825,6 +887,7 @@
int function_token_position,
FunctionLiteral::FunctionType type,
bool* ok);
+ PreParserExpression ParseConditionalExpression(bool accept_IN, bool* ok);
private:
PreParser* pre_parser_;
@@ -989,9 +1052,6 @@
Statement ParseThrowStatement(bool* ok);
Statement ParseTryStatement(bool* ok);
Statement ParseDebuggerStatement(bool* ok);
-
- Expression ParseAssignmentExpression(bool accept_IN, bool* ok);
- Expression ParseYieldExpression(bool* ok);
Expression ParseConditionalExpression(bool accept_IN, bool* ok);
Expression ParseBinaryExpression(int prec, bool accept_IN, bool* ok);
Expression ParseUnaryExpression(bool* ok);
@@ -1537,6 +1597,97 @@
return result;
}
+// Precedence = 2
+template <class Traits>
+typename Traits::Type::Expression ParserBase<Traits>::ParseAssignmentExpression(
+ bool accept_IN, bool* ok) {
+ // AssignmentExpression ::
+ // ConditionalExpression
+ // YieldExpression
+ // LeftHandSideExpression AssignmentOperator AssignmentExpression
+
+ if (peek() == Token::YIELD && is_generator()) {
+ return this->ParseYieldExpression(ok);
+ }
+
+ if (fni_ != NULL) fni_->Enter();
+ typename Traits::Type::Expression expression =
+ this->ParseConditionalExpression(accept_IN, CHECK_OK);
+
+ if (!Token::IsAssignmentOp(peek())) {
+ if (fni_ != NULL) fni_->Leave();
+ // Parsed conditional expression only (no assignment).
+ return expression;
+ }
+
+ // Signal a reference error if the expression is an invalid left-hand
+ // side expression. We could report this as a syntax error here but
+ // for compatibility with JSC we choose to report the error at
+ // runtime.
+ // TODO(ES5): Should change parsing for spec conformance.
+ expression = this->ValidateAssignmentLeftHandSide(expression);
+
+ if (strict_mode() == STRICT) {
+ // Assignment to eval or arguments is disallowed in strict mode.
+ this->CheckStrictModeLValue(expression, CHECK_OK);
+ }
+ expression = this->MarkExpressionAsLValue(expression);
+
+ Token::Value op = Next(); // Get assignment operator.
+ int pos = position();
+ typename Traits::Type::Expression right =
+ this->ParseAssignmentExpression(accept_IN, CHECK_OK);
+
+ // TODO(1231235): We try to estimate the set of properties set by
+ // constructors. We define a new property whenever there is an
+ // assignment to a property of 'this'. We should probably only add
+ // properties if we haven't seen them before. Otherwise we'll
+ // probably overestimate the number of properties.
+ if (op == Token::ASSIGN && this->IsThisProperty(expression)) {
+ function_state_->AddProperty();
+ }
+
+ this->CheckAssigningFunctionLiteralToProperty(expression, right);
+
+ if (fni_ != NULL) {
+ // Check if the right hand side is a call to avoid inferring a
+ // name if we're dealing with "a = function(){...}();"-like
+ // expression.
+ if ((op == Token::INIT_VAR
+ || op == Token::INIT_CONST_LEGACY
+ || op == Token::ASSIGN)
+ && (right->AsCall() == NULL && right->AsCallNew() == NULL)) {
+ fni_->Infer();
+ } else {
+ fni_->RemoveLastFunction();
+ }
+ fni_->Leave();
+ }
+
+ return factory()->NewAssignment(op, expression, right, pos);
+}
+
+template <class Traits>
+typename Traits::Type::Expression ParserBase<Traits>::ParseYieldExpression(
+ bool* ok) {
+ // YieldExpression ::
+ // 'yield' '*'? AssignmentExpression
+ int pos = peek_position();
+ Expect(Token::YIELD, CHECK_OK);
+ Yield::Kind kind =
+ Check(Token::MUL) ? Yield::DELEGATING : Yield::SUSPEND;
+ typename Traits::Type::Expression generator_object =
+ factory()->NewVariableProxy(function_state_->generator_object_variable());
+ typename Traits::Type::Expression expression =
+ ParseAssignmentExpression(false, CHECK_OK);
+ typename Traits::Type::YieldExpression yield =
+ factory()->NewYield(generator_object, expression, kind, pos);
+ if (kind == Yield::DELEGATING) {
+ yield->set_index(function_state_->NextHandlerIndex());
+ }
+ return yield;
+}
+
#undef CHECK_OK
#undef CHECK_OK_CUSTOM
diff --git a/src/profile-generator-inl.h b/src/profile-generator-inl.h
index e363f67..9aeb8f5 100644
--- a/src/profile-generator-inl.h
+++ b/src/profile-generator-inl.h
@@ -47,7 +47,7 @@
line_number_(line_number),
column_number_(column_number),
shared_id_(0),
- script_id_(v8::Script::kNoScriptId),
+ script_id_(v8::UnboundScript::kNoScriptId),
no_frame_ranges_(NULL),
bailout_reason_(kEmptyBailoutReason) { }
diff --git a/src/promise.js b/src/promise.js
index 8e22c31..f700be9 100644
--- a/src/promise.js
+++ b/src/promise.js
@@ -227,7 +227,15 @@
function PromiseCoerce(constructor, x) {
if (!IsPromise(x) && IS_SPEC_OBJECT(x)) {
- var then = x.then;
+ var then;
+ try {
+ then = x.then;
+ } catch(e) {
+ var deferred = %_CallFunction(constructor, PromiseDeferred);
+ PromiseCoerce.table.set(x, deferred.promise);
+ deferred.reject(e);
+ return deferred.promise;
+ }
if (typeof then === 'function') {
if (PromiseCoerce.table.has(x)) {
return PromiseCoerce.table.get(x);
diff --git a/src/runtime.cc b/src/runtime.cc
index 8f0c8a0..02be8a6 100644
--- a/src/runtime.cc
+++ b/src/runtime.cc
@@ -2929,6 +2929,7 @@
// Set the code, scope info, formal parameter count, and the length
// of the target shared function info.
target_shared->ReplaceCode(source_shared->code());
+ target_shared->set_feedback_vector(source_shared->feedback_vector());
target_shared->set_scope_info(source_shared->scope_info());
target_shared->set_length(source_shared->length());
target_shared->set_formal_parameter_count(
@@ -8477,10 +8478,10 @@
HandleScope scope(isolate);
ASSERT(args.length() == 1);
CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
+ function->shared()->ClearTypeFeedbackInfo(isolate->heap());
Code* unoptimized = function->shared()->code();
if (unoptimized->kind() == Code::FUNCTION) {
unoptimized->ClearInlineCaches();
- unoptimized->ClearTypeFeedbackInfo(isolate->heap());
}
return isolate->heap()->undefined_value();
}
@@ -9582,8 +9583,8 @@
ASSERT(args.length() == 1);
CONVERT_DOUBLE_ARG_CHECKED(x, 0);
- int64_t time = isolate->date_cache()->EquivalentTime(static_cast<int64_t>(x));
- const char* zone = OS::LocalTimezone(static_cast<double>(time));
+ const char* zone =
+ isolate->date_cache()->LocalTimezone(static_cast<int64_t>(x));
return isolate->heap()->AllocateStringFromUtf8(CStrVector(zone));
}
diff --git a/src/type-info.cc b/src/type-info.cc
index 35beb18..6282ef6 100644
--- a/src/type-info.cc
+++ b/src/type-info.cc
@@ -43,16 +43,12 @@
TypeFeedbackOracle::TypeFeedbackOracle(Handle<Code> code,
+ Handle<FixedArray> feedback_vector,
Handle<Context> native_context,
Zone* zone)
: native_context_(native_context),
- zone_(zone) {
- Object* raw_info = code->type_feedback_info();
- if (raw_info->IsTypeFeedbackInfo()) {
- feedback_vector_ = Handle<FixedArray>(TypeFeedbackInfo::cast(raw_info)->
- feedback_vector());
- }
-
+ zone_(zone),
+ feedback_vector_(feedback_vector) {
BuildDictionary(code);
ASSERT(dictionary_->IsDictionary());
}
@@ -132,9 +128,9 @@
byte TypeFeedbackOracle::ForInType(int feedback_vector_slot) {
Handle<Object> value = GetInfo(feedback_vector_slot);
- return value->IsSmi() &&
- Smi::cast(*value)->value() == TypeFeedbackInfo::kForInFastCaseMarker
- ? ForInStatement::FAST_FOR_IN : ForInStatement::SLOW_FOR_IN;
+ return value.is_identical_to(
+ TypeFeedbackInfo::UninitializedSentinel(isolate()))
+ ? ForInStatement::FAST_FOR_IN : ForInStatement::SLOW_FOR_IN;
}
diff --git a/src/type-info.h b/src/type-info.h
index 5bf653f..8494424 100644
--- a/src/type-info.h
+++ b/src/type-info.h
@@ -44,6 +44,7 @@
class TypeFeedbackOracle: public ZoneObject {
public:
TypeFeedbackOracle(Handle<Code> code,
+ Handle<FixedArray> feedback_vector,
Handle<Context> native_context,
Zone* zone);
diff --git a/src/typing.cc b/src/typing.cc
index b925dc6..b9d0ba3 100644
--- a/src/typing.cc
+++ b/src/typing.cc
@@ -40,6 +40,7 @@
: info_(info),
oracle_(
Handle<Code>(info->closure()->shared()->code()),
+ Handle<FixedArray>(info->closure()->shared()->feedback_vector()),
Handle<Context>(info->closure()->context()->native_context()),
info->zone()),
store_(info->zone()) {
@@ -561,7 +562,7 @@
RECURSE(Visit(arg));
}
- // We don't know anything about the result type.
+ NarrowType(expr, Bounds(Type::None(zone()), Type::Receiver(zone())));
}
diff --git a/src/version.cc b/src/version.cc
index 912abc8..09f7cb2 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 25
-#define BUILD_NUMBER 11
+#define BUILD_NUMBER 12
#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/deoptimizer-x64.cc b/src/x64/deoptimizer-x64.cc
index 0b6791e..e35664a 100644
--- a/src/x64/deoptimizer-x64.cc
+++ b/src/x64/deoptimizer-x64.cc
@@ -361,6 +361,12 @@
}
+void FrameDescription::SetCallerConstantPool(unsigned offset, intptr_t value) {
+ // No out-of-line constant pool support.
+ UNREACHABLE();
+}
+
+
#undef __
diff --git a/src/x64/full-codegen-x64.cc b/src/x64/full-codegen-x64.cc
index b40ee92..b146809 100644
--- a/src/x64/full-codegen-x64.cc
+++ b/src/x64/full-codegen-x64.cc
@@ -119,8 +119,6 @@
handler_table_ =
isolate()->factory()->NewFixedArray(function()->handler_count(), TENURED);
- InitializeFeedbackVector();
-
profiling_counter_ = isolate()->factory()->NewCell(
Handle<Smi>(Smi::FromInt(FLAG_interrupt_budget), isolate()));
SetFunctionPosition(function());
@@ -1127,15 +1125,10 @@
Label non_proxy;
__ bind(&fixed_array);
- Handle<Object> feedback = Handle<Object>(
- Smi::FromInt(TypeFeedbackInfo::kForInFastCaseMarker),
- isolate());
- StoreFeedbackVectorSlot(slot, feedback);
-
// No need for a write barrier, we are storing a Smi in the feedback vector.
__ Move(rbx, FeedbackVector());
__ Move(FieldOperand(rbx, FixedArray::OffsetOfElementAt(slot)),
- Smi::FromInt(TypeFeedbackInfo::kForInSlowCaseMarker));
+ TypeFeedbackInfo::MegamorphicSentinel(isolate()));
__ Move(rbx, Smi::FromInt(1)); // Smi indicates slow check
__ movp(rcx, Operand(rsp, 0 * kPointerSize)); // Get enumerated object
STATIC_ASSERT(FIRST_JS_PROXY_TYPE == FIRST_SPEC_OBJECT_TYPE);
@@ -2648,9 +2641,6 @@
// Record source position for debugger.
SetSourcePosition(expr->position());
- Handle<Object> uninitialized =
- TypeFeedbackInfo::UninitializedSentinel(isolate());
- StoreFeedbackVectorSlot(expr->CallFeedbackSlot(), uninitialized);
__ Move(rbx, FeedbackVector());
__ Move(rdx, Smi::FromInt(expr->CallFeedbackSlot()));
@@ -2828,9 +2818,6 @@
__ movp(rdi, Operand(rsp, arg_count * kPointerSize));
// Record call targets in unoptimized code, but not in the snapshot.
- Handle<Object> uninitialized =
- TypeFeedbackInfo::UninitializedSentinel(isolate());
- StoreFeedbackVectorSlot(expr->CallNewFeedbackSlot(), uninitialized);
__ Move(rbx, FeedbackVector());
__ Move(rdx, Smi::FromInt(expr->CallNewFeedbackSlot()));
diff --git a/src/x64/lithium-codegen-x64.cc b/src/x64/lithium-codegen-x64.cc
index 11cfa69..332c2ee 100644
--- a/src/x64/lithium-codegen-x64.cc
+++ b/src/x64/lithium-codegen-x64.cc
@@ -5144,7 +5144,11 @@
if (instr->size()->IsConstantOperand()) {
int32_t size = ToInteger32(LConstantOperand::cast(instr->size()));
- __ Allocate(size, result, temp, no_reg, deferred->entry(), flags);
+ if (size <= Page::kMaxRegularHeapObjectSize) {
+ __ Allocate(size, result, temp, no_reg, deferred->entry(), flags);
+ } else {
+ __ jmp(deferred->entry());
+ }
} else {
Register size = ToRegister(instr->size());
__ Allocate(size, result, temp, no_reg, deferred->entry(), flags);