From dcd41ca864749b130b943c1e41eb993388f7e9d8 Mon Sep 17 00:00:00 2001 From: Ryan Dahl Date: Thu, 15 Jul 2010 18:52:48 -0700 Subject: [PATCH] Upgrade V8 to 2.3.0 --- deps/v8/ChangeLog | 8 + deps/v8/include/v8-debug.h | 16 +- deps/v8/src/accessors.cc | 4 +- deps/v8/src/api.cc | 6 + deps/v8/src/arm/codegen-arm.cc | 183 +++++++----- deps/v8/src/arm/full-codegen-arm.cc | 9 +- deps/v8/src/arm/stub-cache-arm.cc | 7 + deps/v8/src/codegen.h | 27 +- deps/v8/src/compiler.cc | 10 +- deps/v8/src/contexts.cc | 22 +- deps/v8/src/debug.cc | 116 ++++++-- deps/v8/src/debug.h | 29 +- deps/v8/src/factory.cc | 2 +- deps/v8/src/factory.h | 2 +- deps/v8/src/frames.cc | 4 +- deps/v8/src/globals.h | 1 + deps/v8/src/heap.cc | 11 +- deps/v8/src/ia32/codegen-ia32.cc | 8 +- deps/v8/src/ia32/stub-cache-ia32.cc | 6 + deps/v8/src/objects-inl.h | 14 +- deps/v8/src/objects.h | 2 +- deps/v8/src/parser.cc | 6 +- deps/v8/src/profile-generator.cc | 7 +- deps/v8/src/runtime.cc | 53 ++-- deps/v8/src/scopeinfo.cc | 275 ++++++++---------- deps/v8/src/scopeinfo.h | 81 +++--- deps/v8/src/v8natives.js | 44 ++- deps/v8/src/version.cc | 4 +- deps/v8/src/x64/codegen-x64.cc | 73 +++-- deps/v8/src/x64/stub-cache-x64.cc | 6 + deps/v8/test/cctest/test-debug.cc | 65 +++++ deps/v8/test/es5conform/es5conform.status | 11 - deps/v8/test/mjsunit/call-stub.js | 15 + deps/v8/test/mjsunit/object-freeze.js | 19 ++ deps/v8/test/mjsunit/object-seal.js | 195 +++++++++++++ deps/v8/test/mjsunit/regress/regress-r4998.js | 94 ++++++ 36 files changed, 1012 insertions(+), 423 deletions(-) create mode 100644 deps/v8/test/mjsunit/object-seal.js create mode 100644 deps/v8/test/mjsunit/regress/regress-r4998.js diff --git a/deps/v8/ChangeLog b/deps/v8/ChangeLog index cdadfba3a2..39bd3e1b2d 100644 --- a/deps/v8/ChangeLog +++ b/deps/v8/ChangeLog @@ -1,3 +1,11 @@ +2010-07-15: Version 2.3.0 + + Added ES5 Object.seal and Object.isSealed. + + Added debugger API for scheduling debugger commands from a + separate thread. + + 2010-07-14: Version 2.2.24 Added API for capturing stack traces for uncaught exceptions. diff --git a/deps/v8/include/v8-debug.h b/deps/v8/include/v8-debug.h index c53b63462a..414fd8622a 100644 --- a/deps/v8/include/v8-debug.h +++ b/deps/v8/include/v8-debug.h @@ -76,7 +76,8 @@ enum DebugEvent { NewFunction = 3, BeforeCompile = 4, AfterCompile = 5, - ScriptCollected = 6 + ScriptCollected = 6, + BreakForCommand = 7 }; @@ -172,6 +173,13 @@ class EXPORT Debug { */ virtual Handle GetCallbackData() const = 0; + /** + * Client data passed to DebugBreakForCommand function. The + * debugger takes ownership of the data and will delete it even if + * there is no message handler. + */ + virtual ClientData* GetClientData() const = 0; + virtual ~EventDetails() {} }; @@ -248,6 +256,12 @@ class EXPORT Debug { // Break execution of JavaScript. static void DebugBreak(); + // Break execution of JavaScript (this method can be invoked from a + // non-VM thread) for further client command execution on a VM + // thread. Client data is then passed in EventDetails to + // EventCallback at the moment when the VM actually stops. + static void DebugBreakForCommand(ClientData* data = NULL); + // Message based interface. The message protocol is JSON. NOTE the message // handler thread is not supported any more parameter must be false. static void SetMessageHandler(MessageHandler handler, diff --git a/deps/v8/src/accessors.cc b/deps/v8/src/accessors.cc index 9fbfe56dae..ed0bbd7a1c 100644 --- a/deps/v8/src/accessors.cc +++ b/deps/v8/src/accessors.cc @@ -549,8 +549,8 @@ Object* Accessors::FunctionGetArguments(Object* object, void*) { if (frame->function() != *function) continue; // If there is an arguments variable in the stack, we return that. - int index = ScopeInfo<>::StackSlotIndex(function->shared()->scope_info(), - Heap::arguments_symbol()); + int index = function->shared()->scope_info()-> + StackSlotIndex(Heap::arguments_symbol()); if (index >= 0) { Handle arguments = Handle(frame->GetExpression(index)); if (!arguments->IsTheHole()) return *arguments; diff --git a/deps/v8/src/api.cc b/deps/v8/src/api.cc index 07d9eb0ac7..b3c77d8cdd 100644 --- a/deps/v8/src/api.cc +++ b/deps/v8/src/api.cc @@ -4213,6 +4213,12 @@ void Debug::DebugBreak() { } +void Debug::DebugBreakForCommand(ClientData* data) { + if (!i::V8::IsRunning()) return; + i::Debugger::EnqueueDebugCommand(data); +} + + static v8::Debug::MessageHandler message_handler = NULL; static void MessageHandlerWrapper(const v8::Debug::Message& message) { diff --git a/deps/v8/src/arm/codegen-arm.cc b/deps/v8/src/arm/codegen-arm.cc index 6e0604bc6e..71775ac971 100644 --- a/deps/v8/src/arm/codegen-arm.cc +++ b/deps/v8/src/arm/codegen-arm.cc @@ -54,11 +54,15 @@ static void EmitIdenticalObjectComparison(MacroAssembler* masm, Condition cc, bool never_nan_nan); static void EmitSmiNonsmiComparison(MacroAssembler* masm, + Register lhs, + Register rhs, Label* lhs_not_nan, Label* slow, bool strict); static void EmitTwoNonNanDoubleComparison(MacroAssembler* masm, Condition cc); -static void EmitStrictTwoHeapObjectCompare(MacroAssembler* masm); +static void EmitStrictTwoHeapObjectCompare(MacroAssembler* masm, + Register lhs, + Register rhs); static void MultiplyByKnownInt(MacroAssembler* masm, Register source, Register destination, @@ -1404,11 +1408,7 @@ void CodeGenerator::Comparison(Condition cc, // Perform non-smi comparison by stub. // CompareStub takes arguments in r0 and r1, returns <0, >0 or 0 in r0. // We call with 0 args because there are 0 on the stack. - if (!rhs.is(r0)) { - __ Swap(rhs, lhs, ip); - } - - CompareStub stub(cc, strict); + CompareStub stub(cc, strict, kBothCouldBeNaN, true, lhs, rhs); frame_->CallStub(&stub, 0); __ cmp(r0, Operand(0)); exit.Jump(); @@ -6968,7 +6968,7 @@ static void EmitIdenticalObjectComparison(MacroAssembler* masm, // undefined >= undefined should fail. __ mov(r0, Operand(LESS)); } - __ mov(pc, Operand(lr)); // Return. + __ Ret(); } } } @@ -6982,7 +6982,7 @@ static void EmitIdenticalObjectComparison(MacroAssembler* masm, } else { __ mov(r0, Operand(EQUAL)); // Things are <=, >=, ==, === themselves. } - __ mov(pc, Operand(lr)); // Return. + __ Ret(); if (cc != eq || !never_nan_nan) { // For less and greater we don't have to check for NaN since the result of @@ -7014,14 +7014,14 @@ static void EmitIdenticalObjectComparison(MacroAssembler* masm, // value if it's a NaN. if (cc != eq) { // All-zero means Infinity means equal. - __ mov(pc, Operand(lr), LeaveCC, eq); // Return equal + __ Ret(eq); if (cc == le) { __ mov(r0, Operand(GREATER)); // NaN <= NaN should fail. } else { __ mov(r0, Operand(LESS)); // NaN >= NaN should fail. } } - __ mov(pc, Operand(lr)); // Return. + __ Ret(); } // No fall through here. } @@ -7032,43 +7032,50 @@ static void EmitIdenticalObjectComparison(MacroAssembler* masm, // See comment at call site. static void EmitSmiNonsmiComparison(MacroAssembler* masm, + Register lhs, + Register rhs, Label* lhs_not_nan, Label* slow, bool strict) { + ASSERT((lhs.is(r0) && rhs.is(r1)) || + (lhs.is(r1) && rhs.is(r0))); + Label rhs_is_smi; - __ tst(r0, Operand(kSmiTagMask)); + __ tst(rhs, Operand(kSmiTagMask)); __ b(eq, &rhs_is_smi); // Lhs is a Smi. Check whether the rhs is a heap number. - __ CompareObjectType(r0, r4, r4, HEAP_NUMBER_TYPE); + __ CompareObjectType(rhs, r4, r4, HEAP_NUMBER_TYPE); if (strict) { // If rhs is not a number and lhs is a Smi then strict equality cannot - // succeed. Return non-equal (r0 is already not zero) - __ mov(pc, Operand(lr), LeaveCC, ne); // Return. + // succeed. Return non-equal + // If rhs is r0 then there is already a non zero value in it. + if (!rhs.is(r0)) { + __ mov(r0, Operand(NOT_EQUAL), LeaveCC, ne); + } + __ Ret(ne); } else { // Smi compared non-strictly with a non-Smi non-heap-number. Call // the runtime. __ b(ne, slow); } - // Lhs (r1) is a smi, rhs (r0) is a number. + // Lhs is a smi, rhs is a number. if (CpuFeatures::IsSupported(VFP3)) { - // Convert lhs to a double in d7 . + // Convert lhs to a double in d7. CpuFeatures::Scope scope(VFP3); - __ mov(r7, Operand(r1, ASR, kSmiTagSize)); - __ vmov(s15, r7); - __ vcvt_f64_s32(d7, s15); + __ SmiToDoubleVFPRegister(lhs, d7, r7, s15); // Load the double from rhs, tagged HeapNumber r0, to d6. - __ sub(r7, r0, Operand(kHeapObjectTag)); + __ sub(r7, rhs, Operand(kHeapObjectTag)); __ vldr(d6, r7, HeapNumber::kValueOffset); } else { __ push(lr); // Convert lhs to a double in r2, r3. - __ mov(r7, Operand(r1)); + __ mov(r7, Operand(lhs)); ConvertToDoubleStub stub1(r3, r2, r7, r6); __ Call(stub1.GetCode(), RelocInfo::CODE_TARGET); // Load rhs to a double in r0, r1. - __ Ldrd(r0, r1, FieldMemOperand(r0, HeapNumber::kValueOffset)); + __ Ldrd(r0, r1, FieldMemOperand(rhs, HeapNumber::kValueOffset)); __ pop(lr); } @@ -7078,34 +7085,35 @@ static void EmitSmiNonsmiComparison(MacroAssembler* masm, __ bind(&rhs_is_smi); // Rhs is a smi. Check whether the non-smi lhs is a heap number. - __ CompareObjectType(r1, r4, r4, HEAP_NUMBER_TYPE); + __ CompareObjectType(lhs, r4, r4, HEAP_NUMBER_TYPE); if (strict) { // If lhs is not a number and rhs is a smi then strict equality cannot // succeed. Return non-equal. - __ mov(r0, Operand(1), LeaveCC, ne); // Non-zero indicates not equal. - __ mov(pc, Operand(lr), LeaveCC, ne); // Return. + // If lhs is r0 then there is already a non zero value in it. + if (!lhs.is(r0)) { + __ mov(r0, Operand(NOT_EQUAL), LeaveCC, ne); + } + __ Ret(ne); } else { // Smi compared non-strictly with a non-smi non-heap-number. Call // the runtime. __ b(ne, slow); } - // Rhs (r0) is a smi, lhs (r1) is a heap number. + // Rhs is a smi, lhs is a heap number. if (CpuFeatures::IsSupported(VFP3)) { - // Convert rhs to a double in d6 . CpuFeatures::Scope scope(VFP3); // Load the double from lhs, tagged HeapNumber r1, to d7. - __ sub(r7, r1, Operand(kHeapObjectTag)); + __ sub(r7, lhs, Operand(kHeapObjectTag)); __ vldr(d7, r7, HeapNumber::kValueOffset); - __ mov(r7, Operand(r0, ASR, kSmiTagSize)); - __ vmov(s13, r7); - __ vcvt_f64_s32(d6, s13); + // Convert rhs to a double in d6 . + __ SmiToDoubleVFPRegister(rhs, d6, r7, s13); } else { __ push(lr); // Load lhs to a double in r2, r3. - __ Ldrd(r2, r3, FieldMemOperand(r1, HeapNumber::kValueOffset)); + __ Ldrd(r2, r3, FieldMemOperand(lhs, HeapNumber::kValueOffset)); // Convert rhs to a double in r0, r1. - __ mov(r7, Operand(r0)); + __ mov(r7, Operand(rhs)); ConvertToDoubleStub stub2(r1, r0, r7, r6); __ Call(stub2.GetCode(), RelocInfo::CODE_TARGET); __ pop(lr); @@ -7159,7 +7167,7 @@ void EmitNanCheck(MacroAssembler* masm, Label* lhs_not_nan, Condition cc) { } else { __ mov(r0, Operand(LESS)); } - __ mov(pc, Operand(lr)); // Return. + __ Ret(); __ bind(&neither_is_nan); } @@ -7180,11 +7188,11 @@ static void EmitTwoNonNanDoubleComparison(MacroAssembler* masm, Condition cc) { __ cmp(rhs_mantissa, Operand(lhs_mantissa)); __ orr(r0, rhs_mantissa, Operand(lhs_mantissa), LeaveCC, ne); // Return non-zero if the numbers are unequal. - __ mov(pc, Operand(lr), LeaveCC, ne); + __ Ret(ne); __ sub(r0, rhs_exponent, Operand(lhs_exponent), SetCC); // If exponents are equal then return 0. - __ mov(pc, Operand(lr), LeaveCC, eq); + __ Ret(eq); // Exponents are unequal. The only way we can return that the numbers // are equal is if one is -0 and the other is 0. We already dealt @@ -7194,11 +7202,11 @@ static void EmitTwoNonNanDoubleComparison(MacroAssembler* masm, Condition cc) { // equal. __ orr(r4, lhs_mantissa, Operand(lhs_exponent, LSL, kSmiTagSize), SetCC); __ mov(r0, Operand(r4), LeaveCC, ne); - __ mov(pc, Operand(lr), LeaveCC, ne); // Return conditionally. + __ Ret(ne); // Now they are equal if and only if the lhs exponent is zero in its // low 31 bits. __ mov(r0, Operand(rhs_exponent, LSL, kSmiTagSize)); - __ mov(pc, Operand(lr)); + __ Ret(); } else { // Call a native function to do a comparison between two non-NaNs. // Call C routine that may not cause GC or other trouble. @@ -7211,7 +7219,12 @@ static void EmitTwoNonNanDoubleComparison(MacroAssembler* masm, Condition cc) { // See comment at call site. -static void EmitStrictTwoHeapObjectCompare(MacroAssembler* masm) { +static void EmitStrictTwoHeapObjectCompare(MacroAssembler* masm, + Register lhs, + Register rhs) { + ASSERT((lhs.is(r0) && rhs.is(r1)) || + (lhs.is(r1) && rhs.is(r0))); + // If either operand is a JSObject or an oddball value, then they are // not equal since their pointers are different. // There is no test for undetectability in strict equality. @@ -7219,20 +7232,20 @@ static void EmitStrictTwoHeapObjectCompare(MacroAssembler* masm) { Label first_non_object; // Get the type of the first operand into r2 and compare it with // FIRST_JS_OBJECT_TYPE. - __ CompareObjectType(r0, r2, r2, FIRST_JS_OBJECT_TYPE); + __ CompareObjectType(rhs, r2, r2, FIRST_JS_OBJECT_TYPE); __ b(lt, &first_non_object); // Return non-zero (r0 is not zero) Label return_not_equal; __ bind(&return_not_equal); - __ mov(pc, Operand(lr)); // Return. + __ Ret(); __ bind(&first_non_object); // Check for oddballs: true, false, null, undefined. __ cmp(r2, Operand(ODDBALL_TYPE)); __ b(eq, &return_not_equal); - __ CompareObjectType(r1, r3, r3, FIRST_JS_OBJECT_TYPE); + __ CompareObjectType(lhs, r3, r3, FIRST_JS_OBJECT_TYPE); __ b(ge, &return_not_equal); // Check for oddballs: true, false, null, undefined. @@ -7251,12 +7264,17 @@ static void EmitStrictTwoHeapObjectCompare(MacroAssembler* masm) { // See comment at call site. static void EmitCheckForTwoHeapNumbers(MacroAssembler* masm, + Register lhs, + Register rhs, Label* both_loaded_as_doubles, Label* not_heap_numbers, Label* slow) { - __ CompareObjectType(r0, r3, r2, HEAP_NUMBER_TYPE); + ASSERT((lhs.is(r0) && rhs.is(r1)) || + (lhs.is(r1) && rhs.is(r0))); + + __ CompareObjectType(rhs, r3, r2, HEAP_NUMBER_TYPE); __ b(ne, not_heap_numbers); - __ ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset)); + __ ldr(r2, FieldMemOperand(lhs, HeapObject::kMapOffset)); __ cmp(r2, r3); __ b(ne, slow); // First was a heap number, second wasn't. Go slow case. @@ -7264,13 +7282,13 @@ static void EmitCheckForTwoHeapNumbers(MacroAssembler* masm, // for that. if (CpuFeatures::IsSupported(VFP3)) { CpuFeatures::Scope scope(VFP3); - __ sub(r7, r0, Operand(kHeapObjectTag)); + __ sub(r7, rhs, Operand(kHeapObjectTag)); __ vldr(d6, r7, HeapNumber::kValueOffset); - __ sub(r7, r1, Operand(kHeapObjectTag)); + __ sub(r7, lhs, Operand(kHeapObjectTag)); __ vldr(d7, r7, HeapNumber::kValueOffset); } else { - __ Ldrd(r2, r3, FieldMemOperand(r1, HeapNumber::kValueOffset)); - __ Ldrd(r0, r1, FieldMemOperand(r0, HeapNumber::kValueOffset)); + __ Ldrd(r2, r3, FieldMemOperand(lhs, HeapNumber::kValueOffset)); + __ Ldrd(r0, r1, FieldMemOperand(rhs, HeapNumber::kValueOffset)); } __ jmp(both_loaded_as_doubles); } @@ -7278,9 +7296,14 @@ static void EmitCheckForTwoHeapNumbers(MacroAssembler* masm, // Fast negative check for symbol-to-symbol equality. static void EmitCheckForSymbolsOrObjects(MacroAssembler* masm, + Register lhs, + Register rhs, Label* possible_strings, Label* not_both_strings) { - // r2 is object type of r0. + ASSERT((lhs.is(r0) && rhs.is(r1)) || + (lhs.is(r1) && rhs.is(r0))); + + // r2 is object type of rhs. // Ensure that no non-strings have the symbol bit set. Label object_test; ASSERT(kSymbolTag != 0); @@ -7288,31 +7311,31 @@ static void EmitCheckForSymbolsOrObjects(MacroAssembler* masm, __ b(ne, &object_test); __ tst(r2, Operand(kIsSymbolMask)); __ b(eq, possible_strings); - __ CompareObjectType(r1, r3, r3, FIRST_NONSTRING_TYPE); + __ CompareObjectType(lhs, r3, r3, FIRST_NONSTRING_TYPE); __ b(ge, not_both_strings); __ tst(r3, Operand(kIsSymbolMask)); __ b(eq, possible_strings); // Both are symbols. We already checked they weren't the same pointer // so they are not equal. - __ mov(r0, Operand(1)); // Non-zero indicates not equal. - __ mov(pc, Operand(lr)); // Return. + __ mov(r0, Operand(NOT_EQUAL)); + __ Ret(); __ bind(&object_test); __ cmp(r2, Operand(FIRST_JS_OBJECT_TYPE)); __ b(lt, not_both_strings); - __ CompareObjectType(r1, r2, r3, FIRST_JS_OBJECT_TYPE); + __ CompareObjectType(lhs, r2, r3, FIRST_JS_OBJECT_TYPE); __ b(lt, not_both_strings); - // If both objects are undetectable, they are equal. Otherwise, they + // If both objects are undetectable, they are equal. Otherwise, they // are not equal, since they are different objects and an object is not // equal to undefined. - __ ldr(r3, FieldMemOperand(r0, HeapObject::kMapOffset)); + __ ldr(r3, FieldMemOperand(rhs, HeapObject::kMapOffset)); __ ldrb(r2, FieldMemOperand(r2, Map::kBitFieldOffset)); __ ldrb(r3, FieldMemOperand(r3, Map::kBitFieldOffset)); __ and_(r0, r2, Operand(r3)); __ and_(r0, r0, Operand(1 << Map::kIsUndetectable)); __ eor(r0, r0, Operand(1 << Map::kIsUndetectable)); - __ mov(pc, Operand(lr)); // Return. + __ Ret(); } @@ -7434,10 +7457,13 @@ void RecordWriteStub::Generate(MacroAssembler* masm) { } -// On entry r0 (rhs) and r1 (lhs) are the values to be compared. +// On entry lhs_ and rhs_ are the values to be compared. // On exit r0 is 0, positive or negative to indicate the result of // the comparison. void CompareStub::Generate(MacroAssembler* masm) { + ASSERT((lhs_.is(r0) && rhs_.is(r1)) || + (lhs_.is(r1) && rhs_.is(r0))); + Label slow; // Call builtin. Label not_smis, both_loaded_as_doubles, lhs_not_nan; @@ -7452,7 +7478,7 @@ void CompareStub::Generate(MacroAssembler* masm) { // be strictly equal if the other is a HeapNumber. ASSERT_EQ(0, kSmiTag); ASSERT_EQ(0, Smi::FromInt(0)); - __ and_(r2, r0, Operand(r1)); + __ and_(r2, lhs_, Operand(rhs_)); __ tst(r2, Operand(kSmiTagMask)); __ b(ne, ¬_smis); // One operand is a smi. EmitSmiNonsmiComparison generates code that can: @@ -7464,7 +7490,7 @@ void CompareStub::Generate(MacroAssembler* masm) { // comparison. If VFP3 is supported the double values of the numbers have // been loaded into d7 and d6. Otherwise, the double values have been loaded // into r0, r1, r2, and r3. - EmitSmiNonsmiComparison(masm, &lhs_not_nan, &slow, strict_); + EmitSmiNonsmiComparison(masm, lhs_, rhs_, &lhs_not_nan, &slow, strict_); __ bind(&both_loaded_as_doubles); // The arguments have been converted to doubles and stored in d6 and d7, if @@ -7481,7 +7507,7 @@ void CompareStub::Generate(MacroAssembler* masm) { __ mov(r0, Operand(EQUAL), LeaveCC, eq); __ mov(r0, Operand(LESS), LeaveCC, lt); __ mov(r0, Operand(GREATER), LeaveCC, gt); - __ mov(pc, Operand(lr)); + __ Ret(); __ bind(&nan); // If one of the sides was a NaN then the v flag is set. Load r0 with @@ -7492,7 +7518,7 @@ void CompareStub::Generate(MacroAssembler* masm) { } else { __ mov(r0, Operand(LESS)); } - __ mov(pc, Operand(lr)); + __ Ret(); } else { // Checks for NaN in the doubles we have loaded. Can return the answer or // fall through if neither is a NaN. Also binds lhs_not_nan. @@ -7504,11 +7530,11 @@ void CompareStub::Generate(MacroAssembler* masm) { __ bind(¬_smis); // At this point we know we are dealing with two different objects, - // and neither of them is a Smi. The objects are in r0 and r1. + // and neither of them is a Smi. The objects are in rhs_ and lhs_. if (strict_) { // This returns non-equal for some object types, or falls through if it // was not lucky. - EmitStrictTwoHeapObjectCompare(masm); + EmitStrictTwoHeapObjectCompare(masm, lhs_, rhs_); } Label check_for_symbols; @@ -7516,8 +7542,10 @@ void CompareStub::Generate(MacroAssembler* masm) { // Check for heap-number-heap-number comparison. Can jump to slow case, // or load both doubles into r0, r1, r2, r3 and jump to the code that handles // that case. If the inputs are not doubles then jumps to check_for_symbols. - // In this case r2 will contain the type of r0. Never falls through. + // In this case r2 will contain the type of rhs_. Never falls through. EmitCheckForTwoHeapNumbers(masm, + lhs_, + rhs_, &both_loaded_as_doubles, &check_for_symbols, &flat_string_check); @@ -7528,20 +7556,20 @@ void CompareStub::Generate(MacroAssembler* masm) { if (cc_ == eq && !strict_) { // Returns an answer for two symbols or two detectable objects. // Otherwise jumps to string case or not both strings case. - // Assumes that r2 is the type of r0 on entry. - EmitCheckForSymbolsOrObjects(masm, &flat_string_check, &slow); + // Assumes that r2 is the type of rhs_ on entry. + EmitCheckForSymbolsOrObjects(masm, lhs_, rhs_, &flat_string_check, &slow); } // Check for both being sequential ASCII strings, and inline if that is the // case. __ bind(&flat_string_check); - __ JumpIfNonSmisNotBothSequentialAsciiStrings(r0, r1, r2, r3, &slow); + __ JumpIfNonSmisNotBothSequentialAsciiStrings(lhs_, rhs_, r2, r3, &slow); __ IncrementCounter(&Counters::string_compare_native, 1, r2, r3); StringCompareStub::GenerateCompareFlatAsciiStrings(masm, - r1, - r0, + lhs_, + rhs_, r2, r3, r4, @@ -7550,7 +7578,7 @@ void CompareStub::Generate(MacroAssembler* masm) { __ bind(&slow); - __ Push(r1, r0); + __ Push(lhs_, rhs_); // Figure out which native to call and setup the arguments. Builtins::JavaScript native; if (cc_ == eq) { @@ -10051,6 +10079,9 @@ void CallFunctionStub::Generate(MacroAssembler* masm) { // Unfortunately you have to run without snapshots to see most of these // names in the profile since most compare stubs end up in the snapshot. const char* CompareStub::GetName() { + ASSERT((lhs_.is(r0) && rhs_.is(r1)) || + (lhs_.is(r1) && rhs_.is(r0))); + if (name_ != NULL) return name_; const int kMaxNameLength = 100; name_ = Bootstrapper::AllocateAutoDeletedArray(kMaxNameLength); @@ -10067,6 +10098,9 @@ const char* CompareStub::GetName() { default: cc_name = "UnknownCondition"; break; } + const char* lhs_name = lhs_.is(r0) ? "_r0" : "_r1"; + const char* rhs_name = rhs_.is(r0) ? "_r0" : "_r1"; + const char* strict_name = ""; if (strict_ && (cc_ == eq || cc_ == ne)) { strict_name = "_STRICT"; @@ -10083,8 +10117,10 @@ const char* CompareStub::GetName() { } OS::SNPrintF(Vector(name_, kMaxNameLength), - "CompareStub_%s%s%s%s", + "CompareStub_%s%s%s%s%s%s", cc_name, + lhs_name, + rhs_name, strict_name, never_nan_nan_name, include_number_compare_name); @@ -10096,8 +10132,11 @@ int CompareStub::MinorKey() { // Encode the three parameters in a unique 16 bit value. To avoid duplicate // stubs the never NaN NaN condition is only taken into account if the // condition is equals. - ASSERT((static_cast(cc_) >> 28) < (1 << 13)); + ASSERT((static_cast(cc_) >> 28) < (1 << 12)); + ASSERT((lhs_.is(r0) && rhs_.is(r1)) || + (lhs_.is(r1) && rhs_.is(r0))); return ConditionField::encode(static_cast(cc_) >> 28) + | RegisterField::encode(lhs_.is(r0)) | StrictField::encode(strict_) | NeverNanNanField::encode(cc_ == eq ? never_nan_nan_ : false) | IncludeNumberCompareField::encode(include_number_compare_); diff --git a/deps/v8/src/arm/full-codegen-arm.cc b/deps/v8/src/arm/full-codegen-arm.cc index 3fb946aa65..ec8f0f4d87 100644 --- a/deps/v8/src/arm/full-codegen-arm.cc +++ b/deps/v8/src/arm/full-codegen-arm.cc @@ -822,8 +822,7 @@ void FullCodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) { // the smi vs. smi case to be handled before it is called. Label slow_case; __ ldr(r1, MemOperand(sp, 0)); // Switch value. - __ mov(r2, r1); - __ orr(r2, r2, r0); + __ orr(r2, r1, r0); __ tst(r2, Operand(kSmiTagMask)); __ b(ne, &slow_case); __ cmp(r1, r0); @@ -832,9 +831,9 @@ void FullCodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) { __ b(clause->body_target()->entry_label()); __ bind(&slow_case); - CompareStub stub(eq, true); + CompareStub stub(eq, true, kBothCouldBeNaN, true, r1, r0); __ CallStub(&stub); - __ tst(r0, r0); + __ cmp(r0, Operand(0)); __ b(ne, &next_test); __ Drop(1); // Switch value is no longer needed. __ b(clause->body_target()->entry_label()); @@ -3088,7 +3087,7 @@ void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) { __ jmp(if_false); __ bind(&slow_case); - CompareStub stub(cc, strict); + CompareStub stub(cc, strict, kBothCouldBeNaN, true, r1, r0); __ CallStub(&stub); __ cmp(r0, Operand(0)); __ b(cc, if_true); diff --git a/deps/v8/src/arm/stub-cache-arm.cc b/deps/v8/src/arm/stub-cache-arm.cc index a0b6bdb413..ff3007c444 100644 --- a/deps/v8/src/arm/stub-cache-arm.cc +++ b/deps/v8/src/arm/stub-cache-arm.cc @@ -176,6 +176,13 @@ static void GenerateDictionaryNegativeLookup(MacroAssembler* masm, __ cmp(entity_name, Operand(Handle(name))); __ b(eq, miss_label); + // Check if the entry name is not a symbol. + __ ldr(entity_name, FieldMemOperand(entity_name, HeapObject::kMapOffset)); + __ ldrb(entity_name, + FieldMemOperand(entity_name, Map::kInstanceTypeOffset)); + __ tst(entity_name, Operand(kIsSymbolMask)); + __ b(eq, miss_label); + // Restore the properties. __ ldr(properties, FieldMemOperand(receiver, JSObject::kPropertiesOffset)); diff --git a/deps/v8/src/codegen.h b/deps/v8/src/codegen.h index 783bef00d1..74855fd5a3 100644 --- a/deps/v8/src/codegen.h +++ b/deps/v8/src/codegen.h @@ -461,11 +461,15 @@ class CompareStub: public CodeStub { CompareStub(Condition cc, bool strict, NaNInformation nan_info = kBothCouldBeNaN, - bool include_number_compare = true) : + bool include_number_compare = true, + Register lhs = no_reg, + Register rhs = no_reg) : cc_(cc), strict_(strict), never_nan_nan_(nan_info == kCantBothBeNaN), include_number_compare_(include_number_compare), + lhs_(lhs), + rhs_(rhs), name_(NULL) { } void Generate(MacroAssembler* masm); @@ -483,12 +487,19 @@ class CompareStub: public CodeStub { // comparison code is used when the number comparison has been inlined, and // the stub will be called if one of the operands is not a number. bool include_number_compare_; - - // Encoding of the minor key CCCCCCCCCCCCCCNS. + // Register holding the left hand side of the comparison if the stub gives + // a choice, no_reg otherwise. + Register lhs_; + // Register holding the right hand side of the comparison if the stub gives + // a choice, no_reg otherwise. + Register rhs_; + + // Encoding of the minor key CCCCCCCCCCCCRCNS. class StrictField: public BitField {}; class NeverNanNanField: public BitField {}; class IncludeNumberCompareField: public BitField {}; - class ConditionField: public BitField {}; + class RegisterField: public BitField {}; + class ConditionField: public BitField {}; Major MajorKey() { return Compare; } @@ -507,11 +518,17 @@ class CompareStub: public CodeStub { #ifdef DEBUG void Print() { PrintF("CompareStub (cc %d), (strict %s), " - "(never_nan_nan %s), (number_compare %s)\n", + "(never_nan_nan %s), (number_compare %s) ", static_cast(cc_), strict_ ? "true" : "false", never_nan_nan_ ? "true" : "false", include_number_compare_ ? "included" : "not included"); + + if (!lhs_.is(no_reg) && !rhs_.is(no_reg)) { + PrintF("(lhs r%d), (rhs r%d)\n", lhs_.code(), rhs_.code()); + } else { + PrintF("\n"); + } } #endif }; diff --git a/deps/v8/src/compiler.cc b/deps/v8/src/compiler.cc index ec6b5ffb4a..0d1fe9952b 100755 --- a/deps/v8/src/compiler.cc +++ b/deps/v8/src/compiler.cc @@ -160,7 +160,7 @@ Handle MakeCodeForLiveEdit(CompilationInfo* info) { Handle code = MakeCode(context, info); if (!info->shared_info().is_null()) { info->shared_info()->set_scope_info( - *ScopeInfo<>::CreateHeapObject(info->scope())); + *SerializedScopeInfo::Create(info->scope())); } return code; } @@ -262,7 +262,7 @@ static Handle MakeFunctionInfo(bool is_global, lit->name(), lit->materialized_literal_count(), code, - ScopeInfo<>::CreateHeapObject(info.scope())); + SerializedScopeInfo::Create(info.scope())); ASSERT_EQ(RelocInfo::kNoPosition, lit->function_token_position()); Compiler::SetFunctionInfo(result, lit, true, script); @@ -450,7 +450,7 @@ bool Compiler::CompileLazy(CompilationInfo* info) { // Update the shared function info with the compiled code and the scope info. shared->set_code(*code); - shared->set_scope_info(*ScopeInfo<>::CreateHeapObject(info->scope())); + shared->set_scope_info(*SerializedScopeInfo::Create(info->scope())); // Set the expected number of properties for instances. SetExpectedNofPropertiesFromEstimate(shared, lit->expected_property_count()); @@ -485,7 +485,7 @@ Handle Compiler::BuildFunctionInfo(FunctionLiteral* literal, bool allow_lazy = literal->AllowsLazyCompilation() && !LiveEditFunctionTracker::IsActive(); - Handle scope_info(ScopeInfo<>::EmptyHeapObject()); + Handle scope_info(SerializedScopeInfo::Empty()); // Generate code Handle code; @@ -568,7 +568,7 @@ Handle Compiler::BuildFunctionInfo(FunctionLiteral* literal, literal->start_position(), script, code); - scope_info = ScopeInfo<>::CreateHeapObject(info.scope()); + scope_info = SerializedScopeInfo::Create(info.scope()); } // Create a shared function info object. diff --git a/deps/v8/src/contexts.cc b/deps/v8/src/contexts.cc index 1eab24c28e..723354fc84 100644 --- a/deps/v8/src/contexts.cc +++ b/deps/v8/src/contexts.cc @@ -120,9 +120,10 @@ Handle Context::Lookup(Handle name, ContextLookupFlags flags, // we have context-local slots // check non-parameter locals in context - Handle scope_info(context->closure()->shared()->scope_info()); + Handle scope_info( + context->closure()->shared()->scope_info()); Variable::Mode mode; - int index = ScopeInfo<>::ContextSlotIndex(*scope_info, *name, &mode); + int index = scope_info->ContextSlotIndex(*name, &mode); ASSERT(index < 0 || index >= MIN_CONTEXT_SLOTS); if (index >= 0) { // slot found @@ -150,13 +151,11 @@ Handle Context::Lookup(Handle name, ContextLookupFlags flags, } // check parameter locals in context - int param_index = ScopeInfo<>::ParameterIndex(*scope_info, *name); + int param_index = scope_info->ParameterIndex(*name); if (param_index >= 0) { // slot found. int index = - ScopeInfo<>::ContextSlotIndex(*scope_info, - Heap::arguments_shadow_symbol(), - NULL); + scope_info->ContextSlotIndex(Heap::arguments_shadow_symbol(), NULL); ASSERT(index >= 0); // arguments must exist and be in the heap context Handle arguments(JSObject::cast(context->get(index))); ASSERT(arguments->HasLocalProperty(Heap::length_symbol())); @@ -170,7 +169,7 @@ Handle Context::Lookup(Handle name, ContextLookupFlags flags, // check intermediate context (holding only the function name variable) if (follow_context_chain) { - int index = ScopeInfo<>::FunctionContextSlotIndex(*scope_info, *name); + int index = scope_info->FunctionContextSlotIndex(*name); if (index >= 0) { // slot found if (FLAG_trace_contexts) { @@ -216,18 +215,19 @@ bool Context::GlobalIfNotShadowedByEval(Handle name) { ASSERT(context->is_function_context()); // Check non-parameter locals. - Handle scope_info(context->closure()->shared()->scope_info()); + Handle scope_info( + context->closure()->shared()->scope_info()); Variable::Mode mode; - int index = ScopeInfo<>::ContextSlotIndex(*scope_info, *name, &mode); + int index = scope_info->ContextSlotIndex(*name, &mode); ASSERT(index < 0 || index >= MIN_CONTEXT_SLOTS); if (index >= 0) return false; // Check parameter locals. - int param_index = ScopeInfo<>::ParameterIndex(*scope_info, *name); + int param_index = scope_info->ParameterIndex(*name); if (param_index >= 0) return false; // Check context only holding the function name variable. - index = ScopeInfo<>::FunctionContextSlotIndex(*scope_info, *name); + index = scope_info->FunctionContextSlotIndex(*name); if (index >= 0) return false; context = Context::cast(context->closure()->context()); } diff --git a/deps/v8/src/debug.cc b/deps/v8/src/debug.cc index 4922a62860..728813514c 100644 --- a/deps/v8/src/debug.cc +++ b/deps/v8/src/debug.cc @@ -1882,6 +1882,7 @@ int Debugger::host_dispatch_micros_ = 100 * 1000; DebuggerAgent* Debugger::agent_ = NULL; LockingCommandMessageQueue Debugger::command_queue_(kQueueInitialSize); Semaphore* Debugger::command_received_ = OS::CreateSemaphore(0); +LockingCommandMessageQueue Debugger::event_command_queue_(kQueueInitialSize); Handle Debugger::MakeJSObject(Vector constructor_name, @@ -2207,39 +2208,75 @@ void Debugger::ProcessDebugEvent(v8::DebugEvent event, event_data, auto_continue); } - // Notify registered debug event listener. This can be either a C or a - // JavaScript function. - if (!event_listener_.is_null()) { - if (event_listener_->IsProxy()) { - // C debug event listener. - Handle callback_obj(Handle::cast(event_listener_)); - v8::Debug::EventCallback2 callback = - FUNCTION_CAST(callback_obj->proxy()); - EventDetailsImpl event_details( - event, - Handle::cast(exec_state), - event_data, - event_listener_data_); - callback(event_details); - } else { - // JavaScript debug event listener. - ASSERT(event_listener_->IsJSFunction()); - Handle fun(Handle::cast(event_listener_)); - - // Invoke the JavaScript debug event listener. - const int argc = 4; - Object** argv[argc] = { Handle(Smi::FromInt(event)).location(), - exec_state.location(), - Handle::cast(event_data).location(), - event_listener_data_.location() }; - Handle result = Execution::TryCall(fun, Top::global(), - argc, argv, &caught_exception); - // Silently ignore exceptions from debug event listeners. + // Notify registered debug event listener. This can be either a C or + // a JavaScript function. Don't call event listener for v8::Break + // here, if it's only a debug command -- they will be processed later. + if ((event != v8::Break || !auto_continue) && !event_listener_.is_null()) { + CallEventCallback(event, exec_state, event_data, NULL); + } + // Process pending debug commands. + if (event == v8::Break) { + while (!event_command_queue_.IsEmpty()) { + CommandMessage command = event_command_queue_.Get(); + if (!event_listener_.is_null()) { + CallEventCallback(v8::BreakForCommand, + exec_state, + event_data, + command.client_data()); + } + command.Dispose(); } } } +void Debugger::CallEventCallback(v8::DebugEvent event, + Handle exec_state, + Handle event_data, + v8::Debug::ClientData* client_data) { + if (event_listener_->IsProxy()) { + CallCEventCallback(event, exec_state, event_data, client_data); + } else { + CallJSEventCallback(event, exec_state, event_data); + } +} + + +void Debugger::CallCEventCallback(v8::DebugEvent event, + Handle exec_state, + Handle event_data, + v8::Debug::ClientData* client_data) { + Handle callback_obj(Handle::cast(event_listener_)); + v8::Debug::EventCallback2 callback = + FUNCTION_CAST(callback_obj->proxy()); + EventDetailsImpl event_details( + event, + Handle::cast(exec_state), + Handle::cast(event_data), + event_listener_data_, + client_data); + callback(event_details); +} + + +void Debugger::CallJSEventCallback(v8::DebugEvent event, + Handle exec_state, + Handle event_data) { + ASSERT(event_listener_->IsJSFunction()); + Handle fun(Handle::cast(event_listener_)); + + // Invoke the JavaScript debug event listener. + const int argc = 4; + Object** argv[argc] = { Handle(Smi::FromInt(event)).location(), + exec_state.location(), + Handle::cast(event_data).location(), + event_listener_data_.location() }; + bool caught_exception = false; + Execution::TryCall(fun, Top::global(), argc, argv, &caught_exception); + // Silently ignore exceptions from debug event listeners. +} + + Handle Debugger::GetDebugContext() { never_unload_debugger_ = true; EnterDebugger debugger; @@ -2273,6 +2310,7 @@ void Debugger::NotifyMessageHandler(v8::DebugEvent event, bool sendEventMessage = false; switch (event) { case v8::Break: + case v8::BreakForCommand: sendEventMessage = !auto_continue; break; case v8::Exception: @@ -2560,6 +2598,17 @@ bool Debugger::HasCommands() { } +void Debugger::EnqueueDebugCommand(v8::Debug::ClientData* client_data) { + CommandMessage message = CommandMessage::New(Vector(), client_data); + event_command_queue_.Put(message); + + // Set the debug command break flag to have the command processed. + if (!Debug::InDebugger()) { + StackGuard::DebugCommand(); + } +} + + bool Debugger::IsDebuggerActive() { ScopedLock with(debugger_access_); @@ -2761,11 +2810,13 @@ v8::Debug::ClientData* MessageImpl::GetClientData() const { EventDetailsImpl::EventDetailsImpl(DebugEvent event, Handle exec_state, Handle event_data, - Handle callback_data) + Handle callback_data, + v8::Debug::ClientData* client_data) : event_(event), exec_state_(exec_state), event_data_(event_data), - callback_data_(callback_data) {} + callback_data_(callback_data), + client_data_(client_data) {} DebugEvent EventDetailsImpl::GetEvent() const { @@ -2793,6 +2844,11 @@ v8::Handle EventDetailsImpl::GetCallbackData() const { } +v8::Debug::ClientData* EventDetailsImpl::GetClientData() const { + return client_data_; +} + + CommandMessage::CommandMessage() : text_(Vector::empty()), client_data_(NULL) { } diff --git a/deps/v8/src/debug.h b/deps/v8/src/debug.h index fb9269272f..7bb4a428f2 100644 --- a/deps/v8/src/debug.h +++ b/deps/v8/src/debug.h @@ -566,18 +566,21 @@ class EventDetailsImpl : public v8::Debug::EventDetails { EventDetailsImpl(DebugEvent event, Handle exec_state, Handle event_data, - Handle callback_data); + Handle callback_data, + v8::Debug::ClientData* client_data); virtual DebugEvent GetEvent() const; virtual v8::Handle GetExecutionState() const; virtual v8::Handle GetEventData() const; virtual v8::Handle GetEventContext() const; virtual v8::Handle GetCallbackData() const; + virtual v8::Debug::ClientData* GetClientData() const; private: DebugEvent event_; // Debug event causing the break. - Handle exec_state_; // Current execution state. - Handle event_data_; // Data associated with the event. - Handle callback_data_; // User data passed with the callback when - // it was registered. + Handle exec_state_; // Current execution state. + Handle event_data_; // Data associated with the event. + Handle callback_data_; // User data passed with the callback + // when it was registered. + v8::Debug::ClientData* client_data_; // Data passed to DebugBreakForCommand. }; @@ -706,6 +709,9 @@ class Debugger { // Check whether there are commands in the command queue. static bool HasCommands(); + // Enqueue a debugger command to the command queue for event listeners. + static void EnqueueDebugCommand(v8::Debug::ClientData* client_data = NULL); + static Handle Call(Handle fun, Handle data, bool* pending_exception); @@ -753,6 +759,17 @@ class Debugger { static bool IsDebuggerActive(); private: + static void CallEventCallback(v8::DebugEvent event, + Handle exec_state, + Handle event_data, + v8::Debug::ClientData* client_data); + static void CallCEventCallback(v8::DebugEvent event, + Handle exec_state, + Handle event_data, + v8::Debug::ClientData* client_data); + static void CallJSEventCallback(v8::DebugEvent event, + Handle exec_state, + Handle event_data); static void ListenersChanged(); static Mutex* debugger_access_; // Mutex guarding debugger variables. @@ -775,6 +792,8 @@ class Debugger { static LockingCommandMessageQueue command_queue_; static Semaphore* command_received_; // Signaled for each command received. + static LockingCommandMessageQueue event_command_queue_; + friend class EnterDebugger; }; diff --git a/deps/v8/src/factory.cc b/deps/v8/src/factory.cc index 18be639f39..d65338385e 100644 --- a/deps/v8/src/factory.cc +++ b/deps/v8/src/factory.cc @@ -684,7 +684,7 @@ Handle Factory::NewSharedFunctionInfo( Handle name, int number_of_literals, Handle code, - Handle scope_info) { + Handle scope_info) { Handle shared = NewSharedFunctionInfo(name); shared->set_code(*code); shared->set_scope_info(*scope_info); diff --git a/deps/v8/src/factory.h b/deps/v8/src/factory.h index 0576d74a6e..22511121cb 100644 --- a/deps/v8/src/factory.h +++ b/deps/v8/src/factory.h @@ -351,7 +351,7 @@ class Factory : public AllStatic { Handle name, int number_of_literals, Handle code, - Handle scope_info); + Handle scope_info); static Handle NewSharedFunctionInfo(Handle name); static Handle DictionaryAtNumberPut( diff --git a/deps/v8/src/frames.cc b/deps/v8/src/frames.cc index 8b601b67b7..bdd5100ed8 100644 --- a/deps/v8/src/frames.cc +++ b/deps/v8/src/frames.cc @@ -532,11 +532,11 @@ void JavaScriptFrame::Print(StringStream* accumulator, if (IsConstructor()) accumulator->Add("new "); accumulator->PrintFunction(function, receiver, &code); - Handle scope_info(ScopeInfo<>::EmptyHeapObject()); + Handle scope_info(SerializedScopeInfo::Empty()); if (function->IsJSFunction()) { Handle shared(JSFunction::cast(function)->shared()); - scope_info = Handle(shared->scope_info()); + scope_info = Handle(shared->scope_info()); Object* script_obj = shared->script(); if (script_obj->IsScript()) { Handle