diff options
80 files changed, 1898 insertions, 861 deletions
diff --git a/deps/v8/.gitignore b/deps/v8/.gitignore index 974628d884..d85ef64d41 100644 --- a/deps/v8/.gitignore +++ b/deps/v8/.gitignore @@ -20,6 +20,8 @@ d8_g shell shell_g /obj/ +/tools/oom_dump/oom_dump +/tools/oom_dump/oom_dump.o /tools/visual_studio/Debug /tools/visual_studio/Release /xcodebuild/ diff --git a/deps/v8/AUTHORS b/deps/v8/AUTHORS index eedf840c55..da864885ae 100644 --- a/deps/v8/AUTHORS +++ b/deps/v8/AUTHORS @@ -32,6 +32,7 @@ Rafal Krypa <rafal@krypa.net> Rene Rebe <rene@exactcode.de> Rodolph Perfetta <rodolph.perfetta@arm.com> Ryan Dahl <coldredlemur@gmail.com> +Sanjoy Das <sanjoy@playingwithpointers.com> Subrato K De <subratokde@codeaurora.org> Vlad Burlik <vladbph@gmail.com> Mike Gilbert <floppymaster@gmail.com> diff --git a/deps/v8/ChangeLog b/deps/v8/ChangeLog index 0e1ccda1eb..f143a40cd2 100644 --- a/deps/v8/ChangeLog +++ b/deps/v8/ChangeLog @@ -1,4 +1,19 @@ -2011-01=31: Version 3.1.0 +2011-02-02: Version 3.1.1 + + Perform security checks before fetching the value in + Object.getOwnPropertyDescriptor. + + Fixed a bug in Array.prototype.splice triggered by passing no + arguments. + + Fixed bugs in -0 in arithmetic and in Math.pow. + + Fixed bugs in the register allocator and in switching from optimized + to unoptimized code. + + +2011-01-31: Version 3.1.0 + Performance improvements on all platforms. diff --git a/deps/v8/include/v8.h b/deps/v8/include/v8.h index 44a7dcc890..44ff2c00e0 100644 --- a/deps/v8/include/v8.h +++ b/deps/v8/include/v8.h @@ -3448,7 +3448,7 @@ class Internals { static const int kFullStringRepresentationMask = 0x07; static const int kExternalTwoByteRepresentationTag = 0x02; - static const int kJSObjectType = 0x9f; + static const int kJSObjectType = 0xa0; static const int kFirstNonstringType = 0x80; static const int kProxyType = 0x85; diff --git a/deps/v8/src/accessors.cc b/deps/v8/src/accessors.cc index c7d9cfe94c..2b205d5d74 100644 --- a/deps/v8/src/accessors.cc +++ b/deps/v8/src/accessors.cc @@ -675,46 +675,36 @@ static void ComputeSlotMappingForArguments(JavaScriptFrame* frame, int inlined_frame_index, Vector<SlotRef>* args_slots) { AssertNoAllocation no_gc; - int deopt_index = AstNode::kNoNumber; - DeoptimizationInputData* data = static_cast<OptimizedFrame*>(frame)->GetDeoptimizationData(&deopt_index); - TranslationIterator it(data->TranslationByteArray(), data->TranslationIndex(deopt_index)->value()); - Translation::Opcode opcode = static_cast<Translation::Opcode>(it.Next()); ASSERT(opcode == Translation::BEGIN); int frame_count = it.Next(); - USE(frame_count); ASSERT(frame_count > inlined_frame_index); - int frames_to_skip = inlined_frame_index; while (true) { opcode = static_cast<Translation::Opcode>(it.Next()); - // Skip over operands to advance to the next opcode. it.Skip(Translation::NumberOfOperandsFor(opcode)); - if (opcode == Translation::FRAME) { if (frames_to_skip == 0) { - // We reached frame corresponding to inlined function in question. - // Process translation commands for arguments. - - // Skip translation command for receiver. + // We reached the frame corresponding to the inlined function + // in question. Process the translation commands for the + // arguments. + // + // Skip the translation command for the receiver. it.Skip(Translation::NumberOfOperandsFor( static_cast<Translation::Opcode>(it.Next()))); - // Compute slots for arguments. for (int i = 0; i < args_slots->length(); ++i) { (*args_slots)[i] = ComputeSlotForNextArgument(&it, data, frame); } - return; } - frames_to_skip--; } } @@ -727,16 +717,11 @@ static MaybeObject* ConstructArgumentsObjectForInlinedFunction( JavaScriptFrame* frame, Handle<JSFunction> inlined_function, int inlined_frame_index) { - int args_count = inlined_function->shared()->formal_parameter_count(); - ScopedVector<SlotRef> args_slots(args_count); - ComputeSlotMappingForArguments(frame, inlined_frame_index, &args_slots); - Handle<JSObject> arguments = Factory::NewArgumentsObject(inlined_function, args_count); - Handle<FixedArray> array = Factory::NewFixedArray(args_count); for (int i = 0; i < args_count; ++i) { Handle<Object> value = args_slots[i].GetValue(); @@ -766,39 +751,43 @@ MaybeObject* Accessors::FunctionGetArguments(Object* object, void*) { if (functions[i] != *function) continue; if (i > 0) { - // Function in question was inlined. + // The function in question was inlined. Inlined functions have the + // correct number of arguments and no allocated arguments object, so + // we can construct a fresh one by interpreting the function's + // deoptimization input data. return ConstructArgumentsObjectForInlinedFunction(frame, function, i); - } else { + } + + if (!frame->is_optimized()) { // If there is an arguments variable in the stack, we return that. - int index = function->shared()->scope_info()-> - StackSlotIndex(Heap::arguments_symbol()); + Handle<SerializedScopeInfo> info(function->shared()->scope_info()); + int index = info->StackSlotIndex(Heap::arguments_symbol()); if (index >= 0) { - Handle<Object> arguments = - Handle<Object>(frame->GetExpression(index)); + Handle<Object> arguments(frame->GetExpression(index)); if (!arguments->IsArgumentsMarker()) return *arguments; } - - // If there isn't an arguments variable in the stack, we need to - // find the frame that holds the actual arguments passed to the - // function on the stack. - it.AdvanceToArgumentsFrame(); - frame = it.frame(); - - // Get the number of arguments and construct an arguments object - // mirror for the right frame. - const int length = frame->GetProvidedParametersCount(); - Handle<JSObject> arguments = Factory::NewArgumentsObject(function, - length); - Handle<FixedArray> array = Factory::NewFixedArray(length); - - // Copy the parameters to the arguments object. - ASSERT(array->length() == length); - for (int i = 0; i < length; i++) array->set(i, frame->GetParameter(i)); - arguments->set_elements(*array); - - // Return the freshly allocated arguments object. - return *arguments; } + + // If there is no arguments variable in the stack or we have an + // optimized frame, we find the frame that holds the actual arguments + // passed to the function. + it.AdvanceToArgumentsFrame(); + frame = it.frame(); + + // Get the number of arguments and construct an arguments object + // mirror for the right frame. + const int length = frame->GetProvidedParametersCount(); + Handle<JSObject> arguments = Factory::NewArgumentsObject(function, + length); + Handle<FixedArray> array = Factory::NewFixedArray(length); + + // Copy the parameters to the arguments object. + ASSERT(array->length() == length); + for (int i = 0; i < length; i++) array->set(i, frame->GetParameter(i)); + arguments->set_elements(*array); + + // Return the freshly allocated arguments object. + return *arguments; } functions.Rewind(0); } diff --git a/deps/v8/src/api.cc b/deps/v8/src/api.cc index 93037822cf..c16244038b 100644 --- a/deps/v8/src/api.cc +++ b/deps/v8/src/api.cc @@ -1478,11 +1478,11 @@ v8::Handle<Value> Message::GetScriptResourceName() const { } ENTER_V8; HandleScope scope; - i::Handle<i::JSObject> obj = - i::Handle<i::JSObject>::cast(Utils::OpenHandle(this)); + i::Handle<i::JSMessageObject> message = + i::Handle<i::JSMessageObject>::cast(Utils::OpenHandle(this)); // Return this.script.name. i::Handle<i::JSValue> script = - i::Handle<i::JSValue>::cast(GetProperty(obj, "script")); + i::Handle<i::JSValue>::cast(i::Handle<i::Object>(message->script())); i::Handle<i::Object> resource_name(i::Script::cast(script->value())->name()); return scope.Close(Utils::ToLocal(resource_name)); } @@ -1494,11 +1494,11 @@ v8::Handle<Value> Message::GetScriptData() const { } ENTER_V8; HandleScope scope; - i::Handle<i::JSObject> obj = - i::Handle<i::JSObject>::cast(Utils::OpenHandle(this)); + i::Handle<i::JSMessageObject> message = + i::Handle<i::JSMessageObject>::cast(Utils::OpenHandle(this)); // Return this.script.data. i::Handle<i::JSValue> script = - i::Handle<i::JSValue>::cast(GetProperty(obj, "script")); + i::Handle<i::JSValue>::cast(i::Handle<i::Object>(message->script())); i::Handle<i::Object> data(i::Script::cast(script->value())->data()); return scope.Close(Utils::ToLocal(data)); } @@ -1510,9 +1510,9 @@ v8::Handle<v8::StackTrace> Message::GetStackTrace() const { } ENTER_V8; HandleScope scope; - i::Handle<i::JSObject> obj = - i::Handle<i::JSObject>::cast(Utils::OpenHandle(this)); - i::Handle<i::Object> stackFramesObj = GetProperty(obj, "stackFrames"); + i::Handle<i::JSMessageObject> message = + i::Handle<i::JSMessageObject>::cast(Utils::OpenHandle(this)); + i::Handle<i::Object> stackFramesObj(message->stack_frames()); if (!stackFramesObj->IsJSArray()) return v8::Handle<v8::StackTrace>(); i::Handle<i::JSArray> stackTrace = i::Handle<i::JSArray>::cast(stackFramesObj); @@ -1552,6 +1552,7 @@ int Message::GetLineNumber() const { ON_BAILOUT("v8::Message::GetLineNumber()", return kNoLineNumberInfo); ENTER_V8; HandleScope scope; + EXCEPTION_PREAMBLE(); i::Handle<i::Object> result = CallV8HeapFunction("GetLineNumber", Utils::OpenHandle(this), @@ -1565,9 +1566,9 @@ int Message::GetStartPosition() const { if (IsDeadCheck("v8::Message::GetStartPosition()")) return 0; ENTER_V8; HandleScope scope; - - i::Handle<i::JSObject> data_obj = Utils::OpenHandle(this); - return static_cast<int>(GetProperty(data_obj, "startPos")->Number()); + i::Handle<i::JSMessageObject> message = + i::Handle<i::JSMessageObject>::cast(Utils::OpenHandle(this)); + return message->start_position(); } @@ -1575,8 +1576,9 @@ int Message::GetEndPosition() const { if (IsDeadCheck("v8::Message::GetEndPosition()")) return 0; ENTER_V8; HandleScope scope; - i::Handle<i::JSObject> data_obj = Utils::OpenHandle(this); - return static_cast<int>(GetProperty(data_obj, "endPos")->Number()); + i::Handle<i::JSMessageObject> message = + i::Handle<i::JSMessageObject>::cast(Utils::OpenHandle(this)); + return message->end_position(); } @@ -1606,8 +1608,10 @@ int Message::GetEndColumn() const { data_obj, &has_pending_exception); EXCEPTION_BAILOUT_CHECK(0); - int start = static_cast<int>(GetProperty(data_obj, "startPos")->Number()); - int end = static_cast<int>(GetProperty(data_obj, "endPos")->Number()); + i::Handle<i::JSMessageObject> message = + i::Handle<i::JSMessageObject>::cast(data_obj); + int start = message->start_position(); + int end = message->end_position(); return static_cast<int>(start_col_obj->Number()) + (end - start); } diff --git a/deps/v8/src/arm/code-stubs-arm.cc b/deps/v8/src/arm/code-stubs-arm.cc index 0a1ffbda5f..590d8ce15e 100644 --- a/deps/v8/src/arm/code-stubs-arm.cc +++ b/deps/v8/src/arm/code-stubs-arm.cc @@ -389,7 +389,7 @@ class FloatingPointHelper : public AllStatic { // floating point registers VFP3 must be supported. If core registers are // requested when VFP3 is supported d6 and d7 will still be scratched. If // either r0 or r1 is not a number (not smi and not heap number object) the - // not_number label is jumped to. + // not_number label is jumped to with r0 and r1 intact. static void LoadOperands(MacroAssembler* masm, FloatingPointHelper::Destination destination, Register heap_number_map, @@ -417,11 +417,11 @@ void FloatingPointHelper::LoadSmis(MacroAssembler* masm, if (CpuFeatures::IsSupported(VFP3)) { CpuFeatures::Scope scope(VFP3); __ mov(scratch1, Operand(r0, ASR, kSmiTagSize)); - __ vmov(s15, scratch1); - __ vcvt_f64_s32(d7, s15); + __ vmov(d7.high(), scratch1); + __ vcvt_f64_s32(d7, d7.high()); __ mov(scratch1, Operand(r1, ASR, kSmiTagSize)); - __ vmov(s13, scratch1); - __ vcvt_f64_s32(d6, s13); + __ vmov(d6.high(), scratch1); + __ vcvt_f64_s32(d6, d6.high()); if (destination == kCoreRegisters) { __ vmov(r2, r3, d7); __ vmov(r0, r1, d6); @@ -476,7 +476,7 @@ void FloatingPointHelper::LoadNumber(MacroAssembler* masm, __ JumpIfNotHeapNumber(object, heap_number_map, scratch1, not_number); // Handle loading a double from a heap number. - if (CpuFeatures::IsSupported(VFP3)) { + if (CpuFeatures::IsSupported(VFP3) && destination == kVFPRegisters) { CpuFeatures::Scope scope(VFP3); // Load the double from tagged HeapNumber to double register. __ sub(scratch1, object, Operand(kHeapObjectTag)); @@ -492,16 +492,17 @@ void FloatingPointHelper::LoadNumber(MacroAssembler* masm, __ bind(&is_smi); if (CpuFeatures::IsSupported(VFP3)) { CpuFeatures::Scope scope(VFP3); - // Convert smi to double. + // Convert smi to double using VFP instructions. __ SmiUntag(scratch1, object); __ vmov(dst.high(), scratch1); __ vcvt_f64_s32(dst, dst.high()); if (destination == kCoreRegisters) { + // Load the converted smi to dst1 and dst2 in double format. __ vmov(dst1, dst2, dst); } } else { ASSERT(destination == kCoreRegisters); - // Write Smi to dst1 and dst2 double format. + // Write smi to dst1 and dst2 double format. __ mov(scratch1, Operand(object)); ConvertToDoubleStub stub(dst2, dst1, scratch1, scratch2); __ push(lr); @@ -2501,6 +2502,33 @@ void TypeRecordingBinaryOpStub::GenerateSmiSmiOperation( // We fall through here if we multiplied a negative number with 0, because // that would mean we should produce -0. break; + case Token::DIV: + // Check for power of two on the right hand side. + __ JumpIfNotPowerOfTwoOrZero(right, scratch1, ¬_smi_result); + // Check for positive and no remainder (scratch1 contains right - 1). + __ orr(scratch2, scratch1, Operand(0x80000000u)); + __ tst(left, scratch2); + __ b(ne, ¬_smi_result); + + // Perform division by shifting. + __ CountLeadingZeros(scratch1, scratch1, scratch2); + __ rsb(scratch1, scratch1, Operand(31)); + __ mov(right, Operand(left, LSR, scratch1)); + __ Ret(); + break; + case Token::MOD: + // Check for two positive smis. + __ orr(scratch1, left, Operand(right)); + __ tst(scratch1, Operand(0x80000000u | kSmiTagMask)); + __ b(ne, ¬_smi_result); + + // Check for power of two on the right hand side. + __ JumpIfNotPowerOfTwoOrZero(right, scratch1, ¬_smi_result); + + // Perform modulus by masking. + __ and_(right, left, Operand(scratch1)); + __ Ret(); + break; default: UNREACHABLE(); } @@ -2508,20 +2536,99 @@ void TypeRecordingBinaryOpStub::GenerateSmiSmiOperation( } -void TypeRecordingBinaryOpStub::GenerateVFPOperation( - MacroAssembler* masm) { - switch (op_) { - case Token::ADD: - __ vadd(d5, d6, d7); - break; - case Token::SUB: - __ vsub(d5, d6, d7); - break; - case Token::MUL: - __ vmul(d5, d6, d7); - break; - default: - UNREACHABLE(); +void TypeRecordingBinaryOpStub::GenerateFPOperation(MacroAssembler* masm, + bool smi_operands, + Label* not_numbers, + Label* gc_required) { + Register left = r1; + Register right = r0; + Register scratch1 = r7; + Register scratch2 = r9; + + // Load left and right operands into d6 and d7 or r0/r1 and r2/r3 depending + // on whether VFP3 is available. + FloatingPointHelper::Destination destination = + CpuFeatures::IsSupported(VFP3) && op_ != Token::MOD ? + FloatingPointHelper::kVFPRegisters : + FloatingPointHelper::kCoreRegisters; + + Register heap_number_map = r6; + __ LoadRoot(heap_number_map, Heap::kHeapNumberMapRootIndex); + + // Allocate new heap number for result. + Register result = r5; + __ AllocateHeapNumber( + result, scratch1, scratch2, heap_number_map, gc_required); + + // Load the operands. + if (smi_operands) { + if (FLAG_debug_code) { + __ AbortIfNotSmi(left); + __ AbortIfNotSmi(right); + } + FloatingPointHelper::LoadSmis(masm, destination, scratch1, scratch2); + } else { + FloatingPointHelper::LoadOperands(masm, + destination, + heap_number_map, + scratch1, + scratch2, + not_numbers); + } + + // Calculate the result. + if (destination == FloatingPointHelper::kVFPRegisters) { + // Using VFP registers: + // d6: Left value + // d7: Right value + CpuFeatures::Scope scope(VFP3); + switch (op_) { + case Token::ADD: + __ vadd(d5, d6, d7); + break; + case Token::SUB: + __ vsub(d5, d6, d7); + break; + case Token::MUL: + __ vmul(d5, d6, d7); + break; + case Token::DIV: + __ vdiv(d5, d6, d7); + break; + default: + UNREACHABLE(); + } + + __ sub(r0, result, Operand(kHeapObjectTag)); + __ vstr(d5, r0, HeapNumber::kValueOffset); + __ add(r0, r0, Operand(kHeapObjectTag)); + __ Ret(); + } else { + // Using core registers: + // r0: Left value (least significant part of mantissa). + // r1: Left value (sign, exponent, top of mantissa). + // r2: Right value (least significant part of mantissa). + // r3: Right value (sign, exponent, top of mantissa). + + __ push(lr); // For later. + __ PrepareCallCFunction(4, scratch1); // Two doubles are 4 arguments. + // Call C routine that may not cause GC or other trouble. r5 is callee + // save. + __ CallCFunction(ExternalReference::double_fp_operation(op_), 4); + // Store answer in the overwritable heap number. +#if !defined(USE_ARM_EABI) + // Double returned in fp coprocessor register 0 and 1, encoded as + // register cr8. Offsets must be divisible by 4 for coprocessor so we + // need to substract the tag from r5. + __ sub(scratch1, result, Operand(kHeapObjectTag)); + __ stc(p1, cr8, MemOperand(scratch1, HeapNumber::kValueOffset)); +#else + // Double returned in registers 0 and 1. + __ Strd(r0, r1, FieldMemOperand(result, HeapNumber::kValueOffset)); +#endif + __ mov(r0, Operand(result)); + // And we are done. + __ pop(pc); } } @@ -2535,7 +2642,11 @@ void TypeRecordingBinaryOpStub::GenerateSmiCode(MacroAssembler* masm, SmiCodeGenerateHeapNumberResults allow_heapnumber_results) { Label not_smis; - ASSERT(op_ == Token::ADD || op_ == Token::SUB || op_ == Token::MUL); + ASSERT(op_ == Token::ADD || + op_ == Token::SUB || + op_ == Token::MUL || + op_ == Token::DIV || + op_ == Token::MOD); Register left = r1; Register right = r0; @@ -2548,66 +2659,13 @@ void TypeRecordingBinaryOpStub::GenerateSmiCode(MacroAssembler* masm, __ tst(scratch1, Operand(kSmiTagMask)); __ b(ne, ¬_smis); + // If the smi-smi operation results in a smi return is generated. GenerateSmiSmiOperation(masm); // If heap number results are possible generate the result in an allocated // heap number. if (allow_heapnumber_results == ALLOW_HEAPNUMBER_RESULTS) { - FloatingPointHelper::Destination destination = - CpuFeatures::IsSupported(VFP3) && Token::MOD != op_ ? - FloatingPointHelper::kVFPRegisters : - FloatingPointHelper::kCoreRegisters; - - Register heap_number_map = r6; - __ LoadRoot(heap_number_map, Heap::kHeapNumberMapRootIndex); - - // Allocate new heap number for result. - Register heap_number = r5; - __ AllocateHeapNumber( - heap_number, scratch1, scratch2, heap_number_map, gc_required); - - // Load the smis. - FloatingPointHelper::LoadSmis(masm, destination, scratch1, scratch2); - - // Calculate the result. - if (destination == FloatingPointHelper::kVFPRegisters) { - // Using VFP registers: - // d6: Left value - // d7: Right value - CpuFeatures::Scope scope(VFP3); - GenerateVFPOperation(masm); - - __ sub(r0, heap_number, Operand(kHeapObjectTag)); - __ vstr(d5, r0, HeapNumber::kValueOffset); - __ add(r0, r0, Operand(kHeapObjectTag)); - __ Ret(); - } else { - // Using core registers: - // r0: Left value (least significant part of mantissa). - // r1: Left value (sign, exponent, top of mantissa). - // r2: Right value (least significant part of mantissa). - // r3: Right value (sign, exponent, top of mantissa). - - __ push(lr); // For later. - __ PrepareCallCFunction(4, scratch1); // Two doubles are 4 arguments. - // Call C routine that may not cause GC or other trouble. r5 is callee - // save. - __ CallCFunction(ExternalReference::double_fp_operation(op_), 4); - // Store answer in the overwritable heap number. -#if !defined(USE_ARM_EABI) - // Double returned in fp coprocessor register 0 and 1, encoded as - // register cr8. Offsets must be divisible by 4 for coprocessor so we - // need to substract the tag from r5. - __ sub(scratch1, heap_number, Operand(kHeapObjectTag)); - __ stc(p1, cr8, MemOperand(scratch1, HeapNumber::kValueOffset)); -#else - // Double returned in registers 0 and 1. - __ Strd(r0, r1, FieldMemOperand(heap_number, HeapNumber::kValueOffset)); -#endif - __ mov(r0, Operand(heap_number)); - // And we are done. - __ pop(pc); - } + GenerateFPOperation(masm, true, NULL, gc_required); } __ bind(¬_smis); } @@ -2616,7 +2674,11 @@ void TypeRecordingBinaryOpStub::GenerateSmiCode(MacroAssembler* masm, void TypeRecordingBinaryOpStub::GenerateSmiStub(MacroAssembler* masm) { Label not_smis, call_runtime; - ASSERT(op_ == Token::ADD || op_ == Token::SUB || op_ == Token::MUL); + ASSERT(op_ == Token::ADD || + op_ == Token::SUB || + op_ == Token::MUL || + op_ == Token::DIV || + op_ == Token::MOD); if (result_type_ == TRBinaryOpIC::UNINITIALIZED || result_type_ == TRBinaryOpIC::SMI) { @@ -2648,7 +2710,11 @@ void TypeRecordingBinaryOpStub::GenerateStringStub(MacroAssembler* masm) { void TypeRecordingBinaryOpStub::GenerateInt32Stub(MacroAssembler* masm) { - ASSERT(op_ == Token::ADD || op_ == Token::SUB || op_ == Token::MUL); + ASSERT(op_ == Token::ADD || + op_ == Token::SUB || + op_ == Token::MUL || + op_ == Token::DIV || + op_ == Token::MOD); ASSERT(operands_type_ == TRBinaryOpIC::INT32); @@ -2657,78 +2723,18 @@ void TypeRecordingBinaryOpStub::GenerateInt32Stub(MacroAssembler* masm) { void TypeRecordingBinaryOpStub::GenerateHeapNumberStub(MacroAssembler* masm) { - ASSERT(op_ == Token::ADD || op_ == Token::SUB || op_ == Token::MUL); - - Register scratch1 = r7; - Register scratch2 = r9; + ASSERT(op_ == Token::ADD || + op_ == Token::SUB || + op_ == Token::MUL || + op_ == Token::DIV || + op_ == Token::MOD); - Label not_number, call_runtime; + Label not_numbers, call_runtime; ASSERT(operands_type_ == TRBinaryOpIC::HEAP_NUMBER); - Register heap_number_map = r6; - __ LoadRoot(heap_number_map, Heap::kHeapNumberMapRootIndex); - - // Load left and right operands into d6 and d7 or r0/r1 and r2/r3 depending on - // whether VFP3 is available. - FloatingPointHelper::Destination destination = - CpuFeatures::IsSupported(VFP3) ? - FloatingPointHelper::kVFPRegisters : - FloatingPointHelper::kCoreRegisters; - FloatingPointHelper::LoadOperands(masm, - destination, - heap_number_map, - scratch1, - scratch2, - ¬_number); - if (destination == FloatingPointHelper::kVFPRegisters) { - // Use floating point instructions for the binary operation. - CpuFeatures::Scope scope(VFP3); - GenerateVFPOperation(masm); + GenerateFPOperation(masm, false, ¬_numbers, &call_runtime); - // Get a heap number object for the result - might be left or right if one - // of these are overwritable. - GenerateHeapResultAllocation( - masm, r4, heap_number_map, scratch1, scratch2, &call_runtime); - - // Fill the result into the allocated heap number and return. - __ sub(r0, r4, Operand(kHeapObjectTag)); - __ vstr(d5, r0, HeapNumber::kValueOffset); - __ add(r0, r0, Operand(kHeapObjectTag)); - __ Ret(); - - } else { - // Call a C function for the binary operation. - // r0/r1: Left operand - // r2/r3: Right operand - - // Get a heap number object for the result - might be left or right if one - // of these are overwritable. Uses a callee-save register to keep the value - // across the c call. - GenerateHeapResultAllocation( - masm, r4, heap_number_map, scratch1, scratch2, &call_runtime); - - __ push(lr); // For returning later (no GC after this point). - __ PrepareCallCFunction(4, scratch1); // Two doubles count as 4 arguments. - // Call C routine that may not cause GC or other trouble. r4 is callee - // saved. - __ CallCFunction(ExternalReference::double_fp_operation(op_), 4); - - // Fill the result into the allocated heap number. - #if !defined(USE_ARM_EABI) - // Double returned in fp coprocessor register 0 and 1, encoded as - // register cr8. Offsets must be divisible by 4 for coprocessor so we - // need to substract the tag from r5. - __ sub(scratch1, r4, Operand(kHeapObjectTag)); - __ stc(p1, cr8, MemOperand(scratch1, HeapNumber::kValueOffset)); - #else - // Double returned in registers 0 and 1. - __ Strd(r0, r1, FieldMemOperand(r4, HeapNumber::kValueOffset)); - #endif - __ mov(r0, Operand(r4)); - __ pop(pc); // Return to the pushed lr. - } - - __ bind(¬_number); + __ bind(¬_numbers); GenerateTypeTransition(masm); __ bind(&call_runtime); @@ -2737,7 +2743,11 @@ void TypeRecordingBinaryOpStub::GenerateHeapNumberStub(MacroAssembler* masm) { void TypeRecordingBinaryOpStub::GenerateGeneric(MacroAssembler* masm) { - ASSERT(op_ == Token::ADD || op_ == Token::SUB || op_ == Token::MUL); + ASSERT(op_ == Token::ADD || + op_ == Token::SUB || + op_ == Token::MUL || + op_ == Token::DIV || + op_ == Token::MOD); Label call_runtime; @@ -2796,6 +2806,12 @@ void TypeRecordingBinaryOpStub::GenerateCallRuntime(MacroAssembler* masm) { case Token::MUL: __ InvokeBuiltin(Builtins::MUL, JUMP_JS); break; + case Token::DIV: + __ InvokeBuiltin(Builtins::DIV, JUMP_JS); + break; + case Token::MOD: + __ InvokeBuiltin(Builtins::MOD, JUMP_JS); + break; default: UNREACHABLE(); } diff --git a/deps/v8/src/arm/code-stubs-arm.h b/deps/v8/src/arm/code-stubs-arm.h index a79b2392d9..9e9047e579 100644 --- a/deps/v8/src/arm/code-stubs-arm.h +++ b/deps/v8/src/arm/code-stubs-arm.h @@ -289,7 +289,10 @@ class TypeRecordingBinaryOpStub: public CodeStub { void Generate(MacroAssembler* masm); void GenerateGeneric(MacroAssembler* masm); void GenerateSmiSmiOperation(MacroAssembler* masm); - void GenerateVFPOperation(MacroAssembler* masm); + void GenerateFPOperation(MacroAssembler* masm, + bool smi_operands, + Label* not_numbers, + Label* gc_required); void GenerateSmiCode(MacroAssembler* masm, Label* gc_required, SmiCodeGenerateHeapNumberResults heapnumber_results); diff --git a/deps/v8/src/arm/codegen-arm.cc b/deps/v8/src/arm/codegen-arm.cc index 0d429d602f..9a60183979 100644 --- a/deps/v8/src/arm/codegen-arm.cc +++ b/deps/v8/src/arm/codegen-arm.cc @@ -4698,12 +4698,15 @@ void CodeGenerator::GenerateMathPow(ZoneList<Expression*>* args) { runtime.entry_label(), AVOID_NANS_AND_INFINITIES); + // Convert -0 into +0 by adding +0. + __ vmov(d2, 0.0); + __ vadd(d0, d2, d0); // Load 1.0 into d2. __ vmov(d2, 1.0); - // Calculate the reciprocal of the square root. 1/sqrt(x) = sqrt(1/x). - __ vdiv(d0, d2, d0); + // Calculate the reciprocal of the square root. __ vsqrt(d0, d0); + __ vdiv(d0, d2, d0); __ b(&allocate_return); @@ -4717,6 +4720,9 @@ void CodeGenerator::GenerateMathPow(ZoneList<Expression*>* args) { scratch1, scratch2, heap_number_map, s0, runtime.entry_label(), AVOID_NANS_AND_INFINITIES); + // Convert -0 into +0 by adding +0. + __ vmov(d2, 0.0); + __ vadd(d0, d2, d0); __ vsqrt(d0, d0); __ bind(&allocate_return); diff --git a/deps/v8/src/arm/deoptimizer-arm.cc b/deps/v8/src/arm/deoptimizer-arm.cc index 3fd1e394e7..75399c69db 100644 --- a/deps/v8/src/arm/deoptimizer-arm.cc +++ b/deps/v8/src/arm/deoptimizer-arm.cc @@ -1,4 +1,4 @@ -// Copyright 2010 the V8 project authors. All rights reserved. +// Copyright 2011 the V8 project authors. All rights reserved. // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: @@ -37,6 +37,14 @@ namespace internal { int Deoptimizer::table_entry_size_ = 16; + +int Deoptimizer::patch_size() { + const int kCallInstructionSizeInWords = 3; + return kCallInstructionSizeInWords * Assembler::kInstrSize; +} + + + void Deoptimizer::DeoptimizeFunction(JSFunction* function) { AssertNoAllocation no_allocation; @@ -51,6 +59,8 @@ void Deoptimizer::DeoptimizeFunction(JSFunction* function) { // For each return after a safepoint insert an absolute call to the // corresponding deoptimization entry. + ASSERT(patch_size() % Assembler::kInstrSize == 0); + int call_size_in_words = patch_size() / Assembler::kInstrSize; unsigned last_pc_offset = 0; SafepointTable table(function->code()); for (unsigned i = 0; i < table.length(); i++) { @@ -73,14 +83,13 @@ void Deoptimizer::DeoptimizeFunction(JSFunction* function) { #endif last_pc_offset = pc_offset; if (deoptimization_index != Safepoint::kNoDeoptimizationIndex) { - const int kCallInstructionSizeInWords = 3; - CodePatcher patcher(code->instruction_start() + pc_offset + gap_code_size, - kCallInstructionSizeInWords); + last_pc_offset += gap_code_size; + CodePatcher patcher(code->instruction_start() + last_pc_offset, + call_size_in_words); Address deoptimization_entry = Deoptimizer::GetDeoptimizationEntry( deoptimization_index, Deoptimizer::LAZY); patcher.masm()->Call(deoptimization_entry, RelocInfo::NONE); - last_pc_offset += - gap_code_size + kCallInstructionSizeInWords * Assembler::kInstrSize; + last_pc_offset += patch_size(); } } @@ -112,16 +121,16 @@ void Deoptimizer::DeoptimizeFunction(JSFunction* function) { } -void Deoptimizer::PatchStackCheckCode(Code* unoptimized_code, - Code* check_code, - Code* replacement_code) { +void Deoptimizer::PatchStackCheckCodeAt(Address pc_after, + Code* check_code, + Code* replacement_code) { UNIMPLEMENTED(); } -void Deoptimizer::RevertStackCheckCode(Code* unoptimized_code, - Code* check_code, - Code* replacement_code) { +void Deoptimizer::RevertStackCheckCodeAt(Address pc_after, + Code* check_code, + Code* replacement_code) { UNIMPLEMENTED(); } diff --git a/deps/v8/src/arm/full-codegen-arm.cc b/deps/v8/src/arm/full-codegen-arm.cc index c29886f58d..23e5f69ebe 100644 --- a/deps/v8/src/arm/full-codegen-arm.cc +++ b/deps/v8/src/arm/full-codegen-arm.cc @@ -1550,7 +1550,11 @@ void FullCodeGenerator::EmitInlineSmiBinaryOp(Expression* expr, void FullCodeGenerator::EmitBinaryOp(Token::Value op, OverwriteMode mode) { __ pop(r1); - if (op == Token::ADD || op == Token::SUB || op == Token::MUL) { + if (op == Token::ADD || + op == Token::SUB || + op == Token::MUL || + op == Token::DIV || + op == Token::MOD) { TypeRecordingBinaryOpStub stub(op, mode); __ CallStub(&stub); } else { diff --git a/deps/v8/src/arm/jump-target-arm.cc b/deps/v8/src/arm/jump-target-arm.cc index b9e6ebf247..df370c4437 100644 --- a/deps/v8/src/arm/jump-target-arm.cc +++ b/deps/v8/src/arm/jump-target-arm.cc @@ -143,6 +143,16 @@ void JumpTarget::DoBind() { entry_frame_set_ = true; } else { cgen()->frame()->MergeTo(&entry_frame_); + // On fall through we may have to merge both ways. + if (direction_ != FORWARD_ONLY) { + // This will not need to adjust the virtual frame entries that are + // register allocated since that was done above and they now match. + // But it does need to adjust the entry_frame_ of this jump target + // to make it potentially less optimistic. Later code can branch back + // to this jump target and we need to assert that that code does not + // have weaker assumptions about types. + entry_frame_.MergeTo(cgen()->frame()); + } } } else { // If there is no current frame we must have an entry frame which we can diff --git a/deps/v8/src/arm/lithium-arm.cc b/deps/v8/src/arm/lithium-arm.cc index c458138380..b7c1b78d1b 100644 --- a/deps/v8/src/arm/lithium-arm.cc +++ b/deps/v8/src/arm/lithium-arm.cc @@ -655,16 +655,16 @@ LInstruction* LChunkBuilder::AssignEnvironment(LInstruction* instr) { LInstruction* LChunkBuilder::SetInstructionPendingDeoptimizationEnvironment( LInstruction* instr, int ast_id) { - ASSERT(instructions_pending_deoptimization_environment_ == NULL); + ASSERT(instruction_pending_deoptimization_environment_ == NULL); ASSERT(pending_deoptimization_ast_id_ == AstNode::kNoNumber); - instructions_pending_deoptimization_environment_ = instr; + instruction_pending_deoptimization_environment_ = instr; pending_deoptimization_ast_id_ = ast_id; return instr; } void LChunkBuilder::ClearInstructionPendingDeoptimizationEnvironment() { - instructions_pending_deoptimization_environment_ = NULL; + instruction_pending_deoptimization_environment_ = NULL; pending_deoptimization_ast_id_ = AstNode::kNoNumber; } @@ -1463,6 +1463,13 @@ LInstruction* LChunkBuilder::DoBoundsCheck(HBoundsCheck* instr) { } +LInstruction* LChunkBuilder::DoAbnormalExit(HAbnormalExit* instr) { + // The control instruction marking the end of a block that completed + // abruptly (e.g., threw an exception). There is nothing specific to do. + return NULL; +} + + LInstruction* LChunkBuilder::DoThrow(HThrow* instr) { LOperand* value = UseFixed(instr->value(), r0); return MarkAsCall(new LThrow(value), instr); @@ -1837,7 +1844,7 @@ LInstruction* LChunkBuilder::DoSimulate(HSimulate* instr) { if (pending_deoptimization_ast_id_ == instr->ast_id()) { LInstruction* result = new LLazyBailout; result = AssignEnvironment(result); - instructions_pending_deoptimization_environment_-> + instruction_pending_deoptimization_environment_-> set_deoptimization_environment(result->environment()); ClearInstructionPendingDeoptimizationEnvironment(); return result; diff --git a/deps/v8/src/arm/lithium-arm.h b/deps/v8/src/arm/lithium-arm.h index 3de5832981..7f89ee2922 100644 --- a/deps/v8/src/arm/lithium-arm.h +++ b/deps/v8/src/arm/lithium-arm.h @@ -1855,7 +1855,7 @@ class LChunkBuilder BASE_EMBEDDED { argument_count_(0), allocator_(allocator), position_(RelocInfo::kNoPosition), - instructions_pending_deoptimization_environment_(NULL), + instruction_pending_deoptimization_environment_(NULL), pending_deoptimization_ast_id_(AstNode::kNoNumber) { } // Build the sequence for the graph. @@ -1989,7 +1989,7 @@ class LChunkBuilder BASE_EMBEDDED { int argument_count_; LAllocator* allocator_; int position_; - LInstruction* instructions_pending_deoptimization_environment_; + LInstruction* instruction_pending_deoptimization_environment_; int pending_deoptimization_ast_id_; DISALLOW_COPY_AND_ASSIGN(LChunkBuilder); diff --git a/deps/v8/src/arm/lithium-codegen-arm.cc b/deps/v8/src/arm/lithium-codegen-arm.cc index 36498077cf..a1adae389d 100644 --- a/deps/v8/src/arm/lithium-codegen-arm.cc +++ b/deps/v8/src/arm/lithium-codegen-arm.cc @@ -562,17 +562,11 @@ void LCodeGen::AddToTranslation(Translation* translation, void LCodeGen::CallCode(Handle<Code> code, RelocInfo::Mode mode, LInstruction* instr) { - if (instr != NULL) { - LPointerMap* pointers = instr->pointer_map(); - RecordPosition(pointers->position()); - __ Call(code, mode); - RegisterLazyDeoptimization(instr); - } else { - LPointerMap no_pointers(0); - RecordPosition(no_pointers.position()); - __ Call(code, mode); - RecordSafepoint(&no_pointers, Safepoint::kNoDeoptimizationIndex); - } + ASSERT(instr != NULL); + LPointerMap* pointers = instr->pointer_map(); + RecordPosition(pointers->position()); + __ Call(code, mode); + RegisterLazyDeoptimization(instr); } @@ -585,15 +579,7 @@ void LCodeGen::CallRuntime(Runtime::Function* function, RecordPosition(pointers->position()); __ CallRuntime(function, num_arguments); - // Runtime calls to Throw are not supposed to ever return at the - // call site, so don't register lazy deoptimization for these. We do - // however have to record a safepoint since throwing exceptions can - // cause garbage collections. - if (!instr->IsThrow()) { - RegisterLazyDeoptimization(instr); - } else { - RecordSafepoint(instr->pointer_map(), Safepoint::kNoDeoptimizationIndex); - } + RegisterLazyDeoptimization(instr); } @@ -1053,11 +1039,8 @@ void LCodeGen::DoModI(LModI* instr) { } // Check for power of two on the right hand side. - __ sub(scratch, right, Operand(1), SetCC); - __ b(mi, &call_stub); - __ tst(scratch, right); - __ b(ne, &call_stub); - // Perform modulo operation. + __ JumpIfNotPowerOfTwoOrZero(right, scratch, &call_stub); + // Perform modulo operation (scratch contains right - 1). __ and_(result, scratch, Operand(left)); __ bind(&call_stub); @@ -2449,12 +2432,17 @@ void LCodeGen::DoApplyArguments(LApplyArguments* instr) { __ b(ne, &loop); __ bind(&invoke); - // Invoke the function. The number of arguments is stored in receiver - // which is r0, as expected by InvokeFunction. - v8::internal::ParameterCount actual(receiver); + ASSERT(instr->HasPointerMap() && instr->HasDeoptimizationEnvironment()); + LPointerMap* pointers = instr->pointer_map(); + LEnvironment* env = instr->deoptimization_environment(); + RecordPosition(pointers->position()); + RegisterEnvironmentForDeoptimization(env); SafepointGenerator safepoint_generator(this, - instr->pointer_map(), - Safepoint::kNoDeoptimizationIndex); + pointers, + env->deoptimization_index()); + // The number of arguments is stored in receiver which is r0, as expected + // by InvokeFunction. + v8::internal::ParameterCount actual(receiver); __ InvokeFunction(function, actual, CALL_FUNCTION, &safepoint_generator); } @@ -3669,10 +3657,14 @@ void LCodeGen::DoDeleteProperty(LDeleteProperty* instr) { Register object = ToRegister(instr->object()); Register key = ToRegister(instr->key()); __ Push(object, key); - RecordPosition(instr->pointer_map()->position()); + ASSERT(instr->HasPointerMap() && instr->HasDeoptimizationEnvironment()); + LPointerMap* pointers = instr->pointer_map(); + LEnvironment* env = instr->deoptimization_environment(); + RecordPosition(pointers->position()); + RegisterEnvironmentForDeoptimization(env); SafepointGenerator safepoint_generator(this, - instr->pointer_map(), - Safepoint::kNoDeoptimizationIndex); + pointers, + env->deoptimization_index()); __ InvokeBuiltin(Builtins::DELETE, CALL_JS, &safepoint_generator); } diff --git a/deps/v8/src/arm/macro-assembler-arm.cc b/deps/v8/src/arm/macro-assembler-arm.cc index 60d0a6b6a1..ef351022a8 100644 --- a/deps/v8/src/arm/macro-assembler-arm.cc +++ b/deps/v8/src/arm/macro-assembler-arm.cc @@ -1954,6 +1954,17 @@ void MacroAssembler::LoadGlobalFunctionInitialMap(Register function, } +void MacroAssembler::JumpIfNotPowerOfTwoOrZero( + Register reg, + Register scratch, + Label* not_power_of_two_or_zero) { + sub(scratch, reg, Operand(1), SetCC); + b(mi, not_power_of_two_or_zero); + tst(scratch, reg); + b(ne, not_power_of_two_or_zero); +} + + void MacroAssembler::JumpIfNotBothSmi(Register reg1, Register reg2, Label* on_not_both_smi) { @@ -2102,7 +2113,7 @@ void MacroAssembler::CopyFields(Register dst, void MacroAssembler::CountLeadingZeros(Register zeros, // Answer. Register source, // Input. Register scratch) { - ASSERT(!zeros.is(source) || !source.is(zeros)); + ASSERT(!zeros.is(source) || !source.is(scratch)); ASSERT(!zeros.is(scratch)); ASSERT(!scratch.is(ip)); ASSERT(!source.is(ip)); diff --git a/deps/v8/src/arm/macro-assembler-arm.h b/deps/v8/src/arm/macro-assembler-arm.h index b6675e47ce..a1a13e32ef 100644 --- a/deps/v8/src/arm/macro-assembler-arm.h +++ b/deps/v8/src/arm/macro-assembler-arm.h @@ -707,6 +707,17 @@ class MacroAssembler: public Assembler { bool allow_stub_calls() { return allow_stub_calls_; } // --------------------------------------------------------------------------- + // Number utilities + + // Check whether the value of reg is a power of two and not zero. If not + // control continues at the label not_power_of_two. If reg is a power of two + // the register scratch contains the value of (reg - 1) when control falls + // through. + void JumpIfNotPowerOfTwoOrZero(Register reg, + Register scratch, + Label* not_power_of_two_or_zero); + + // --------------------------------------------------------------------------- // Smi utilities void SmiTag(Register reg, SBit s = LeaveCC) { diff --git a/deps/v8/src/arm/virtual-frame-arm.cc b/deps/v8/src/arm/virtual-frame-arm.cc index 45f48767c4..3266a16e3a 100644 --- a/deps/v8/src/arm/virtual-frame-arm.cc +++ b/deps/v8/src/arm/virtual-frame-arm.cc @@ -68,6 +68,8 @@ void VirtualFrame::PopToR0() { void VirtualFrame::MergeTo(const VirtualFrame* expected, Condition cond) { if (Equals(expected)) return; + ASSERT((expected->tos_known_smi_map_ & tos_known_smi_map_) == + expected->tos_known_smi_map_); ASSERT(expected->IsCompatibleWith(this)); MergeTOSTo(expected->top_of_stack_state_, cond); ASSERT(register_allocation_map_ == expected->register_allocation_map_); @@ -76,7 +78,7 @@ void VirtualFrame::MergeTo(const VirtualFrame* expected, Condition cond) { void VirtualFrame::MergeTo(VirtualFrame* expected, Condition cond) { if (Equals(expected)) return; - expected->tos_known_smi_map_ &= tos_known_smi_map_; + tos_known_smi_map_ &= expected->tos_known_smi_map_; MergeTOSTo(expected->top_of_stack_state_, cond); ASSERT(register_allocation_map_ == expected->register_allocation_map_); } diff --git a/deps/v8/src/array.js b/deps/v8/src/array.js index 0d7a7cbc85..a0e3e0bb4e 100644 --- a/deps/v8/src/array.js +++ b/deps/v8/src/array.js @@ -171,8 +171,9 @@ function Join(array, length, separator, convert) { } return %StringBuilderConcat(elements, length2, ''); } finally { - // Make sure to pop the visited array no matter what happens. - if (is_array) visited_arrays.pop(); + // Make sure to remove the last element of the visited array no + // matter what happens. + if (is_array) visited_arrays.length = visited_arrays.length - 1; } } @@ -603,16 +604,17 @@ function ArraySplice(start, delete_count) { } // SpiderMonkey, TraceMonkey and JSC treat the case where no delete count is - // given differently from when an undefined delete count is given. + // given as a request to delete all the elements from the start. + // And it differs from the case of undefined delete count. // This does not follow ECMA-262, but we do the same for // compatibility. var del_count = 0; - if (num_arguments > 1) { + if (num_arguments == 1) { + del_count = len - start_i; + } else { del_count = TO_INTEGER(delete_count); if (del_count < 0) del_count = 0; if (del_count > len - start_i) del_count = len - start_i; - } else { - del_count = len - start_i; } var deleted_elements = []; diff --git a/deps/v8/src/assembler.cc b/deps/v8/src/assembler.cc index fb9a4af14e..ca72d63992 100644 --- a/deps/v8/src/assembler.cc +++ b/deps/v8/src/assembler.cc @@ -838,8 +838,8 @@ double power_double_double(double x, double y) { return power_double_int(x, y_int); // Returns 1.0 for exponent 0. } if (!isinf(x)) { - if (y == 0.5) return sqrt(x); - if (y == -0.5) return 1.0 / sqrt(x); + if (y == 0.5) return sqrt(x + 0.0); // -0 must be converted to +0. + if (y == -0.5) return 1.0 / sqrt(x + 0.0); } if (isnan(y) || ((x == 1 || x == -1) && isinf(y))) { return OS::nan_value(); diff --git a/deps/v8/src/ast.cc b/deps/v8/src/ast.cc index 80927a88fd..ccfa2b4ecf 100644 --- a/deps/v8/src/ast.cc +++ b/deps/v8/src/ast.cc @@ -215,17 +215,28 @@ bool IsEqualString(void* first, void* second) { return (*h1)->Equals(*h2); } -bool IsEqualSmi(void* first, void* second) { - ASSERT((*reinterpret_cast<Smi**>(first))->IsSmi()); - ASSERT((*reinterpret_cast<Smi**>(second))->IsSmi()); - Handle<Smi> h1(reinterpret_cast<Smi**>(first)); - Handle<Smi> h2(reinterpret_cast<Smi**>(second)); - return (*h1)->value() == (*h2)->value(); + +bool IsEqualNumber(void* first, void* second) { + ASSERT((*reinterpret_cast<Object**>(first))->IsNumber()); + ASSERT((*reinterpret_cast<Object**>(second))->IsNumber()); + + Handle<Object> h1(reinterpret_cast<Object**>(first)); + Handle<Object> h2(reinterpret_cast<Object**>(second)); + if (h1->IsSmi()) { + return h2->IsSmi() && *h1 == *h2; + } + if (h2->IsSmi()) return false; + Handle<HeapNumber> n1 = Handle<HeapNumber>::cast(h1); + Handle<HeapNumber> n2 = Handle<HeapNumber>::cast(h2); + ASSERT(isfinite(n1->value())); + ASSERT(isfinite(n2->value())); + return n1->value() == n2->value(); } + void ObjectLiteral::CalculateEmitStore() { HashMap properties(&IsEqualString); - HashMap elements(&IsEqualSmi); + HashMap elements(&IsEqualNumber); for (int i = this->properties()->length() - 1; i >= 0; i--) { ObjectLiteral::Property* property = this->properties()->at(i); Literal* literal = property->key(); @@ -238,23 +249,19 @@ void ObjectLiteral::CalculateEmitStore() { uint32_t hash; HashMap* table; void* key; - uint32_t index; - Smi* smi_key_location; if (handle->IsSymbol()) { Handle<String> name(String::cast(*handle)); - if (name->AsArrayIndex(&index)) { - smi_key_location = Smi::FromInt(index); - key = &smi_key_location; - hash = index; + if (name->AsArrayIndex(&hash)) { + Handle<Object> key_handle = Factory::NewNumberFromUint(hash); + key = key_handle.location(); table = &elements; } else { key = name.location(); hash = name->Hash(); table = &properties; } - } else if (handle->ToArrayIndex(&index)) { + } else if (handle->ToArrayIndex(&hash)) { key = handle.location(); - hash = index; table = &elements; } else { ASSERT(handle->IsNumber()); diff --git a/deps/v8/src/bootstrapper.cc b/deps/v8/src/bootstrapper.cc index 16a186fe6e..6db9a4819a 100644 --- a/deps/v8/src/bootstrapper.cc +++ b/deps/v8/src/bootstrapper.cc @@ -1050,7 +1050,6 @@ void Genesis::InstallNativeFunctions() { INSTALL_NATIVE(JSFunction, "Instantiate", instantiate_fun); INSTALL_NATIVE(JSFunction, "ConfigureTemplateInstance", configure_instance_fun); - INSTALL_NATIVE(JSFunction, "MakeMessage", make_message_fun); INSTALL_NATIVE(JSFunction, "GetStackTraceLine", get_stack_trace_line_fun); INSTALL_NATIVE(JSObject, "functionCache", function_cache); } diff --git a/deps/v8/src/builtins.cc b/deps/v8/src/builtins.cc index 58dd439d25..d604226d75 100644 --- a/deps/v8/src/builtins.cc +++ b/deps/v8/src/builtins.cc @@ -734,35 +734,39 @@ BUILTIN(ArraySplice) { int n_arguments = args.length() - 1; - // Return empty array when no arguments are supplied. - if (n_arguments == 0) { - return AllocateEmptyJSArray(); - } - int relative_start = 0; - Object* arg1 = args[1]; - if (arg1->IsSmi()) { - relative_start = Smi::cast(arg1)->value(); - } else if (!arg1->IsUndefined()) { - return CallJsBuiltin("ArraySplice", args); + if (n_arguments > 0) { + Object* arg1 = args[1]; + if (arg1->IsSmi()) { + relative_start = Smi::cast(arg1)->value(); + } else if (!arg1->IsUndefined()) { + return CallJsBuiltin("ArraySplice", args); + } } int actual_start = (relative_start < 0) ? Max(len + relative_start, 0) : Min(relative_start, len); // SpiderMonkey, TraceMonkey and JSC treat the case where no delete count is - // given differently from when an undefined delete count is given. + // given as a request to delete all the elements from the start. + // And it differs from the case of undefined delete count. // This does not follow ECMA-262, but we do the same for // compatibility. - int delete_count = len; - if (n_arguments > 1) { - Object* arg2 = args[2]; - if (arg2->IsSmi()) { - delete_count = Smi::cast(arg2)->value(); - } else { - return CallJsBuiltin("ArraySplice", args); + int actual_delete_count; + if (n_arguments == 1) { + ASSERT(len - actual_start >= 0); + actual_delete_count = len - actual_start; + } else { + int value = 0; // ToInteger(undefined) == 0 + if (n_arguments > 1) { + Object* arg2 = args[2]; + if (arg2->IsSmi()) { + value = Smi::cast(arg2)->value(); + } else { + return CallJsBuiltin("ArraySplice", args); + } } + actual_delete_count = Min(Max(value, 0), len - actual_start); } - int actual_delete_count = Min(Max(delete_count, 0), len - actual_start); JSArray* result_array = NULL; if (actual_delete_count == 0) { diff --git a/deps/v8/src/deoptimizer.cc b/deps/v8/src/deoptimizer.cc index a3d2002178..f081576aa8 100644 --- a/deps/v8/src/deoptimizer.cc +++ b/deps/v8/src/deoptimizer.cc @@ -810,6 +810,44 @@ bool Deoptimizer::DoOsrTranslateCommand(TranslationIterator* iterator, } +void Deoptimizer::PatchStackCheckCode(Code* unoptimized_code, + Code* check_code, + Code* replacement_code) { + // Iterate over the stack check table and patch every stack check + // call to an unconditional call to the replacement code. + ASSERT(unoptimized_code->kind() == Code::FUNCTION); + Address stack_check_cursor = unoptimized_code->instruction_start() + + unoptimized_code->stack_check_table_start(); + uint32_t table_length = Memory::uint32_at(stack_check_cursor); + stack_check_cursor += kIntSize; + for (uint32_t i = 0; i < table_length; ++i) { + uint32_t pc_offset = Memory::uint32_at(stack_check_cursor + kIntSize); + Address pc_after = unoptimized_code->instruction_start() + pc_offset; + PatchStackCheckCodeAt(pc_after, check_code, replacement_code); + stack_check_cursor += 2 * kIntSize; + } +} + + +void Deoptimizer::RevertStackCheckCode(Code* unoptimized_code, + Code* check_code, + Code* replacement_code) { + // Iterate over the stack check table and revert the patched + // stack check calls. + ASSERT(unoptimized_code->kind() == Code::FUNCTION); + Address stack_check_cursor = unoptimized_code->instruction_start() + + unoptimized_code->stack_check_table_start(); + uint32_t table_length = Memory::uint32_at(stack_check_cursor); + stack_check_cursor += kIntSize; + for (uint32_t i = 0; i < table_length; ++i) { + uint32_t pc_offset = Memory::uint32_at(stack_check_cursor + kIntSize); + Address pc_after = unoptimized_code->instruction_start() + pc_offset; + RevertStackCheckCodeAt(pc_after, check_code, replacement_code); + stack_check_cursor += 2 * kIntSize; + } +} + + unsigned Deoptimizer::ComputeInputFrameSize() const { unsigned fixed_size = ComputeFixedSize(function_); // The fp-to-sp delta already takes the context and the function diff --git a/deps/v8/src/deoptimizer.h b/deps/v8/src/deoptimizer.h index 69aa497f8c..1d4f4770f9 100644 --- a/deps/v8/src/deoptimizer.h +++ b/deps/v8/src/deoptimizer.h @@ -1,4 +1,4 @@ -// Copyright 2010 the V8 project authors. All rights reserved. +// Copyright 2011 the V8 project authors. All rights reserved. // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: @@ -128,18 +128,33 @@ class Deoptimizer : public Malloced { static void VisitAllOptimizedFunctions(OptimizedFunctionVisitor* visitor); + // The size in bytes of the code required at a lazy deopt patch site. + static int patch_size(); + // Patch all stack guard checks in the unoptimized code to // unconditionally call replacement_code. static void PatchStackCheckCode(Code* unoptimized_code, Code* check_code, Code* replacement_code); + // Patch stack guard check at instruction before pc_after in + // the unoptimized code to unconditionally call replacement_code. + static void PatchStackCheckCodeAt(Address pc_after, + Code* check_code, + Code* replacement_code); + // Change all patched stack guard checks in the unoptimized code // back to a normal stack guard check. static void RevertStackCheckCode(Code* unoptimized_code, Code* check_code, Code* replacement_code); + // Change all patched stack guard checks in the unoptimized code + // back to a normal stack guard check. + static void RevertStackCheckCodeAt(Address pc_after, + Code* check_code, + Code* replacement_code); + ~Deoptimizer(); void InsertHeapNumberValues(int index, JavaScriptFrame* frame); diff --git a/deps/v8/src/factory.cc b/deps/v8/src/factory.cc index 2bc878cc4d..a3d55921b6 100644 --- a/deps/v8/src/factory.cc +++ b/deps/v8/src/factory.cc @@ -755,6 +755,24 @@ Handle<SharedFunctionInfo> Factory::NewSharedFunctionInfo( } +Handle<JSMessageObject> Factory::NewJSMessageObject( + Handle<String> type, + Handle<JSArray> arguments, + int start_position, + int end_position, + Handle<Object> script, + Handle<Object> stack_trace, + Handle<Object> stack_frames) { + CALL_HEAP_FUNCTION(Heap::AllocateJSMessageObject(*type, + *arguments, + start_position, + end_position, + *script, + *stack_trace, + *stack_frames), + JSMessageObject); +} + Handle<SharedFunctionInfo> Factory::NewSharedFunctionInfo(Handle<String> name) { CALL_HEAP_FUNCTION(Heap::AllocateSharedFunctionInfo(*name), SharedFunctionInfo); diff --git a/deps/v8/src/factory.h b/deps/v8/src/factory.h index a5e1591238..ba2b181a34 100644 --- a/deps/v8/src/factory.h +++ b/deps/v8/src/factory.h @@ -365,6 +365,15 @@ class Factory : public AllStatic { Handle<SerializedScopeInfo> scope_info); static Handle<SharedFunctionInfo> NewSharedFunctionInfo(Handle<String> name); + static Handle<JSMessageObject> NewJSMessageObject( + Handle<String> type, + Handle<JSArray> arguments, + int start_position, + int end_position, + Handle<Object> script, + Handle<Object> stack_trace, + Handle<Object> stack_frames); + static Handle<NumberDictionary> DictionaryAtNumberPut( Handle<NumberDictionary>, uint32_t key, diff --git a/deps/v8/src/gdb-jit.cc b/deps/v8/src/gdb-jit.cc index b1782cbdd0..c26ecf5ea8 100644 --- a/deps/v8/src/gdb-jit.cc +++ b/deps/v8/src/gdb-jit.cc @@ -201,6 +201,7 @@ class ELFSection : public ZoneObject { TYPE_SHLIB = 10, TYPE_DYNSYM = 11, TYPE_LOPROC = 0x70000000, + TYPE_X86_64_UNWIND = 0x70000001, TYPE_HIPROC = 0x7fffffff, TYPE_LOUSER = 0x80000000, TYPE_HIUSER = 0xffffffff @@ -639,26 +640,53 @@ class ELFSymbolTable : public ELFSection { class CodeDescription BASE_EMBEDDED { public: + +#ifdef V8_TARGET_ARCH_X64 + enum StackState { + POST_RBP_PUSH, + POST_RBP_SET, + POST_RBP_POP, + STACK_STATE_MAX + }; +#endif + CodeDescription(const char* name, Code* code, Handle<Script> script, - GDBJITLineInfo* lineinfo) - : name_(name), code_(code), script_(script), lineinfo_(lineinfo) - { } + GDBJITLineInfo* lineinfo, + GDBJITInterface::CodeTag tag) + : name_(name), + code_(code), + script_(script), + lineinfo_(lineinfo), + tag_(tag) { + } - const char* code_name() const { + const char* name() const { return name_; } - uintptr_t code_size() const { - return code_->instruction_end() - code_->instruction_start(); + GDBJITLineInfo* lineinfo() const { + return lineinfo_; + } + + GDBJITInterface::CodeTag tag() const { + return tag_; + } + + uintptr_t CodeStart() const { + return reinterpret_cast<uintptr_t>(code_->instruction_start()); } - uintptr_t code_start() const { - return (uintptr_t)code_->instruction_start(); + uintptr_t CodeEnd() const { + return reinterpret_cast<uintptr_t>(code_->instruction_end()); } - bool is_line_info_available() { + uintptr_t CodeSize() const { + return CodeEnd() - CodeStart(); + } + + bool IsLineInfoAvailable() { return !script_.is_null() && script_->source()->IsString() && script_->HasValidSource() && @@ -666,9 +694,19 @@ class CodeDescription BASE_EMBEDDED { lineinfo_ != NULL; } - GDBJITLineInfo* lineinfo() const { return lineinfo_; } +#ifdef V8_TARGET_ARCH_X64 + uintptr_t GetStackStateStartAddress(StackState state) const { + ASSERT(state < STACK_STATE_MAX); + return stack_state_start_addresses_[state]; + } - SmartPointer<char> filename() { + void SetStackStateStartAddress(StackState state, uintptr_t addr) { + ASSERT(state < STACK_STATE_MAX); + stack_state_start_addresses_[state] = addr; + } +#endif + + SmartPointer<char> GetFilename() { return String::cast(script_->name())->ToCString(); } @@ -676,11 +714,16 @@ class CodeDescription BASE_EMBEDDED { return GetScriptLineNumberSafe(script_, pos) + 1; } + private: const char* name_; Code* code_; Handle<Script> script_; GDBJITLineInfo* lineinfo_; + GDBJITInterface::CodeTag tag_; +#ifdef V8_TARGET_ARCH_X64 + uintptr_t stack_state_start_addresses_[STACK_STATE_MAX]; +#endif }; @@ -701,9 +744,9 @@ static void CreateSymbolsTable(CodeDescription* desc, ELFSymbol::TYPE_FILE, ELFSection::INDEX_ABSOLUTE)); - symtab->Add(ELFSymbol(desc->code_name(), + symtab->Add(ELFSymbol(desc->name(), 0, - desc->code_size(), + desc->CodeSize(), ELFSymbol::BIND_GLOBAL, ELFSymbol::TYPE_FUNC, text_section_index)); @@ -723,9 +766,9 @@ class DebugInfoSection : public ELFSection { w->Write<uint8_t>(sizeof(intptr_t)); w->WriteULEB128(1); // Abbreviation code. - w->WriteString(*desc_->filename()); - w->Write<intptr_t>(desc_->code_start()); - w->Write<intptr_t>(desc_->code_start() + desc_->code_size()); + w->WriteString(*desc_->GetFilename()); + w->Write<intptr_t>(desc_->CodeStart()); + w->Write<intptr_t>(desc_->CodeStart() + desc_->CodeSize()); w->Write<uint32_t>(0); size.set(static_cast<uint32_t>(w->position() - start)); return true; @@ -829,7 +872,7 @@ class DebugLineSection : public ELFSection { w->Write<uint8_t>(1); // DW_LNS_SET_COLUMN operands count. w->Write<uint8_t>(0); // DW_LNS_NEGATE_STMT operands count. w->Write<uint8_t>(0); // Empty include_directories sequence. - w->WriteString(*desc_->filename()); // File name. + w->WriteString(*desc_->GetFilename()); // File name. w->WriteULEB128(0); // Current directory. w->WriteULEB128(0); // Unknown modification time. w->WriteULEB128(0); // Unknown file size. @@ -837,7 +880,7 @@ class DebugLineSection : public ELFSection { prologue_length.set(static_cast<uint32_t>(w->position() - prologue_start)); WriteExtendedOpcode(w, DW_LNE_SET_ADDRESS, sizeof(intptr_t)); - w->Write<intptr_t>(desc_->code_start()); + w->Write<intptr_t>(desc_->CodeStart()); intptr_t pc = 0; intptr_t line = 1; @@ -900,12 +943,238 @@ class DebugLineSection : public ELFSection { }; +#ifdef V8_TARGET_ARCH_X64 + + +class UnwindInfoSection : public ELFSection { + public: + explicit UnwindInfoSection(CodeDescription *desc); + virtual bool WriteBody(Writer *w); + + int WriteCIE(Writer *w); + void WriteFDE(Writer *w, int); + + void WriteFDEStateOnEntry(Writer *w); + void WriteFDEStateAfterRBPPush(Writer *w); + void WriteFDEStateAfterRBPSet(Writer *w); + void WriteFDEStateAfterRBPPop(Writer *w); + + void WriteLength(Writer *w, + Writer::Slot<uint32_t>* length_slot, + int initial_position); + + private: + CodeDescription *desc_; + + // DWARF3 Specification, Table 7.23 + enum CFIInstructions { + DW_CFA_ADVANCE_LOC = 0x40, + DW_CFA_OFFSET = 0x80, + DW_CFA_RESTORE = 0xC0, + DW_CFA_NOP = 0x00, + DW_CFA_SET_LOC = 0x01, + DW_CFA_ADVANCE_LOC1 = 0x02, + DW_CFA_ADVANCE_LOC2 = 0x03, + DW_CFA_ADVANCE_LOC4 = 0x04, + DW_CFA_OFFSET_EXTENDED = 0x05, + DW_CFA_RESTORE_EXTENDED = 0x06, + DW_CFA_UNDEFINED = 0x07, + DW_CFA_SAME_VALUE = 0x08, + DW_CFA_REGISTER = 0x09, + DW_CFA_REMEMBER_STATE = 0x0A, + DW_CFA_RESTORE_STATE = 0x0B, + DW_CFA_DEF_CFA = 0x0C, + DW_CFA_DEF_CFA_REGISTER = 0x0D, + DW_CFA_DEF_CFA_OFFSET = 0x0E, + + DW_CFA_DEF_CFA_EXPRESSION = 0x0F, + DW_CFA_EXPRESSION = 0x10, + DW_CFA_OFFSET_EXTENDED_SF = 0x11, + DW_CFA_DEF_CFA_SF = 0x12, + DW_CFA_DEF_CFA_OFFSET_SF = 0x13, + DW_CFA_VAL_OFFSET = 0x14, + DW_CFA_VAL_OFFSET_SF = 0x15, + DW_CFA_VAL_EXPRESSION = 0x16 + }; + + // System V ABI, AMD64 Supplement, Version 0.99.5, Figure 3.36 + enum RegisterMapping { + // Only the relevant ones have been added to reduce clutter. + AMD64_RBP = 6, + AMD64_RSP = 7, + AMD64_RA = 16 + }; + + enum CFIConstants { + CIE_ID = 0, + CIE_VERSION = 1, + CODE_ALIGN_FACTOR = 1, + DATA_ALIGN_FACTOR = 1, + RETURN_ADDRESS_REGISTER = AMD64_RA + }; +}; + + +void UnwindInfoSection::WriteLength(Writer *w, + Writer::Slot<uint32_t>* length_slot, + int initial_position) { + uint32_t align = (w->position() - initial_position) % kPointerSize; + + if (align != 0) { + for (uint32_t i = 0; i < (kPointerSize - align); i++) { + w->Write<uint8_t>(DW_CFA_NOP); + } + } + + ASSERT((w->position() - initial_position) % kPointerSize == 0); + length_slot->set(w->position() - initial_position); +} + + +UnwindInfoSection::UnwindInfoSection(CodeDescription *desc) + : ELFSection(".eh_frame", TYPE_X86_64_UNWIND, 1), desc_(desc) +{ } + +int UnwindInfoSection::WriteCIE(Writer *w) { + Writer::Slot<uint32_t> cie_length_slot = w->CreateSlotHere<uint32_t>(); + uint32_t cie_position = w->position(); + + // Write out the CIE header. Currently no 'common instructions' are + // emitted onto the CIE; every FDE has its own set of instructions. + + w->Write<uint32_t>(CIE_ID); + w->Write<uint8_t>(CIE_VERSION); + w->Write<uint8_t>(0); // Null augmentation string. + w->WriteSLEB128(CODE_ALIGN_FACTOR); + w->WriteSLEB128(DATA_ALIGN_FACTOR); + w->Write<uint8_t>(RETURN_ADDRESS_REGISTER); + + WriteLength(w, &cie_length_slot, cie_position); + + return cie_position; +} + + +void UnwindInfoSection::WriteFDE(Writer *w, int cie_position) { + // The only FDE for this function. The CFA is the current RBP. + Writer::Slot<uint32_t> fde_length_slot = w->CreateSlotHere<uint32_t>(); + int fde_position = w->position(); + w->Write<int32_t>(fde_position - cie_position + 4); + + w->Write<uintptr_t>(desc_->CodeStart()); + w->Write<uintptr_t>(desc_->CodeSize()); + + WriteFDEStateOnEntry(w); + WriteFDEStateAfterRBPPush(w); + WriteFDEStateAfterRBPSet(w); + WriteFDEStateAfterRBPPop(w); + + WriteLength(w, &fde_length_slot, fde_position); +} + + +void UnwindInfoSection::WriteFDEStateOnEntry(Writer *w) { + // The first state, just after the control has been transferred to the the + // function. + + // RBP for this function will be the value of RSP after pushing the RBP + // for the previous function. The previous RBP has not been pushed yet. + w->Write<uint8_t>(DW_CFA_DEF_CFA_SF); + w->WriteULEB128(AMD64_RSP); + w->WriteSLEB128(-kPointerSize); + + // The RA is stored at location CFA + kCallerPCOffset. This is an invariant, + // and hence omitted from the next states. + w->Write<uint8_t>(DW_CFA_OFFSET_EXTENDED); + w->WriteULEB128(AMD64_RA); + w->WriteSLEB128(StandardFrameConstants::kCallerPCOffset); + + // The RBP of the previous function is still in RBP. + w->Write<uint8_t>(DW_CFA_SAME_VALUE); + w->WriteULEB128(AMD64_RBP); + + // Last location described by this entry. + w->Write<uint8_t>(DW_CFA_SET_LOC); + w->Write<uint64_t>( + desc_->GetStackStateStartAddress(CodeDescription::POST_RBP_PUSH)); +} + + +void UnwindInfoSection::WriteFDEStateAfterRBPPush(Writer *w) { + // The second state, just after RBP has been pushed. + + // RBP / CFA for this function is now the current RSP, so just set the + // offset from the previous rule (from -8) to 0. + w->Write<uint8_t>(DW_CFA_DEF_CFA_OFFSET); + w->WriteULEB128(0); + + // The previous RBP is stored at CFA + kCallerFPOffset. This is an invariant + // in this and the next state, and hence omitted in the next state. + w->Write<uint8_t>(DW_CFA_OFFSET_EXTENDED); + w->WriteULEB128(AMD64_RBP); + w->WriteSLEB128(StandardFrameConstants::kCallerFPOffset); + + // Last location described by this entry. + w->Write<uint8_t>(DW_CFA_SET_LOC); + w->Write<uint64_t>( + desc_->GetStackStateStartAddress(CodeDescription::POST_RBP_SET)); +} + + +void UnwindInfoSection::WriteFDEStateAfterRBPSet(Writer *w) { + // The third state, after the RBP has been set. + + // The CFA can now directly be set to RBP. + w->Write<uint8_t>(DW_CFA_DEF_CFA); + w->WriteULEB128(AMD64_RBP); + w->WriteULEB128(0); + + // Last location described by this entry. + w->Write<uint8_t>(DW_CFA_SET_LOC); + w->Write<uint64_t>( + desc_->GetStackStateStartAddress(CodeDescription::POST_RBP_POP)); +} + + +void UnwindInfoSection::WriteFDEStateAfterRBPPop(Writer *w) { + // The fourth (final) state. The RBP has been popped (just before issuing a + // return). + + // The CFA can is now calculated in the same way as in the first state. + w->Write<uint8_t>(DW_CFA_DEF_CFA_SF); + w->WriteULEB128(AMD64_RSP); + w->WriteSLEB128(-kPointerSize); + + // The RBP + w->Write<uint8_t>(DW_CFA_OFFSET_EXTENDED); + w->WriteULEB128(AMD64_RBP); + w->WriteSLEB128(StandardFrameConstants::kCallerFPOffset); + + // Last location described by this entry. + w->Write<uint8_t>(DW_CFA_SET_LOC); + w->Write<uint64_t>(desc_->CodeEnd()); +} + + +bool UnwindInfoSection::WriteBody(Writer *w) { + uint32_t cie_position = WriteCIE(w); + WriteFDE(w, cie_position); + return true; +} + + +#endif // V8_TARGET_ARCH_X64 + + static void CreateDWARFSections(CodeDescription* desc, ELF* elf) { - if (desc->is_line_info_available()) { + if (desc->IsLineInfoAvailable()) { elf->AddSection(new DebugInfoSection(desc)); elf->AddSection(new DebugAbbrevSection); elf->AddSection(new DebugLineSection(desc)); } +#ifdef V8_TARGET_ARCH_X64 + elf->AddSection(new UnwindInfoSection(desc)); +#endif } @@ -1005,9 +1274,9 @@ static JITCodeEntry* CreateELFObject(CodeDescription* desc) { new FullHeaderELFSection(".text", ELFSection::TYPE_NOBITS, kCodeAlignment, - desc->code_start(), + desc->CodeStart(), 0, - desc->code_size(), + desc->CodeSize(), ELFSection::FLAG_ALLOC | ELFSection::FLAG_EXEC)); CreateSymbolsTable(desc, &elf, text_section_index); @@ -1065,15 +1334,66 @@ void GDBJITInterface::AddCode(Handle<String> name, if (!name.is_null()) { SmartPointer<char> name_cstring = name->ToCString(DISALLOW_NULLS); - AddCode(*name_cstring, *code, *script); + AddCode(*name_cstring, *code, GDBJITInterface::FUNCTION, *script); + } else { + AddCode("", *code, GDBJITInterface::FUNCTION, *script); + } +} + +static void AddUnwindInfo(CodeDescription *desc) { +#ifdef V8_TARGET_ARCH_X64 + if (desc->tag() == GDBJITInterface::FUNCTION) { + // To avoid propagating unwinding information through + // compilation pipeline we rely on function prologue + // and epilogue being the same for all code objects generated + // by the full code generator. + static const int kFramePointerPushOffset = 1; + static const int kFramePointerSetOffset = 4; + static const int kFramePointerPopOffset = -3; + + uintptr_t frame_pointer_push_address = + desc->CodeStart() + kFramePointerPushOffset; + + uintptr_t frame_pointer_set_address = + desc->CodeStart() + kFramePointerSetOffset; + + uintptr_t frame_pointer_pop_address = + desc->CodeEnd() + kFramePointerPopOffset; + +#ifdef DEBUG + static const uint8_t kFramePointerPushInstruction = 0x48; // push ebp + static const uint16_t kFramePointerSetInstruction = 0x5756; // mov ebp, esp + static const uint8_t kFramePointerPopInstruction = 0xBE; // pop ebp + + ASSERT(*reinterpret_cast<uint8_t*>(frame_pointer_push_address) == + kFramePointerPushInstruction); + ASSERT(*reinterpret_cast<uint16_t*>(frame_pointer_set_address) == + kFramePointerSetInstruction); + ASSERT(*reinterpret_cast<uint8_t*>(frame_pointer_pop_address) == + kFramePointerPopInstruction); +#endif + + desc->SetStackStateStartAddress(CodeDescription::POST_RBP_PUSH, + frame_pointer_push_address); + desc->SetStackStateStartAddress(CodeDescription::POST_RBP_SET, + frame_pointer_set_address); + desc->SetStackStateStartAddress(CodeDescription::POST_RBP_POP, + frame_pointer_pop_address); } else { - AddCode("", *code, *script); + desc->SetStackStateStartAddress(CodeDescription::POST_RBP_PUSH, + desc->CodeStart()); + desc->SetStackStateStartAddress(CodeDescription::POST_RBP_SET, + desc->CodeStart()); + desc->SetStackStateStartAddress(CodeDescription::POST_RBP_POP, + desc->CodeEnd()); } +#endif // V8_TARGET_ARCH_X64 } void GDBJITInterface::AddCode(const char* name, Code* code, + GDBJITInterface::CodeTag tag, Script* script) { if (!FLAG_gdbjit) return; AssertNoAllocation no_gc; @@ -1086,14 +1406,16 @@ void GDBJITInterface::AddCode(const char* name, code, script != NULL ? Handle<Script>(script) : Handle<Script>(), - lineinfo); + lineinfo, + tag); - if (!FLAG_gdbjit_full && !code_desc.is_line_info_available()) { + if (!FLAG_gdbjit_full && !code_desc.IsLineInfoAvailable()) { delete lineinfo; entries.Remove(code, HashForCodeObject(code)); return; } + AddUnwindInfo(&code_desc); JITCodeEntry* entry = CreateELFObject(&code_desc); ASSERT(!IsLineInfoTagged(entry)); @@ -1120,7 +1442,7 @@ void GDBJITInterface::AddCode(GDBJITInterface::CodeTag tag, builder.AddFormatted(": code object %p", static_cast<void*>(code)); } - AddCode(builder.Finalize(), code); + AddCode(builder.Finalize(), code, tag); } diff --git a/deps/v8/src/gdb-jit.h b/deps/v8/src/gdb-jit.h index 5d348b69a1..d46fec63a6 100644 --- a/deps/v8/src/gdb-jit.h +++ b/deps/v8/src/gdb-jit.h @@ -55,7 +55,8 @@ namespace internal { V(STUB) \ V(BUILTIN) \ V(SCRIPT) \ - V(EVAL) + V(EVAL) \ + V(FUNCTION) class GDBJITLineInfo : public Malloced { public: @@ -109,6 +110,7 @@ class GDBJITInterface: public AllStatic { static void AddCode(const char* name, Code* code, + CodeTag tag, Script* script = NULL); static void AddCode(Handle<String> name, diff --git a/deps/v8/src/hashmap.h b/deps/v8/src/hashmap.h index 3b947beb53..27989889c3 100644 --- a/deps/v8/src/hashmap.h +++ b/deps/v8/src/hashmap.h @@ -49,7 +49,8 @@ class HashMap { typedef bool (*MatchFun) (void* key1, void* key2); // Dummy constructor. This constructor doesn't set up the hash - // map properly so don't use it unless you have good reason. + // map properly so don't use it unless you have good reason (e.g., + // you know that the HashMap will never be used). HashMap(); // initial_capacity is the size of the initial hash map; diff --git a/deps/v8/src/heap.cc b/deps/v8/src/heap.cc index 7c7f3d269e..0093829b1c 100644 --- a/deps/v8/src/heap.cc +++ b/deps/v8/src/heap.cc @@ -1826,6 +1826,12 @@ bool Heap::CreateInitialMaps() { } set_shared_function_info_map(Map::cast(obj)); + { MaybeObject* maybe_obj = AllocateMap(JS_MESSAGE_OBJECT_TYPE, + JSMessageObject::kSize); + if (!maybe_obj->ToObject(&obj)) return false; + } + set_message_object_map(Map::cast(obj)); + ASSERT(!Heap::InNewSpace(Heap::empty_fixed_array())); return true; } @@ -2329,6 +2335,32 @@ MaybeObject* Heap::AllocateSharedFunctionInfo(Object* name) { } +MaybeObject* Heap::AllocateJSMessageObject(String* type, + JSArray* arguments, + int start_position, + int end_position, + Object* script, + Object* stack_trace, + Object* stack_frames) { + Object* result; + { MaybeObject* maybe_result = Allocate(message_object_map(), NEW_SPACE); + if (!maybe_result->ToObject(&result)) return maybe_result; + } + JSMessageObject* message = JSMessageObject::cast(result); + message->set_properties(Heap::empty_fixed_array()); + message->set_elements(Heap::empty_fixed_array()); + message->set_type(type); + message->set_arguments(arguments); + message->set_start_position(start_position); + message->set_end_position(end_position); + message->set_script(script); + message->set_stack_trace(stack_trace); + message->set_stack_frames(stack_frames); + return result; +} + + + // Returns true for a character in a range. Both limits are inclusive. static inline bool Between(uint32_t character, uint32_t from, uint32_t to) { // This makes uses of the the unsigned wraparound. diff --git a/deps/v8/src/heap.h b/deps/v8/src/heap.h index 1c86817aa8..e051b50235 100644 --- a/deps/v8/src/heap.h +++ b/deps/v8/src/heap.h @@ -94,6 +94,7 @@ namespace internal { V(Map, oddball_map, OddballMap) \ V(Map, global_property_cell_map, GlobalPropertyCellMap) \ V(Map, shared_function_info_map, SharedFunctionInfoMap) \ + V(Map, message_object_map, JSMessageObjectMap) \ V(Map, proxy_map, ProxyMap) \ V(Object, nan_value, NanValue) \ V(Object, minus_zero_value, MinusZeroValue) \ @@ -628,6 +629,19 @@ class Heap : public AllStatic { // Please note this does not perform a garbage collection. MUST_USE_RESULT static MaybeObject* AllocateSharedFunctionInfo(Object* name); + // Allocates a new JSMessageObject object. + // Returns Failure::RetryAfterGC(requested_bytes, space) if the allocation + // failed. + // Please note that this does not perform a garbage collection. + MUST_USE_RESULT static MaybeObject* AllocateJSMessageObject( + String* type, + JSArray* arguments, + int start_position, + int end_position, + Object* script, + Object* stack_trace, + Object* stack_frames); + // Allocates a new cons string object. // Returns Failure::RetryAfterGC(requested_bytes, space) if the allocation // failed. diff --git a/deps/v8/src/hydrogen-instructions.cc b/deps/v8/src/hydrogen-instructions.cc index 2f8b6e263d..c24ddfc80c 100644 --- a/deps/v8/src/hydrogen-instructions.cc +++ b/deps/v8/src/hydrogen-instructions.cc @@ -253,6 +253,7 @@ bool HValue::Equals(HValue* other) const { if (other->opcode() != opcode()) return false; if (!other->representation().Equals(representation())) return false; if (!other->type_.Equals(type_)) return false; + if (other->flags() != flags()) return false; if (OperandCount() != other->OperandCount()) return false; for (int i = 0; i < OperandCount(); ++i) { if (OperandAt(i)->id() != other->OperandAt(i)->id()) return false; diff --git a/deps/v8/src/hydrogen-instructions.h b/deps/v8/src/hydrogen-instructions.h index ff8170012e..eaab8adef2 100644 --- a/deps/v8/src/hydrogen-instructions.h +++ b/deps/v8/src/hydrogen-instructions.h @@ -64,6 +64,7 @@ class LChunkBuilder; #define HYDROGEN_CONCRETE_INSTRUCTION_LIST(V) \ + V(AbnormalExit) \ V(AccessArgumentsAt) \ V(Add) \ V(ApplyArguments) \ @@ -834,12 +835,11 @@ class HReturn: public HUnaryControlInstruction { }; -class HThrow: public HUnaryControlInstruction { +class HAbnormalExit: public HControlInstruction { public: - explicit HThrow(HValue* value) - : HUnaryControlInstruction(value, NULL, NULL) { } + HAbnormalExit() : HControlInstruction(NULL, NULL) { } - DECLARE_CONCRETE_INSTRUCTION(Throw, "throw") + DECLARE_CONCRETE_INSTRUCTION(AbnormalExit, "abnormal_exit") }; @@ -866,6 +866,20 @@ class HUnaryOperation: public HInstruction { }; +class HThrow: public HUnaryOperation { + public: + explicit HThrow(HValue* value) : HUnaryOperation(value) { + SetAllSideEffects(); + } + + virtual Representation RequiredInputRepresentation(int index) const { + return Representation::Tagged(); + } + + DECLARE_CONCRETE_INSTRUCTION(Throw, "throw") +}; + + class HChange: public HUnaryOperation { public: HChange(HValue* value, @@ -989,7 +1003,7 @@ class HStackCheck: public HInstruction { public: HStackCheck() { } - DECLARE_CONCRETE_INSTRUCTION(Throw, "stack_check") + DECLARE_CONCRETE_INSTRUCTION(StackCheck, "stack_check") }; @@ -1831,6 +1845,7 @@ class HApplyArguments: public HInstruction { SetOperandAt(1, receiver); SetOperandAt(2, length); SetOperandAt(3, elements); + SetAllSideEffects(); } virtual Representation RequiredInputRepresentation(int index) const { @@ -1850,8 +1865,6 @@ class HApplyArguments: public HInstruction { DECLARE_CONCRETE_INSTRUCTION(ApplyArguments, "apply_arguments") - - protected: virtual void InternalSetOperandAt(int index, HValue* value) { operands_[index] = value; @@ -3073,6 +3086,10 @@ class HTypeof: public HUnaryOperation { set_representation(Representation::Tagged()); } + virtual Representation RequiredInputRepresentation(int index) const { + return Representation::Tagged(); + } + DECLARE_CONCRETE_INSTRUCTION(Typeof, "typeof") }; diff --git a/deps/v8/src/hydrogen.cc b/deps/v8/src/hydrogen.cc index 84623069a0..9d5aa2be31 100644 --- a/deps/v8/src/hydrogen.cc +++ b/deps/v8/src/hydrogen.cc @@ -1813,15 +1813,6 @@ void HGraph::InsertRepresentationChangeForUse(HValue* value, HValue* use, Representation to, bool is_truncating) { - // Propagate flags for negative zero checks upwards from conversions - // int32-to-tagged and int32-to-double. - Representation from = value->representation(); - if (from.IsInteger32()) { - ASSERT(to.IsTagged() || to.IsDouble()); - BitVector visited(GetMaximumValueID()); - PropagateMinusZeroChecks(value, &visited); - } - // Insert the representation change right before its use. For phi-uses we // insert at the end of the corresponding predecessor. HBasicBlock* insert_block = use->block(); @@ -1984,6 +1975,30 @@ void HGraph::InsertRepresentationChanges() { } +void HGraph::ComputeMinusZeroChecks() { + BitVector visited(GetMaximumValueID()); + for (int i = 0; i < blocks_.length(); ++i) { + for (HInstruction* current = blocks_[i]->first(); + current != NULL; + current = current->next()) { + if (current->IsChange()) { + HChange* change = HChange::cast(current); + // Propagate flags for negative zero checks upwards from conversions + // int32-to-tagged and int32-to-double. + Representation from = change->value()->representation(); + ASSERT(from.Equals(change->from())); + if (from.IsInteger32()) { + ASSERT(change->to().IsTagged() || change->to().IsDouble()); + ASSERT(visited.IsEmpty()); + PropagateMinusZeroChecks(change->value(), &visited); + visited.Clear(); + } + } + } + } +} + + // Implementation of utility classes to represent an expression's context in // the AST. AstContext::AstContext(HGraphBuilder* owner, Expression::Context kind) @@ -2243,6 +2258,7 @@ HGraph* HGraphBuilder::CreateGraph(CompilationInfo* info) { graph_->InitializeInferredTypes(); graph_->Canonicalize(); graph_->InsertRepresentationChanges(); + graph_->ComputeMinusZeroChecks(); // Eliminate redundant stack checks on backwards branches. HStackCheckEliminator sce(graph_); @@ -3540,9 +3556,11 @@ void HGraphBuilder::VisitThrow(Throw* expr) { VISIT_FOR_VALUE(expr->exception()); HValue* value = environment()->Pop(); - HControlInstruction* instr = new HThrow(value); + HThrow* instr = new HThrow(value); instr->set_position(expr->position()); - current_subgraph_->FinishExit(instr); + AddInstruction(instr); + AddSimulate(expr->id()); + current_subgraph_->FinishExit(new HAbnormalExit); } diff --git a/deps/v8/src/hydrogen.h b/deps/v8/src/hydrogen.h index dbcb82e6e8..952c04fdec 100644 --- a/deps/v8/src/hydrogen.h +++ b/deps/v8/src/hydrogen.h @@ -307,6 +307,7 @@ class HGraph: public HSubgraph { void InitializeInferredTypes(); void InsertTypeConversions(); void InsertRepresentationChanges(); + void ComputeMinusZeroChecks(); bool ProcessArgumentsObject(); void EliminateRedundantPhis(); void Canonicalize(); diff --git a/deps/v8/src/ia32/code-stubs-ia32.cc b/deps/v8/src/ia32/code-stubs-ia32.cc index 006ee46ed4..a9c3085bad 100644 --- a/deps/v8/src/ia32/code-stubs-ia32.cc +++ b/deps/v8/src/ia32/code-stubs-ia32.cc @@ -3499,10 +3499,12 @@ void MathPowStub::Generate(MacroAssembler* masm) { __ j(not_equal, ¬_minus_half); // Calculates reciprocal of square root. - // Note that 1/sqrt(x) = sqrt(1/x)) - __ divsd(xmm3, xmm0); - __ movsd(xmm1, xmm3); + // sqrtsd returns -0 when input is -0. ECMA spec requires +0. + __ xorpd(xmm1, xmm1); + __ addsd(xmm1, xmm0); __ sqrtsd(xmm1, xmm1); + __ divsd(xmm3, xmm1); + __ movsd(xmm1, xmm3); __ jmp(&allocate_return); // Test for 0.5. @@ -3514,7 +3516,9 @@ void MathPowStub::Generate(MacroAssembler* masm) { __ ucomisd(xmm2, xmm1); __ j(not_equal, &call_runtime); // Calculates square root. - __ movsd(xmm1, xmm0); + // sqrtsd returns -0 when input is -0. ECMA spec requires +0. + __ xorpd(xmm1, xmm1); + __ addsd(xmm1, xmm0); __ sqrtsd(xmm1, xmm1); __ bind(&allocate_return); diff --git a/deps/v8/src/ia32/codegen-ia32.cc b/deps/v8/src/ia32/codegen-ia32.cc index 2b48b0bc99..73c952a351 100644 --- a/deps/v8/src/ia32/codegen-ia32.cc +++ b/deps/v8/src/ia32/codegen-ia32.cc @@ -7951,10 +7951,12 @@ void CodeGenerator::GenerateMathPow(ZoneList<Expression*>* args) { __ j(not_equal, ¬_minus_half); // Calculates reciprocal of square root. - // Note that 1/sqrt(x) = sqrt(1/x)) - __ divsd(xmm3, xmm0); - __ movsd(xmm1, xmm3); + // sqrtsd returns -0 when input is -0. ECMA spec requires +0. + __ xorpd(xmm1, xmm1); + __ addsd(xmm1, xmm0); __ sqrtsd(xmm1, xmm1); + __ divsd(xmm3, xmm1); + __ movsd(xmm1, xmm3); __ jmp(&allocate_return); // Test for 0.5. @@ -7966,7 +7968,9 @@ void CodeGenerator::GenerateMathPow(ZoneList<Expression*>* args) { __ ucomisd(xmm2, xmm1); call_runtime.Branch(not_equal); // Calculates square root. - __ movsd(xmm1, xmm0); + // sqrtsd returns -0 when input is -0. ECMA spec requires +0. + __ xorpd(xmm1, xmm1); + __ addsd(xmm1, xmm0); __ sqrtsd(xmm1, xmm1); JumpTarget done; diff --git a/deps/v8/src/ia32/deoptimizer-ia32.cc b/deps/v8/src/ia32/deoptimizer-ia32.cc index e9e3fcfb7f..35c671365d 100644 --- a/deps/v8/src/ia32/deoptimizer-ia32.cc +++ b/deps/v8/src/ia32/deoptimizer-ia32.cc @@ -37,9 +37,14 @@ namespace v8 { namespace internal { - int Deoptimizer::table_entry_size_ = 10; + +int Deoptimizer::patch_size() { + return Assembler::kCallInstructionLength; +} + + void Deoptimizer::DeoptimizeFunction(JSFunction* function) { AssertNoAllocation no_allocation; @@ -48,14 +53,19 @@ void Deoptimizer::DeoptimizeFunction(JSFunction* function) { // Get the optimized code. Code* code = function->code(); - // Invalidate the relocation information, as it will become invalid by the - // code patching below, and is not needed any more. - code->InvalidateRelocation(); - // For each return after a safepoint insert a absolute call to the // corresponding deoptimization entry. unsigned last_pc_offset = 0; SafepointTable table(function->code()); + + // We will overwrite the code's relocation info in-place. Relocation info + // is written backward. The relocation info is the payload of a byte array. + // Later on we will align this at the start of the byte array and create + // a trash byte array of the remaining space. + ByteArray* reloc_info = code->relocation_info(); + Address end_address = reloc_info->address() + reloc_info->Size(); + RelocInfoWriter reloc_info_writer(end_address, code->instruction_start()); + for (unsigned i = 0; i < table.length(); i++) { unsigned pc_offset = table.GetPcOffset(i); SafepointEntry safepoint_entry = table.GetEntry(i); @@ -72,12 +82,15 @@ void Deoptimizer::DeoptimizeFunction(JSFunction* function) { #endif last_pc_offset = pc_offset; if (deoptimization_index != Safepoint::kNoDeoptimizationIndex) { - CodePatcher patcher( - code->instruction_start() + pc_offset + gap_code_size, - Assembler::kCallInstructionLength); - patcher.masm()->call(GetDeoptimizationEntry(deoptimization_index, LAZY), - RelocInfo::NONE); - last_pc_offset += gap_code_size + Assembler::kCallInstructionLength; + last_pc_offset += gap_code_size; + Address call_pc = code->instruction_start() + last_pc_offset; + CodePatcher patcher(call_pc, patch_size()); + Address entry = GetDeoptimizationEntry(deoptimization_index, LAZY); + patcher.masm()->call(entry, RelocInfo::NONE); + last_pc_offset += patch_size(); + RelocInfo rinfo(call_pc + 1, RelocInfo::RUNTIME_ENTRY, + reinterpret_cast<intptr_t>(entry)); + reloc_info_writer.Write(&rinfo); } } #ifdef DEBUG @@ -90,6 +103,40 @@ void Deoptimizer::DeoptimizeFunction(JSFunction* function) { } #endif + // Move the relocation info to the beginning of the byte array. + int reloc_size = end_address - reloc_info_writer.pos(); + memmove(code->relocation_start(), reloc_info_writer.pos(), reloc_size); + + // The relocation info is in place, update the size. + reloc_info->set_length(reloc_size); + + // Handle the junk part after the new relocation info. We will create + // a non-live object in the extra space at the end of the former reloc info. + Address junk = reloc_info->address() + reloc_info->Size(); + ASSERT(junk <= end_address); + + if (end_address - junk <= ByteArray::kHeaderSize) { + // We get in here if there is not enough space for a ByteArray. + + // Both addresses are kPointerSize alligned. + CHECK_EQ((end_address - junk) % 4, 0); + Map* filler_map = Heap::one_pointer_filler_map(); + while (junk < end_address) { + HeapObject::FromAddress(junk)->set_map(filler_map); + junk += kPointerSize; + } + } else { + int size = end_address - junk; + // Since the reloc_end address and junk are both alligned, we shouild, + // never have junk which is not a multipla of kPointerSize. + CHECK_EQ(size % kPointerSize, 0); + CHECK_GT(size, 0); + HeapObject* junk_object = HeapObject::FromAddress(junk); + junk_object->set_map(Heap::byte_array_map()); + int length = ByteArray::LengthFor(end_address - junk); + ByteArray::cast(junk_object)->set_length(length); + } + // Add the deoptimizing code to the list. DeoptimizingCodeListNode* node = new DeoptimizingCodeListNode(code); node->set_next(deoptimizing_code_list_); @@ -106,71 +153,53 @@ void Deoptimizer::DeoptimizeFunction(JSFunction* function) { } -void Deoptimizer::PatchStackCheckCode(Code* unoptimized_code, - Code* check_code, - Code* replacement_code) { - // Iterate the unoptimized code and patch every stack check except at - // the function entry. This code assumes the function entry stack - // check appears first i.e., is not deferred or otherwise reordered. - ASSERT(unoptimized_code->kind() == Code::FUNCTION); - bool first = true; - for (RelocIterator it(unoptimized_code, RelocInfo::kCodeTargetMask); - !it.done(); - it.next()) { - RelocInfo* rinfo = it.rinfo(); - if (rinfo->target_address() == Code::cast(check_code)->entry()) { - if (first) { - first = false; - } else { - // The stack check code matches the pattern: - // - // cmp esp, <limit> - // jae ok - // call <stack guard> - // test eax, <loop nesting depth> - // ok: ... - // - // We will patch away the branch so the code is: - // - // cmp esp, <limit> ;; Not changed - // nop - // nop - // call <on-stack replacment> - // test eax, <loop nesting depth> - // ok: - Address call_target_address = rinfo->pc(); - ASSERT(*(call_target_address - 3) == 0x73 && // jae - *(call_target_address - 2) == 0x07 && // offset - *(call_target_address - 1) == 0xe8); // call - *(call_target_address - 3) = 0x90; // nop - *(call_target_address - 2) = 0x90; // nop - rinfo->set_target_address(replacement_code->entry()); - } - } - } +void Deoptimizer::PatchStackCheckCodeAt(Address pc_after, + Code* check_code, + Code* replacement_code) { + Address call_target_address = pc_after - kPointerSize; + ASSERT(check_code->entry() == + Assembler::target_address_at(call_target_address)); + // The stack check code matches the pattern: + // + // cmp esp, <limit> + // jae ok + // call <stack guard> + // test eax, <loop nesting depth> + // ok: ... + // + // We will patch away the branch so the code is: + // + // cmp esp, <limit> ;; Not changed + // nop + // nop + // call <on-stack replacment> + // test eax, <loop nesting depth> + // ok: + ASSERT(*(call_target_address - 3) == 0x73 && // jae + *(call_target_address - 2) == 0x07 && // offset + *(call_target_address - 1) == 0xe8); // call + *(call_target_address - 3) = 0x90; // nop + *(call_target_address - 2) = 0x90; // nop + Assembler::set_target_address_at(call_target_address, + replacement_code->entry()); } -void Deoptimizer::RevertStackCheckCode(Code* unoptimized_code, - Code* check_code, - Code* replacement_code) { - // Iterate the unoptimized code and revert all the patched stack checks. - for (RelocIterator it(unoptimized_code, RelocInfo::kCodeTargetMask); - !it.done(); - it.next()) { - RelocInfo* rinfo = it.rinfo(); - if (rinfo->target_address() == replacement_code->entry()) { - // Replace the nops from patching (Deoptimizer::PatchStackCheckCode) to - // restore the conditional branch. - Address call_target_address = rinfo->pc(); - ASSERT(*(call_target_address - 3) == 0x90 && // nop - *(call_target_address - 2) == 0x90 && // nop - *(call_target_address - 1) == 0xe8); // call - *(call_target_address - 3) = 0x73; // jae - *(call_target_address - 2) = 0x07; // offset - rinfo->set_target_address(check_code->entry()); - } - } +void Deoptimizer::RevertStackCheckCodeAt(Address pc_after, + Code* check_code, + Code* replacement_code) { + Address call_target_address = pc_after - kPointerSize; + ASSERT(replacement_code->entry() == + Assembler::target_address_at(call_target_address)); + // Replace the nops from patching (Deoptimizer::PatchStackCheckCode) to + // restore the conditional branch. + ASSERT(*(call_target_address - 3) == 0x90 && // nop + *(call_target_address - 2) == 0x90 && // nop + *(call_target_address - 1) == 0xe8); // call + *(call_target_address - 3) = 0x73; // jae + *(call_target_address - 2) = 0x07; // offset + Assembler::set_target_address_at(call_target_address, + check_code->entry()); } diff --git a/deps/v8/src/ia32/lithium-codegen-ia32.cc b/deps/v8/src/ia32/lithium-codegen-ia32.cc index d35bfc9a2b..ae8fe8d65a 100644 --- a/deps/v8/src/ia32/lithium-codegen-ia32.cc +++ b/deps/v8/src/ia32/lithium-codegen-ia32.cc @@ -37,6 +37,8 @@ namespace v8 { namespace internal { +// When invoking builtins, we need to record the safepoint in the middle of +// the invoke instruction sequence generated by the macro assembler. class SafepointGenerator : public PostCallGenerator { public: SafepointGenerator(LCodeGen* codegen, @@ -366,17 +368,11 @@ void LCodeGen::AddToTranslation(Translation* translation, void LCodeGen::CallCode(Handle<Code> code, RelocInfo::Mode mode, LInstruction* instr) { - if (instr != NULL) { - LPointerMap* pointers = instr->pointer_map(); - RecordPosition(pointers->position()); - __ call(code, mode); - RegisterLazyDeoptimization(instr); - } else { - LPointerMap no_pointers(0); - RecordPosition(no_pointers.position()); - __ call(code, mode); - RecordSafepoint(&no_pointers, Safepoint::kNoDeoptimizationIndex); - } + ASSERT(instr != NULL); + LPointerMap* pointers = instr->pointer_map(); + RecordPosition(pointers->position()); + __ call(code, mode); + RegisterLazyDeoptimization(instr); // Signal that we don't inline smi code before these stubs in the // optimizing code generator. @@ -391,22 +387,12 @@ void LCodeGen::CallRuntime(Runtime::Function* function, int num_arguments, LInstruction* instr) { ASSERT(instr != NULL); + ASSERT(instr->HasPointerMap()); LPointerMap* pointers = instr->pointer_map(); - ASSERT(pointers != NULL); RecordPosition(pointers->position()); __ CallRuntime(function, num_arguments); - // Runtime calls to Throw are not supposed to ever return at the - // call site, so don't register lazy deoptimization for these. We do - // however have to record a safepoint since throwing exceptions can - // cause garbage collections. - // BUG(3243555): register a lazy deoptimization point at throw. We need - // it to be able to inline functions containing a throw statement. - if (!instr->IsThrow()) { - RegisterLazyDeoptimization(instr); - } else { - RecordSafepoint(instr->pointer_map(), Safepoint::kNoDeoptimizationIndex); - } + RegisterLazyDeoptimization(instr); } @@ -2145,11 +2131,16 @@ void LCodeGen::DoApplyArguments(LApplyArguments* instr) { // Invoke the function. __ bind(&invoke); + ASSERT(instr->HasPointerMap() && instr->HasDeoptimizationEnvironment()); + LPointerMap* pointers = instr->pointer_map(); + LEnvironment* env = instr->deoptimization_environment(); + RecordPosition(pointers->position()); + RegisterEnvironmentForDeoptimization(env); + SafepointGenerator safepoint_generator(this, + pointers, + env->deoptimization_index()); ASSERT(receiver.is(eax)); v8::internal::ParameterCount actual(eax); - SafepointGenerator safepoint_generator(this, - instr->pointer_map(), - Safepoint::kNoDeoptimizationIndex); __ InvokeFunction(edi, actual, CALL_FUNCTION, &safepoint_generator); } @@ -2397,6 +2388,8 @@ void LCodeGen::DoMathPowHalf(LUnaryMathOperation* instr) { __ movdbl(xmm_scratch, Operand::StaticVariable(negative_infinity)); __ ucomisd(xmm_scratch, input_reg); DeoptimizeIf(equal, instr->environment()); + __ xorpd(xmm_scratch, xmm_scratch); + __ addsd(input_reg, xmm_scratch); // Convert -0 to +0. __ sqrtsd(input_reg, input_reg); } @@ -3575,10 +3568,14 @@ void LCodeGen::DoDeleteProperty(LDeleteProperty* instr) { } else { __ push(ToOperand(key)); } - RecordPosition(instr->pointer_map()->position()); + ASSERT(instr->HasPointerMap() && instr->HasDeoptimizationEnvironment()); + LPointerMap* pointers = instr->pointer_map(); + LEnvironment* env = instr->deoptimization_environment(); + RecordPosition(pointers->position()); + RegisterEnvironmentForDeoptimization(env); SafepointGenerator safepoint_generator(this, - instr->pointer_map(), - Safepoint::kNoDeoptimizationIndex); + pointers, + env->deoptimization_index()); __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION, &safepoint_generator); } diff --git a/deps/v8/src/ia32/lithium-ia32.cc b/deps/v8/src/ia32/lithium-ia32.cc index 100a2d44fa..2070367320 100644 --- a/deps/v8/src/ia32/lithium-ia32.cc +++ b/deps/v8/src/ia32/lithium-ia32.cc @@ -658,16 +658,16 @@ LInstruction* LChunkBuilder::AssignEnvironment(LInstruction* instr) { LInstruction* LChunkBuilder::SetInstructionPendingDeoptimizationEnvironment( LInstruction* instr, int ast_id) { - ASSERT(instructions_pending_deoptimization_environment_ == NULL); + ASSERT(instruction_pending_deoptimization_environment_ == NULL); ASSERT(pending_deoptimization_ast_id_ == AstNode::kNoNumber); - instructions_pending_deoptimization_environment_ = instr; + instruction_pending_deoptimization_environment_ = instr; pending_deoptimization_ast_id_ = ast_id; return instr; } void LChunkBuilder::ClearInstructionPendingDeoptimizationEnvironment() { - instructions_pending_deoptimization_environment_ = NULL; + instruction_pending_deoptimization_environment_ = NULL; pending_deoptimization_ast_id_ = AstNode::kNoNumber; } @@ -1507,6 +1507,13 @@ LInstruction* LChunkBuilder::DoBoundsCheck(HBoundsCheck* instr) { } +LInstruction* LChunkBuilder::DoAbnormalExit(HAbnormalExit* instr) { + // The control instruction marking the end of a block that completed + // abruptly (e.g., threw an exception). There is nothing specific to do. + return NULL; +} + + LInstruction* LChunkBuilder::DoThrow(HThrow* instr) { LOperand* value = UseFixed(instr->value(), eax); return MarkAsCall(new LThrow(value), instr); @@ -1875,10 +1882,11 @@ LInstruction* LChunkBuilder::DoSimulate(HSimulate* instr) { // If there is an instruction pending deoptimization environment create a // lazy bailout instruction to capture the environment. - if (pending_deoptimization_ast_id_ == instr->ast_id()) { + if (pending_deoptimization_ast_id_ != AstNode::kNoNumber) { + ASSERT(pending_deoptimization_ast_id_ == instr->ast_id()); LLazyBailout* lazy_bailout = new LLazyBailout; LInstruction* result = AssignEnvironment(lazy_bailout); - instructions_pending_deoptimization_environment_-> + instruction_pending_deoptimization_environment_-> set_deoptimization_environment(result->environment()); ClearInstructionPendingDeoptimizationEnvironment(); return result; diff --git a/deps/v8/src/ia32/lithium-ia32.h b/deps/v8/src/ia32/lithium-ia32.h index 1cdd31ede8..1adc13e4d4 100644 --- a/deps/v8/src/ia32/lithium-ia32.h +++ b/deps/v8/src/ia32/lithium-ia32.h @@ -1881,7 +1881,7 @@ class LChunkBuilder BASE_EMBEDDED { argument_count_(0), allocator_(allocator), position_(RelocInfo::kNoPosition), - instructions_pending_deoptimization_environment_(NULL), + instruction_pending_deoptimization_environment_(NULL), pending_deoptimization_ast_id_(AstNode::kNoNumber) { } // Build the sequence for the graph. @@ -2015,7 +2015,7 @@ class LChunkBuilder BASE_EMBEDDED { int argument_count_; LAllocator* allocator_; int position_; - LInstruction* instructions_pending_deoptimization_environment_; + LInstruction* instruction_pending_deoptimization_environment_; int pending_deoptimization_ast_id_; DISALLOW_COPY_AND_ASSIGN(LChunkBuilder); diff --git a/deps/v8/src/lithium-allocator.cc b/deps/v8/src/lithium-allocator.cc index cac7d65e98..81877f3768 100644 --- a/deps/v8/src/lithium-allocator.cc +++ b/deps/v8/src/lithium-allocator.cc @@ -1068,9 +1068,7 @@ void LAllocator::ResolveControlFlow(LiveRange* range, HBasicBlock* block, HBasicBlock* pred) { LifetimePosition pred_end = - LifetimePosition::FromInstructionIndex(pred->last_instruction_index()). - PrevInstruction(); - + LifetimePosition::FromInstructionIndex(pred->last_instruction_index()); LifetimePosition cur_start = LifetimePosition::FromInstructionIndex(block->first_instruction_index()); LiveRange* pred_cover = NULL; @@ -1245,7 +1243,7 @@ void LAllocator::BuildLiveRanges() { LifetimePosition start = LifetimePosition::FromInstructionIndex( block->first_instruction_index()); LifetimePosition end = LifetimePosition::FromInstructionIndex( - back_edge->last_instruction_index()); + back_edge->last_instruction_index()).NextInstruction(); while (!iterator.Done()) { int operand_index = iterator.Current(); LiveRange* range = LiveRangeFor(operand_index); @@ -2019,6 +2017,11 @@ LiveRange* LAllocator::SplitAt(LiveRange* range, LifetimePosition pos) { if (pos.Value() <= range->Start().Value()) return range; + // We can't properly connect liveranges if split occured at the end + // of control instruction. + ASSERT(pos.IsInstructionStart() || + !chunk_->instructions()->at(pos.InstructionIndex())->IsControl()); + LiveRange* result = LiveRangeFor(next_virtual_register_++); range->SplitAt(pos, result); return result; diff --git a/deps/v8/src/messages.cc b/deps/v8/src/messages.cc index 42fc3c9bd6..432364919b 100644 --- a/deps/v8/src/messages.cc +++ b/deps/v8/src/messages.cc @@ -62,67 +62,45 @@ void MessageHandler::ReportMessage(const char* msg) { } -Handle<Object> MessageHandler::MakeMessageObject( +Handle<JSMessageObject> MessageHandler::MakeMessageObject( const char* type, MessageLocation* loc, Vector< Handle<Object> > args, Handle<String> stack_trace, Handle<JSArray> stack_frames) { - // Build error message object - v8::HandleScope scope; // Instantiate a closeable HandleScope for EscapeFrom. - Handle<Object> type_str = Factory::LookupAsciiSymbol(type); - Handle<Object> array = Factory::NewJSArray(args.length()); - for (int i = 0; i < args.length(); i++) - SetElement(Handle<JSArray>::cast(array), i, args[i]); - - Handle<JSFunction> fun(Top::global_context()->make_message_fun()); - int start, end; - Handle<Object> script; + Handle<String> type_handle = Factory::LookupAsciiSymbol(type); + Handle<JSArray> arguments_handle = Factory::NewJSArray(args.length()); + for (int i = 0; i < args.length(); i++) { + SetElement(arguments_handle, i, args[i]); + } + + int start = 0; + int end = 0; + Handle<Object> script_handle = Factory::undefined_value(); if (loc) { start = loc->start_pos(); end = loc->end_pos(); - script = GetScriptWrapper(loc->script()); - } else { - start = end = 0; - script = Factory::undefined_value(); + script_handle = GetScriptWrapper(loc->script()); } - Handle<Object> start_handle(Smi::FromInt(start)); - Handle<Object> end_handle(Smi::FromInt(end)); - Handle<Object> stack_trace_val = stack_trace.is_null() - ? Factory::undefined_value() - : Handle<Object>::cast(stack_trace); - Handle<Object> stack_frames_val = stack_frames.is_null() - ? Factory::undefined_value() - : Handle<Object>::cast(stack_frames); - const int argc = 7; - Object** argv[argc] = { type_str.location(), - array.location(), - start_handle.location(), - end_handle.location(), - script.location(), - stack_trace_val.location(), - stack_frames_val.location() }; - - // Setup a catch handler to catch exceptions in creating the message. This - // handler is non-verbose to avoid calling MakeMessage recursively in case of - // an exception. - v8::TryCatch catcher; - catcher.SetVerbose(false); - catcher.SetCaptureMessage(false); - - // Format the message. - bool caught_exception = false; - Handle<Object> message = - Execution::Call(fun, Factory::undefined_value(), argc, argv, - &caught_exception); - - // If creating the message (in JS code) resulted in an exception, we - // skip doing the callback. This usually only happens in case of - // stack overflow exceptions being thrown by the parser when the - // stack is almost full. - if (caught_exception) return Handle<Object>(); - - return message.EscapeFrom(&scope); + + Handle<Object> stack_trace_handle = stack_trace.is_null() + ? Factory::undefined_value() + : Handle<Object>::cast(stack_trace); + + Handle<Object> stack_frames_handle = stack_frames.is_null() + ? Factory::undefined_value() + : Handle<Object>::cast(stack_frames); + + Handle<JSMessageObject> message = + Factory::NewJSMessageObject(type_handle, + arguments_handle, + start, + end, + script_handle, + stack_trace_handle, + stack_frames_handle); + + return message; } diff --git a/deps/v8/src/messages.h b/deps/v8/src/messages.h index 440bde87e9..48f3244777 100644 --- a/deps/v8/src/messages.h +++ b/deps/v8/src/messages.h @@ -93,11 +93,12 @@ class MessageHandler { static void ReportMessage(const char* msg); // Returns a message object for the API to use. - static Handle<Object> MakeMessageObject(const char* type, - MessageLocation* loc, - Vector< Handle<Object> > args, - Handle<String> stack_trace, - Handle<JSArray> stack_frames); + static Handle<JSMessageObject> MakeMessageObject( + const char* type, + MessageLocation* loc, + Vector< Handle<Object> > args, + Handle<String> stack_trace, + Handle<JSArray> stack_frames); // Report a formatted message (needs JS allocation). static void ReportMessage(MessageLocation* loc, Handle<Object> message); diff --git a/deps/v8/src/messages.js b/deps/v8/src/messages.js index fcd7285ecf..4c3d1e70e0 100644 --- a/deps/v8/src/messages.js +++ b/deps/v8/src/messages.js @@ -53,20 +53,23 @@ var kAddMessageAccessorsMarker = { }; var kMessages = 0; var kReplacementMarkers = - [ "%0", "%1", "%2", "%3", "%4", "%5", "%6", "%7", "%8", "%9", "%10" ]; - -function FormatString(format, args) { - var result = format; - for (var i = 0; i < args.length; i++) { - var str; - try { - str = ToDetailString(args[i]); - } catch (e) { - str = "#<error>"; + [ "%0", "%1", "%2", "%3" ] + +function FormatString(format, message) { + var args = %MessageGetArguments(message); + var result = ""; + var arg_num = 0; + for (var i = 0; i < format.length; i++) { + var str = format[i]; + for (arg_num = 0; arg_num < kReplacementMarkers.length; arg_num++) { + if (format[i] !== kReplacementMarkers[arg_num]) continue; + try { + str = ToDetailString(args[arg_num]); + } catch (e) { + str = "#<error>"; + } } - var replacement_marker = kReplacementMarkers[i]; - var split = %_CallFunction(result, replacement_marker, StringSplit); - result = %_CallFunction(split, str, ArrayJoin); + result += str; } return result; } @@ -143,97 +146,100 @@ function FormatMessage(message) { if (kMessages === 0) { kMessages = { // Error - cyclic_proto: "Cyclic __proto__ value", + cyclic_proto: ["Cyclic __proto__ value"], // TypeError - unexpected_token: "Unexpected token %0", - unexpected_token_number: "Unexpected number", - unexpected_token_string: "Unexpected string", - unexpected_token_identifier: "Unexpected identifier", - unexpected_eos: "Unexpected end of input", - malformed_regexp: "Invalid regular expression: /%0/: %1", - unterminated_regexp: "Invalid regular expression: missing /", - regexp_flags: "Cannot supply flags when constructing one RegExp from another", - incompatible_method_receiver: "Method %0 called on incompatible receiver %1", - invalid_lhs_in_assignment: "Invalid left-hand side in assignment", - invalid_lhs_in_for_in: "Invalid left-hand side in for-in", - invalid_lhs_in_postfix_op: "Invalid left-hand side expression in postfix operation", - invalid_lhs_in_prefix_op: "Invalid left-hand side expression in prefix operation", - multiple_defaults_in_switch: "More than one default clause in switch statement", - newline_after_throw: "Illegal newline after throw", - redeclaration: "%0 '%1' has already been declared", - no_catch_or_finally: "Missing catch or finally after try", - unknown_label: "Undefined label '%0'", - uncaught_exception: "Uncaught %0", - stack_trace: "Stack Trace:\n%0", - called_non_callable: "%0 is not a function", - undefined_method: "Object %1 has no method '%0'", - property_not_function: "Property '%0' of object %1 is not a function", - cannot_convert_to_primitive: "Cannot convert object to primitive value", - not_constructor: "%0 is not a constructor", - not_defined: "%0 is not defined", - non_object_property_load: "Cannot read property '%0' of %1", - non_object_property_store: "Cannot set property '%0' of %1", - non_object_property_call: "Cannot call method '%0' of %1", - with_expression: "%0 has no properties", - illegal_invocation: "Illegal invocation", - no_setter_in_callback: "Cannot set property %0 of %1 which has only a getter", - apply_non_function: "Function.prototype.apply was called on %0, which is a %1 and not a function", - apply_wrong_args: "Function.prototype.apply: Arguments list has wrong type", - invalid_in_operator_use: "Cannot use 'in' operator to search for '%0' in %1", - instanceof_function_expected: "Expecting a function in instanceof check, but got %0", - instanceof_nonobject_proto: "Function has non-object prototype '%0' in instanceof check", - null_to_object: "Cannot convert null to object", - reduce_no_initial: "Reduce of empty array with no initial value", - getter_must_be_callable: "Getter must be a function: %0", - setter_must_be_callable: "Setter must be a function: %0", - value_and_accessor: "Invalid property. A property cannot both have accessors and be writable or have a value: %0", - proto_object_or_null: "Object prototype may only be an Object or null", - property_desc_object: "Property description must be an object: %0", - redefine_disallowed: "Cannot redefine property: %0", - define_disallowed: "Cannot define property, object is not extensible: %0", + unexpected_token: ["Unexpected token ", "%0"], + unexpected_token_number: ["Unexpected number"], + unexpected_token_string: ["Unexpected string"], + unexpected_token_identifier: ["Unexpected identifier"], + unexpected_eos: ["Unexpected end of input"], + malformed_regexp: ["Invalid regular expression: /", "%0", "/: ", "%1"], + unterminated_regexp: ["Invalid regular expression: missing /"], + regexp_flags: ["Cannot supply flags when constructing one RegExp from another"], + incompatible_method_receiver: ["Method ", "%0", " called on incompatible receiver ", "%1"], + invalid_lhs_in_assignment: ["Invalid left-hand side in assignment"], + invalid_lhs_in_for_in: ["Invalid left-hand side in for-in"], + invalid_lhs_in_postfix_op: ["Invalid left-hand side expression in postfix operation"], + invalid_lhs_in_prefix_op: ["Invalid left-hand side expression in prefix operation"], + multiple_defaults_in_switch: ["More than one default clause in switch statement"], + newline_after_throw: ["Illegal newline after throw"], + redeclaration: ["%0", " '", "%1", "' has already been declared"], + no_catch_or_finally: ["Missing catch or finally after try"], + unknown_label: ["Undefined label '", "%0", "'"], + uncaught_exception: ["Uncaught ", "%0"], + stack_trace: ["Stack Trace:\n", "%0"], + called_non_callable: ["%0", " is not a function"], + undefined_method: ["Object ", "%1", " has no method '", "%0", "'"], + property_not_function: ["Property '", "%0", "' of object ", "%1", " is not a function"], + cannot_convert_to_primitive: ["Cannot convert object to primitive value"], + not_constructor: ["%0", " is not a constructor"], + not_defined: ["%0", " is not defined"], + non_object_property_load: ["Cannot read property '", "%0", "' of ", "%1"], + non_object_property_store: ["Cannot set property '", "%0", "' of ", "%1"], + non_object_property_call: ["Cannot call method '", "%0", "' of ", "%1"], + with_expression: ["%0", " has no properties"], + illegal_invocation: ["Illegal invocation"], + no_setter_in_callback: ["Cannot set property ", "%0", " of ", "%1", " which has only a getter"], + apply_non_function: ["Function.prototype.apply was called on ", "%0", ", which is a ", "%1", " and not a function"], + apply_wrong_args: ["Function.prototype.apply: Arguments list has wrong type"], + invalid_in_operator_use: ["Cannot use 'in' operator to search for '", "%0", "' in ", "%1"], + instanceof_function_expected: ["Expecting a function in instanceof check, but got ", "%0"], + instanceof_nonobject_proto: ["Function has non-object prototype '", "%0", "' in instanceof check"], + null_to_object: ["Cannot convert null to object"], + reduce_no_initial: ["Reduce of empty array with no initial value"], + getter_must_be_callable: ["Getter must be a function: ", "%0"], + setter_must_be_callable: ["Setter must be a function: ", "%0"], + value_and_accessor: ["Invalid property. A property cannot both have accessors and be writable or have a value: ", "%0"], + proto_object_or_null: ["Object prototype may only be an Object or null"], + property_desc_object: ["Property description must be an object: ", "%0"], + redefine_disallowed: ["Cannot redefine property: ", "%0"], + define_disallowed: ["Cannot define property, object is not extensible: ", "%0"], // RangeError - invalid_array_length: "Invalid array length", - stack_overflow: "Maximum call stack size exceeded", + invalid_array_length: ["Invalid array length"], + stack_overflow: ["Maximum call stack size exceeded"], // SyntaxError - unable_to_parse: "Parse error", - duplicate_regexp_flag: "Duplicate RegExp flag %0", - invalid_regexp: "Invalid RegExp pattern /%0/", - illegal_break: "Illegal break statement", - illegal_continue: "Illegal continue statement", - illegal_return: "Illegal return statement", - error_loading_debugger: "Error loading debugger", - no_input_to_regexp: "No input to %0", - invalid_json: "String '%0' is not valid JSON", - circular_structure: "Converting circular structure to JSON", - obj_ctor_property_non_object: "Object.%0 called on non-object", - array_indexof_not_defined: "Array.getIndexOf: Argument undefined", - object_not_extensible: "Can't add property %0, object is not extensible", - illegal_access: "Illegal access", - invalid_preparser_data: "Invalid preparser data for function %0", - strict_mode_with: "Strict mode code may not include a with statement", - strict_catch_variable: "Catch variable may not be eval or arguments in strict mode", - strict_param_name: "Parameter name eval or arguments is not allowed in strict mode", - strict_param_dupe: "Strict mode function may not have duplicate parameter names", - strict_var_name: "Variable name may not be eval or arguments in strict mode", - strict_function_name: "Function name may not be eval or arguments in strict mode", - strict_octal_literal: "Octal literals are not allowed in strict mode.", - strict_duplicate_property: "Duplicate data property in object literal not allowed in strict mode", - accessor_data_property: "Object literal may not have data and accessor property with the same name", - accessor_get_set: "Object literal may not have multiple get/set accessors with the same name", - strict_lhs_eval_assignment: "Assignment to eval or arguments is not allowed in strict mode", - strict_lhs_postfix: "Postfix increment/decrement may not have eval or arguments operand in strict mode", - strict_lhs_prefix: "Prefix increment/decrement may not have eval or arguments operand in strict mode", + unable_to_parse: ["Parse error"], + duplicate_regexp_flag: ["Duplicate RegExp flag ", "%0"], + invalid_regexp: ["Invalid RegExp pattern /", "%0", "/"], + illegal_break: ["Illegal break statement"], + illegal_continue: ["Illegal continue statement"], + illegal_return: ["Illegal return statement"], + error_loading_debugger: ["Error loading debugger"], + no_input_to_regexp: ["No input to ", "%0"], + invalid_json: ["String '", "%0", "' is not valid JSON"], + circular_structure: ["Converting circular structure to JSON"], + obj_ctor_property_non_object: ["Object.", "%0", " called on non-object"], + array_indexof_not_defined: ["Array.getIndexOf: Argument undefined"], + object_not_extensible: ["Can't add property ", "%0", ", object is not extensible"], + illegal_access: ["Illegal access"], + invalid_preparser_data: ["Invalid preparser data for function ", "%0"], + strict_mode_with: ["Strict mode code may not include a with statement"], + strict_catch_variable: ["Catch variable may not be eval or arguments in strict mode"], + strict_param_name: ["Parameter name eval or arguments is not allowed in strict mode"], + strict_param_dupe: ["Strict mode function may not have duplicate parameter names"], + strict_var_name: ["Variable name may not be eval or arguments in strict mode"], + strict_function_name: ["Function name may not be eval or arguments in strict mode"], + strict_octal_literal: ["Octal literals are not allowed in strict mode."], + strict_duplicate_property: ["Duplicate data property in object literal not allowed in strict mode"], + accessor_data_property: ["Object literal may not have data and accessor property with the same name"], + accessor_get_set: ["Object literal may not have multiple get/set accessors with the same name"], + strict_lhs_assignment: ["Assignment to eval or arguments is not allowed in strict mode"], + strict_lhs_postfix: ["Postfix increment/decrement may not have eval or arguments operand in strict mode"], + strict_lhs_prefix: ["Prefix increment/decrement may not have eval or arguments operand in strict mode"], }; } - var format = kMessages[message.type]; - if (!format) return "<unknown message " + message.type + ">"; - return FormatString(format, message.args); + var message_type = %MessageGetType(message); + var format = kMessages[message_type]; + if (!format) return "<unknown message " + message_type + ">"; + return FormatString(format, message); } function GetLineNumber(message) { - if (message.startPos == -1) return kNoLineNumberInfo; - var location = message.script.locationFromPosition(message.startPos, true); + var start_position = %MessageGetStartPosition(message); + if (start_position == -1) return kNoLineNumberInfo; + var script = %MessageGetScript(message); + var location = script.locationFromPosition(start_position, true); if (location == null) return kNoLineNumberInfo; return location.line + 1; } @@ -242,7 +248,9 @@ function GetLineNumber(message) { // Returns the source code line containing the given source // position, or the empty string if the position is invalid. function GetSourceLine(message) { - var location = message.script.locationFromPosition(message.startPos, true); + var script = %MessageGetScript(message); + var start_position = %MessageGetStartPosition(message); + var location = script.locationFromPosition(start_position, true); if (location == null) return ""; location.restrict(); return location.sourceText(); @@ -621,29 +629,12 @@ SourceSlice.prototype.sourceText = function () { // Returns the offset of the given position within the containing // line. function GetPositionInLine(message) { - var location = message.script.locationFromPosition(message.startPos, false); + var script = %MessageGetScript(message); + var start_position = %MessageGetStartPosition(message); + var location = script.locationFromPosition(start_position, false); if (location == null) return -1; location.restrict(); - return message.startPos - location.start; -} - - -function ErrorMessage(type, args, startPos, endPos, script, stackTrace, - stackFrames) { - this.startPos = startPos; - this.endPos = endPos; - this.type = type; - this.args = args; - this.script = script; - this.stackTrace = stackTrace; - this.stackFrames = stackFrames; -} - - -function MakeMessage(type, args, startPos, endPos, script, stackTrace, - stackFrames) { - return new ErrorMessage(type, args, startPos, endPos, script, stackTrace, - stackFrames); + return start_position - location.start; } @@ -990,7 +981,7 @@ function DefineError(f) { // DefineOneShotAccessor always inserts a message property and // ignores setters. DefineOneShotAccessor(this, 'message', function (obj) { - return FormatMessage({type: obj.type, args: obj.arguments}); + return FormatMessage(%NewMessageObject(obj.type, obj.arguments)); }); } else if (!IS_UNDEFINED(m)) { %IgnoreAttributesAndSetProperty(this, 'message', ToString(m)); @@ -1004,11 +995,12 @@ function DefineError(f) { function captureStackTrace(obj, cons_opt) { var stackTraceLimit = $Error.stackTraceLimit; - if (!stackTraceLimit) return; + if (!stackTraceLimit || !IS_NUMBER(stackTraceLimit)) return; if (stackTraceLimit < 0 || stackTraceLimit > 10000) stackTraceLimit = 10000; - var raw_stack = %CollectStackTrace(cons_opt ? cons_opt : captureStackTrace, - stackTraceLimit); + var raw_stack = %CollectStackTrace(cons_opt + ? cons_opt + : captureStackTrace, stackTraceLimit); DefineOneShotAccessor(obj, 'stack', function (obj) { return FormatRawStackTrace(obj, raw_stack); }); @@ -1038,14 +1030,16 @@ function errorToStringDetectCycle() { if (!%PushIfAbsent(visited_errors, this)) throw cyclic_error_marker; try { var type = this.type; - if (type && !this.hasOwnProperty("message")) { - var formatted = FormatMessage({ type: type, args: this.arguments }); + if (type && !%_CallFunction(this, "message", ObjectHasOwnProperty)) { + var formatted = FormatMessage(%NewMessageObject(type, this.arguments)); return this.name + ": " + formatted; } - var message = this.hasOwnProperty("message") ? (": " + this.message) : ""; + var message = %_CallFunction(this, "message", ObjectHasOwnProperty) + ? (": " + this.message) + : ""; return this.name + message; } finally { - visited_errors.pop(); + visited_errors.length = visited_errors.length - 1; } } diff --git a/deps/v8/src/mirror-debugger.js b/deps/v8/src/mirror-debugger.js index 80d385952b..416f88794d 100644 --- a/deps/v8/src/mirror-debugger.js +++ b/deps/v8/src/mirror-debugger.js @@ -1084,9 +1084,9 @@ ErrorMirror.prototype.toText = function() { // Use the same text representation as in messages.js. var text; try { - str = builtins.ToDetailString(this.value_); + str = %_CallFunction(this.value_, builtins.errorToString); } catch (e) { - str = '#<an Error>'; + str = '#<Error>'; } return str; } diff --git a/deps/v8/src/objects-debug.cc b/deps/v8/src/objects-debug.cc index f9c57e6960..c8246c86c9 100644 --- a/deps/v8/src/objects-debug.cc +++ b/deps/v8/src/objects-debug.cc @@ -158,6 +158,9 @@ void HeapObject::HeapObjectVerify() { case SHARED_FUNCTION_INFO_TYPE: SharedFunctionInfo::cast(this)->SharedFunctionInfoVerify(); break; + case JS_MESSAGE_OBJECT_TYPE: + JSMessageObject::cast(this)->JSMessageObjectVerify(); + break; #define MAKE_STRUCT_CASE(NAME, Name, name) \ case NAME##_TYPE: \ @@ -296,6 +299,19 @@ void JSValue::JSValueVerify() { } +void JSMessageObject::JSMessageObjectVerify() { + CHECK(IsJSMessageObject()); + CHECK(type()->IsString()); + CHECK(arguments()->IsJSArray()); + VerifyObjectField(kStartPositionOffset); + VerifyObjectField(kEndPositionOffset); + VerifyObjectField(kArgumentsOffset); + VerifyObjectField(kScriptOffset); + VerifyObjectField(kStackTraceOffset); + VerifyObjectField(kStackFramesOffset); +} + + void String::StringVerify() { CHECK(IsString()); CHECK(length() >= 0 && length() <= Smi::kMaxValue); diff --git a/deps/v8/src/objects-inl.h b/deps/v8/src/objects-inl.h index db9e2ef7b1..50f4031b79 100644 --- a/deps/v8/src/objects-inl.h +++ b/deps/v8/src/objects-inl.h @@ -408,7 +408,7 @@ bool MaybeObject::IsRetryAfterGC() { bool MaybeObject::IsOutOfMemory() { return HAS_FAILURE_TAG(this) - && Failure::cast(this)->IsOutOfMemoryException(); + && Failure::cast(this)->IsOutOfMemoryException(); } @@ -430,26 +430,26 @@ Failure* Failure::cast(MaybeObject* obj) { bool Object::IsJSObject() { return IsHeapObject() - && HeapObject::cast(this)->map()->instance_type() >= FIRST_JS_OBJECT_TYPE; + && HeapObject::cast(this)->map()->instance_type() >= FIRST_JS_OBJECT_TYPE; } bool Object::IsJSContextExtensionObject() { return IsHeapObject() - && (HeapObject::cast(this)->map()->instance_type() == - JS_CONTEXT_EXTENSION_OBJECT_TYPE); + && (HeapObject::cast(this)->map()->instance_type() == + JS_CONTEXT_EXTENSION_OBJECT_TYPE); } bool Object::IsMap() { return Object::IsHeapObject() - && HeapObject::cast(this)->map()->instance_type() == MAP_TYPE; + && HeapObject::cast(this)->map()->instance_type() == MAP_TYPE; } bool Object::IsFixedArray() { return Object::IsHeapObject() - && HeapObject::cast(this)->map()->instance_type() == FIXED_ARRAY_TYPE; + && HeapObject::cast(this)->map()->instance_type() == FIXED_ARRAY_TYPE; } @@ -495,19 +495,19 @@ bool Object::IsContext() { bool Object::IsCatchContext() { return Object::IsHeapObject() - && HeapObject::cast(this)->map() == Heap::catch_context_map(); + && HeapObject::cast(this)->map() == Heap::catch_context_map(); } bool Object::IsGlobalContext() { return Object::IsHeapObject() - && HeapObject::cast(this)->map() == Heap::global_context_map(); + && HeapObject::cast(this)->map() == Heap::global_context_map(); } bool Object::IsJSFunction() { return Object::IsHeapObject() - && HeapObject::cast(this)->map()->instance_type() == JS_FUNCTION_TYPE; + && HeapObject::cast(this)->map()->instance_type() == JS_FUNCTION_TYPE; } @@ -518,7 +518,7 @@ template <> inline bool Is<JSFunction>(Object* obj) { bool Object::IsCode() { return Object::IsHeapObject() - && HeapObject::cast(this)->map()->instance_type() == CODE_TYPE; + && HeapObject::cast(this)->map()->instance_type() == CODE_TYPE; } @@ -544,7 +544,14 @@ bool Object::IsSharedFunctionInfo() { bool Object::IsJSValue() { return Object::IsHeapObject() - && HeapObject::cast(this)->map()->instance_type() == JS_VALUE_TYPE; + && HeapObject::cast(this)->map()->instance_type() == JS_VALUE_TYPE; +} + + +bool Object::IsJSMessageObject() { + return Object::IsHeapObject() + && (HeapObject::cast(this)->map()->instance_type() == + JS_MESSAGE_OBJECT_TYPE); } @@ -555,7 +562,7 @@ bool Object::IsStringWrapper() { bool Object::IsProxy() { return Object::IsHeapObject() - && HeapObject::cast(this)->map()->instance_type() == PROXY_TYPE; + && HeapObject::cast(this)->map()->instance_type() == PROXY_TYPE; } @@ -566,13 +573,13 @@ bool Object::IsBoolean() { bool Object::IsJSArray() { return Object::IsHeapObject() - && HeapObject::cast(this)->map()->instance_type() == JS_ARRAY_TYPE; + && HeapObject::cast(this)->map()->instance_type() == JS_ARRAY_TYPE; } bool Object::IsJSRegExp() { return Object::IsHeapObject() - && HeapObject::cast(this)->map()->instance_type() == JS_REGEXP_TYPE; + && HeapObject::cast(this)->map()->instance_type() == JS_REGEXP_TYPE; } @@ -583,7 +590,7 @@ template <> inline bool Is<JSArray>(Object* obj) { bool Object::IsHashTable() { return Object::IsHeapObject() - && HeapObject::cast(this)->map() == Heap::hash_table_map(); + && HeapObject::cast(this)->map() == Heap::hash_table_map(); } @@ -1285,6 +1292,8 @@ int JSObject::GetHeaderSize() { return JSValue::kSize; case JS_CONTEXT_EXTENSION_OBJECT_TYPE: return JSObject::kHeaderSize; + case JS_MESSAGE_OBJECT_TYPE: + return JSMessageObject::kSize; default: UNREACHABLE(); return 0; @@ -3289,6 +3298,22 @@ JSValue* JSValue::cast(Object* obj) { } +ACCESSORS(JSMessageObject, type, String, kTypeOffset) +ACCESSORS(JSMessageObject, arguments, JSArray, kArgumentsOffset) +ACCESSORS(JSMessageObject, script, Object, kScriptOffset) +ACCESSORS(JSMessageObject, stack_trace, Object, kStackTraceOffset) +ACCESSORS(JSMessageObject, stack_frames, Object, kStackFramesOffset) +SMI_ACCESSORS(JSMessageObject, start_position, kStartPositionOffset) +SMI_ACCESSORS(JSMessageObject, end_position, kEndPositionOffset) + + +JSMessageObject* JSMessageObject::cast(Object* obj) { + ASSERT(obj->IsJSMessageObject()); + ASSERT(HeapObject::cast(obj)->Size() == JSMessageObject::kSize); + return reinterpret_cast<JSMessageObject*>(obj); +} + + INT_ACCESSORS(Code, instruction_size, kInstructionSizeOffset) ACCESSORS(Code, relocation_info, ByteArray, kRelocationInfoOffset) ACCESSORS(Code, deoptimization_data, FixedArray, kDeoptimizationDataOffset) diff --git a/deps/v8/src/objects-printer.cc b/deps/v8/src/objects-printer.cc index 9f05b0f62d..237358dcc7 100644 --- a/deps/v8/src/objects-printer.cc +++ b/deps/v8/src/objects-printer.cc @@ -151,6 +151,9 @@ void HeapObject::HeapObjectPrint(FILE* out) { case SHARED_FUNCTION_INFO_TYPE: SharedFunctionInfo::cast(this)->SharedFunctionInfoPrint(out); break; + case JS_MESSAGE_OBJECT_TYPE: + JSMessageObject::cast(this)->JSMessageObjectPrint(out); + break; case JS_GLOBAL_PROPERTY_CELL_TYPE: JSGlobalPropertyCell::cast(this)->JSGlobalPropertyCellPrint(out); break; @@ -396,6 +399,7 @@ static const char* TypeToString(InstanceType type) { case JS_GLOBAL_PROXY_TYPE: return "JS_GLOBAL_PROXY"; case PROXY_TYPE: return "PROXY"; case LAST_STRING_TYPE: return "LAST_STRING_TYPE"; + case JS_MESSAGE_OBJECT_TYPE: return "JS_MESSAGE_OBJECT_TYPE"; #define MAKE_STRUCT_CASE(NAME, Name, name) case NAME##_TYPE: return #NAME; STRUCT_LIST(MAKE_STRUCT_CASE) #undef MAKE_STRUCT_CASE @@ -466,6 +470,24 @@ void JSValue::JSValuePrint(FILE* out) { } +void JSMessageObject::JSMessageObjectPrint(FILE* out) { + HeapObject::PrintHeader(out, "JSMessageObject"); + PrintF(out, " - type: "); + type()->ShortPrint(out); + PrintF(out, "\n - arguments: "); + arguments()->ShortPrint(out); + PrintF(out, "\n - start_position: %d", start_position()); + PrintF(out, "\n - end_position: %d", end_position()); + PrintF(out, "\n - script: "); + script()->ShortPrint(out); + PrintF(out, "\n - stack_trace: "); + stack_trace()->ShortPrint(out); + PrintF(out, "\n - stack_frames: "); + stack_frames()->ShortPrint(out); + PrintF(out, "\n"); +} + + void String::StringPrint(FILE* out) { if (StringShape(this).IsSymbol()) { PrintF(out, "#"); diff --git a/deps/v8/src/objects-visiting.cc b/deps/v8/src/objects-visiting.cc index c35e02cc9c..5f054bd326 100644 --- a/deps/v8/src/objects-visiting.cc +++ b/deps/v8/src/objects-visiting.cc @@ -104,6 +104,7 @@ StaticVisitorBase::VisitorId StaticVisitorBase::GetVisitorId( case JS_GLOBAL_PROXY_TYPE: case JS_GLOBAL_OBJECT_TYPE: case JS_BUILTINS_OBJECT_TYPE: + case JS_MESSAGE_OBJECT_TYPE: return GetVisitorIdForSize(kVisitJSObject, kVisitJSObjectGeneric, instance_size); diff --git a/deps/v8/src/objects.cc b/deps/v8/src/objects.cc index 36a8e5c2aa..8bced586b3 100644 --- a/deps/v8/src/objects.cc +++ b/deps/v8/src/objects.cc @@ -979,6 +979,9 @@ void HeapObject::HeapObjectShortPrint(StringStream* accumulator) { case SHARED_FUNCTION_INFO_TYPE: accumulator->Add("<SharedFunctionInfo>"); break; + case JS_MESSAGE_OBJECT_TYPE: + accumulator->Add("<JSMessageObject>"); + break; #define MAKE_STRUCT_CASE(NAME, Name, name) \ case NAME##_TYPE: \ accumulator->Put('<'); \ @@ -1069,6 +1072,7 @@ void HeapObject::IterateBody(InstanceType type, int object_size, case JS_GLOBAL_PROXY_TYPE: case JS_GLOBAL_OBJECT_TYPE: case JS_BUILTINS_OBJECT_TYPE: + case JS_MESSAGE_OBJECT_TYPE: JSObject::BodyDescriptor::IterateBody(this, object_size, v); break; case JS_FUNCTION_TYPE: diff --git a/deps/v8/src/objects.h b/deps/v8/src/objects.h index 8c63022db8..c9b3757df9 100644 --- a/deps/v8/src/objects.h +++ b/deps/v8/src/objects.h @@ -54,7 +54,8 @@ // - JSGlobalObject // - JSBuiltinsObject // - JSGlobalProxy -// - JSValue +// - JSValue +// - JSMessageObject // - ByteArray // - PixelArray // - ExternalArray @@ -288,6 +289,8 @@ static const int kVariableSizeSentinel = 0; V(FIXED_ARRAY_TYPE) \ V(SHARED_FUNCTION_INFO_TYPE) \ \ + V(JS_MESSAGE_OBJECT_TYPE) \ + \ V(JS_VALUE_TYPE) \ V(JS_OBJECT_TYPE) \ V(JS_CONTEXT_EXTENSION_OBJECT_TYPE) \ @@ -518,6 +521,8 @@ enum InstanceType { FIXED_ARRAY_TYPE, SHARED_FUNCTION_INFO_TYPE, + JS_MESSAGE_OBJECT_TYPE, + JS_VALUE_TYPE, // FIRST_JS_OBJECT_TYPE JS_OBJECT_TYPE, JS_CONTEXT_EXTENSION_OBJECT_TYPE, @@ -675,6 +680,7 @@ class MaybeObject BASE_EMBEDDED { V(Oddball) \ V(SharedFunctionInfo) \ V(JSValue) \ + V(JSMessageObject) \ V(StringWrapper) \ V(Proxy) \ V(Boolean) \ @@ -4696,6 +4702,68 @@ class JSValue: public JSObject { DISALLOW_IMPLICIT_CONSTRUCTORS(JSValue); }; + +// Representation of message objects used for error reporting through +// the API. The messages are formatted in JavaScript so this object is +// a real JavaScript object. The information used for formatting the +// error messages are not directly accessible from JavaScript to +// prevent leaking information to user code called during error +// formatting. +class JSMessageObject: public JSObject { + public: + // [type]: the type of error message. + DECL_ACCESSORS(type, String) + + // [arguments]: the arguments for formatting the error message. + DECL_ACCESSORS(arguments, JSArray) + + // [script]: the script from which the error message originated. + DECL_ACCESSORS(script, Object) + + // [stack_trace]: the stack trace for this error message. + DECL_ACCESSORS(stack_trace, Object) + + // [stack_frames]: an array of stack frames for this error object. + DECL_ACCESSORS(stack_frames, Object) + + // [start_position]: the start position in the script for the error message. + inline int start_position(); + inline void set_start_position(int value); + + // [end_position]: the end position in the script for the error message. + inline int end_position(); + inline void set_end_position(int value); + + // Casting. + static inline JSMessageObject* cast(Object* obj); + + // Dispatched behavior. +#ifdef OBJECT_PRINT + inline void JSMessageObjectPrint() { + JSMessageObjectPrint(stdout); + } + void JSMessageObjectPrint(FILE* out); +#endif +#ifdef DEBUG + void JSMessageObjectVerify(); +#endif + + // Layout description. + static const int kTypeOffset = JSObject::kHeaderSize; + static const int kArgumentsOffset = kTypeOffset + kPointerSize; + static const int kScriptOffset = kArgumentsOffset + kPointerSize; + static const int kStackTraceOffset = kScriptOffset + kPointerSize; + static const int kStackFramesOffset = kStackTraceOffset + kPointerSize; + static const int kStartPositionOffset = kStackFramesOffset + kPointerSize; + static const int kEndPositionOffset = kStartPositionOffset + kPointerSize; + static const int kSize = kEndPositionOffset + kPointerSize; + + typedef FixedBodyDescriptor<HeapObject::kMapOffset, + kStackFramesOffset + kPointerSize, + kSize> BodyDescriptor; +}; + + // Regular expressions // The regular expression holds a single reference to a FixedArray in // the kDataOffset field. diff --git a/deps/v8/src/parser.cc b/deps/v8/src/parser.cc index c0976988ea..ccb3f64e10 100644 --- a/deps/v8/src/parser.cc +++ b/deps/v8/src/parser.cc @@ -3035,7 +3035,7 @@ Handle<Object> Parser::GetBoilerplateValue(Expression* expression) { // Defined in ast.cc bool IsEqualString(void* first, void* second); -bool IsEqualSmi(void* first, void* second); +bool IsEqualNumber(void* first, void* second); // Validation per 11.1.5 Object Initialiser @@ -3043,7 +3043,7 @@ class ObjectLiteralPropertyChecker { public: ObjectLiteralPropertyChecker(Parser* parser, bool strict) : props(&IsEqualString), - elems(&IsEqualSmi), + elems(&IsEqualNumber), parser_(parser), strict_(strict) { } @@ -3092,13 +3092,12 @@ void ObjectLiteralPropertyChecker::CheckProperty( uint32_t hash; HashMap* map; void* key; - Smi* smi_key_location; if (handle->IsSymbol()) { Handle<String> name(String::cast(*handle)); if (name->AsArrayIndex(&hash)) { - smi_key_location = Smi::FromInt(hash); - key = &smi_key_location; + Handle<Object> key_handle = Factory::NewNumberFromUint(hash); + key = key_handle.location(); map = &elems; } else { key = handle.location(); diff --git a/deps/v8/src/runtime.cc b/deps/v8/src/runtime.cc index 96d07a859b..d55a201e59 100644 --- a/deps/v8/src/runtime.cc +++ b/deps/v8/src/runtime.cc @@ -10748,6 +10748,45 @@ static MaybeObject* Runtime_GetFromCache(Arguments args) { return *value; } + +static MaybeObject* Runtime_NewMessageObject(Arguments args) { + HandleScope scope; + CONVERT_ARG_CHECKED(String, type, 0); + CONVERT_ARG_CHECKED(JSArray, arguments, 1); + return *Factory::NewJSMessageObject(type, + arguments, + 0, + 0, + Factory::undefined_value(), + Factory::undefined_value(), + Factory::undefined_value()); +} + + +static MaybeObject* Runtime_MessageGetType(Arguments args) { + CONVERT_CHECKED(JSMessageObject, message, args[0]); + return message->type(); +} + + +static MaybeObject* Runtime_MessageGetArguments(Arguments args) { + CONVERT_CHECKED(JSMessageObject, message, args[0]); + return message->arguments(); +} + + +static MaybeObject* Runtime_MessageGetStartPosition(Arguments args) { + CONVERT_CHECKED(JSMessageObject, message, args[0]); + return Smi::FromInt(message->start_position()); +} + + +static MaybeObject* Runtime_MessageGetScript(Arguments args) { + CONVERT_CHECKED(JSMessageObject, message, args[0]); + return message->script(); +} + + #ifdef DEBUG // ListNatives is ONLY used by the fuzz-natives.js in debug mode // Exclude the code in release mode. diff --git a/deps/v8/src/runtime.h b/deps/v8/src/runtime.h index d8b34570c3..b201eb8614 100644 --- a/deps/v8/src/runtime.h +++ b/deps/v8/src/runtime.h @@ -310,6 +310,13 @@ namespace internal { /* Cache suport */ \ F(GetFromCache, 2, 1) \ \ + /* Message objects */ \ + F(NewMessageObject, 2, 1) \ + F(MessageGetType, 1, 1) \ + F(MessageGetArguments, 1, 1) \ + F(MessageGetStartPosition, 1, 1) \ + F(MessageGetScript, 1, 1) \ + \ /* Pseudo functions - handled as macros by parser */ \ F(IS_VAR, 1, 1) diff --git a/deps/v8/src/safepoint-table.cc b/deps/v8/src/safepoint-table.cc index 153bf4327f..34e9cf4aba 100644 --- a/deps/v8/src/safepoint-table.cc +++ b/deps/v8/src/safepoint-table.cc @@ -1,4 +1,4 @@ -// Copyright 2010 the V8 project authors. All rights reserved. +// Copyright 2011 the V8 project authors. All rights reserved. // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: @@ -27,6 +27,7 @@ #include "safepoint-table.h" +#include "deoptimizer.h" #include "disasm.h" #include "macro-assembler.h" @@ -144,6 +145,14 @@ unsigned SafepointTableBuilder::GetCodeOffset() const { void SafepointTableBuilder::Emit(Assembler* assembler, int bits_per_entry) { + // For lazy deoptimization we need space to patch a call after every call. + // Ensure there is always space for such patching, even if the code ends + // in a call. + int target_offset = assembler->pc_offset() + Deoptimizer::patch_size(); + while (assembler->pc_offset() < target_offset) { + assembler->nop(); + } + // Make sure the safepoint table is properly aligned. Pad with nops. assembler->Align(kIntSize); assembler->RecordComment(";;; Safepoint table."); diff --git a/deps/v8/src/safepoint-table.h b/deps/v8/src/safepoint-table.h index fa3590511e..eeeae37fbe 100644 --- a/deps/v8/src/safepoint-table.h +++ b/deps/v8/src/safepoint-table.h @@ -1,4 +1,4 @@ -// Copyright 2010 the V8 project authors. All rights reserved. +// Copyright 2011 the V8 project authors. All rights reserved. // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: @@ -215,11 +215,10 @@ class SafepointTableBuilder BASE_EMBEDDED { unsigned GetCodeOffset() const; // Define a new safepoint for the current position in the body. - Safepoint DefineSafepoint( - Assembler* assembler, - Safepoint::Kind kind, - int arguments, - int deoptimization_index = Safepoint::kNoDeoptimizationIndex); + Safepoint DefineSafepoint(Assembler* assembler, + Safepoint::Kind kind, + int arguments, + int deoptimization_index); // Update the last safepoint with the size of the code generated for the gap // following it. diff --git a/deps/v8/src/scanner-base.cc b/deps/v8/src/scanner-base.cc index e141d0eb70..fe33f38e72 100644 --- a/deps/v8/src/scanner-base.cc +++ b/deps/v8/src/scanner-base.cc @@ -99,9 +99,9 @@ uc32 Scanner::ScanHexEscape(uc32 c, int length) { // Octal escapes of the forms '\0xx' and '\xxx' are not a part of // ECMA-262. Other JS VMs support them. uc32 Scanner::ScanOctalEscape(uc32 c, int length) { - octal_pos_ = source_pos() - 1; // Already advanced uc32 x = c - '0'; - for (int i = 0; i < length; i++) { + int i = 0; + for (; i < length; i++) { int d = c0_ - '0'; if (d < 0 || d > 7) break; int nx = x * 8 + d; @@ -109,6 +109,12 @@ uc32 Scanner::ScanOctalEscape(uc32 c, int length) { x = nx; Advance(); } + // Anything excelt '\0' is an octal escape sequence, illegal in strict mode. + // Remember the position of octal escape sequences so that better error + // can be reported later (in strict mode). + if (c != '0' || i > 0) { + octal_pos_ = source_pos() - i - 1; // Already advanced + } return x; } diff --git a/deps/v8/src/scanner-base.h b/deps/v8/src/scanner-base.h index 3d9800f02a..7ac1d358e1 100644 --- a/deps/v8/src/scanner-base.h +++ b/deps/v8/src/scanner-base.h @@ -409,6 +409,8 @@ class Scanner { } uc32 ScanHexEscape(uc32 c, int length); + + // Scans octal escape sequence. Also accepts "\0" decimal escape sequence. uc32 ScanOctalEscape(uc32 c, int length); // Return the current source position. diff --git a/deps/v8/src/utils.h b/deps/v8/src/utils.h index 21e70d758e..219343b7fa 100644 --- a/deps/v8/src/utils.h +++ b/deps/v8/src/utils.h @@ -760,20 +760,32 @@ static inline int TenToThe(int exponent) { // you can use BitCast to cast one pointer type to another. This confuses gcc // enough that it can no longer see that you have cast one pointer type to // another thus avoiding the warning. + +// We need different implementations of BitCast for pointer and non-pointer +// values. We use partial specialization of auxiliary struct to work around +// issues with template functions overloading. template <class Dest, class Source> -inline Dest BitCast(const Source& source) { - // Compile time assertion: sizeof(Dest) == sizeof(Source) - // A compile error here means your Dest and Source have different sizes. - typedef char VerifySizesAreEqual[sizeof(Dest) == sizeof(Source) ? 1 : -1]; +struct BitCastHelper { + STATIC_ASSERT(sizeof(Dest) == sizeof(Source)); - Dest dest; - memcpy(&dest, &source, sizeof(dest)); - return dest; -} + INLINE(static Dest cast(const Source& source)) { + Dest dest; + memcpy(&dest, &source, sizeof(dest)); + return dest; + } +}; template <class Dest, class Source> -inline Dest BitCast(Source* source) { - return BitCast<Dest>(reinterpret_cast<uintptr_t>(source)); +struct BitCastHelper<Dest, Source*> { + INLINE(static Dest cast(Source* source)) { + return BitCastHelper<Dest, uintptr_t>:: + cast(reinterpret_cast<uintptr_t>(source)); + } +}; + +template <class Dest, class Source> +inline Dest BitCast(const Source& source) { + return BitCastHelper<Dest, Source>::cast(source); } } } // namespace v8::internal diff --git a/deps/v8/src/version.cc b/deps/v8/src/version.cc index 0a43561db2..e17f78047a 100644 --- a/deps/v8/src/version.cc +++ b/deps/v8/src/version.cc @@ -1,4 +1,4 @@ -// Copyright 2010 the V8 project authors. All rights reserved. +// Copyright 2011 the V8 project authors. All rights reserved. // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: @@ -34,8 +34,8 @@ // cannot be changed without changing the SCons build script. #define MAJOR_VERSION 3 #define MINOR_VERSION 1 -#define BUILD_NUMBER 0 -#define PATCH_LEVEL 1 +#define BUILD_NUMBER 1 +#define PATCH_LEVEL 0 #define CANDIDATE_VERSION false // Define SONAME to have the SCons build the put a specific SONAME into the diff --git a/deps/v8/src/x64/codegen-x64.cc b/deps/v8/src/x64/codegen-x64.cc index bebe4682d6..91686f9206 100644 --- a/deps/v8/src/x64/codegen-x64.cc +++ b/deps/v8/src/x64/codegen-x64.cc @@ -6969,10 +6969,12 @@ void CodeGenerator::GenerateMathPow(ZoneList<Expression*>* args) { __ j(not_equal, ¬_minus_half); // Calculates reciprocal of square root. - // Note that 1/sqrt(x) = sqrt(1/x)) - __ divsd(xmm3, xmm0); - __ movsd(xmm1, xmm3); + // sqrtsd returns -0 when input is -0. ECMA spec requires +0. + __ xorpd(xmm1, xmm1); + __ addsd(xmm1, xmm0); __ sqrtsd(xmm1, xmm1); + __ divsd(xmm3, xmm1); + __ movsd(xmm1, xmm3); __ jmp(&allocate_return); // Test for 0.5. @@ -6985,7 +6987,9 @@ void CodeGenerator::GenerateMathPow(ZoneList<Expression*>* args) { call_runtime.Branch(not_equal); // Calculates square root. - __ movsd(xmm1, xmm0); + // sqrtsd returns -0 when input is -0. ECMA spec requires +0. + __ xorpd(xmm1, xmm1); + __ addsd(xmm1, xmm0); __ sqrtsd(xmm1, xmm1); JumpTarget done; diff --git a/deps/v8/src/x64/deoptimizer-x64.cc b/deps/v8/src/x64/deoptimizer-x64.cc index 60d46ef2bb..29b9023d42 100644 --- a/deps/v8/src/x64/deoptimizer-x64.cc +++ b/deps/v8/src/x64/deoptimizer-x64.cc @@ -1,4 +1,4 @@ -// Copyright 2010 the V8 project authors. All rights reserved. +// Copyright 2011 the V8 project authors. All rights reserved. // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: @@ -40,6 +40,12 @@ namespace internal { int Deoptimizer::table_entry_size_ = 10; + +int Deoptimizer::patch_size() { + return Assembler::kCallInstructionLength; +} + + void Deoptimizer::DeoptimizeFunction(JSFunction* function) { AssertNoAllocation no_allocation; @@ -72,12 +78,12 @@ void Deoptimizer::DeoptimizeFunction(JSFunction* function) { #endif last_pc_offset = pc_offset; if (deoptimization_index != Safepoint::kNoDeoptimizationIndex) { - CodePatcher patcher( - code->instruction_start() + pc_offset + gap_code_size, - Assembler::kCallInstructionLength); + last_pc_offset += gap_code_size; + CodePatcher patcher(code->instruction_start() + last_pc_offset, + patch_size()); patcher.masm()->Call(GetDeoptimizationEntry(deoptimization_index, LAZY), RelocInfo::NONE); - last_pc_offset += gap_code_size + Assembler::kCallInstructionLength; + last_pc_offset += patch_size(); } } #ifdef DEBUG @@ -107,16 +113,16 @@ void Deoptimizer::DeoptimizeFunction(JSFunction* function) { } -void Deoptimizer::PatchStackCheckCode(Code* unoptimized_code, - Code* check_code, - Code* replacement_code) { +void Deoptimizer::PatchStackCheckCodeAt(Address pc_after, + Code* check_code, + Code* replacement_code) { UNIMPLEMENTED(); } -void Deoptimizer::RevertStackCheckCode(Code* unoptimized_code, - Code* check_code, - Code* replacement_code) { +void Deoptimizer::RevertStackCheckCodeAt(Address pc_after, + Code* check_code, + Code* replacement_code) { UNIMPLEMENTED(); } diff --git a/deps/v8/src/x64/lithium-codegen-x64.cc b/deps/v8/src/x64/lithium-codegen-x64.cc index 513c98407c..4f1efc480b 100644 --- a/deps/v8/src/x64/lithium-codegen-x64.cc +++ b/deps/v8/src/x64/lithium-codegen-x64.cc @@ -346,17 +346,11 @@ void LCodeGen::AddToTranslation(Translation* translation, void LCodeGen::CallCode(Handle<Code> code, RelocInfo::Mode mode, LInstruction* instr) { - if (instr != NULL) { - LPointerMap* pointers = instr->pointer_map(); - RecordPosition(pointers->position()); - __ call(code, mode); - RegisterLazyDeoptimization(instr); - } else { - LPointerMap no_pointers(0); - RecordPosition(no_pointers.position()); - __ call(code, mode); - RecordSafepoint(&no_pointers, Safepoint::kNoDeoptimizationIndex); - } + ASSERT(instr != NULL); + LPointerMap* pointers = instr->pointer_map(); + RecordPosition(pointers->position()); + __ call(code, mode); + RegisterLazyDeoptimization(instr); // Signal that we don't inline smi code before these stubs in the // optimizing code generator. diff --git a/deps/v8/src/x64/lithium-x64.cc b/deps/v8/src/x64/lithium-x64.cc index 2dd5cf7337..0a52c6da18 100644 --- a/deps/v8/src/x64/lithium-x64.cc +++ b/deps/v8/src/x64/lithium-x64.cc @@ -653,16 +653,16 @@ LInstruction* LChunkBuilder::AssignEnvironment(LInstruction* instr) { LInstruction* LChunkBuilder::SetInstructionPendingDeoptimizationEnvironment( LInstruction* instr, int ast_id) { - ASSERT(instructions_pending_deoptimization_environment_ == NULL); + ASSERT(instruction_pending_deoptimization_environment_ == NULL); ASSERT(pending_deoptimization_ast_id_ == AstNode::kNoNumber); - instructions_pending_deoptimization_environment_ = instr; + instruction_pending_deoptimization_environment_ = instr; pending_deoptimization_ast_id_ = ast_id; return instr; } void LChunkBuilder::ClearInstructionPendingDeoptimizationEnvironment() { - instructions_pending_deoptimization_environment_ = NULL; + instruction_pending_deoptimization_environment_ = NULL; pending_deoptimization_ast_id_ = AstNode::kNoNumber; } @@ -1328,6 +1328,13 @@ LInstruction* LChunkBuilder::DoBoundsCheck(HBoundsCheck* instr) { } +LInstruction* LChunkBuilder::DoAbnormalExit(HAbnormalExit* instr) { + // The control instruction marking the end of a block that completed + // abruptly (e.g., threw an exception). There is nothing specific to do. + return NULL; +} + + LInstruction* LChunkBuilder::DoThrow(HThrow* instr) { Abort("Unimplemented: %s", "DoThrow"); return NULL; @@ -1663,7 +1670,7 @@ LInstruction* LChunkBuilder::DoSimulate(HSimulate* instr) { if (pending_deoptimization_ast_id_ == instr->ast_id()) { LLazyBailout* lazy_bailout = new LLazyBailout; LInstruction* result = AssignEnvironment(lazy_bailout); - instructions_pending_deoptimization_environment_-> + instruction_pending_deoptimization_environment_-> set_deoptimization_environment(result->environment()); ClearInstructionPendingDeoptimizationEnvironment(); return result; diff --git a/deps/v8/src/x64/lithium-x64.h b/deps/v8/src/x64/lithium-x64.h index 3195791654..abeb2a360d 100644 --- a/deps/v8/src/x64/lithium-x64.h +++ b/deps/v8/src/x64/lithium-x64.h @@ -1847,7 +1847,7 @@ class LChunkBuilder BASE_EMBEDDED { argument_count_(0), allocator_(allocator), position_(RelocInfo::kNoPosition), - instructions_pending_deoptimization_environment_(NULL), + instruction_pending_deoptimization_environment_(NULL), pending_deoptimization_ast_id_(AstNode::kNoNumber) { } // Build the sequence for the graph. @@ -1981,7 +1981,7 @@ class LChunkBuilder BASE_EMBEDDED { int argument_count_; LAllocator* allocator_; int position_; - LInstruction* instructions_pending_deoptimization_environment_; + LInstruction* instruction_pending_deoptimization_environment_; int pending_deoptimization_ast_id_; DISALLOW_COPY_AND_ASSIGN(LChunkBuilder); diff --git a/deps/v8/test/cctest/cctest.status b/deps/v8/test/cctest/cctest.status index 1009f85c0f..d7e446d1c3 100644 --- a/deps/v8/test/cctest/cctest.status +++ b/deps/v8/test/cctest/cctest.status @@ -29,11 +29,6 @@ prefix cctest test-api/Bug*: FAIL -# The problem is that a code object can get a different optimizable flag -# in crankshaft after creation. -test-log/EquivalenceOfLoggingAndTraversal: SKIP - - ############################################################################## # BUG(281): This test fails on some Linuxes. test-debug/DebuggerAgent: PASS, (PASS || FAIL) if $system == linux @@ -51,9 +46,6 @@ test-heap-profiler/HeapSnapshotsDiff: PASS || FAIL test-serialize/TestThatAlwaysFails: FAIL test-serialize/DependentTestThatAlwaysFails: FAIL -# BUG(1079) -test-api/CaptureStackTraceForUncaughtException: PASS || FAIL - ############################################################################## [ $arch == x64 ] diff --git a/deps/v8/test/cctest/test-api.cc b/deps/v8/test/cctest/test-api.cc index 9b9f469f60..ee620678a7 100644 --- a/deps/v8/test/cctest/test-api.cc +++ b/deps/v8/test/cctest/test-api.cc @@ -2369,13 +2369,30 @@ static void check_reference_error_message( } -// Test that overwritten toString methods are not invoked on uncaught -// exception formatting. However, they are invoked when performing -// normal error string conversions. +static v8::Handle<Value> Fail(const v8::Arguments& args) { + ApiTestFuzzer::Fuzz(); + CHECK(false); + return v8::Undefined(); +} + + +// Test that overwritten methods are not invoked on uncaught exception +// formatting. However, they are invoked when performing normal error +// string conversions. TEST(APIThrowMessageOverwrittenToString) { v8::HandleScope scope; v8::V8::AddMessageListener(check_reference_error_message); - LocalContext context; + Local<ObjectTemplate> templ = ObjectTemplate::New(); + templ->Set(v8_str("fail"), v8::FunctionTemplate::New(Fail)); + LocalContext context(NULL, templ); + CompileRun("asdf;"); + CompileRun("var limit = {};" + "limit.valueOf = fail;" + "Error.stackTraceLimit = limit;"); + CompileRun("asdf"); + CompileRun("Array.prototype.pop = fail;"); + CompileRun("Object.prototype.hasOwnProperty = fail;"); + CompileRun("Object.prototype.toString = function f() { return 'Yikes'; }"); CompileRun("Number.prototype.toString = function f() { return 'Yikes'; }"); CompileRun("String.prototype.toString = function f() { return 'Yikes'; }"); CompileRun("ReferenceError.prototype.toString =" diff --git a/deps/v8/test/cctest/test-log.cc b/deps/v8/test/cctest/test-log.cc index 503e0cf7c3..032a183661 100644 --- a/deps/v8/test/cctest/test-log.cc +++ b/deps/v8/test/cctest/test-log.cc @@ -1074,6 +1074,21 @@ static bool AreFuncNamesEqual(CodeEntityInfo ref_s, CodeEntityInfo new_s) { return true; } } + // Code objects can change their optimizability: code object may start + // as optimizable, but later be discovered to be actually not optimizable. + // Alas, we don't record this info as of now, so we allow cases when + // ref is thought to be optimizable while traverse finds it to be + // not optimizable. + if (ref_s[1] == '~') { // Code object used to be optimizable + if (new_s[1] == ' ') { // ...but later was set unoptimizable. + CHECK_EQ('"', ref_s[0]); + CHECK_EQ('"', new_s[0]); + ref_s += 2; // Cut the leading quote and the marker + ref_len -= 2; + new_s += 1; // Cut the leading quote only. + new_len -= 1; + } + } return ref_len == new_len && strncmp(ref_s, new_s, ref_len) == 0; } diff --git a/deps/v8/test/mjsunit/array-splice.js b/deps/v8/test/mjsunit/array-splice.js index 68dd9b2baf..0e307b5d3d 100644 --- a/deps/v8/test/mjsunit/array-splice.js +++ b/deps/v8/test/mjsunit/array-splice.js @@ -339,6 +339,20 @@ })(); +// Check the case of JS builtin .splice() +(function() { + for (var i = 0; i < 7; i++) { + var array = [1, 2, 3, 4]; + Array.prototype[3] = 'foo'; // To force JS builtin. + + var spliced = array.splice(); + + assertEquals([], spliced); + assertEquals([1, 2, 3, 4], array); + } +})(); + + // Check the behaviour when approaching maximal values for length. (function() { for (var i = 0; i < 7; i++) { diff --git a/deps/v8/test/mjsunit/compiler/literals.js b/deps/v8/test/mjsunit/compiler/literals.js index d846cf5b78..e910bb3c6a 100644 --- a/deps/v8/test/mjsunit/compiler/literals.js +++ b/deps/v8/test/mjsunit/compiler/literals.js @@ -88,3 +88,6 @@ assertEquals(17, eval('[1,2,3,4]; 17')); assertEquals(19, eval('var a=1, b=2; [a,b,3,4]; 19')); assertEquals(23, eval('var a=1, b=2; c=23; [a,b,3,4]; c')); +// Test that literals work for non-smi indices. +// Ensure hash-map collision if using value as hash. +var o = {"2345678901" : 42, "2345678901" : 30}; diff --git a/deps/v8/test/mjsunit/compiler/regress-1085.js b/deps/v8/test/mjsunit/compiler/regress-1085.js new file mode 100644 index 0000000000..5d787a45e6 --- /dev/null +++ b/deps/v8/test/mjsunit/compiler/regress-1085.js @@ -0,0 +1,35 @@ +// Copyright 2011 the V8 project authors. All rights reserved. +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +// Test correct checks for negative zero. +// This test relies on specific type feedback for Math.min. +function f(x) { return 1 / Math.min(1, x); } + +for (var i=0; i<1000000; i++) f(1); + +assertEquals(-Infinity, f(-0)); diff --git a/deps/v8/test/mjsunit/math-pow.js b/deps/v8/test/mjsunit/math-pow.js index e732955c98..30d0cbdced 100644 --- a/deps/v8/test/mjsunit/math-pow.js +++ b/deps/v8/test/mjsunit/math-pow.js @@ -58,10 +58,11 @@ assertEquals(Infinity, Math.pow(-1.1, Infinity)); assertEquals(Infinity, Math.pow(2, Infinity)); assertEquals(Infinity, Math.pow(-2, Infinity)); -assertEquals(+0, Math.pow(1.1, -Infinity)); -assertEquals(+0, Math.pow(-1.1, -Infinity)); -assertEquals(+0, Math.pow(2, -Infinity)); -assertEquals(+0, Math.pow(-2, -Infinity)); +// Because +0 == -0, we need to compare 1/{+,-}0 to {+,-}Infinity +assertEquals(+Infinity, 1/Math.pow(1.1, -Infinity)); +assertEquals(+Infinity, 1/Math.pow(-1.1, -Infinity)); +assertEquals(+Infinity, 1/Math.pow(2, -Infinity)); +assertEquals(+Infinity, 1/Math.pow(-2, -Infinity)); assertEquals(NaN, Math.pow(1, Infinity)); assertEquals(NaN, Math.pow(1, -Infinity)); @@ -81,8 +82,8 @@ assertEquals(Infinity, Math.pow(-0.999, -Infinity)); assertEquals(Infinity, Math.pow(Infinity, 0.1)); assertEquals(Infinity, Math.pow(Infinity, 2)); -assertEquals(+0, Math.pow(Infinity, -0.1)); -assertEquals(+0, Math.pow(Infinity, -2)); +assertEquals(+Infinity, 1/Math.pow(Infinity, -0.1)); +assertEquals(+Infinity, 1/Math.pow(Infinity, -2)); assertEquals(-Infinity, Math.pow(-Infinity, 3)); assertEquals(-Infinity, Math.pow(-Infinity, 13)); @@ -90,23 +91,23 @@ assertEquals(-Infinity, Math.pow(-Infinity, 13)); assertEquals(Infinity, Math.pow(-Infinity, 3.1)); assertEquals(Infinity, Math.pow(-Infinity, 2)); -assertEquals(-0, Math.pow(-Infinity, -3)); -assertEquals(-0, Math.pow(-Infinity, -13)); +assertEquals(-Infinity, 1/Math.pow(-Infinity, -3)); +assertEquals(-Infinity, 1/Math.pow(-Infinity, -13)); -assertEquals(+0, Math.pow(-Infinity, -3.1)); -assertEquals(+0, Math.pow(-Infinity, -2)); +assertEquals(+Infinity, 1/Math.pow(-Infinity, -3.1)); +assertEquals(+Infinity, 1/Math.pow(-Infinity, -2)); -assertEquals(+0, Math.pow(+0, 1.1)); -assertEquals(+0, Math.pow(+0, 2)); +assertEquals(+Infinity, 1/Math.pow(+0, 1.1)); +assertEquals(+Infinity, 1/Math.pow(+0, 2)); assertEquals(Infinity, Math.pow(+0, -1.1)); assertEquals(Infinity, Math.pow(+0, -2)); -assertEquals(-0, Math.pow(-0, 3)); -assertEquals(-0, Math.pow(-0, 13)); +assertEquals(-Infinity, 1/Math.pow(-0, 3)); +assertEquals(-Infinity, 1/Math.pow(-0, 13)); -assertEquals(+0, Math.pow(-0, 3.1)); -assertEquals(+0, Math.pow(-0, 2)); +assertEquals(+Infinity, 1/Math.pow(-0, 3.1)); +assertEquals(+Infinity, 1/Math.pow(-0, 2)); assertEquals(-Infinity, Math.pow(-0, -3)); assertEquals(-Infinity, Math.pow(-0, -13)); @@ -123,6 +124,18 @@ assertEquals(NaN, Math.pow(-2, -1.1)); assertEquals(NaN, Math.pow(-1000, 1.1)); assertEquals(NaN, Math.pow(-1000, -1.1)); +assertEquals(+Infinity, 1/Math.pow(-0, 0.5)); +assertEquals(+Infinity, 1/Math.pow(-0, 0.6)); +assertEquals(-Infinity, 1/Math.pow(-0, 1)); +assertEquals(-Infinity, 1/Math.pow(-0, 10000000001)); + +assertEquals(+Infinity, Math.pow(-0, -0.5)); +assertEquals(+Infinity, Math.pow(-0, -0.6)); +assertEquals(-Infinity, Math.pow(-0, -1)); +assertEquals(-Infinity, Math.pow(-0, -10000000001)); + + + // Tests from Sputnik S8.5_A13_T1. assertTrue((1*((Math.pow(2,53))-1)*(Math.pow(2,-1074))) === 4.4501477170144023e-308); assertTrue((1*(Math.pow(2,52))*(Math.pow(2,-1074))) === 2.2250738585072014e-308); diff --git a/deps/v8/test/mjsunit/mirror-error.js b/deps/v8/test/mjsunit/mirror-error.js index 4ed8c1b421..9fea17cf1c 100644 --- a/deps/v8/test/mjsunit/mirror-error.js +++ b/deps/v8/test/mjsunit/mirror-error.js @@ -76,7 +76,7 @@ function testErrorMirror(e) { } assertTrue(found_message, 'Property message not found'); } - + // Check the formatted text (regress 1231579). assertEquals(fromJSON.text, e.toString(), 'toString'); } diff --git a/deps/v8/test/mjsunit/regress/regress-1079.js b/deps/v8/test/mjsunit/regress/regress-1079.js new file mode 100644 index 0000000000..f3f3ce5bab --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-1079.js @@ -0,0 +1,45 @@ +// Copyright 2011 the V8 project authors. All rights reserved. +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Getting the arguments property of an optimized function should not crash, +// even if called through our optimized version of Function.prototype.apply. + +function optimized() { + return unoptimized.apply(null, arguments); +} + +// It's not crucial that this is unoptimized. +function unoptimized() { + with ({}) { + return optimized.arguments; + } +} + +for (var i = 0; i < 100000; ++i) { + assertEquals(3, optimized(1, 2, 3).length); +} + diff --git a/deps/v8/test/mjsunit/regress/regress-3408144.js b/deps/v8/test/mjsunit/regress/regress-3408144.js new file mode 100644 index 0000000000..6e292d635a --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-3408144.js @@ -0,0 +1,37 @@ +// Copyright 2011 the V8 project authors. All rights reserved. +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Test incorrect code generation for alternations on ARM. + + +// Flags: --nofull-compiler + +function foo() { + return (0 > ("10"||10) - 1); +} + +assertFalse(foo()); diff --git a/deps/v8/test/mjsunit/regress/regress-71647.js b/deps/v8/test/mjsunit/regress/regress-71647.js new file mode 100644 index 0000000000..44510116d9 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-71647.js @@ -0,0 +1,34 @@ +// Copyright 2011 the V8 project authors. All rights reserved. +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +var qe = 'object'; + +function g() { + for (var i = 0; i < 10000; i++) typeof i === qe; +} + +g(); diff --git a/deps/v8/test/mjsunit/strict-mode.js b/deps/v8/test/mjsunit/strict-mode.js index 6f3a244134..3cb6d32923 100644 --- a/deps/v8/test/mjsunit/strict-mode.js +++ b/deps/v8/test/mjsunit/strict-mode.js @@ -62,17 +62,17 @@ function CheckFunctionConstructorStrictMode() { } // Incorrect 'use strict' directive. -function UseStrictEscape() { +(function UseStrictEscape() { "use\\x20strict"; with ({}) {}; -} +})(); // 'use strict' in non-directive position. -function UseStrictNonDirective() { +(function UseStrictNonDirective() { void(0); "use strict"; with ({}) {}; -} +})(); // Multiple directives, including "use strict". assertThrows('\ @@ -87,47 +87,47 @@ with({}) {}', SyntaxError); CheckStrictMode("with({}) {}", SyntaxError); // Function named 'eval'. -CheckStrictMode("function eval() {}", SyntaxError) +CheckStrictMode("function eval() {}", SyntaxError); // Function named 'arguments'. -CheckStrictMode("function arguments() {}", SyntaxError) +CheckStrictMode("function arguments() {}", SyntaxError); // Function parameter named 'eval'. -CheckStrictMode("function foo(a, b, eval, c, d) {}", SyntaxError) +CheckStrictMode("function foo(a, b, eval, c, d) {}", SyntaxError); // Function parameter named 'arguments'. -CheckStrictMode("function foo(a, b, arguments, c, d) {}", SyntaxError) +CheckStrictMode("function foo(a, b, arguments, c, d) {}", SyntaxError); // Property accessor parameter named 'eval'. -CheckStrictMode("var o = { set foo(eval) {} }", SyntaxError) +CheckStrictMode("var o = { set foo(eval) {} }", SyntaxError); // Property accessor parameter named 'arguments'. -CheckStrictMode("var o = { set foo(arguments) {} }", SyntaxError) +CheckStrictMode("var o = { set foo(arguments) {} }", SyntaxError); // Duplicate function parameter name. -CheckStrictMode("function foo(a, b, c, d, b) {}", SyntaxError) +CheckStrictMode("function foo(a, b, c, d, b) {}", SyntaxError); // Function constructor: eval parameter name. -CheckFunctionConstructorStrictMode("eval") +CheckFunctionConstructorStrictMode("eval"); // Function constructor: arguments parameter name. -CheckFunctionConstructorStrictMode("arguments") +CheckFunctionConstructorStrictMode("arguments"); // Function constructor: duplicate parameter name. -CheckFunctionConstructorStrictMode("a", "b", "c", "b") -CheckFunctionConstructorStrictMode("a,b,c,b") +CheckFunctionConstructorStrictMode("a", "b", "c", "b"); +CheckFunctionConstructorStrictMode("a,b,c,b"); // catch(eval) -CheckStrictMode("try{}catch(eval){};", SyntaxError) +CheckStrictMode("try{}catch(eval){};", SyntaxError); // catch(arguments) -CheckStrictMode("try{}catch(arguments){};", SyntaxError) +CheckStrictMode("try{}catch(arguments){};", SyntaxError); // var eval -CheckStrictMode("var eval;", SyntaxError) +CheckStrictMode("var eval;", SyntaxError); // var arguments -CheckStrictMode("var arguments;", SyntaxError) +CheckStrictMode("var arguments;", SyntaxError); // Strict mode applies to the function in which the directive is used.. assertThrows('\ @@ -136,12 +136,12 @@ function foo(eval) {\ }', SyntaxError); // Strict mode doesn't affect the outer stop of strict code. -function NotStrict(eval) { +(function NotStrict(eval) { function Strict() { "use strict"; } with ({}) {}; -} +})(); // Octal literal CheckStrictMode("var x = 012"); @@ -150,6 +150,12 @@ CheckStrictMode("'Hello octal\\032'"); CheckStrictMode("function octal() { return 012; }"); CheckStrictMode("function octal() { return '\\032'; }"); +(function ValidEscape() { + "use strict"; + var x = '\0'; + var y = "\0"; +})(); + // Octal before "use strict" assertThrows('\ function strict() {\ @@ -158,110 +164,110 @@ assertThrows('\ }', SyntaxError); // Duplicate data properties. -CheckStrictMode("var x = { dupe : 1, nondupe: 3, dupe : 2 };", SyntaxError) -CheckStrictMode("var x = { '1234' : 1, '2345' : 2, '1234' : 3 };", SyntaxError) -CheckStrictMode("var x = { '1234' : 1, '2345' : 2, 1234 : 3 };", SyntaxError) -CheckStrictMode("var x = { 3.14 : 1, 2.71 : 2, 3.14 : 3 };", SyntaxError) -CheckStrictMode("var x = { 3.14 : 1, '3.14' : 2 };", SyntaxError) -CheckStrictMode("var x = { 123: 1, 123.00000000000000000000000000000000000000000000000000000000000000000001 : 2 }", SyntaxError) +CheckStrictMode("var x = { dupe : 1, nondupe: 3, dupe : 2 };", SyntaxError); +CheckStrictMode("var x = { '1234' : 1, '2345' : 2, '1234' : 3 };", SyntaxError); +CheckStrictMode("var x = { '1234' : 1, '2345' : 2, 1234 : 3 };", SyntaxError); +CheckStrictMode("var x = { 3.14 : 1, 2.71 : 2, 3.14 : 3 };", SyntaxError); +CheckStrictMode("var x = { 3.14 : 1, '3.14' : 2 };", SyntaxError); +CheckStrictMode("var x = { 123: 1, 123.00000000000000000000000000000000000000000000000000000000000000000001 : 2 }", SyntaxError); // Non-conflicting data properties. -function StrictModeNonDuplicate() { +(function StrictModeNonDuplicate() { "use strict"; var x = { 123 : 1, "0123" : 2 }; var x = { 123: 1, '123.00000000000000000000000000000000000000000000000000000000000000000001' : 2 } -} +})(); // Two getters (non-strict) -assertThrows("var x = { get foo() { }, get foo() { } };", SyntaxError) -assertThrows("var x = { get foo(){}, get 'foo'(){}};", SyntaxError) -assertThrows("var x = { get 12(){}, get '12'(){}};", SyntaxError) +assertThrows("var x = { get foo() { }, get foo() { } };", SyntaxError); +assertThrows("var x = { get foo(){}, get 'foo'(){}};", SyntaxError); +assertThrows("var x = { get 12(){}, get '12'(){}};", SyntaxError); // Two setters (non-strict) -assertThrows("var x = { set foo(v) { }, set foo(v) { } };", SyntaxError) -assertThrows("var x = { set foo(v) { }, set 'foo'(v) { } };", SyntaxError) -assertThrows("var x = { set 13(v) { }, set '13'(v) { } };", SyntaxError) +assertThrows("var x = { set foo(v) { }, set foo(v) { } };", SyntaxError); +assertThrows("var x = { set foo(v) { }, set 'foo'(v) { } };", SyntaxError); +assertThrows("var x = { set 13(v) { }, set '13'(v) { } };", SyntaxError); // Setter and data (non-strict) -assertThrows("var x = { foo: 'data', set foo(v) { } };", SyntaxError) -assertThrows("var x = { set foo(v) { }, foo: 'data' };", SyntaxError) -assertThrows("var x = { foo: 'data', set 'foo'(v) { } };", SyntaxError) -assertThrows("var x = { set foo(v) { }, 'foo': 'data' };", SyntaxError) -assertThrows("var x = { 'foo': 'data', set foo(v) { } };", SyntaxError) -assertThrows("var x = { set 'foo'(v) { }, foo: 'data' };", SyntaxError) -assertThrows("var x = { 'foo': 'data', set 'foo'(v) { } };", SyntaxError) -assertThrows("var x = { set 'foo'(v) { }, 'foo': 'data' };", SyntaxError) +assertThrows("var x = { foo: 'data', set foo(v) { } };", SyntaxError); +assertThrows("var x = { set foo(v) { }, foo: 'data' };", SyntaxError); +assertThrows("var x = { foo: 'data', set 'foo'(v) { } };", SyntaxError); +assertThrows("var x = { set foo(v) { }, 'foo': 'data' };", SyntaxError); +assertThrows("var x = { 'foo': 'data', set foo(v) { } };", SyntaxError); +assertThrows("var x = { set 'foo'(v) { }, foo: 'data' };", SyntaxError); +assertThrows("var x = { 'foo': 'data', set 'foo'(v) { } };", SyntaxError); +assertThrows("var x = { set 'foo'(v) { }, 'foo': 'data' };", SyntaxError); assertThrows("var x = { 12: 1, set '12'(v){}};", SyntaxError); assertThrows("var x = { 12: 1, set 12(v){}};", SyntaxError); assertThrows("var x = { '12': 1, set '12'(v){}};", SyntaxError); assertThrows("var x = { '12': 1, set 12(v){}};", SyntaxError); // Getter and data (non-strict) -assertThrows("var x = { foo: 'data', get foo() { } };", SyntaxError) -assertThrows("var x = { get foo() { }, foo: 'data' };", SyntaxError) -assertThrows("var x = { 'foo': 'data', get foo() { } };", SyntaxError) -assertThrows("var x = { get 'foo'() { }, 'foo': 'data' };", SyntaxError) +assertThrows("var x = { foo: 'data', get foo() { } };", SyntaxError); +assertThrows("var x = { get foo() { }, foo: 'data' };", SyntaxError); +assertThrows("var x = { 'foo': 'data', get foo() { } };", SyntaxError); +assertThrows("var x = { get 'foo'() { }, 'foo': 'data' };", SyntaxError); assertThrows("var x = { '12': 1, get '12'(){}};", SyntaxError); assertThrows("var x = { '12': 1, get 12(){}};", SyntaxError); // Assignment to eval or arguments -CheckStrictMode("function strict() { eval = undefined; }", SyntaxError) -CheckStrictMode("function strict() { arguments = undefined; }", SyntaxError) -CheckStrictMode("function strict() { print(eval = undefined); }", SyntaxError) -CheckStrictMode("function strict() { print(arguments = undefined); }", SyntaxError) -CheckStrictMode("function strict() { var x = eval = undefined; }", SyntaxError) -CheckStrictMode("function strict() { var x = arguments = undefined; }", SyntaxError) +CheckStrictMode("function strict() { eval = undefined; }", SyntaxError); +CheckStrictMode("function strict() { arguments = undefined; }", SyntaxError); +CheckStrictMode("function strict() { print(eval = undefined); }", SyntaxError); +CheckStrictMode("function strict() { print(arguments = undefined); }", SyntaxError); +CheckStrictMode("function strict() { var x = eval = undefined; }", SyntaxError); +CheckStrictMode("function strict() { var x = arguments = undefined; }", SyntaxError); // Compound assignment to eval or arguments -CheckStrictMode("function strict() { eval *= undefined; }", SyntaxError) -CheckStrictMode("function strict() { arguments /= undefined; }", SyntaxError) -CheckStrictMode("function strict() { print(eval %= undefined); }", SyntaxError) -CheckStrictMode("function strict() { print(arguments %= undefined); }", SyntaxError) -CheckStrictMode("function strict() { var x = eval += undefined; }", SyntaxError) -CheckStrictMode("function strict() { var x = arguments -= undefined; }", SyntaxError) -CheckStrictMode("function strict() { eval <<= undefined; }", SyntaxError) -CheckStrictMode("function strict() { arguments >>= undefined; }", SyntaxError) -CheckStrictMode("function strict() { print(eval >>>= undefined); }", SyntaxError) -CheckStrictMode("function strict() { print(arguments &= undefined); }", SyntaxError) -CheckStrictMode("function strict() { var x = eval ^= undefined; }", SyntaxError) -CheckStrictMode("function strict() { var x = arguments |= undefined; }", SyntaxError) +CheckStrictMode("function strict() { eval *= undefined; }", SyntaxError); +CheckStrictMode("function strict() { arguments /= undefined; }", SyntaxError); +CheckStrictMode("function strict() { print(eval %= undefined); }", SyntaxError); +CheckStrictMode("function strict() { print(arguments %= undefined); }", SyntaxError); +CheckStrictMode("function strict() { var x = eval += undefined; }", SyntaxError); +CheckStrictMode("function strict() { var x = arguments -= undefined; }", SyntaxError); +CheckStrictMode("function strict() { eval <<= undefined; }", SyntaxError); +CheckStrictMode("function strict() { arguments >>= undefined; }", SyntaxError); +CheckStrictMode("function strict() { print(eval >>>= undefined); }", SyntaxError); +CheckStrictMode("function strict() { print(arguments &= undefined); }", SyntaxError); +CheckStrictMode("function strict() { var x = eval ^= undefined; }", SyntaxError); +CheckStrictMode("function strict() { var x = arguments |= undefined; }", SyntaxError); // Postfix increment with eval or arguments -CheckStrictMode("function strict() { eval++; }", SyntaxError) -CheckStrictMode("function strict() { arguments++; }", SyntaxError) -CheckStrictMode("function strict() { print(eval++); }", SyntaxError) -CheckStrictMode("function strict() { print(arguments++); }", SyntaxError) -CheckStrictMode("function strict() { var x = eval++; }", SyntaxError) -CheckStrictMode("function strict() { var x = arguments++; }", SyntaxError) +CheckStrictMode("function strict() { eval++; }", SyntaxError); +CheckStrictMode("function strict() { arguments++; }", SyntaxError); +CheckStrictMode("function strict() { print(eval++); }", SyntaxError); +CheckStrictMode("function strict() { print(arguments++); }", SyntaxError); +CheckStrictMode("function strict() { var x = eval++; }", SyntaxError); +CheckStrictMode("function strict() { var x = arguments++; }", SyntaxError); // Postfix decrement with eval or arguments -CheckStrictMode("function strict() { eval--; }", SyntaxError) -CheckStrictMode("function strict() { arguments--; }", SyntaxError) -CheckStrictMode("function strict() { print(eval--); }", SyntaxError) -CheckStrictMode("function strict() { print(arguments--); }", SyntaxError) -CheckStrictMode("function strict() { var x = eval--; }", SyntaxError) -CheckStrictMode("function strict() { var x = arguments--; }", SyntaxError) +CheckStrictMode("function strict() { eval--; }", SyntaxError); +CheckStrictMode("function strict() { arguments--; }", SyntaxError); +CheckStrictMode("function strict() { print(eval--); }", SyntaxError); +CheckStrictMode("function strict() { print(arguments--); }", SyntaxError); +CheckStrictMode("function strict() { var x = eval--; }", SyntaxError); +CheckStrictMode("function strict() { var x = arguments--; }", SyntaxError); // Prefix increment with eval or arguments -CheckStrictMode("function strict() { ++eval; }", SyntaxError) -CheckStrictMode("function strict() { ++arguments; }", SyntaxError) -CheckStrictMode("function strict() { print(++eval); }", SyntaxError) -CheckStrictMode("function strict() { print(++arguments); }", SyntaxError) -CheckStrictMode("function strict() { var x = ++eval; }", SyntaxError) -CheckStrictMode("function strict() { var x = ++arguments; }", SyntaxError) +CheckStrictMode("function strict() { ++eval; }", SyntaxError); +CheckStrictMode("function strict() { ++arguments; }", SyntaxError); +CheckStrictMode("function strict() { print(++eval); }", SyntaxError); +CheckStrictMode("function strict() { print(++arguments); }", SyntaxError); +CheckStrictMode("function strict() { var x = ++eval; }", SyntaxError); +CheckStrictMode("function strict() { var x = ++arguments; }", SyntaxError); // Prefix decrement with eval or arguments -CheckStrictMode("function strict() { --eval; }", SyntaxError) -CheckStrictMode("function strict() { --arguments; }", SyntaxError) -CheckStrictMode("function strict() { print(--eval); }", SyntaxError) -CheckStrictMode("function strict() { print(--arguments); }", SyntaxError) -CheckStrictMode("function strict() { var x = --eval; }", SyntaxError) -CheckStrictMode("function strict() { var x = --arguments; }", SyntaxError) +CheckStrictMode("function strict() { --eval; }", SyntaxError); +CheckStrictMode("function strict() { --arguments; }", SyntaxError); +CheckStrictMode("function strict() { print(--eval); }", SyntaxError); +CheckStrictMode("function strict() { print(--arguments); }", SyntaxError); +CheckStrictMode("function strict() { var x = --eval; }", SyntaxError); +CheckStrictMode("function strict() { var x = --arguments; }", SyntaxError); // Prefix unary operators other than delete, ++, -- are valid in strict mode -function StrictModeUnaryOperators() { +(function StrictModeUnaryOperators() { "use strict"; var x = [void eval, typeof eval, +eval, -eval, ~eval, !eval]; var y = [void arguments, typeof arguments, +arguments, -arguments, ~arguments, !arguments]; -}
\ No newline at end of file +})(); diff --git a/deps/v8/tools/v8.xcodeproj/project.pbxproj b/deps/v8/tools/v8.xcodeproj/project.pbxproj index d02d2b1d5d..86fcd8dcab 100644 --- a/deps/v8/tools/v8.xcodeproj/project.pbxproj +++ b/deps/v8/tools/v8.xcodeproj/project.pbxproj @@ -47,6 +47,7 @@ 890A14020EE9C4B400E49346 /* regexp-macro-assembler-irregexp.cc in Sources */ = {isa = PBXBuildFile; fileRef = 89A15C750EE466D000B48DEB /* regexp-macro-assembler-irregexp.cc */; }; 890A14030EE9C4B500E49346 /* regexp-macro-assembler-tracer.cc in Sources */ = {isa = PBXBuildFile; fileRef = 89A15C770EE466D000B48DEB /* regexp-macro-assembler-tracer.cc */; }; 890A14040EE9C4B700E49346 /* regexp-macro-assembler.cc in Sources */ = {isa = PBXBuildFile; fileRef = 89A15C790EE466D000B48DEB /* regexp-macro-assembler.cc */; }; + 8924315C12F8539900906AB2 /* lithium-gap-resolver-x64.cc in Sources */ = {isa = PBXBuildFile; fileRef = 8924315A12F8539900906AB2 /* lithium-gap-resolver-x64.cc */; }; 8938A2A312D63B630080CDDE /* lithium-x64.cc in Sources */ = {isa = PBXBuildFile; fileRef = 8938A2A212D63B630080CDDE /* lithium-x64.cc */; }; 893988070F2A35FA007D5254 /* libv8.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 8970F2F00E719FB2006AE7B5 /* libv8.a */; }; 8939880D0F2A362A007D5254 /* d8.cc in Sources */ = {isa = PBXBuildFile; fileRef = 89A15C920EE46A1700B48DEB /* d8.cc */; }; @@ -563,6 +564,8 @@ 58950D5A0F55514900F3E8BA /* virtual-frame.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = "virtual-frame.cc"; sourceTree = "<group>"; }; 58950D5B0F55514900F3E8BA /* virtual-frame.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "virtual-frame.h"; sourceTree = "<group>"; }; 8900116B0E71CA2300F91F35 /* libraries.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = libraries.cc; sourceTree = "<group>"; }; + 8924315A12F8539900906AB2 /* lithium-gap-resolver-x64.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = "lithium-gap-resolver-x64.cc"; path = "x64/lithium-gap-resolver-x64.cc"; sourceTree = "<group>"; }; + 8924315B12F8539900906AB2 /* lithium-gap-resolver-x64.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "lithium-gap-resolver-x64.h"; path = "x64/lithium-gap-resolver-x64.h"; sourceTree = "<group>"; }; 8938A2A212D63B630080CDDE /* lithium-x64.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = "lithium-x64.cc"; path = "x64/lithium-x64.cc"; sourceTree = "<group>"; }; 893986D40F29020C007D5254 /* apiutils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = apiutils.h; sourceTree = "<group>"; }; 8939880B0F2A35FA007D5254 /* d8 */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = d8; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -1458,6 +1461,8 @@ 89B91B8C12D4EF95002FF4BC /* jump-target-x64.cc */, 89F3605A12DCDF6400ACF8A6 /* lithium-codegen-x64.cc */, 89B91B8D12D4EF95002FF4BC /* lithium-codegen-x64.h */, + 8924315A12F8539900906AB2 /* lithium-gap-resolver-x64.cc */, + 8924315B12F8539900906AB2 /* lithium-gap-resolver-x64.h */, 8938A2A212D63B630080CDDE /* lithium-x64.cc */, 89B91B8E12D4EF95002FF4BC /* lithium-x64.h */, 89B91B8F12D4EF95002FF4BC /* macro-assembler-x64.cc */, @@ -1979,6 +1984,7 @@ 89F3605B12DCDF6400ACF8A6 /* lithium-codegen-x64.cc in Sources */, 89D7DDDE12E8DE09001E2B82 /* gdb-jit.cc in Sources */, 89D7DDDF12E8DE09001E2B82 /* inspector.cc in Sources */, + 8924315C12F8539900906AB2 /* lithium-gap-resolver-x64.cc in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; |