diff options
author | Ryan Dahl <ry@tinyclouds.org> | 2010-11-02 00:10:35 +0300 |
---|---|---|
committer | Ryan Dahl <ry@tinyclouds.org> | 2010-11-02 00:10:35 +0300 |
commit | ea78d995e06c3cd9037021d0deb59b1688548b83 (patch) | |
tree | 9dcd896973eeffe9ac993ad3eec784879a879029 /deps | |
parent | fd725efa8f98c3a4d70165a6bcb4a3085621509e (diff) |
Upgrade V8 to 2.5.3
Diffstat (limited to 'deps')
61 files changed, 1439 insertions, 934 deletions
diff --git a/deps/v8/ChangeLog b/deps/v8/ChangeLog index 07859597bf8..69aff33d185 100644 --- a/deps/v8/ChangeLog +++ b/deps/v8/ChangeLog @@ -1,3 +1,12 @@ +2010-11-01: Version 2.5.3 + + Fixed a bug that prevents constants from overwriting function values + in object literals (issue 907). + + Fixed a bug with reporting of impossible nested calls of DOM functions + (issue http://crbug.com/60753). + + 2010-10-27: Version 2.5.2 Improved sampler resolution on Linux. diff --git a/deps/v8/include/v8.h b/deps/v8/include/v8.h index 89502cb9156..c7e4552b4d4 100644 --- a/deps/v8/include/v8.h +++ b/deps/v8/include/v8.h @@ -1790,18 +1790,19 @@ class Arguments { inline bool IsConstructCall() const; inline Local<Value> Data() const; private: + static const int kDataIndex = 0; + static const int kCalleeIndex = -1; + static const int kHolderIndex = -2; + friend class ImplementationUtilities; - inline Arguments(Local<Value> data, - Local<Object> holder, - Local<Function> callee, - bool is_construct_call, - void** values, int length); - Local<Value> data_; - Local<Object> holder_; - Local<Function> callee_; - bool is_construct_call_; - void** values_; + inline Arguments(internal::Object** implicit_args, + internal::Object** values, + int length, + bool is_construct_call); + internal::Object** implicit_args_; + internal::Object** values_; int length_; + bool is_construct_call_; }; @@ -3470,14 +3471,13 @@ void Persistent<T>::ClearWeak() { } -Arguments::Arguments(v8::Local<v8::Value> data, - v8::Local<v8::Object> holder, - v8::Local<v8::Function> callee, - bool is_construct_call, - void** values, int length) - : data_(data), holder_(holder), callee_(callee), - is_construct_call_(is_construct_call), - values_(values), length_(length) { } +Arguments::Arguments(internal::Object** implicit_args, + internal::Object** values, int length, + bool is_construct_call) + : implicit_args_(implicit_args), + values_(values), + length_(length), + is_construct_call_(is_construct_call) { } Local<Value> Arguments::operator[](int i) const { @@ -3487,7 +3487,8 @@ Local<Value> Arguments::operator[](int i) const { Local<Function> Arguments::Callee() const { - return callee_; + return Local<Function>(reinterpret_cast<Function*>( + &implicit_args_[kCalleeIndex])); } @@ -3497,12 +3498,13 @@ Local<Object> Arguments::This() const { Local<Object> Arguments::Holder() const { - return holder_; + return Local<Object>(reinterpret_cast<Object*>( + &implicit_args_[kHolderIndex])); } Local<Value> Arguments::Data() const { - return data_; + return Local<Value>(reinterpret_cast<Value*>(&implicit_args_[kDataIndex])); } diff --git a/deps/v8/src/api.cc b/deps/v8/src/api.cc index 2df31df3533..617922dd5a7 100644 --- a/deps/v8/src/api.cc +++ b/deps/v8/src/api.cc @@ -1155,13 +1155,13 @@ void ObjectTemplate::SetInternalFieldCount(int value) { ScriptData* ScriptData::PreCompile(const char* input, int length) { unibrow::Utf8InputBuffer<> buf(input, length); - return i::Parser::PreParse(i::Handle<i::String>(), &buf, NULL); + return i::ParserApi::PreParse(i::Handle<i::String>(), &buf, NULL); } ScriptData* ScriptData::PreCompile(v8::Handle<String> source) { i::Handle<i::String> str = Utils::OpenHandle(*source); - return i::Parser::PreParse(str, NULL, NULL); + return i::ParserApi::PreParse(str, NULL, NULL); } diff --git a/deps/v8/src/apiutils.h b/deps/v8/src/apiutils.h index 8c791ebdd57..1313ddaabea 100644 --- a/deps/v8/src/apiutils.h +++ b/deps/v8/src/apiutils.h @@ -29,7 +29,6 @@ #define V8_APIUTILS_H_ namespace v8 { - class ImplementationUtilities { public: static v8::Handle<v8::Primitive> Undefined(); @@ -45,12 +44,21 @@ class ImplementationUtilities { return that->names_; } - static v8::Arguments NewArguments(Local<Value> data, - Local<Object> holder, - Local<Function> callee, - bool is_construct_call, - void** argv, int argc) { - return v8::Arguments(data, holder, callee, is_construct_call, argv, argc); + // Packs additional parameters for the NewArguments function. |implicit_args| + // is a pointer to the last element of 3-elements array controlled by GC. + static void PrepareArgumentsData(internal::Object** implicit_args, + internal::Object* data, + internal::JSFunction* callee, + internal::Object* holder) { + implicit_args[v8::Arguments::kDataIndex] = data; + implicit_args[v8::Arguments::kCalleeIndex] = callee; + implicit_args[v8::Arguments::kHolderIndex] = holder; + } + + static v8::Arguments NewArguments(internal::Object** implicit_args, + internal::Object** argv, int argc, + bool is_construct_call) { + return v8::Arguments(implicit_args, argv, argc, is_construct_call); } // Introduce an alias for the handle scope data to allow non-friends diff --git a/deps/v8/src/arguments.h b/deps/v8/src/arguments.h index c17f4cf80bb..d51c9e4cb15 100644 --- a/deps/v8/src/arguments.h +++ b/deps/v8/src/arguments.h @@ -84,6 +84,15 @@ class CustomArguments : public Relocatable { values_[1] = holder; values_[0] = data; } + + inline CustomArguments() { +#ifdef DEBUG + for (size_t i = 0; i < ARRAY_SIZE(values_); i++) { + values_[i] = reinterpret_cast<Object*>(kZapValue); + } +#endif + } + void IterateInstance(ObjectVisitor* v); Object** end() { return values_ + ARRAY_SIZE(values_) - 1; } private: diff --git a/deps/v8/src/arm/assembler-arm.cc b/deps/v8/src/arm/assembler-arm.cc index 7d368bf4158..ebbd9b1138a 100644 --- a/deps/v8/src/arm/assembler-arm.cc +++ b/deps/v8/src/arm/assembler-arm.cc @@ -1004,7 +1004,7 @@ void Assembler::blx(int branch_offset) { // v5 and above int h = ((branch_offset & 2) >> 1)*B24; int imm24 = branch_offset >> 2; ASSERT(is_int24(imm24)); - emit(15 << 28 | B27 | B25 | h | (imm24 & Imm24Mask)); + emit(nv | B27 | B25 | h | (imm24 & Imm24Mask)); } @@ -1634,15 +1634,29 @@ void Assembler::stm(BlockAddrMode am, // Exception-generating instructions and debugging support. -void Assembler::stop(const char* msg) { +// Stops with a non-negative code less than kNumOfWatchedStops support +// enabling/disabling and a counter feature. See simulator-arm.h . +void Assembler::stop(const char* msg, Condition cond, int32_t code) { #ifndef __arm__ - // The simulator handles these special instructions and stops execution. - emit(15 << 28 | ((intptr_t) msg)); + // See constants-arm.h SoftwareInterruptCodes. Unluckily the Assembler and + // Simulator do not share constants declaration. + ASSERT(code >= kDefaultStopCode); + static const uint32_t kStopInterruptCode = 1 << 23; + static const uint32_t kMaxStopCode = kStopInterruptCode - 1; + // The Simulator will handle the stop instruction and get the message address. + // It expects to find the address just after the svc instruction. + BlockConstPoolFor(2); + if (code >= 0) { + svc(kStopInterruptCode + code, cond); + } else { + svc(kStopInterruptCode + kMaxStopCode, cond); + } + emit(reinterpret_cast<Instr>(msg)); #else // def __arm__ #ifdef CAN_USE_ARMV5_INSTRUCTIONS bkpt(0); #else // ndef CAN_USE_ARMV5_INSTRUCTIONS - swi(0x9f0001); + svc(0x9f0001); #endif // ndef CAN_USE_ARMV5_INSTRUCTIONS #endif // def __arm__ } @@ -1654,7 +1668,7 @@ void Assembler::bkpt(uint32_t imm16) { // v5 and above } -void Assembler::swi(uint32_t imm24, Condition cond) { +void Assembler::svc(uint32_t imm24, Condition cond) { ASSERT(is_uint24(imm24)); emit(cond | 15*B24 | imm24); } diff --git a/deps/v8/src/arm/assembler-arm.h b/deps/v8/src/arm/assembler-arm.h index 1c4fd6094d2..5b647a7537e 100644 --- a/deps/v8/src/arm/assembler-arm.h +++ b/deps/v8/src/arm/assembler-arm.h @@ -904,10 +904,13 @@ class Assembler : public Malloced { void stm(BlockAddrMode am, Register base, RegList src, Condition cond = al); // Exception-generating instructions and debugging support - void stop(const char* msg); + static const int kDefaultStopCode = -1; + void stop(const char* msg, + Condition cond = al, + int32_t code = kDefaultStopCode); void bkpt(uint32_t imm16); // v5 and above - void swi(uint32_t imm24, Condition cond = al); + void svc(uint32_t imm24, Condition cond = al); // Coprocessor instructions diff --git a/deps/v8/src/arm/codegen-arm.cc b/deps/v8/src/arm/codegen-arm.cc index 0c060f0f6ff..70ff244649c 100644 --- a/deps/v8/src/arm/codegen-arm.cc +++ b/deps/v8/src/arm/codegen-arm.cc @@ -3596,6 +3596,12 @@ void CodeGenerator::VisitObjectLiteral(ObjectLiteral* node) { frame_->CallRuntime(Runtime::kCreateObjectLiteralShallow, 4); } frame_->EmitPush(r0); // save the result + + // Mark all computed expressions that are bound to a key that + // is shadowed by a later occurrence of the same key. For the + // marked expressions, no store code is emitted. + node->CalculateEmitStore(); + for (int i = 0; i < node->properties()->length(); i++) { // At the start of each iteration, the top of stack contains // the newly created object literal. @@ -3612,11 +3618,15 @@ void CodeGenerator::VisitObjectLiteral(ObjectLiteral* node) { if (key->handle()->IsSymbol()) { Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); Load(value); - frame_->PopToR0(); - // Fetch the object literal. - frame_->SpillAllButCopyTOSToR1(); - __ mov(r2, Operand(key->handle())); - frame_->CallCodeObject(ic, RelocInfo::CODE_TARGET, 0); + if (property->emit_store()) { + frame_->PopToR0(); + // Fetch the object literal. + frame_->SpillAllButCopyTOSToR1(); + __ mov(r2, Operand(key->handle())); + frame_->CallCodeObject(ic, RelocInfo::CODE_TARGET, 0); + } else { + frame_->Drop(); + } break; } // else fall through @@ -3624,7 +3634,11 @@ void CodeGenerator::VisitObjectLiteral(ObjectLiteral* node) { frame_->Dup(); Load(key); Load(value); - frame_->CallRuntime(Runtime::kSetProperty, 3); + if (property->emit_store()) { + frame_->CallRuntime(Runtime::kSetProperty, 3); + } else { + frame_->Drop(3); + } break; } case ObjectLiteral::Property::SETTER: { diff --git a/deps/v8/src/arm/constants-arm.h b/deps/v8/src/arm/constants-arm.h index b2b5cb56b0f..123c5e79720 100644 --- a/deps/v8/src/arm/constants-arm.h +++ b/deps/v8/src/arm/constants-arm.h @@ -186,12 +186,18 @@ enum Shift { // Special Software Interrupt codes when used in the presence of the ARM // simulator. +// svc (formerly swi) provides a 24bit immediate value. Use bits 22:0 for +// standard SoftwareInterrupCode. Bit 23 is reserved for the stop feature. enum SoftwareInterruptCodes { // transition to C code call_rt_redirected = 0x10, // break point - break_point = 0x20 + break_point = 0x20, + // stop + stop = 1 << 23 }; +static const int32_t kStopCodeMask = stop - 1; +static const uint32_t kMaxStopCode = stop - 1; // Type of VFP register. Determines register encoding. @@ -325,7 +331,7 @@ class Instr { inline int SImmed24Field() const { return ((InstructionBits() << 8) >> 8); } // Fields used in Software interrupt instructions - inline SoftwareInterruptCodes SwiField() const { + inline SoftwareInterruptCodes SvcField() const { return static_cast<SoftwareInterruptCodes>(Bits(23, 0)); } diff --git a/deps/v8/src/arm/cpu-arm.cc b/deps/v8/src/arm/cpu-arm.cc index a3bf48328d0..e998b6f596c 100644 --- a/deps/v8/src/arm/cpu-arm.cc +++ b/deps/v8/src/arm/cpu-arm.cc @@ -70,7 +70,7 @@ void CPU::FlushICache(void* start, size_t size) { // __arm__ may be defined in thumb mode. register uint32_t scno asm("r7") = __ARM_NR_cacheflush; asm volatile( - "swi 0x0" + "svc 0x0" : "=r" (beg) : "0" (beg), "r" (end), "r" (flg), "r" (scno)); #else @@ -83,7 +83,7 @@ void CPU::FlushICache(void* start, size_t size) { ".ARM \n" "1: push {r7} \n\t" "mov r7, %4 \n\t" - "swi 0x0 \n\t" + "svc 0x0 \n\t" "pop {r7} \n\t" "@ Enter THUMB Mode\n\t" "adr r3, 2f+1 \n\t" @@ -98,20 +98,20 @@ void CPU::FlushICache(void* start, size_t size) { #if defined (__arm__) && !defined(__thumb__) // __arm__ may be defined in thumb mode. asm volatile( - "swi %1" + "svc %1" : "=r" (beg) : "i" (__ARM_NR_cacheflush), "0" (beg), "r" (end), "r" (flg)); #else // Do not use the value of __ARM_NR_cacheflush in the inline assembly // below, because the thumb mode value would be used, which would be - // wrong, since we switch to ARM mode before executing the swi instruction + // wrong, since we switch to ARM mode before executing the svc instruction asm volatile( "@ Enter ARM Mode \n\t" "adr r3, 1f \n\t" "bx r3 \n\t" ".ALIGN 4 \n\t" ".ARM \n" - "1: swi 0x9f0002 \n" + "1: svc 0x9f0002 \n" "@ Enter THUMB Mode\n\t" "adr r3, 2f+1 \n\t" "bx r3 \n\t" diff --git a/deps/v8/src/arm/disasm-arm.cc b/deps/v8/src/arm/disasm-arm.cc index 5122f437b94..4e7580f8684 100644 --- a/deps/v8/src/arm/disasm-arm.cc +++ b/deps/v8/src/arm/disasm-arm.cc @@ -108,7 +108,7 @@ class Decoder { void PrintShiftImm(Instr* instr); void PrintShiftSat(Instr* instr); void PrintPU(Instr* instr); - void PrintSoftwareInterrupt(SoftwareInterruptCodes swi); + void PrintSoftwareInterrupt(SoftwareInterruptCodes svc); // Handle formatting of instructions and their options. int FormatRegister(Instr* instr, const char* option); @@ -126,8 +126,8 @@ class Decoder { void DecodeType4(Instr* instr); void DecodeType5(Instr* instr); void DecodeType6(Instr* instr); - void DecodeType7(Instr* instr); - void DecodeUnconditional(Instr* instr); + // Type 7 includes special Debugger instructions. + int DecodeType7(Instr* instr); // For VFP support. void DecodeTypeVFP(Instr* instr); void DecodeType6CoprocessorIns(Instr* instr); @@ -290,8 +290,8 @@ void Decoder::PrintPU(Instr* instr) { // Print SoftwareInterrupt codes. Factoring this out reduces the complexity of // the FormatOption method. -void Decoder::PrintSoftwareInterrupt(SoftwareInterruptCodes swi) { - switch (swi) { +void Decoder::PrintSoftwareInterrupt(SoftwareInterruptCodes svc) { + switch (svc) { case call_rt_redirected: Print("call_rt_redirected"); return; @@ -299,9 +299,16 @@ void Decoder::PrintSoftwareInterrupt(SoftwareInterruptCodes swi) { Print("break_point"); return; default: - out_buffer_pos_ += v8i::OS::SNPrintF(out_buffer_ + out_buffer_pos_, - "%d", - swi); + if (svc >= stop) { + out_buffer_pos_ += v8i::OS::SNPrintF(out_buffer_ + out_buffer_pos_, + "%d - 0x%x", + svc & kStopCodeMask, + svc & kStopCodeMask); + } else { + out_buffer_pos_ += v8i::OS::SNPrintF(out_buffer_ + out_buffer_pos_, + "%d", + svc); + } return; } } @@ -553,9 +560,9 @@ int Decoder::FormatOption(Instr* instr, const char* format) { PrintShiftRm(instr); return 8; } - } else if (format[1] == 'w') { // 'swi - ASSERT(STRING_STARTS_WITH(format, "swi")); - PrintSoftwareInterrupt(instr->SwiField()); + } else if (format[1] == 'v') { // 'svc + ASSERT(STRING_STARTS_WITH(format, "svc")); + PrintSoftwareInterrupt(instr->SvcField()); return 3; } else if (format[1] == 'i') { // 'sign: signed extra loads and stores ASSERT(STRING_STARTS_WITH(format, "sign")); @@ -1004,72 +1011,27 @@ void Decoder::DecodeType6(Instr* instr) { } -void Decoder::DecodeType7(Instr* instr) { +int Decoder::DecodeType7(Instr* instr) { if (instr->Bit(24) == 1) { - Format(instr, "swi'cond 'swi"); + if (instr->SvcField() >= stop) { + Format(instr, "stop'cond 'svc"); + // Also print the stop message. Its address is encoded + // in the following 4 bytes. + out_buffer_pos_ += + v8i::OS::SNPrintF(out_buffer_ + out_buffer_pos_, + "\n %p %08x stop message: %s", + reinterpret_cast<int32_t*>(instr + Instr::kInstrSize), + *reinterpret_cast<char**>(instr + Instr::kInstrSize), + *reinterpret_cast<char**>(instr + Instr::kInstrSize)); + // We have decoded 2 * Instr::kInstrSize bytes. + return 2 * Instr::kInstrSize; + } else { + Format(instr, "svc'cond 'svc"); + } } else { DecodeTypeVFP(instr); } -} - -void Decoder::DecodeUnconditional(Instr* instr) { - if (instr->Bits(7, 4) == 0xB && instr->Bits(27, 25) == 0 && instr->HasL()) { - Format(instr, "'memop'h'pu 'rd, "); - bool immediate = instr->HasB(); - switch (instr->PUField()) { - case 0: { - // Post index, negative. - if (instr->HasW()) { - Unknown(instr); - break; - } - if (immediate) { - Format(instr, "['rn], #-'imm12"); - } else { - Format(instr, "['rn], -'rm"); - } - break; - } - case 1: { - // Post index, positive. - if (instr->HasW()) { - Unknown(instr); - break; - } - if (immediate) { - Format(instr, "['rn], #+'imm12"); - } else { - Format(instr, "['rn], +'rm"); - } - break; - } - case 2: { - // Pre index or offset, negative. - if (immediate) { - Format(instr, "['rn, #-'imm12]'w"); - } else { - Format(instr, "['rn, -'rm]'w"); - } - break; - } - case 3: { - // Pre index or offset, positive. - if (immediate) { - Format(instr, "['rn, #+'imm12]'w"); - } else { - Format(instr, "['rn, +'rm]'w"); - } - break; - } - default: { - // The PU field is a 2-bit field. - UNREACHABLE(); - break; - } - } - return; - } - Format(instr, "break 'msg"); + return Instr::kInstrSize; } @@ -1332,7 +1294,7 @@ int Decoder::InstructionDecode(byte* instr_ptr) { "%08x ", instr->InstructionBits()); if (instr->ConditionField() == special_condition) { - DecodeUnconditional(instr); + UNIMPLEMENTED(); return Instr::kInstrSize; } switch (instr->TypeField()) { @@ -1362,8 +1324,7 @@ int Decoder::InstructionDecode(byte* instr_ptr) { break; } case 7: { - DecodeType7(instr); - break; + return DecodeType7(instr); } default: { // The type field is 3-bits in the ARM encoding. diff --git a/deps/v8/src/arm/full-codegen-arm.cc b/deps/v8/src/arm/full-codegen-arm.cc index 2855ca4f3b3..9935e038f5c 100644 --- a/deps/v8/src/arm/full-codegen-arm.cc +++ b/deps/v8/src/arm/full-codegen-arm.cc @@ -1169,6 +1169,11 @@ void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { // result_saved is false the result is in r0. bool result_saved = false; + // Mark all computed expressions that are bound to a key that + // is shadowed by a later occurrence of the same key. For the + // marked expressions, no store code is emitted. + expr->CalculateEmitStore(); + for (int i = 0; i < expr->properties()->length(); i++) { ObjectLiteral::Property* property = expr->properties()->at(i); if (property->IsCompileTimeValue()) continue; @@ -1190,8 +1195,10 @@ void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { VisitForAccumulatorValue(value); __ mov(r2, Operand(key->handle())); __ ldr(r1, MemOperand(sp)); - Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); - EmitCallIC(ic, RelocInfo::CODE_TARGET); + if (property->emit_store()) { + Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); + EmitCallIC(ic, RelocInfo::CODE_TARGET); + } break; } // Fall through. @@ -1201,7 +1208,11 @@ void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { __ push(r0); VisitForStackValue(key); VisitForStackValue(value); - __ CallRuntime(Runtime::kSetProperty, 3); + if (property->emit_store()) { + __ CallRuntime(Runtime::kSetProperty, 3); + } else { + __ Drop(3); + } break; case ObjectLiteral::Property::GETTER: case ObjectLiteral::Property::SETTER: diff --git a/deps/v8/src/arm/ic-arm.cc b/deps/v8/src/arm/ic-arm.cc index c460f9ca6f7..a09afdf754e 100644 --- a/deps/v8/src/arm/ic-arm.cc +++ b/deps/v8/src/arm/ic-arm.cc @@ -544,7 +544,7 @@ static void GenerateMonomorphicCacheProbe(MacroAssembler* masm, // Probe the stub cache. Code::Flags flags = Code::ComputeFlags(kind, NOT_IN_LOOP, MONOMORPHIC, NORMAL, argc); - StubCache::GenerateProbe(masm, flags, r1, r2, r3, no_reg); + StubCache::GenerateProbe(masm, flags, r1, r2, r3, r4, r5); // If the stub cache probing failed, the receiver might be a value. // For value objects, we use the map of the prototype objects for @@ -583,7 +583,7 @@ static void GenerateMonomorphicCacheProbe(MacroAssembler* masm, // Probe the stub cache for the value object. __ bind(&probe); - StubCache::GenerateProbe(masm, flags, r1, r2, r3, no_reg); + StubCache::GenerateProbe(masm, flags, r1, r2, r3, r4, r5); __ bind(&miss); } @@ -858,7 +858,7 @@ void LoadIC::GenerateMegamorphic(MacroAssembler* masm) { Code::Flags flags = Code::ComputeFlags(Code::LOAD_IC, NOT_IN_LOOP, MONOMORPHIC); - StubCache::GenerateProbe(masm, flags, r0, r2, r3, no_reg); + StubCache::GenerateProbe(masm, flags, r0, r2, r3, r4, r5); // Cache miss: Jump to runtime. GenerateMiss(masm); @@ -2163,7 +2163,7 @@ void StoreIC::GenerateMegamorphic(MacroAssembler* masm) { Code::Flags flags = Code::ComputeFlags(Code::STORE_IC, NOT_IN_LOOP, MONOMORPHIC); - StubCache::GenerateProbe(masm, flags, r1, r2, r3, no_reg); + StubCache::GenerateProbe(masm, flags, r1, r2, r3, r4, r5); // Cache miss: Jump to runtime. GenerateMiss(masm); diff --git a/deps/v8/src/arm/simulator-arm.cc b/deps/v8/src/arm/simulator-arm.cc index 534e394af16..cb91520f3a5 100644 --- a/deps/v8/src/arm/simulator-arm.cc +++ b/deps/v8/src/arm/simulator-arm.cc @@ -112,15 +112,29 @@ static void InitializeCoverage() { void Debugger::Stop(Instr* instr) { - char* str = reinterpret_cast<char*>(instr->InstructionBits() & 0x0fffffff); - if (strlen(str) > 0) { + // Get the stop code. + uint32_t code = instr->SvcField() & kStopCodeMask; + // Retrieve the encoded address, which comes just after this stop. + char** msg_address = + reinterpret_cast<char**>(sim_->get_pc() + Instr::kInstrSize); + char* msg = *msg_address; + ASSERT(msg != NULL); + + // Update this stop description. + if (isWatchedStop(code) && !watched_stops[code].desc) { + watched_stops[code].desc = msg; + } + + if (strlen(msg) > 0) { if (coverage_log != NULL) { - fprintf(coverage_log, "%s\n", str); + fprintf(coverage_log, "%s\n", msg); fflush(coverage_log); } - instr->SetInstructionBits(0xe1a00000); // Overwrite with nop. + // Overwrite the instruction and address with nops. + instr->SetInstructionBits(kNopInstr); + reinterpret_cast<Instr*>(msg_address)->SetInstructionBits(kNopInstr); } - sim_->set_pc(sim_->get_pc() + Instr::kInstrSize); + sim_->set_pc(sim_->get_pc() + 2 * Instr::kInstrSize); } #else // ndef GENERATED_CODE_COVERAGE @@ -130,9 +144,16 @@ static void InitializeCoverage() { void Debugger::Stop(Instr* instr) { - const char* str = (const char*)(instr->InstructionBits() & 0x0fffffff); - PrintF("Simulator hit %s\n", str); - sim_->set_pc(sim_->get_pc() + Instr::kInstrSize); + // Get the stop code. + uint32_t code = instr->SvcField() & kStopCodeMask; + // Retrieve the encoded address, which comes just after this stop. + char* msg = *reinterpret_cast<char**>(sim_->get_pc() + Instr::kInstrSize); + // Update this stop description. + if (sim_->isWatchedStop(code) && !sim_->watched_stops[code].desc) { + sim_->watched_stops[code].desc = msg; + } + PrintF("Simulator hit %s\n", msg); + sim_->set_pc(sim_->get_pc() + 2 * Instr::kInstrSize); Debug(); } #endif @@ -359,6 +380,7 @@ void Debugger::Debug() { // use a reasonably large buffer v8::internal::EmbeddedVector<char, 256> buffer; + byte* prev = NULL; byte* cur = NULL; byte* end = NULL; @@ -368,9 +390,9 @@ void Debugger::Debug() { } else if (argc == 2) { int32_t value; if (GetValue(arg1, &value)) { - cur = reinterpret_cast<byte*>(value); - // no length parameter passed, assume 10 instructions - end = cur + (10 * Instr::kInstrSize); + cur = reinterpret_cast<byte*>(sim_->get_pc()); + // Disassemble <arg1> instructions. + end = cur + (value * Instr::kInstrSize); } } else { int32_t value1; @@ -382,10 +404,10 @@ void Debugger::Debug() { } while (cur < end) { - dasm.InstructionDecode(buffer, cur); + prev = cur; + cur += dasm.InstructionDecode(buffer, cur); PrintF(" 0x%08x %s\n", - reinterpret_cast<intptr_t>(cur), buffer.start()); - cur += Instr::kInstrSize; + reinterpret_cast<intptr_t>(prev), buffer.start()); } } else if (strcmp(cmd, "gdb") == 0) { PrintF("relinquishing control to gdb\n"); @@ -418,13 +440,58 @@ void Debugger::Debug() { PrintF("OVERFLOW flag: %d; ", sim_->overflow_vfp_flag_); PrintF("UNDERFLOW flag: %d; ", sim_->underflow_vfp_flag_); PrintF("INEXACT flag: %d; ", sim_->inexact_vfp_flag_); - } else if (strcmp(cmd, "unstop") == 0) { - intptr_t stop_pc = sim_->get_pc() - Instr::kInstrSize; + } else if (strcmp(cmd, "stop") == 0) { + int32_t value; + intptr_t stop_pc = sim_->get_pc() - 2 * Instr::kInstrSize; Instr* stop_instr = reinterpret_cast<Instr*>(stop_pc); - if (stop_instr->ConditionField() == special_condition) { - stop_instr->SetInstructionBits(kNopInstr); + Instr* msg_address = + reinterpret_cast<Instr*>(stop_pc + Instr::kInstrSize); + if ((argc == 2) && (strcmp(arg1, "unstop") == 0)) { + // Remove the current stop. + if (sim_->isStopInstruction(stop_instr)) { + stop_instr->SetInstructionBits(kNopInstr); + msg_address->SetInstructionBits(kNopInstr); + } else { + PrintF("Not at debugger stop.\n"); + } + } else if (argc == 3) { + // Print information about all/the specified breakpoint(s). + if (strcmp(arg1, "info") == 0) { + if (strcmp(arg2, "all") == 0) { + PrintF("Stop information:\n"); + for (uint32_t i = 0; i < sim_->kNumOfWatchedStops; i++) { + sim_->PrintStopInfo(i); + } + } else if (GetValue(arg2, &value)) { + sim_->PrintStopInfo(value); + } else { + PrintF("Unrecognized argument.\n"); + } + } else if (strcmp(arg1, "enable") == 0) { + // Enable all/the specified breakpoint(s). + if (strcmp(arg2, "all") == 0) { + for (uint32_t i = 0; i < sim_->kNumOfWatchedStops; i++) { + sim_->EnableStop(i); + } + } else if (GetValue(arg2, &value)) { + sim_->EnableStop(value); + } else { + PrintF("Unrecognized argument.\n"); + } + } else if (strcmp(arg1, "disable") == 0) { + // Disable all/the specified breakpoint(s). + if (strcmp(arg2, "all") == 0) { + for (uint32_t i = 0; i < sim_->kNumOfWatchedStops; i++) { + sim_->DisableStop(i); + } + } else if (GetValue(arg2, &value)) { + sim_->DisableStop(value); + } else { + PrintF("Unrecognized argument.\n"); + } + } } else { - PrintF("Not at debugger stop."); + PrintF("Wrong usage. Use help command for more information.\n"); } } else if ((strcmp(cmd, "t") == 0) || strcmp(cmd, "trace") == 0) { ::v8::internal::FLAG_trace_sim = !::v8::internal::FLAG_trace_sim; @@ -455,11 +522,29 @@ void Debugger::Debug() { PrintF(" set a break point on the address\n"); PrintF("del\n"); PrintF(" delete the breakpoint\n"); - PrintF("unstop\n"); - PrintF(" ignore the stop instruction at the current location"); - PrintF(" from now on\n"); PrintF("trace (alias 't')\n"); PrintF(" toogle the tracing of all executed statements\n"); + PrintF("stop feature:\n"); + PrintF(" Description:\n"); + PrintF(" Stops are debug instructions inserted by\n"); + PrintF(" the Assembler::stop() function.\n"); + PrintF(" When hitting a stop, the Simulator will\n"); + PrintF(" stop and and give control to the Debugger.\n"); + PrintF(" The first %d stop codes are watched:\n", + Simulator::kNumOfWatchedStops); + PrintF(" - They can be enabled / disabled: the Simulator\n"); + PrintF(" will / won't stop when hitting them.\n"); + PrintF(" - The Simulator keeps track of how many times they \n"); + PrintF(" are met. (See the info command.) Going over a\n"); + PrintF(" disabled stop still increases its counter. \n"); + PrintF(" Commands:\n"); + PrintF(" stop info all/<code> : print infos about number <code>\n"); + PrintF(" or all stop(s).\n"); + PrintF(" stop enable/disable all/<code> : enables / disables\n"); + PrintF(" all or number <code> stop(s)\n"); + PrintF(" stop unstop\n"); + PrintF(" ignore the stop instruction at the current location\n"); + PrintF(" from now on\n"); } else { PrintF("Unknown command: %s\n", cmd); } @@ -643,9 +728,9 @@ Simulator::Simulator() { // the simulator. The external reference will be a function compiled for the // host architecture. We need to call that function instead of trying to // execute it with the simulator. We do that by redirecting the external -// reference to a swi (software-interrupt) instruction that is handled by +// reference to a svc (Supervisor Call) instruction that is handled by // the simulator. We write the original destination of the jump just at a known -// offset from the swi instruction so the simulator knows what to call. +// offset from the svc instruction so the simulator knows what to call. class Redirection { public: Redirection(void* external_function, bool fp_return) @@ -1434,8 +1519,8 @@ typedef double (*SimulatorRuntimeFPCall)(int32_t arg0, // Software interrupt instructions are used by the simulator to call into the // C-based V8 runtime. void Simulator::SoftwareInterrupt(Instr* instr) { - int swi = instr->SwiField(); - switch (swi) { + int svc = instr->SvcField(); + switch (svc) { case call_rt_redirected: { // Check if stack is aligned. Error if not aligned is reported below to // include information on the function called. @@ -1505,9 +1590,98 @@ void Simulator::SoftwareInterrupt(Instr* instr) { dbg.Debug(); break; } + // stop uses all codes greater than 1 << 23. default: { - UNREACHABLE(); - break; + if (svc >= (1 << 23)) { + uint32_t code = svc & kStopCodeMask; + if (isWatchedStop(code)) { + IncreaseStopCounter(code); + } + // Stop if it is enabled, otherwise go on jumping over the stop + // and the message address. + if (isEnabledStop(code)) { + Debugger dbg(this); + dbg.Stop(instr); + } else { + set_pc(get_pc() + 2 * Instr::kInstrSize); + } + } else { + // This is not a valid svc code. + UNREACHABLE(); + break; + } + } + } +} + + +// Stop helper functions. +bool Simulator::isStopInstruction(Instr* instr) { + return (instr->Bits(27, 24) == 0xF) && (instr->SvcField() >= stop); +} + + +bool Simulator::isWatchedStop(uint32_t code) { + ASSERT(code <= kMaxStopCode); + return code < kNumOfWatchedStops; +} + + +bool Simulator::isEnabledStop(uint32_t code) { + ASSERT(code <= kMaxStopCode); + // Unwatched stops are always enabled. + return !isWatchedStop(code) || + !(watched_stops[code].count & kStopDisabledBit); +} + + +void Simulator::EnableStop(uint32_t code) { + ASSERT(isWatchedStop(code)); + if (!isEnabledStop(code)) { + watched_stops[code].count &= ~kStopDisabledBit; + } +} + + +void Simulator::DisableStop(uint32_t code) { + ASSERT(isWatchedStop(code)); + if (isEnabledStop(code)) { + watched_stops[code].count |= kStopDisabledBit; + } +} + + +void Simulator::IncreaseStopCounter(uint32_t code) { + ASSERT(code <= kMaxStopCode); + ASSERT(isWatchedStop(code)); + if ((watched_stops[code].count & ~(1 << 31)) == 0x7fffffff) { + PrintF("Stop counter for code %i has overflowed.\n" + "Enabling this code and reseting the counter to 0.\n", code); + watched_stops[code].count = 0; + EnableStop(code); + } else { + watched_stops[code].count++; + } +} + + +// Print a stop status. +void Simulator::PrintStopInfo(uint32_t code) { + ASSERT(code <= kMaxStopCode); + if (!isWatchedStop(code)) { + PrintF("Stop not watched."); + } else { + const char* state = isEnabledStop(code) ? "Enabled" : "Disabled"; + int32_t count = watched_stops[code].count & ~kStopDisabledBit; + // Don't print the state of unused breakpoints. + if (count != 0) { + if (watched_stops[code].desc) { + PrintF("stop %i - 0x%x: \t%s, \tcounter = %i, \t%s\n", + code, code, state, count, watched_stops[code].desc); + } else { + PrintF("stop %i - 0x%x: \t%s, \tcounter = %i\n", + code, code, state, count); + } } } } @@ -2216,73 +2390,6 @@ void Simulator::DecodeType7(Instr* instr) { } -void Simulator::DecodeUnconditional(Instr* instr) { - if (instr->Bits(7, 4) == 0x0B && instr->Bits(27, 25) == 0 && instr->HasL()) { - // Load halfword instruction, either register or immediate offset. - int rd = instr->RdField(); - int rn = instr->RnField(); - int32_t rn_val = get_register(rn); - int32_t addr = 0; - int32_t offset; - if (instr->Bit(22) == 0) { - // Register offset. - int rm = instr->RmField(); - offset = get_register(rm); - } else { - // Immediate offset - offset = instr->Bits(3, 0) + (instr->Bits(11, 8) << 4); - } - switch (instr->PUField()) { - case 0: { - // Post index, negative. - ASSERT(!instr->HasW()); - addr = rn_val; - rn_val -= offset; - set_register(rn, rn_val); - break; - } - case 1: { - // Post index, positive. - ASSERT(!instr->HasW()); - addr = rn_val; - rn_val += offset; - set_register(rn, rn_val); - break; - } - case 2: { - // Pre index or offset, negative. - rn_val -= offset; - addr = rn_val; - if (instr->HasW()) { - set_register(rn, rn_val); - } - break; - } - case 3: { - // Pre index or offset, positive. - rn_val += offset; - addr = rn_val; - if (instr->HasW()) { - set_register(rn, rn_val); - } - break; - } - default: { - // The PU field is a 2-bit field. - UNREACHABLE(); - break; - } - } - // Not sign extending, so load as unsigned. - uint16_t halfword = ReadH(addr, instr); - set_register(rd, halfword); - } else { - Debugger dbg(this); - dbg.Stop(instr); - } -} - - // void Simulator::DecodeTypeVFP(Instr* instr) // The Following ARMv7 VFPv instructions are currently supported. // vmov :Sn = Rt @@ -2655,7 +2762,7 @@ void Simulator::InstructionDecode(Instr* instr) { PrintF(" 0x%08x %s\n", reinterpret_cast<intptr_t>(instr), buffer.start()); } if (instr->ConditionField() == special_condition) { - DecodeUnconditional(instr); + UNIMPLEMENTED(); } else if (ConditionallyExecute(instr)) { switch (instr->TypeField()) { case 0: diff --git a/deps/v8/src/arm/simulator-arm.h b/deps/v8/src/arm/simulator-arm.h index e0658fc9977..3e023489eef 100644 --- a/deps/v8/src/arm/simulator-arm.h +++ b/deps/v8/src/arm/simulator-arm.h @@ -226,6 +226,15 @@ class Simulator { void HandleRList(Instr* instr, bool load); void SoftwareInterrupt(Instr* instr); + // Stop helper functions. + inline bool isStopInstruction(Instr* instr); + inline bool isWatchedStop(uint32_t bkpt_code); + inline bool isEnabledStop(uint32_t bkpt_code); + inline void EnableStop(uint32_t bkpt_code); + inline void DisableStop(uint32_t bkpt_code); + inline void IncreaseStopCounter(uint32_t bkpt_code); + void PrintStopInfo(uint32_t code); + // Read and write memory. inline uint8_t ReadBU(int32_t addr); inline int8_t ReadB(int32_t addr); @@ -252,7 +261,6 @@ class Simulator { void DecodeType5(Instr* instr); void DecodeType6(Instr* instr); void DecodeType7(Instr* instr); - void DecodeUnconditional(Instr* instr); // Support for VFP. void DecodeTypeVFP(Instr* instr); @@ -317,6 +325,23 @@ class Simulator { // Registered breakpoints. Instr* break_pc_; instr_t break_instr_; + + // A stop is watched if its code is less than kNumOfWatchedStops. + // Only watched stops support enabling/disabling and the counter feature. + static const uint32_t kNumOfWatchedStops = 256; + + // Breakpoint is disabled if bit 31 is set. + static const uint32_t kStopDisabledBit = 1 << 31; + + // A stop is enabled, meaning the simulator will stop when meeting the + // instruction, if bit 31 of watched_stops[code].count is unset. + // The value watched_stops[code].count & ~(1 << 31) indicates how many times + // the breakpoint was hit or gone through. + struct StopCoundAndDesc { + uint32_t count; + char* desc; + }; + StopCoundAndDesc watched_stops[kNumOfWatchedStops]; }; } } // namespace assembler::arm diff --git a/deps/v8/src/arm/stub-cache-arm.cc b/deps/v8/src/arm/stub-cache-arm.cc index fbad6698bd8..5e29c2e4850 100644 --- a/deps/v8/src/arm/stub-cache-arm.cc +++ b/deps/v8/src/arm/stub-cache-arm.cc @@ -43,43 +43,49 @@ static void ProbeTable(MacroAssembler* masm, Code::Flags flags, StubCache::Table table, Register name, - Register offset) { + Register offset, + Register scratch, + Register scratch2) { ExternalReference key_offset(SCTableReference::keyReference(table)); ExternalReference value_offset(SCTableReference::valueReference(table)); - Label miss; + uint32_t key_off_addr = reinterpret_cast<uint32_t>(key_offset.address()); + uint32_t value_off_addr = reinterpret_cast<uint32_t>(value_offset.address()); + + // Check the relative positions of the address fields. + ASSERT(value_off_addr > key_off_addr); + ASSERT((value_off_addr - key_off_addr) % 4 == 0); + ASSERT((value_off_addr - key_off_addr) < (256 * 4)); - // Save the offset on the stack. - __ push(offset); + Label miss; + Register offsets_base_addr = scratch; // Check that the key in the entry matches the name. - __ mov(ip, Operand(key_offset)); - __ ldr(ip, MemOperand(ip, offset, LSL, 1)); + __ mov(offsets_base_addr, Operand(key_offset)); + __ ldr(ip, MemOperand(offsets_base_addr, offset, LSL, 1)); __ cmp(name, ip); __ b(ne, &miss); // Get the code entry from the cache. - __ mov(ip, Operand(value_offset)); - __ ldr(offset, MemOperand(ip, offset, LSL, 1)); + __ add(offsets_base_addr, offsets_base_addr, + Operand(value_off_addr - key_off_addr)); + __ ldr(scratch2, MemOperand(offsets_base_addr, offset, LSL, 1)); // Check that the flags match what we're looking for. - __ ldr(offset, FieldMemOperand(offset, Code::kFlagsOffset)); - __ and_(offset, offset, Operand(~Code::kFlagsNotUsedInLookup)); - __ cmp(offset, Operand(flags)); + __ ldr(scratch2, FieldMemOperand(scratch2, Code::kFlagsOffset)); + __ bic(scratch2, scratch2, Operand(Code::kFlagsNotUsedInLookup)); + __ cmp(scratch2, Operand(flags)); __ b(ne, &miss); - // Restore offset and re-load code entry from cache. - __ pop(offset); - __ mov(ip, Operand(value_offset)); - __ ldr(offset, MemOperand(ip, offset, LSL, 1)); + // Re-load code entry from cache. + __ ldr(offset, MemOperand(offsets_base_addr, offset, LSL, 1)); // Jump to the first instruction in the code stub. __ add(offset, offset, Operand(Code::kHeaderSize - kHeapObjectTag)); __ Jump(offset); - // Miss: Restore offset and fall through. + // Miss: fall through. __ bind(&miss); - __ pop(offset); } @@ -201,7 +207,8 @@ void StubCache::GenerateProbe(MacroAssembler* masm, Register receiver, Register name, Register scratch, - Register extra) { + Register extra, + Register extra2) { Label miss; // Make sure that code is valid. The shifting code relies on the @@ -214,6 +221,18 @@ void StubCache::GenerateProbe(MacroAssembler* masm, // Make sure that there are no register conflicts. ASSERT(!scratch.is(receiver)); ASSERT(!scratch.is(name)); + ASSERT(!extra.is(receiver)); + ASSERT(!extra.is(name)); + ASSERT(!extra.is(scratch)); + ASSERT(!extra2.is(receiver)); + ASSERT(!extra2.is(name)); + ASSERT(!extra2.is(scratch)); + ASSERT(!extra2.is(extra)); + + // Check scratch, extra and extra2 registers are valid. + ASSERT(!scratch.is(no_reg)); + ASSERT(!extra.is(no_reg)); + ASSERT(!extra2.is(no_reg)); // Check that the receiver isn't a smi. __ tst(receiver, Operand(kSmiTagMask)); @@ -229,7 +248,7 @@ void StubCache::GenerateProbe(MacroAssembler* masm, Operand((kPrimaryTableSize - 1) << kHeapObjectTagSize)); // Probe the primary table. - ProbeTable(masm, flags, kPrimary, name, scratch); + ProbeTable(masm, flags, kPrimary, name, scratch, extra, extra2); // Primary miss: Compute hash for secondary probe. __ sub(scratch, scratch, Operand(name)); @@ -239,7 +258,7 @@ void StubCache::GenerateProbe(MacroAssembler* masm, Operand((kSecondaryTableSize - 1) << kHeapObjectTagSize)); // Probe the secondary table. - ProbeTable(masm, flags, kSecondary, name, scratch); + ProbeTable(masm, flags, kSecondary, name, scratch, extra, extra2); // Cache miss: Fall-through and let caller handle the miss by // entering the runtime system. diff --git a/deps/v8/src/ast.cc b/deps/v8/src/ast.cc index 92f14961b80..bb445c4d243 100644 --- a/deps/v8/src/ast.cc +++ b/deps/v8/src/ast.cc @@ -140,6 +140,7 @@ bool FunctionLiteral::AllowsLazyCompilation() { ObjectLiteral::Property::Property(Literal* key, Expression* value) { + emit_store_ = true; key_ = key; value_ = value; Object* k = *key->handle(); @@ -156,6 +157,7 @@ ObjectLiteral::Property::Property(Literal* key, Expression* value) { ObjectLiteral::Property::Property(bool is_getter, FunctionLiteral* value) { + emit_store_ = true; key_ = new Literal(value->name()); value_ = value; kind_ = is_getter ? GETTER : SETTER; @@ -169,6 +171,78 @@ bool ObjectLiteral::Property::IsCompileTimeValue() { } +void ObjectLiteral::Property::set_emit_store(bool emit_store) { + emit_store_ = emit_store; +} + + +bool ObjectLiteral::Property::emit_store() { + return emit_store_; +} + + +bool IsEqualString(void* first, void* second) { + Handle<String> h1(reinterpret_cast<String**>(first)); + Handle<String> h2(reinterpret_cast<String**>(second)); + return (*h1)->Equals(*h2); +} + +bool IsEqualSmi(void* first, void* second) { + Handle<Smi> h1(reinterpret_cast<Smi**>(first)); + Handle<Smi> h2(reinterpret_cast<Smi**>(second)); + return (*h1)->value() == (*h2)->value(); +} + +void ObjectLiteral::CalculateEmitStore() { + HashMap properties(&IsEqualString); + HashMap elements(&IsEqualSmi); + for (int i = this->properties()->length() - 1; i >= 0; i--) { + ObjectLiteral::Property* property = this->properties()->at(i); + Literal* literal = property->key(); + Handle<Object> handle = literal->handle(); + + if (handle->IsNull()) { + continue; + } + + uint32_t hash; + HashMap* table; + void* key; + uint32_t index; + if (handle->IsSymbol()) { + Handle<String> name(String::cast(*handle)); + ASSERT(!name->AsArrayIndex(&index)); + key = name.location(); + hash = name->Hash(); + table = &properties; + } else if (handle->ToArrayIndex(&index)) { + key = handle.location(); + hash = index; + table = &elements; + } else { + ASSERT(handle->IsNumber()); + double num = handle->Number(); + char arr[100]; + Vector<char> buffer(arr, ARRAY_SIZE(arr)); + const char* str = DoubleToCString(num, buffer); + Handle<String> name = Factory::NewStringFromAscii(CStrVector(str)); + key = name.location(); + hash = name->Hash(); + table = &properties; + } + // If the key of a computed property is in the table, do not emit + // a store for the property later. + if (property->kind() == ObjectLiteral::Property::COMPUTED) { + if (table->Lookup(literal, hash, false) != NULL) { + property->set_emit_store(false); + } + } + // Add key to the table. + table->Lookup(literal, hash, true); + } +} + + void TargetCollector::AddTarget(BreakTarget* target) { // Add the label to the collector, but discard duplicates. int length = targets_->length(); diff --git a/deps/v8/src/ast.h b/deps/v8/src/ast.h index a01e48daeb3..04c29775701 100644 --- a/deps/v8/src/ast.h +++ b/deps/v8/src/ast.h @@ -832,10 +832,14 @@ class ObjectLiteral: public MaterializedLiteral { bool IsCompileTimeValue(); + void set_emit_store(bool emit_store); + bool emit_store(); + private: Literal* key_; Expression* value_; Kind kind_; + bool emit_store_; }; ObjectLiteral(Handle<FixedArray> constant_properties, @@ -858,6 +862,12 @@ class ObjectLiteral: public MaterializedLiteral { bool fast_elements() const { return fast_elements_; } + + // Mark all computed expressions that are bound to a key that + // is shadowed by a later occurrence of the same key. For the + // marked expressions, no store code is emitted. + void CalculateEmitStore(); + private: Handle<FixedArray> constant_properties_; ZoneList<Property*>* properties_; diff --git a/deps/v8/src/builtins.cc b/deps/v8/src/builtins.cc index 52d5530cec6..aede3020358 100644 --- a/deps/v8/src/builtins.cc +++ b/deps/v8/src/builtins.cc @@ -1014,20 +1014,18 @@ MUST_USE_RESULT static MaybeObject* HandleApiCallHelper( Object* data_obj = call_data->data(); Object* result; - Handle<Object> data_handle(data_obj); - v8::Local<v8::Value> data = v8::Utils::ToLocal(data_handle); - ASSERT(raw_holder->IsJSObject()); - v8::Local<v8::Function> callee = v8::Utils::ToLocal(function); - Handle<JSObject> holder_handle(JSObject::cast(raw_holder)); - v8::Local<v8::Object> holder = v8::Utils::ToLocal(holder_handle); LOG(ApiObjectAccess("call", JSObject::cast(*args.receiver()))); + ASSERT(raw_holder->IsJSObject()); + + CustomArguments custom; + v8::ImplementationUtilities::PrepareArgumentsData(custom.end(), + data_obj, *function, raw_holder); + v8::Arguments new_args = v8::ImplementationUtilities::NewArguments( - data, - holder, - callee, - is_construct, - reinterpret_cast<void**>(&args[0] - 1), - args.length() - 1); + custom.end(), + &args[0] - 1, + args.length() - 1, + is_construct); v8::Handle<v8::Value> value; { @@ -1089,26 +1087,22 @@ BUILTIN(FastHandleApiCall) { Handle<JSFunction> function = args.at<JSFunction>(args_length); Object* callback_obj = args[args_length + 1]; - Handle<Object> data_handle = args.at<Object>(args_length + 2); + Handle<Object> data = args.at<Object>(args_length + 2); Handle<JSObject> checked_holder = args.at<JSObject>(args_length + 3); #ifdef DEBUG VerifyTypeCheck(checked_holder, function); #endif - v8::Local<v8::Object> holder = v8::Utils::ToLocal(checked_holder); - v8::Local<v8::Function> callee = v8::Utils::ToLocal(function); - v8::InvocationCallback callback = - v8::ToCData<v8::InvocationCallback>(callback_obj); - v8::Local<v8::Value> data = v8::Utils::ToLocal(data_handle); + CustomArguments custom; + v8::ImplementationUtilities::PrepareArgumentsData(custom.end(), + *data, *function, *checked_holder); v8::Arguments new_args = v8::ImplementationUtilities::NewArguments( - data, - holder, - callee, - is_construct, - reinterpret_cast<void**>(&args[0] - 1), - args_length - 1); + custom.end(), + &args[0] - 1, + args_length - 1, + is_construct); HandleScope scope; Object* result; @@ -1119,6 +1113,9 @@ BUILTIN(FastHandleApiCall) { #ifdef ENABLE_LOGGING_AND_PROFILING state.set_external_callback(v8::ToCData<Address>(callback_obj)); #endif + v8::InvocationCallback callback = + v8::ToCData<v8::InvocationCallback>(callback_obj); + value = callback(new_args); } if (value.IsEmpty()) { @@ -1161,23 +1158,20 @@ MUST_USE_RESULT static MaybeObject* HandleApiCallAsFunctionOrConstructor( v8::ToCData<v8::InvocationCallback>(callback_obj); // Get the data for the call and perform the callback. - Object* data_obj = call_data->data(); Object* result; - { HandleScope scope; - v8::Local<v8::Object> self = - v8::Utils::ToLocal(Handle<JSObject>::cast(args.receiver())); - Handle<Object> data_handle(data_obj); - v8::Local<v8::Value> data = v8::Utils::ToLocal(data_handle); - Handle<JSFunction> callee_handle(constructor); - v8::Local<v8::Function> callee = v8::Utils::ToLocal(callee_handle); - LOG(ApiObjectAccess("call non-function", JSObject::cast(*args.receiver()))); + { + HandleScope scope; + + LOG(ApiObjectAccess("call non-function", obj)); + + CustomArguments custom; + v8::ImplementationUtilities::PrepareArgumentsData(custom.end(), + call_data->data(), constructor, obj); v8::Arguments new_args = v8::ImplementationUtilities::NewArguments( - data, - self, - callee, - is_construct_call, - reinterpret_cast<void**>(&args[0] - 1), - args.length() - 1); + custom.end(), + &args[0] - 1, + args.length() - 1, + is_construct_call); v8::Handle<v8::Value> value; { // Leaving JavaScript. diff --git a/deps/v8/src/compiler.cc b/deps/v8/src/compiler.cc index 6cc09713d61..6f02960dda7 100755 --- a/deps/v8/src/compiler.cc +++ b/deps/v8/src/compiler.cc @@ -152,10 +152,8 @@ static Handle<SharedFunctionInfo> MakeFunctionInfo(CompilationInfo* info) { script->set_context_data((*i::Top::global_context())->data()); #ifdef ENABLE_DEBUGGER_SUPPORT - if (info->is_eval() || info->is_json()) { - Script::CompilationType compilation_type = info->is_json() - ? Script::COMPILATION_TYPE_JSON - : Script::COMPILATION_TYPE_EVAL; + if (info->is_eval()) { + Script::CompilationType compilation_type = Script::COMPILATION_TYPE_EVAL; script->set_compilation_type(Smi::FromInt(compilation_type)); // For eval scripts add information on the function from which eval was // called. @@ -178,7 +176,7 @@ static Handle<SharedFunctionInfo> MakeFunctionInfo(CompilationInfo* info) { // Only allow non-global compiles for eval. ASSERT(info->is_eval() || info->is_global()); - if (!Parser::Parse(info)) return Handle<SharedFunctionInfo>::null(); + if (!ParserApi::Parse(info)) return Handle<SharedFunctionInfo>::null(); // Measure how long it takes to do the compilation; only take the // rest of the function into account to avoid overlap with the @@ -283,7 +281,7 @@ Handle<SharedFunctionInfo> Compiler::Compile(Handle<String> source, if (pre_data == NULL && FLAG_lazy && source_length >= FLAG_min_preparse_length) { - pre_data = Parser::PartialPreParse(source, NULL, extension); + pre_data = ParserApi::PartialPreParse(source, NULL, extension); } // Create a script object describing the script to be compiled. @@ -323,13 +321,7 @@ Handle<SharedFunctionInfo> Compiler::Compile(Handle<String> source, Handle<SharedFunctionInfo> Compiler::CompileEval(Handle<String> source, Handle<Context> context, - bool is_global, - ValidationState validate) { - // Note that if validation is required then no path through this function - // is allowed to return a value without validating that the input is legal - // json. - bool is_json = (validate == VALIDATE_JSON); - + bool is_global) { int source_length = source->length(); Counters::total_eval_size.Increment(source_length); Counters::total_compile_size.Increment(source_length); @@ -338,13 +330,9 @@ Handle<SharedFunctionInfo> Compiler::CompileEval(Handle<String> source, VMState state(COMPILER); // Do a lookup in the compilation cache; if the entry is not there, invoke - // the compiler and add the result to the cache. If we're evaluating json - // we bypass the cache since we can't be sure a potential value in the - // cache has been validated. + // the compiler and add the result to the cache. Handle<SharedFunctionInfo> result; - if (!is_json) { - result = CompilationCache::LookupEval(source, context, is_global); - } + result = CompilationCache::LookupEval(source, context, is_global); if (result.is_null()) { // Create a script object describing the script to be compiled. @@ -352,12 +340,9 @@ Handle<SharedFunctionInfo> Compiler::CompileEval(Handle<String> source, CompilationInfo info(script); info.MarkAsEval(); if (is_global) info.MarkAsGlobal(); - if (is_json) info.MarkAsJson(); info.SetCallingContext(context); result = MakeFunctionInfo(&info); - if (!result.is_null() && !is_json) { - // For json it's unlikely that we'll ever see exactly the same string - // again so we don't use the compilation cache. + if (!result.is_null()) { CompilationCache::PutEval(source, context, is_global, result); } } @@ -379,7 +364,7 @@ bool Compiler::CompileLazy(CompilationInfo* info) { Counters::total_compile_size.Increment(compiled_size); // Generate the AST for the lazily compiled function. - if (Parser::Parse(info)) { + if (ParserApi::Parse(info)) { // Measure how long it takes to do the lazy compilation; only take the // rest of the function into account to avoid overlap with the lazy // parsing statistics. diff --git a/deps/v8/src/compiler.h b/deps/v8/src/compiler.h index d6f4e69d525..20868e54887 100644 --- a/deps/v8/src/compiler.h +++ b/deps/v8/src/compiler.h @@ -49,7 +49,6 @@ class CompilationInfo BASE_EMBEDDED { bool is_lazy() const { return (flags_ & IsLazy::mask()) != 0; } bool is_eval() const { return (flags_ & IsEval::mask()) != 0; } bool is_global() const { return (flags_ & IsGlobal::mask()) != 0; } - bool is_json() const { return (flags_ & IsJson::mask()) != 0; } bool is_in_loop() const { return (flags_ & IsInLoop::mask()) != 0; } FunctionLiteral* function() const { return function_; } Scope* scope() const { return scope_; } @@ -69,10 +68,6 @@ class CompilationInfo BASE_EMBEDDED { ASSERT(!is_lazy()); flags_ |= IsGlobal::encode(true); } - void MarkAsJson() { - ASSERT(!is_lazy()); - flags_ |= IsJson::encode(true); - } void MarkAsInLoop() { ASSERT(is_lazy()); flags_ |= IsInLoop::encode(true); @@ -108,16 +103,15 @@ class CompilationInfo BASE_EMBEDDED { // Flags that can be set for eager compilation. class IsEval: public BitField<bool, 1, 1> {}; class IsGlobal: public BitField<bool, 2, 1> {}; - class IsJson: public BitField<bool, 3, 1> {}; // Flags that can be set for lazy compilation. - class IsInLoop: public BitField<bool, 4, 1> {}; + class IsInLoop: public BitField<bool, 3, 1> {}; unsigned flags_; // Fields filled in by the compilation pipeline. // AST filled in by the parser. FunctionLiteral* function_; - // The scope of the function literal as a convenience. Set to indidicate + // The scope of the function literal as a convenience. Set to indicate // that scopes have been analyzed. Scope* scope_; // The compiled code. @@ -153,8 +147,6 @@ class CompilationInfo BASE_EMBEDDED { class Compiler : public AllStatic { public: - enum ValidationState { DONT_VALIDATE_JSON, VALIDATE_JSON }; - // All routines return a JSFunction. // If an error occurs an exception is raised and // the return handle contains NULL. @@ -172,8 +164,7 @@ class Compiler : public AllStatic { // Compile a String source within a context for Eval. static Handle<SharedFunctionInfo> CompileEval(Handle<String> source, Handle<Context> context, - bool is_global, - ValidationState validation); + bool is_global); // Compile from function info (used for lazy compilation). Returns true on // success and false if the compilation resulted in a stack overflow. diff --git a/deps/v8/src/debug-debugger.js b/deps/v8/src/debug-debugger.js index a0c6808102b..0eab8d1b831 100644 --- a/deps/v8/src/debug-debugger.js +++ b/deps/v8/src/debug-debugger.js @@ -1301,7 +1301,7 @@ DebugCommandProcessor.prototype.processDebugJSONRequest = function(json_request) try { try { // Convert the JSON string to an object. - request = %CompileString('(' + json_request + ')', false)(); + request = %CompileString('(' + json_request + ')')(); // Create an initial response. response = this.createResponse(request); diff --git a/deps/v8/src/debug.cc b/deps/v8/src/debug.cc index 5c6ddbe3556..24f04098610 100644 --- a/deps/v8/src/debug.cc +++ b/deps/v8/src/debug.cc @@ -1464,8 +1464,7 @@ bool Debug::IsSourceBreakStub(Code* code) { // location. bool Debug::IsBreakStub(Code* code) { CodeStub::Major major_key = CodeStub::GetMajorKey(code); - return major_key == CodeStub::CallFunction || - major_key == CodeStub::StackCheck; + return major_key == CodeStub::CallFunction; } @@ -1503,8 +1502,7 @@ Handle<Code> Debug::FindDebugBreak(Handle<Code> code, RelocInfo::Mode mode) { return result; } if (code->kind() == Code::STUB) { - ASSERT(code->major_key() == CodeStub::CallFunction || - code->major_key() == CodeStub::StackCheck); + ASSERT(code->major_key() == CodeStub::CallFunction); Handle<Code> result = Handle<Code>(Builtins::builtin(Builtins::StubNoRegisters_DebugBreak)); return result; diff --git a/deps/v8/src/execution.cc b/deps/v8/src/execution.cc index 3bbac0fa07e..885bf63cf1b 100644 --- a/deps/v8/src/execution.cc +++ b/deps/v8/src/execution.cc @@ -797,6 +797,7 @@ v8::Handle<v8::Value> ExternalizeStringExtension::Externalize( if (result && !string->IsSymbol()) { i::ExternalStringTable::AddString(*string); } + if (!result) delete resource; } else { uc16* data = new uc16[string->length()]; String::WriteToFlat(*string, data, 0, string->length()); @@ -806,6 +807,7 @@ v8::Handle<v8::Value> ExternalizeStringExtension::Externalize( if (result && !string->IsSymbol()) { i::ExternalStringTable::AddString(*string); } + if (!result) delete resource; } if (!result) { return v8::ThrowException(v8::String::New("externalizeString() failed.")); diff --git a/deps/v8/src/flag-definitions.h b/deps/v8/src/flag-definitions.h index 2474c62bc3e..54501ec95d9 100644 --- a/deps/v8/src/flag-definitions.h +++ b/deps/v8/src/flag-definitions.h @@ -140,6 +140,9 @@ DEFINE_bool(stack_trace_on_abort, true, // codegen-ia32.cc / codegen-arm.cc DEFINE_bool(trace, false, "trace function calls") DEFINE_bool(defer_negation, true, "defer negation operation") +DEFINE_bool(mask_constants_with_cookie, + true, + "use random jit cookie to mask large constants") // codegen.cc DEFINE_bool(lazy, true, "use lazy compilation") diff --git a/deps/v8/src/heap.cc b/deps/v8/src/heap.cc index fc908665520..b037efd8045 100644 --- a/deps/v8/src/heap.cc +++ b/deps/v8/src/heap.cc @@ -581,25 +581,22 @@ void Heap::EnsureFromSpaceIsCommitted() { } -class ClearThreadJSFunctionResultCachesVisitor: public ThreadVisitor { - virtual void VisitThread(ThreadLocalTop* top) { - Context* context = top->context_; - if (context == NULL) return; +void Heap::ClearJSFunctionResultCaches() { + if (Bootstrapper::IsActive()) return; + Object* context = global_contexts_list_; + while (!context->IsUndefined()) { + // Get the caches for this context: FixedArray* caches = - context->global()->global_context()->jsfunction_result_caches(); + Context::cast(context)->jsfunction_result_caches(); + // Clear the caches: int length = caches->length(); for (int i = 0; i < length; i++) { JSFunctionResultCache::cast(caches->get(i))->Clear(); } + // Get the next context: + context = Context::cast(context)->get(Context::NEXT_CONTEXT_LINK); } -}; - - -void Heap::ClearJSFunctionResultCaches() { - if (Bootstrapper::IsActive()) return; - ClearThreadJSFunctionResultCachesVisitor visitor; - ThreadManager::IterateArchivedThreads(&visitor); } diff --git a/deps/v8/src/ia32/codegen-ia32.cc b/deps/v8/src/ia32/codegen-ia32.cc index f2ac7f7022e..6d23dd7df99 100644 --- a/deps/v8/src/ia32/codegen-ia32.cc +++ b/deps/v8/src/ia32/codegen-ia32.cc @@ -153,7 +153,8 @@ CodeGenerator::CodeGenerator(MacroAssembler* masm) in_safe_int32_mode_(false), safe_int32_mode_enabled_(true), function_return_is_shadowed_(false), - in_spilled_code_(false) { + in_spilled_code_(false), + jit_cookie_((FLAG_mask_constants_with_cookie) ? V8::Random() : 0) { } @@ -5363,16 +5364,16 @@ void CodeGenerator::VisitLiteral(Literal* node) { void CodeGenerator::PushUnsafeSmi(Handle<Object> value) { ASSERT(value->IsSmi()); int bits = reinterpret_cast<int>(*value); - __ push(Immediate(bits & 0x0000FFFF)); - __ or_(Operand(esp, 0), Immediate(bits & 0xFFFF0000)); + __ push(Immediate(bits ^ jit_cookie_)); + __ xor_(Operand(esp, 0), Immediate(jit_cookie_)); } void CodeGenerator::StoreUnsafeSmiToLocal(int offset, Handle<Object> value) { ASSERT(value->IsSmi()); int bits = reinterpret_cast<int>(*value); - __ mov(Operand(ebp, offset), Immediate(bits & 0x0000FFFF)); - __ or_(Operand(ebp, offset), Immediate(bits & 0xFFFF0000)); + __ mov(Operand(ebp, offset), Immediate(bits ^ jit_cookie_)); + __ xor_(Operand(ebp, offset), Immediate(jit_cookie_)); } @@ -5380,8 +5381,8 @@ void CodeGenerator::MoveUnsafeSmi(Register target, Handle<Object> value) { ASSERT(target.is_valid()); ASSERT(value->IsSmi()); int bits = reinterpret_cast<int>(*value); - __ Set(target, Immediate(bits & 0x0000FFFF)); - __ or_(target, bits & 0xFFFF0000); + __ Set(target, Immediate(bits ^ jit_cookie_)); + __ xor_(target, jit_cookie_); } @@ -5559,6 +5560,11 @@ void CodeGenerator::VisitObjectLiteral(ObjectLiteral* node) { } frame_->Push(&clone); + // Mark all computed expressions that are bound to a key that + // is shadowed by a later occurrence of the same key. For the + // marked expressions, no store code is emitted. + node->CalculateEmitStore(); + for (int i = 0; i < node->properties()->length(); i++) { ObjectLiteral::Property* property = node->properties()->at(i); switch (property->kind()) { @@ -5573,24 +5579,32 @@ void CodeGenerator::VisitObjectLiteral(ObjectLiteral* node) { // Duplicate the object as the IC receiver. frame_->Dup(); Load(property->value()); - Result ignored = - frame_->CallStoreIC(Handle<String>::cast(key), false); - // A test eax instruction following the store IC call would - // indicate the presence of an inlined version of the - // store. Add a nop to indicate that there is no such - // inlined version. - __ nop(); + if (property->emit_store()) { + Result ignored = + frame_->CallStoreIC(Handle<String>::cast(key), false); + // A test eax instruction following the store IC call would + // indicate the presence of an inlined version of the + // store. Add a nop to indicate that there is no such + // inlined version. + __ nop(); + } else { + frame_->Drop(2); + } break; } // Fall through } case ObjectLiteral::Property::PROTOTYPE: { - // Duplicate the object as an argument to the runtime call. - frame_->Dup(); - Load(property->key()); - Load(property->value()); - Result ignored = frame_->CallRuntime(Runtime::kSetProperty, 3); - // Ignore the result. + // Duplicate the object as an argument to the runtime call. + frame_->Dup(); + Load(property->key()); + Load(property->value()); + if (property->emit_store()) { + // Ignore the result. + Result ignored = frame_->CallRuntime(Runtime::kSetProperty, 3); + } else { + frame_->Drop(3); + } break; } case ObjectLiteral::Property::SETTER: { diff --git a/deps/v8/src/ia32/codegen-ia32.h b/deps/v8/src/ia32/codegen-ia32.h index b0724092f8e..4594b19ddd2 100644 --- a/deps/v8/src/ia32/codegen-ia32.h +++ b/deps/v8/src/ia32/codegen-ia32.h @@ -785,6 +785,11 @@ class CodeGenerator: public AstVisitor { // in a spilled state. bool in_spilled_code_; + // A cookie that is used for JIT IMM32 Encoding. Initialized to a + // random number when the command-line + // FLAG_mask_constants_with_cookie is true, zero otherwise. + int jit_cookie_; + friend class VirtualFrame; friend class JumpTarget; friend class Reference; diff --git a/deps/v8/src/ia32/full-codegen-ia32.cc b/deps/v8/src/ia32/full-codegen-ia32.cc index 150df9953b0..ee4e6458ae3 100644 --- a/deps/v8/src/ia32/full-codegen-ia32.cc +++ b/deps/v8/src/ia32/full-codegen-ia32.cc @@ -1202,6 +1202,11 @@ void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { // result_saved is false the result is in eax. bool result_saved = false; + // Mark all computed expressions that are bound to a key that + // is shadowed by a later occurrence of the same key. For the + // marked expressions, no store code is emitted. + expr->CalculateEmitStore(); + for (int i = 0; i < expr->properties()->length(); i++) { ObjectLiteral::Property* property = expr->properties()->at(i); if (property->IsCompileTimeValue()) continue; @@ -1221,8 +1226,10 @@ void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { VisitForAccumulatorValue(value); __ mov(ecx, Immediate(key->handle())); __ mov(edx, Operand(esp, 0)); - Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); - EmitCallIC(ic, RelocInfo::CODE_TARGET); + if (property->emit_store()) { + Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); + EmitCallIC(ic, RelocInfo::CODE_TARGET); + } break; } // Fall through. @@ -1230,7 +1237,11 @@ void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { __ push(Operand(esp, 0)); // Duplicate receiver. VisitForStackValue(key); VisitForStackValue(value); - __ CallRuntime(Runtime::kSetProperty, 3); + if (property->emit_store()) { + __ CallRuntime(Runtime::kSetProperty, 3); + } else { + __ Drop(3); + } break; case ObjectLiteral::Property::SETTER: case ObjectLiteral::Property::GETTER: diff --git a/deps/v8/src/ia32/stub-cache-ia32.cc b/deps/v8/src/ia32/stub-cache-ia32.cc index 90dabed0e56..e3870883599 100644 --- a/deps/v8/src/ia32/stub-cache-ia32.cc +++ b/deps/v8/src/ia32/stub-cache-ia32.cc @@ -206,8 +206,10 @@ void StubCache::GenerateProbe(MacroAssembler* masm, Register receiver, Register name, Register scratch, - Register extra) { + Register extra, + Register extra2) { Label miss; + USE(extra2); // The register extra2 is not used on the ia32 platform. // Make sure that code is valid. The shifting code relies on the // entry size being 8. @@ -223,6 +225,10 @@ void StubCache::GenerateProbe(MacroAssembler* masm, ASSERT(!extra.is(name)); ASSERT(!extra.is(scratch)); + // Check scratch and extra registers are valid, and extra2 is unused. + ASSERT(!scratch.is(no_reg)); + ASSERT(extra2.is(no_reg)); + // Check that the receiver isn't a smi. __ test(receiver, Immediate(kSmiTagMask)); __ j(zero, &miss, not_taken); diff --git a/deps/v8/src/json.js b/deps/v8/src/json.js index a39d7c4a97c..5993100f539 100644 --- a/deps/v8/src/json.js +++ b/deps/v8/src/json.js @@ -29,8 +29,7 @@ var $JSON = global.JSON; function ParseJSONUnfiltered(text) { var s = $String(text); - var f = %CompileString(s, true); - return f(); + return %ParseJson(s); } function Revive(holder, name, reviver) { diff --git a/deps/v8/src/jsregexp.cc b/deps/v8/src/jsregexp.cc index 3c5ddfbeb4f..8cd13bc4166 100644 --- a/deps/v8/src/jsregexp.cc +++ b/deps/v8/src/jsregexp.cc @@ -125,7 +125,8 @@ Handle<Object> RegExpImpl::Compile(Handle<JSRegExp> re, PostponeInterruptsScope postpone; RegExpCompileData parse_result; FlatStringReader reader(pattern); - if (!Parser::ParseRegExp(&reader, flags.is_multiline(), &parse_result)) { + if (!RegExpParser::ParseRegExp(&reader, flags.is_multiline(), + &parse_result)) { // Throw an exception if we fail to parse the pattern. ThrowRegExpException(re, pattern, @@ -267,7 +268,8 @@ bool RegExpImpl::CompileIrregexp(Handle<JSRegExp> re, bool is_ascii) { RegExpCompileData compile_data; FlatStringReader reader(pattern); - if (!Parser::ParseRegExp(&reader, flags.is_multiline(), &compile_data)) { + if (!RegExpParser::ParseRegExp(&reader, flags.is_multiline(), + &compile_data)) { // Throw an exception if we fail to parse the pattern. // THIS SHOULD NOT HAPPEN. We already pre-parsed it successfully once. ThrowRegExpException(re, diff --git a/deps/v8/src/liveedit.cc b/deps/v8/src/liveedit.cc index 49f221a466e..642b3e6a047 100644 --- a/deps/v8/src/liveedit.cc +++ b/deps/v8/src/liveedit.cc @@ -404,7 +404,7 @@ static void CompileScriptForTracker(Handle<Script> script) { // Build AST. CompilationInfo info(script); info.MarkAsGlobal(); - if (Parser::Parse(&info)) { + if (ParserApi::Parse(&info)) { // Compile the code. LiveEditFunctionTracker tracker(info.function()); if (Compiler::MakeCodeForLiveEdit(&info)) { diff --git a/deps/v8/src/log.cc b/deps/v8/src/log.cc index 2cc2b8ffa85..d12aafb6df8 100644 --- a/deps/v8/src/log.cc +++ b/deps/v8/src/log.cc @@ -164,7 +164,10 @@ void StackTracer::Trace(TickSample* sample) { int i = 0; const Address callback = VMState::external_callback(); - if (callback != NULL) { + // Surprisingly, PC can point _exactly_ to callback start, with good + // probability, and this will result in reporting fake nested + // callback call. + if (callback != NULL && callback != sample->pc) { sample->stack[i++] = callback; } diff --git a/deps/v8/src/mips/stub-cache-mips.cc b/deps/v8/src/mips/stub-cache-mips.cc index faaacbc4db4..91dec1757bc 100644 --- a/deps/v8/src/mips/stub-cache-mips.cc +++ b/deps/v8/src/mips/stub-cache-mips.cc @@ -44,7 +44,8 @@ void StubCache::GenerateProbe(MacroAssembler* masm, Register receiver, Register name, Register scratch, - Register extra) { + Register extra, + Register extra2) { UNIMPLEMENTED_MIPS(); } diff --git a/deps/v8/src/objects-inl.h b/deps/v8/src/objects-inl.h index 4d210172b8b..1852b549bf1 100644 --- a/deps/v8/src/objects-inl.h +++ b/deps/v8/src/objects-inl.h @@ -1952,7 +1952,9 @@ void JSFunctionResultCache::MakeZeroSize() { void JSFunctionResultCache::Clear() { int cache_size = Smi::cast(get(kCacheSizeIndex))->value(); Object** entries_start = RawField(this, OffsetOfElementAt(kEntriesIndex)); - MemsetPointer(entries_start, Heap::the_hole_value(), cache_size); + MemsetPointer(entries_start, + Heap::the_hole_value(), + cache_size - kEntriesIndex); MakeZeroSize(); } diff --git a/deps/v8/src/objects.h b/deps/v8/src/objects.h index 87234ea2cbe..6029ad545b4 100644 --- a/deps/v8/src/objects.h +++ b/deps/v8/src/objects.h @@ -3409,8 +3409,7 @@ class Script: public Struct { // Script compilation types. enum CompilationType { COMPILATION_TYPE_HOST = 0, - COMPILATION_TYPE_EVAL = 1, - COMPILATION_TYPE_JSON = 2 + COMPILATION_TYPE_EVAL = 1 }; // [source]: the script source. diff --git a/deps/v8/src/parser.cc b/deps/v8/src/parser.cc index 180d0d2456d..aad7a615a51 100644 --- a/deps/v8/src/parser.cc +++ b/deps/v8/src/parser.cc @@ -87,112 +87,6 @@ class PositionStack { }; -template <typename T, int initial_size> -class BufferedZoneList { - public: - BufferedZoneList() : list_(NULL), last_(NULL) {} - - // Adds element at end of list. This element is buffered and can - // be read using last() or removed using RemoveLast until a new Add or until - // RemoveLast or GetList has been called. - void Add(T* value) { - if (last_ != NULL) { - if (list_ == NULL) { - list_ = new ZoneList<T*>(initial_size); - } - list_->Add(last_); - } - last_ = value; - } - - T* last() { - ASSERT(last_ != NULL); - return last_; - } - - T* RemoveLast() { - ASSERT(last_ != NULL); - T* result = last_; - if (list_ != NULL && list_->length() > 0) - last_ = list_->RemoveLast(); - else - last_ = NULL; - return result; - } - - T* Get(int i) { - ASSERT(0 <= i && i < length()); - if (list_ == NULL) { - ASSERT_EQ(0, i); - return last_; - } else { - if (i == list_->length()) { - ASSERT(last_ != NULL); - return last_; - } else { - return list_->at(i); - } - } - } - - void Clear() { - list_ = NULL; - last_ = NULL; - } - - int length() { - int length = (list_ == NULL) ? 0 : list_->length(); - return length + ((last_ == NULL) ? 0 : 1); - } - - ZoneList<T*>* GetList() { - if (list_ == NULL) { - list_ = new ZoneList<T*>(initial_size); - } - if (last_ != NULL) { - list_->Add(last_); - last_ = NULL; - } - return list_; - } - - private: - ZoneList<T*>* list_; - T* last_; -}; - - -// Accumulates RegExp atoms and assertions into lists of terms and alternatives. -class RegExpBuilder: public ZoneObject { - public: - RegExpBuilder(); - void AddCharacter(uc16 character); - // "Adds" an empty expression. Does nothing except consume a - // following quantifier - void AddEmpty(); - void AddAtom(RegExpTree* tree); - void AddAssertion(RegExpTree* tree); - void NewAlternative(); // '|' - void AddQuantifierToAtom(int min, int max, RegExpQuantifier::Type type); - RegExpTree* ToRegExp(); - private: - void FlushCharacters(); - void FlushText(); - void FlushTerms(); - bool pending_empty_; - ZoneList<uc16>* characters_; - BufferedZoneList<RegExpTree, 2> terms_; - BufferedZoneList<RegExpTree, 2> text_; - BufferedZoneList<RegExpTree, 2> alternatives_; -#ifdef DEBUG - enum {ADD_NONE, ADD_CHAR, ADD_TERM, ADD_ASSERT, ADD_ATOM} last_added_; -#define LAST(x) last_added_ = x; -#else -#define LAST(x) -#endif -}; - - RegExpBuilder::RegExpBuilder() : pending_empty_(false), characters_(NULL), @@ -352,124 +246,13 @@ void RegExpBuilder::AddQuantifierToAtom(int min, } -class RegExpParser { - public: - RegExpParser(FlatStringReader* in, - Handle<String>* error, - bool multiline_mode); - RegExpTree* ParsePattern(); - RegExpTree* ParseDisjunction(); - RegExpTree* ParseGroup(); - RegExpTree* ParseCharacterClass(); - - // Parses a {...,...} quantifier and stores the range in the given - // out parameters. - bool ParseIntervalQuantifier(int* min_out, int* max_out); - - // Parses and returns a single escaped character. The character - // must not be 'b' or 'B' since they are usually handle specially. - uc32 ParseClassCharacterEscape(); - - // Checks whether the following is a length-digit hexadecimal number, - // and sets the value if it is. - bool ParseHexEscape(int length, uc32* value); - - uc32 ParseControlLetterEscape(); - uc32 ParseOctalLiteral(); - - // Tries to parse the input as a back reference. If successful it - // stores the result in the output parameter and returns true. If - // it fails it will push back the characters read so the same characters - // can be reparsed. - bool ParseBackReferenceIndex(int* index_out); - - CharacterRange ParseClassAtom(uc16* char_class); - RegExpTree* ReportError(Vector<const char> message); - void Advance(); - void Advance(int dist); - void Reset(int pos); - - // Reports whether the pattern might be used as a literal search string. - // Only use if the result of the parse is a single atom node. - bool simple(); - bool contains_anchor() { return contains_anchor_; } - void set_contains_anchor() { contains_anchor_ = true; } - int captures_started() { return captures_ == NULL ? 0 : captures_->length(); } - int position() { return next_pos_ - 1; } - bool failed() { return failed_; } - - static const int kMaxCaptures = 1 << 16; - static const uc32 kEndMarker = (1 << 21); - - private: - enum SubexpressionType { - INITIAL, - CAPTURE, // All positive values represent captures. - POSITIVE_LOOKAHEAD, - NEGATIVE_LOOKAHEAD, - GROUPING - }; - - class RegExpParserState : public ZoneObject { - public: - RegExpParserState(RegExpParserState* previous_state, - SubexpressionType group_type, - int disjunction_capture_index) - : previous_state_(previous_state), - builder_(new RegExpBuilder()), - group_type_(group_type), - disjunction_capture_index_(disjunction_capture_index) {} - // Parser state of containing expression, if any. - RegExpParserState* previous_state() { return previous_state_; } - bool IsSubexpression() { return previous_state_ != NULL; } - // RegExpBuilder building this regexp's AST. - RegExpBuilder* builder() { return builder_; } - // Type of regexp being parsed (parenthesized group or entire regexp). - SubexpressionType group_type() { return group_type_; } - // Index in captures array of first capture in this sub-expression, if any. - // Also the capture index of this sub-expression itself, if group_type - // is CAPTURE. - int capture_index() { return disjunction_capture_index_; } - private: - // Linked list implementation of stack of states. - RegExpParserState* previous_state_; - // Builder for the stored disjunction. - RegExpBuilder* builder_; - // Stored disjunction type (capture, look-ahead or grouping), if any. - SubexpressionType group_type_; - // Stored disjunction's capture index (if any). - int disjunction_capture_index_; - }; - - uc32 current() { return current_; } - bool has_more() { return has_more_; } - bool has_next() { return next_pos_ < in()->length(); } - uc32 Next(); - FlatStringReader* in() { return in_; } - void ScanForCaptures(); - uc32 current_; - bool has_more_; - bool multiline_; - int next_pos_; - FlatStringReader* in_; - Handle<String>* error_; - bool simple_; - bool contains_anchor_; - ZoneList<RegExpCapture*>* captures_; - bool is_scanned_for_captures_; - // The capture count is only valid after we have scanned for captures. - int capture_count_; - bool failed_; -}; - - // A temporary scope stores information during parsing, just like // a plain scope. However, temporary scopes are not kept around // after parsing or referenced by syntax trees so they can be stack- // allocated and hence used by the pre-parser. class TemporaryScope BASE_EMBEDDED { public: - explicit TemporaryScope(Parser* parser); + explicit TemporaryScope(TemporaryScope** variable); ~TemporaryScope(); int NextMaterializedLiteralIndex() { @@ -518,27 +301,25 @@ class TemporaryScope BASE_EMBEDDED { int loop_count_; // Bookkeeping - Parser* parser_; + TemporaryScope** variable_; TemporaryScope* parent_; - - friend class Parser; }; -TemporaryScope::TemporaryScope(Parser* parser) +TemporaryScope::TemporaryScope(TemporaryScope** variable) : materialized_literal_count_(0), expected_property_count_(0), only_simple_this_property_assignments_(false), this_property_assignments_(Factory::empty_fixed_array()), loop_count_(0), - parser_(parser), - parent_(parser->temp_scope_) { - parser->temp_scope_ = this; + variable_(variable), + parent_(*variable) { + *variable = this; } TemporaryScope::~TemporaryScope() { - parser_->temp_scope_ = parent_; + *variable_ = parent_; } @@ -1141,20 +922,20 @@ VariableProxy* PreParser::Declare(Handle<String> name, Variable::Mode mode, class Target BASE_EMBEDDED { public: - Target(Parser* parser, AstNode* node) - : parser_(parser), node_(node), previous_(parser_->target_stack_) { - parser_->target_stack_ = this; + Target(Target** variable, AstNode* node) + : variable_(variable), node_(node), previous_(*variable) { + *variable = this; } ~Target() { - parser_->target_stack_ = previous_; + *variable_ = previous_; } Target* previous() { return previous_; } AstNode* node() { return node_; } private: - Parser* parser_; + Target** variable_; AstNode* node_; Target* previous_; }; @@ -1162,17 +943,17 @@ class Target BASE_EMBEDDED { class TargetScope BASE_EMBEDDED { public: - explicit TargetScope(Parser* parser) - : parser_(parser), previous_(parser->target_stack_) { - parser->target_stack_ = NULL; + explicit TargetScope(Target** variable) + : variable_(variable), previous_(*variable) { + *variable = NULL; } ~TargetScope() { - parser_->target_stack_ = previous_; + *variable_ = previous_; } private: - Parser* parser_; + Target** variable_; Target* previous_; }; @@ -1184,22 +965,26 @@ class TargetScope BASE_EMBEDDED { class LexicalScope BASE_EMBEDDED { public: - LexicalScope(Parser* parser, Scope* scope) - : parser_(parser), - prev_scope_(parser->top_scope_), - prev_level_(parser->with_nesting_level_) { - parser_->top_scope_ = scope; - parser_->with_nesting_level_ = 0; + LexicalScope(Scope** scope_variable, + int* with_nesting_level_variable, + Scope* scope) + : scope_variable_(scope_variable), + with_nesting_level_variable_(with_nesting_level_variable), + prev_scope_(*scope_variable), + prev_level_(*with_nesting_level_variable) { + *scope_variable = scope; + *with_nesting_level_variable = 0; } ~LexicalScope() { - parser_->top_scope_->Leave(); - parser_->top_scope_ = prev_scope_; - parser_->with_nesting_level_ = prev_level_; + (*scope_variable_)->Leave(); + *scope_variable_ = prev_scope_; + *with_nesting_level_variable_ = prev_level_; } private: - Parser* parser_; + Scope** scope_variable_; + int* with_nesting_level_variable_; Scope* prev_scope_; int prev_level_; }; @@ -1262,8 +1047,8 @@ bool Parser::PreParseProgram(Handle<String> source, mode_ = FLAG_lazy ? PARSE_LAZILY : PARSE_EAGERLY; if (allow_natives_syntax_ || extension_ != NULL) mode_ = PARSE_EAGERLY; DummyScope top_scope; - LexicalScope scope(this, &top_scope); - TemporaryScope temp_scope(this); + LexicalScope scope(&this->top_scope_, &this->with_nesting_level_, &top_scope); + TemporaryScope temp_scope(&this->temp_scope_); ZoneListWrapper<Statement> processor; bool ok = true; ParseSourceElements(&processor, Token::EOS, &ok); @@ -1297,8 +1082,9 @@ FunctionLiteral* Parser::ParseProgram(Handle<String> source, FunctionLiteral* result = NULL; { Scope* scope = factory()->NewScope(top_scope_, type, inside_with()); - LexicalScope lexical_scope(this, scope); - TemporaryScope temp_scope(this); + LexicalScope lexical_scope(&this->top_scope_, &this->with_nesting_level_, + scope); + TemporaryScope temp_scope(&this->temp_scope_); ZoneListWrapper<Statement> body(16); bool ok = true; ParseSourceElements(&body, Token::EOS, &ok); @@ -1356,8 +1142,9 @@ FunctionLiteral* Parser::ParseLazy(Handle<SharedFunctionInfo> info) { Handle<String> no_name = factory()->EmptySymbol(); Scope* scope = factory()->NewScope(top_scope_, Scope::GLOBAL_SCOPE, inside_with()); - LexicalScope lexical_scope(this, scope); - TemporaryScope temp_scope(this); + LexicalScope lexical_scope(&this->top_scope_, &this->with_nesting_level_, + scope); + TemporaryScope temp_scope(&this->temp_scope_); FunctionLiteralType type = info->is_expression() ? EXPRESSION : DECLARATION; @@ -1382,56 +1169,6 @@ FunctionLiteral* Parser::ParseLazy(Handle<SharedFunctionInfo> info) { } -FunctionLiteral* Parser::ParseJson(Handle<String> source) { - CompilationZoneScope zone_scope(DONT_DELETE_ON_EXIT); - - HistogramTimerScope timer(&Counters::parse); - Counters::total_parse_size.Increment(source->length()); - - // Initialize parser state. - source->TryFlatten(TENURED); - scanner_.Initialize(source, JSON); - ASSERT(target_stack_ == NULL); - - FunctionLiteral* result = NULL; - Handle<String> no_name = factory()->EmptySymbol(); - - { - Scope* scope = factory()->NewScope(top_scope_, Scope::GLOBAL_SCOPE, false); - LexicalScope lexical_scope(this, scope); - TemporaryScope temp_scope(this); - bool ok = true; - Expression* expression = ParseJson(&ok); - if (ok) { - ZoneListWrapper<Statement> statement = factory()->NewList<Statement>(1); - statement.Add(new ExpressionStatement(expression)); - result = NEW(FunctionLiteral( - no_name, - top_scope_, - statement.elements(), - temp_scope.materialized_literal_count(), - temp_scope.expected_property_count(), - temp_scope.only_simple_this_property_assignments(), - temp_scope.this_property_assignments(), - 0, - 0, - source->length(), - false, - temp_scope.ContainsLoops())); - } else if (scanner().stack_overflow()) { - Top::StackOverflow(); - } - } - - // Make sure the target stack is empty. - ASSERT(target_stack_ == NULL); - - // If there was a syntax error we have to get rid of the AST - // and it is not safe to do so before the scope has been deleted. - if (result == NULL) zone_scope.DeleteOnExit(); - return result; -} - void Parser::ReportMessage(const char* type, Vector<const char*> args) { Scanner::Location source_location = scanner_.location(); ReportMessageAt(source_location, type, args); @@ -1733,7 +1470,7 @@ void* Parser::ParseSourceElements(ZoneListWrapper<Statement>* processor, // elements. This way, all scripts and functions get their own // target stack thus avoiding illegal breaks and continues across // functions. - TargetScope scope(this); + TargetScope scope(&this->target_stack_); ASSERT(processor != NULL); InitializationBlockFinder block_finder; @@ -1857,7 +1594,7 @@ Statement* Parser::ParseStatement(ZoneStringList* labels, bool* ok) { // fall-through. It is much easier just to wrap the entire // try-statement in a statement block and put the labels there Block* result = NEW(Block(labels, 1, false)); - Target target(this, result); + Target target(&this->target_stack_, result); TryStatement* statement = ParseTryStatement(CHECK_OK); if (statement) { statement->set_statement_pos(statement_pos); @@ -2073,7 +1810,7 @@ Block* Parser::ParseBlock(ZoneStringList* labels, bool* ok) { // // Construct block expecting 16 statements. Block* result = NEW(Block(labels, 16, false)); - Target target(this, result); + Target target(&this->target_stack_, result); Expect(Token::LBRACE, CHECK_OK); while (peek() != Token::RBRACE) { Statement* stat = ParseStatement(NULL, CHECK_OK); @@ -2468,7 +2205,7 @@ Block* Parser::WithHelper(Expression* obj, ZoneList<BreakTarget*>* target_list = NEW(ZoneList<BreakTarget*>(0)); TargetCollector collector(target_list); Statement* stat; - { Target target(this, &collector); + { Target target(&this->target_stack_, &collector); with_nesting_level_++; top_scope_->RecordWithStatement(); stat = ParseStatement(labels, CHECK_OK); @@ -2551,7 +2288,7 @@ SwitchStatement* Parser::ParseSwitchStatement(ZoneStringList* labels, // 'switch' '(' Expression ')' '{' CaseClause* '}' SwitchStatement* statement = NEW(SwitchStatement(labels)); - Target target(this, statement); + Target target(&this->target_stack_, statement); Expect(Token::SWITCH, CHECK_OK); Expect(Token::LPAREN, CHECK_OK); @@ -2608,7 +2345,7 @@ TryStatement* Parser::ParseTryStatement(bool* ok) { TargetCollector collector(target_list); Block* try_block; - { Target target(this, &collector); + { Target target(&this->target_stack_, &collector); try_block = ParseBlock(NULL, CHECK_OK); } @@ -2644,7 +2381,7 @@ TryStatement* Parser::ParseTryStatement(bool* ok) { catch_var = top_scope_->NewTemporary(Factory::catch_var_symbol()); Literal* name_literal = NEW(Literal(name)); Expression* obj = NEW(CatchExtensionObject(name_literal, catch_var)); - { Target target(this, &catch_collector); + { Target target(&this->target_stack_, &catch_collector); catch_block = WithHelper(obj, NULL, true, CHECK_OK); } } else { @@ -2703,7 +2440,7 @@ DoWhileStatement* Parser::ParseDoWhileStatement(ZoneStringList* labels, temp_scope_->AddLoop(); DoWhileStatement* loop = NEW(DoWhileStatement(labels)); - Target target(this, loop); + Target target(&this->target_stack_, loop); Expect(Token::DO, CHECK_OK); Statement* body = ParseStatement(NULL, CHECK_OK); @@ -2736,7 +2473,7 @@ WhileStatement* Parser::ParseWhileStatement(ZoneStringList* labels, bool* ok) { temp_scope_->AddLoop(); WhileStatement* loop = NEW(WhileStatement(labels)); - Target target(this, loop); + Target target(&this->target_stack_, loop); Expect(Token::WHILE, CHECK_OK); Expect(Token::LPAREN, CHECK_OK); @@ -2766,7 +2503,7 @@ Statement* Parser::ParseForStatement(ZoneStringList* labels, bool* ok) { ParseVariableDeclarations(false, &each, CHECK_OK); if (peek() == Token::IN && each != NULL) { ForInStatement* loop = NEW(ForInStatement(labels)); - Target target(this, loop); + Target target(&this->target_stack_, loop); Expect(Token::IN, CHECK_OK); Expression* enumerable = ParseExpression(true, CHECK_OK); @@ -2800,7 +2537,7 @@ Statement* Parser::ParseForStatement(ZoneStringList* labels, bool* ok) { expression = NewThrowReferenceError(type); } ForInStatement* loop = NEW(ForInStatement(labels)); - Target target(this, loop); + Target target(&this->target_stack_, loop); Expect(Token::IN, CHECK_OK); Expression* enumerable = ParseExpression(true, CHECK_OK); @@ -2819,7 +2556,7 @@ Statement* Parser::ParseForStatement(ZoneStringList* labels, bool* ok) { // Standard 'for' loop ForStatement* loop = NEW(ForStatement(labels)); - Target target(this, loop); + Target target(&this->target_stack_, loop); // Parsed initializer at this point. Expect(Token::SEMICOLON, CHECK_OK); @@ -3909,8 +3646,9 @@ FunctionLiteral* Parser::ParseFunctionLiteral(Handle<String> var_name, // Parse function body. { Scope* scope = factory()->NewScope(top_scope_, Scope::FUNCTION_SCOPE, inside_with()); - LexicalScope lexical_scope(this, scope); - TemporaryScope temp_scope(this); + LexicalScope lexical_scope(&this->top_scope_, &this->with_nesting_level_, + scope); + TemporaryScope temp_scope(&this->temp_scope_); top_scope_->SetScopeName(name); // FormalParameterList :: @@ -4281,145 +4019,165 @@ Expression* Parser::NewThrowError(Handle<String> constructor, // ---------------------------------------------------------------------------- // JSON -Expression* Parser::ParseJson(bool* ok) { - Expression* result = ParseJsonValue(CHECK_OK); - Expect(Token::EOS, CHECK_OK); +Handle<Object> JsonParser::ParseJson(Handle<String> source) { + source->TryFlatten(); + scanner_.Initialize(source, JSON); + Handle<Object> result = ParseJsonValue(); + if (result.is_null() || scanner_.Next() != Token::EOS) { + if (scanner_.stack_overflow()) { + // Scanner failed. + Top::StackOverflow(); + } else { + // Parse failed. Scanner's current token is the unexpected token. + Token::Value token = scanner_.current_token(); + + const char* message; + const char* name_opt = NULL; + + switch (token) { + case Token::EOS: + message = "unexpected_eos"; + break; + case Token::NUMBER: + message = "unexpected_token_number"; + break; + case Token::STRING: + message = "unexpected_token_string"; + break; + case Token::IDENTIFIER: + message = "unexpected_token_identifier"; + break; + default: + message = "unexpected_token"; + name_opt = Token::String(token); + ASSERT(name_opt != NULL); + break; + } + + Scanner::Location source_location = scanner_.location(); + MessageLocation location(Factory::NewScript(source), + source_location.beg_pos, + source_location.end_pos); + int argc = (name_opt == NULL) ? 0 : 1; + Handle<JSArray> array = Factory::NewJSArray(argc); + if (name_opt != NULL) { + SetElement(array, + 0, + Factory::NewStringFromUtf8(CStrVector(name_opt))); + } + Handle<Object> result = Factory::NewSyntaxError(message, array); + Top::Throw(*result, &location); + return Handle<Object>::null(); + } + } return result; } +Handle<String> JsonParser::GetString() { + int literal_length = scanner_.literal_length(); + if (literal_length == 0) { + return Factory::empty_string(); + } + const char* literal_string = scanner_.literal_string(); + Vector<const char> literal(literal_string, literal_length); + return Factory::NewStringFromUtf8(literal); +} + + // Parse any JSON value. -Expression* Parser::ParseJsonValue(bool* ok) { - Token::Value token = peek(); +Handle<Object> JsonParser::ParseJsonValue() { + Token::Value token = scanner_.Next(); switch (token) { case Token::STRING: { - Consume(Token::STRING); - int literal_length = scanner_.literal_length(); - const char* literal_string = scanner_.literal_string(); - if (literal_length == 0) { - return NEW(Literal(Factory::empty_string())); - } - Vector<const char> literal(literal_string, literal_length); - return NEW(Literal(Factory::NewStringFromUtf8(literal, TENURED))); + return GetString(); } case Token::NUMBER: { - Consume(Token::NUMBER); - ASSERT(scanner_.literal_length() > 0); double value = StringToDouble(scanner_.literal(), NO_FLAGS, // Hex, octal or trailing junk. OS::nan_value()); - return NewNumberLiteral(value); + return Factory::NewNumber(value); } case Token::FALSE_LITERAL: - Consume(Token::FALSE_LITERAL); - return NEW(Literal(Factory::false_value())); + return Factory::false_value(); case Token::TRUE_LITERAL: - Consume(Token::TRUE_LITERAL); - return NEW(Literal(Factory::true_value())); + return Factory::true_value(); case Token::NULL_LITERAL: - Consume(Token::NULL_LITERAL); - return NEW(Literal(Factory::null_value())); - case Token::LBRACE: { - Expression* result = ParseJsonObject(CHECK_OK); - return result; - } - case Token::LBRACK: { - Expression* result = ParseJsonArray(CHECK_OK); - return result; - } + return Factory::null_value(); + case Token::LBRACE: + return ParseJsonObject(); + case Token::LBRACK: + return ParseJsonArray(); default: - *ok = false; - ReportUnexpectedToken(token); - return NULL; + return ReportUnexpectedToken(); } } // Parse a JSON object. Scanner must be right after '{' token. -Expression* Parser::ParseJsonObject(bool* ok) { - Consume(Token::LBRACE); - ZoneListWrapper<ObjectLiteral::Property> properties = - factory()->NewList<ObjectLiteral::Property>(4); - int boilerplate_properties = 0; - if (peek() != Token::RBRACE) { +Handle<Object> JsonParser::ParseJsonObject() { + Handle<JSFunction> object_constructor( + Top::global_context()->object_function()); + Handle<JSObject> json_object = Factory::NewJSObject(object_constructor); + if (scanner_.peek() == Token::RBRACE) { + scanner_.Next(); + } else { do { - Expect(Token::STRING, CHECK_OK); - Handle<String> key = GetSymbol(CHECK_OK); - Expect(Token::COLON, CHECK_OK); - Expression* value = ParseJsonValue(CHECK_OK); - Literal* key_literal; + if (scanner_.Next() != Token::STRING) { + return ReportUnexpectedToken(); + } + Handle<String> key = GetString(); + if (scanner_.Next() != Token::COLON) { + return ReportUnexpectedToken(); + } + Handle<Object> value = ParseJsonValue(); + if (value.is_null()) return Handle<Object>::null(); uint32_t index; if (key->AsArrayIndex(&index)) { - key_literal = NewNumberLiteral(index); + SetElement(json_object, index, value); } else { - key_literal = NEW(Literal(key)); - } - ObjectLiteral::Property* property = - NEW(ObjectLiteral::Property(key_literal, value)); - properties.Add(property); - - if (IsBoilerplateProperty(property)) { - boilerplate_properties++; + SetProperty(json_object, key, value, NONE); } - } while (Check(Token::COMMA)); + } while (scanner_.Next() == Token::COMMA); + if (scanner_.current_token() != Token::RBRACE) { + return ReportUnexpectedToken(); + } } - Expect(Token::RBRACE, CHECK_OK); - - int literal_index = temp_scope_->NextMaterializedLiteralIndex(); - if (is_pre_parsing_) return NULL; - - Handle<FixedArray> constant_properties = - Factory::NewFixedArray(boilerplate_properties * 2, TENURED); - bool is_simple = true; - bool fast_elements = true; - int depth = 1; - BuildObjectLiteralConstantProperties(properties.elements(), - constant_properties, - &is_simple, - &fast_elements, - &depth); - return new ObjectLiteral(constant_properties, - properties.elements(), - literal_index, - is_simple, - fast_elements, - depth); + return json_object; } // Parse a JSON array. Scanner must be right after '[' token. -Expression* Parser::ParseJsonArray(bool* ok) { - Consume(Token::LBRACK); +Handle<Object> JsonParser::ParseJsonArray() { + ZoneScope zone_scope(DELETE_ON_EXIT); + ZoneList<Handle<Object> > elements(4); - ZoneListWrapper<Expression> values = factory()->NewList<Expression>(4); - if (peek() != Token::RBRACK) { + Token::Value token = scanner_.peek(); + if (token == Token::RBRACK) { + scanner_.Next(); + } else { do { - Expression* exp = ParseJsonValue(CHECK_OK); - values.Add(exp); - } while (Check(Token::COMMA)); + Handle<Object> element = ParseJsonValue(); + if (element.is_null()) return Handle<Object>::null(); + elements.Add(element); + token = scanner_.Next(); + } while (token == Token::COMMA); + if (token != Token::RBRACK) { + return ReportUnexpectedToken(); + } } - Expect(Token::RBRACK, CHECK_OK); - // Update the scope information before the pre-parsing bailout. - int literal_index = temp_scope_->NextMaterializedLiteralIndex(); + // Allocate a fixed array with all the elements. + Handle<FixedArray> fast_elements = + Factory::NewFixedArray(elements.length()); - if (is_pre_parsing_) return NULL; - - // Allocate a fixed array with all the literals. - Handle<FixedArray> literals = - Factory::NewFixedArray(values.length(), TENURED); + for (int i = 0, n = elements.length(); i < n; i++) { + fast_elements->set(i, *elements[i]); + } - bool is_simple; - int depth; - BuildArrayLiteralBoilerplateLiterals(values.elements(), - literals, - &is_simple, - &depth); - return NEW(ArrayLiteral(literals, values.elements(), - literal_index, is_simple, depth)); + return Factory::NewJSArrayWithElements(fast_elements); } - // ---------------------------------------------------------------------------- // Regular expressions @@ -5247,9 +5005,9 @@ bool ScriptDataImpl::HasError() { // Preparse, but only collect data that is immediately useful, // even if the preparser data is only used once. -ScriptDataImpl* Parser::PartialPreParse(Handle<String> source, - unibrow::CharacterStream* stream, - v8::Extension* extension) { +ScriptDataImpl* ParserApi::PartialPreParse(Handle<String> source, + unibrow::CharacterStream* stream, + v8::Extension* extension) { Handle<Script> no_script; bool allow_natives_syntax = FLAG_allow_natives_syntax || Bootstrapper::IsActive(); @@ -5305,9 +5063,9 @@ int ScriptDataImpl::ReadNumber(byte** source) { } -ScriptDataImpl* Parser::PreParse(Handle<String> source, - unibrow::CharacterStream* stream, - v8::Extension* extension) { +ScriptDataImpl* ParserApi::PreParse(Handle<String> source, + unibrow::CharacterStream* stream, + v8::Extension* extension) { Handle<Script> no_script; bool allow_natives_syntax = FLAG_allow_natives_syntax || Bootstrapper::IsActive(); @@ -5320,9 +5078,9 @@ ScriptDataImpl* Parser::PreParse(Handle<String> source, } -bool Parser::ParseRegExp(FlatStringReader* input, - bool multiline, - RegExpCompileData* result) { +bool RegExpParser::ParseRegExp(FlatStringReader* input, + bool multiline, + RegExpCompileData* result) { ASSERT(result != NULL); RegExpParser parser(input, &result->error, multiline); RegExpTree* tree = parser.ParsePattern(); @@ -5342,7 +5100,7 @@ bool Parser::ParseRegExp(FlatStringReader* input, } -bool Parser::Parse(CompilationInfo* info) { +bool ParserApi::Parse(CompilationInfo* info) { ASSERT(info->function() == NULL); FunctionLiteral* result = NULL; Handle<Script> script = info->script(); @@ -5368,11 +5126,7 @@ bool Parser::Parse(CompilationInfo* info) { ASSERT(Top::has_pending_exception()); } else { Handle<String> source = Handle<String>(String::cast(script->source())); - // JSON is always global. - ASSERT(!info->is_json() || info->is_global()); - result = info->is_json() - ? parser.ParseJson(source) - : parser.ParseProgram(source, info->is_global()); + result = parser.ParseProgram(source, info->is_global()); } } diff --git a/deps/v8/src/parser.h b/deps/v8/src/parser.h index 7142551c220..19b382e8ded 100644 --- a/deps/v8/src/parser.h +++ b/deps/v8/src/parser.h @@ -177,13 +177,8 @@ class ScriptDataImpl : public ScriptData { }; -class Parser { +class ParserApi { public: - Parser(Handle<Script> script, bool allow_natives_syntax, - v8::Extension* extension, ParserMode is_pre_parsing, - ParserFactory* factory, ParserLog* log, ScriptDataImpl* pre_data); - virtual ~Parser() { } - // Parses the source code represented by the compilation info and sets its // function literal. Returns false (and deallocates any allocated AST // nodes) if parsing failed. @@ -199,11 +194,246 @@ class Parser { static ScriptDataImpl* PartialPreParse(Handle<String> source, unibrow::CharacterStream* stream, v8::Extension* extension); +}; + + +// A BuffferedZoneList is an automatically growing list, just like (and backed +// by) a ZoneList, that is optimized for the case of adding and removing +// a single element. The last element added is stored outside the backing list, +// and if no more than one element is ever added, the ZoneList isn't even +// allocated. +// Elements must not be NULL pointers. +template <typename T, int initial_size> +class BufferedZoneList { + public: + BufferedZoneList() : list_(NULL), last_(NULL) {} + + // Adds element at end of list. This element is buffered and can + // be read using last() or removed using RemoveLast until a new Add or until + // RemoveLast or GetList has been called. + void Add(T* value) { + if (last_ != NULL) { + if (list_ == NULL) { + list_ = new ZoneList<T*>(initial_size); + } + list_->Add(last_); + } + last_ = value; + } + + T* last() { + ASSERT(last_ != NULL); + return last_; + } + + T* RemoveLast() { + ASSERT(last_ != NULL); + T* result = last_; + if ((list_ != NULL) && (list_->length() > 0)) + last_ = list_->RemoveLast(); + else + last_ = NULL; + return result; + } + + T* Get(int i) { + ASSERT((0 <= i) && (i < length())); + if (list_ == NULL) { + ASSERT_EQ(0, i); + return last_; + } else { + if (i == list_->length()) { + ASSERT(last_ != NULL); + return last_; + } else { + return list_->at(i); + } + } + } + + void Clear() { + list_ = NULL; + last_ = NULL; + } + + int length() { + int length = (list_ == NULL) ? 0 : list_->length(); + return length + ((last_ == NULL) ? 0 : 1); + } + + ZoneList<T*>* GetList() { + if (list_ == NULL) { + list_ = new ZoneList<T*>(initial_size); + } + if (last_ != NULL) { + list_->Add(last_); + last_ = NULL; + } + return list_; + } + + private: + ZoneList<T*>* list_; + T* last_; +}; + + +// Accumulates RegExp atoms and assertions into lists of terms and alternatives. +class RegExpBuilder: public ZoneObject { + public: + RegExpBuilder(); + void AddCharacter(uc16 character); + // "Adds" an empty expression. Does nothing except consume a + // following quantifier + void AddEmpty(); + void AddAtom(RegExpTree* tree); + void AddAssertion(RegExpTree* tree); + void NewAlternative(); // '|' + void AddQuantifierToAtom(int min, int max, RegExpQuantifier::Type type); + RegExpTree* ToRegExp(); + + private: + void FlushCharacters(); + void FlushText(); + void FlushTerms(); + bool pending_empty_; + ZoneList<uc16>* characters_; + BufferedZoneList<RegExpTree, 2> terms_; + BufferedZoneList<RegExpTree, 2> text_; + BufferedZoneList<RegExpTree, 2> alternatives_; +#ifdef DEBUG + enum {ADD_NONE, ADD_CHAR, ADD_TERM, ADD_ASSERT, ADD_ATOM} last_added_; +#define LAST(x) last_added_ = x; +#else +#define LAST(x) +#endif +}; + + +class RegExpParser { + public: + RegExpParser(FlatStringReader* in, + Handle<String>* error, + bool multiline_mode); static bool ParseRegExp(FlatStringReader* input, bool multiline, RegExpCompileData* result); + RegExpTree* ParsePattern(); + RegExpTree* ParseDisjunction(); + RegExpTree* ParseGroup(); + RegExpTree* ParseCharacterClass(); + + // Parses a {...,...} quantifier and stores the range in the given + // out parameters. + bool ParseIntervalQuantifier(int* min_out, int* max_out); + + // Parses and returns a single escaped character. The character + // must not be 'b' or 'B' since they are usually handle specially. + uc32 ParseClassCharacterEscape(); + + // Checks whether the following is a length-digit hexadecimal number, + // and sets the value if it is. + bool ParseHexEscape(int length, uc32* value); + + uc32 ParseControlLetterEscape(); + uc32 ParseOctalLiteral(); + + // Tries to parse the input as a back reference. If successful it + // stores the result in the output parameter and returns true. If + // it fails it will push back the characters read so the same characters + // can be reparsed. + bool ParseBackReferenceIndex(int* index_out); + + CharacterRange ParseClassAtom(uc16* char_class); + RegExpTree* ReportError(Vector<const char> message); + void Advance(); + void Advance(int dist); + void Reset(int pos); + + // Reports whether the pattern might be used as a literal search string. + // Only use if the result of the parse is a single atom node. + bool simple(); + bool contains_anchor() { return contains_anchor_; } + void set_contains_anchor() { contains_anchor_ = true; } + int captures_started() { return captures_ == NULL ? 0 : captures_->length(); } + int position() { return next_pos_ - 1; } + bool failed() { return failed_; } + + static const int kMaxCaptures = 1 << 16; + static const uc32 kEndMarker = (1 << 21); + + private: + enum SubexpressionType { + INITIAL, + CAPTURE, // All positive values represent captures. + POSITIVE_LOOKAHEAD, + NEGATIVE_LOOKAHEAD, + GROUPING + }; + + class RegExpParserState : public ZoneObject { + public: + RegExpParserState(RegExpParserState* previous_state, + SubexpressionType group_type, + int disjunction_capture_index) + : previous_state_(previous_state), + builder_(new RegExpBuilder()), + group_type_(group_type), + disjunction_capture_index_(disjunction_capture_index) {} + // Parser state of containing expression, if any. + RegExpParserState* previous_state() { return previous_state_; } + bool IsSubexpression() { return previous_state_ != NULL; } + // RegExpBuilder building this regexp's AST. + RegExpBuilder* builder() { return builder_; } + // Type of regexp being parsed (parenthesized group or entire regexp). + SubexpressionType group_type() { return group_type_; } + // Index in captures array of first capture in this sub-expression, if any. + // Also the capture index of this sub-expression itself, if group_type + // is CAPTURE. + int capture_index() { return disjunction_capture_index_; } + + private: + // Linked list implementation of stack of states. + RegExpParserState* previous_state_; + // Builder for the stored disjunction. + RegExpBuilder* builder_; + // Stored disjunction type (capture, look-ahead or grouping), if any. + SubexpressionType group_type_; + // Stored disjunction's capture index (if any). + int disjunction_capture_index_; + }; + + uc32 current() { return current_; } + bool has_more() { return has_more_; } + bool has_next() { return next_pos_ < in()->length(); } + uc32 Next(); + FlatStringReader* in() { return in_; } + void ScanForCaptures(); + uc32 current_; + bool has_more_; + bool multiline_; + int next_pos_; + FlatStringReader* in_; + Handle<String>* error_; + bool simple_; + bool contains_anchor_; + ZoneList<RegExpCapture*>* captures_; + bool is_scanned_for_captures_; + // The capture count is only valid after we have scanned for captures. + int capture_count_; + bool failed_; +}; + + +class Parser { + public: + Parser(Handle<Script> script, bool allow_natives_syntax, + v8::Extension* extension, ParserMode is_pre_parsing, + ParserFactory* factory, ParserLog* log, ScriptDataImpl* pre_data); + virtual ~Parser() { } + // Pre-parse the program from the character stream; returns true on // success, false if a stack-overflow happened during parsing. bool PreParseProgram(Handle<String> source, unibrow::CharacterStream* stream); @@ -218,7 +448,6 @@ class Parser { FunctionLiteral* ParseProgram(Handle<String> source, bool in_global_context); FunctionLiteral* ParseLazy(Handle<SharedFunctionInfo> info); - FunctionLiteral* ParseJson(Handle<String> source); // The minimum number of contiguous assignment that will // be treated as an initialization block. Benchmarks show that @@ -410,34 +639,6 @@ class Parser { Expression* NewThrowError(Handle<String> constructor, Handle<String> type, Vector< Handle<Object> > arguments); - - // JSON is a subset of JavaScript, as specified in, e.g., the ECMAScript 5 - // specification section 15.12.1 (and appendix A.8). - // The grammar is given section 15.12.1.2 (and appendix A.8.2). - - // Parse JSON input as a single JSON value. - Expression* ParseJson(bool* ok); - - // Parse a single JSON value from input (grammar production JSONValue). - // A JSON value is either a (double-quoted) string literal, a number literal, - // one of "true", "false", or "null", or an object or array literal. - Expression* ParseJsonValue(bool* ok); - // Parse a JSON object literal (grammar production JSONObject). - // An object literal is a squiggly-braced and comma separated sequence - // (possibly empty) of key/value pairs, where the key is a JSON string - // literal, the value is a JSON value, and the two are spearated by a colon. - // A JavaScript object also allows numbers and identifiers as keys. - Expression* ParseJsonObject(bool* ok); - // Parses a JSON array literal (grammar production JSONArray). An array - // literal is a square-bracketed and comma separated sequence (possibly empty) - // of JSON values. - // A JavaScript array allows leaving out values from the sequence. - Expression* ParseJsonArray(bool* ok); - - friend class Target; - friend class TargetScope; - friend class LexicalScope; - friend class TemporaryScope; }; @@ -472,6 +673,49 @@ class CompileTimeValue: public AllStatic { }; +// JSON is a subset of JavaScript, as specified in, e.g., the ECMAScript 5 +// specification section 15.12.1 (and appendix A.8). +// The grammar is given section 15.12.1.2 (and appendix A.8.2). +class JsonParser BASE_EMBEDDED { + public: + // Parse JSON input as a single JSON value. + // Returns null handle and sets exception if parsing failed. + static Handle<Object> Parse(Handle<String> source) { + return JsonParser().ParseJson(source); + } + + private: + JsonParser() { } + ~JsonParser() { } + + // Parse a string containing a single JSON value. + Handle<Object> ParseJson(Handle<String>); + // Parse a single JSON value from input (grammar production JSONValue). + // A JSON value is either a (double-quoted) string literal, a number literal, + // one of "true", "false", or "null", or an object or array literal. + Handle<Object> ParseJsonValue(); + // Parse a JSON object literal (grammar production JSONObject). + // An object literal is a squiggly-braced and comma separated sequence + // (possibly empty) of key/value pairs, where the key is a JSON string + // literal, the value is a JSON value, and the two are separated by a colon. + // A JSON array dosn't allow numbers and identifiers as keys, like a + // JavaScript array. + Handle<Object> ParseJsonObject(); + // Parses a JSON array literal (grammar production JSONArray). An array + // literal is a square-bracketed and comma separated sequence (possibly empty) + // of JSON values. + // A JSON array doesn't allow leaving out values from the sequence, nor does + // it allow a terminal comma, like a JavaScript array does. + Handle<Object> ParseJsonArray(); + + // Mark that a parsing error has happened at the current token, and + // return a null handle. Primarily for readability. + Handle<Object> ReportUnexpectedToken() { return Handle<Object>::null(); } + // Converts the currently parsed literal to a JavaScript String. + Handle<String> GetString(); + + Scanner scanner_; +}; } } // namespace v8::internal #endif // V8_PARSER_H_ diff --git a/deps/v8/src/platform-linux.cc b/deps/v8/src/platform-linux.cc index eefaec9042b..c0eb21395fe 100644 --- a/deps/v8/src/platform-linux.cc +++ b/deps/v8/src/platform-linux.cc @@ -856,7 +856,7 @@ void Sampler::Start() { struct sigaction sa; sa.sa_sigaction = ProfilerSignalHandler; sigemptyset(&sa.sa_mask); - sa.sa_flags = SA_SIGINFO; + sa.sa_flags = SA_RESTART | SA_SIGINFO; if (sigaction(SIGPROF, &sa, &data_->old_signal_handler_) != 0) return; data_->signal_handler_installed_ = true; diff --git a/deps/v8/src/runtime.cc b/deps/v8/src/runtime.cc index f701c031132..fc1a0232295 100644 --- a/deps/v8/src/runtime.cc +++ b/deps/v8/src/runtime.cc @@ -7129,20 +7129,31 @@ static MaybeObject* Runtime_GlobalReceiver(Arguments args) { } +static MaybeObject* Runtime_ParseJson(Arguments args) { + HandleScope scope; + ASSERT_EQ(1, args.length()); + CONVERT_ARG_CHECKED(String, source, 0); + + Handle<Object> result = JsonParser::Parse(source); + if (result.is_null()) { + // Syntax error or stack overflow in scanner. + ASSERT(Top::has_pending_exception()); + return Failure::Exception(); + } + return *result; +} + + static MaybeObject* Runtime_CompileString(Arguments args) { HandleScope scope; - ASSERT_EQ(2, args.length()); + ASSERT_EQ(1, args.length()); CONVERT_ARG_CHECKED(String, source, 0); - CONVERT_ARG_CHECKED(Oddball, is_json, 1) // Compile source string in the global context. Handle<Context> context(Top::context()->global_context()); - Compiler::ValidationState validate = (is_json->IsTrue()) - ? Compiler::VALIDATE_JSON : Compiler::DONT_VALIDATE_JSON; Handle<SharedFunctionInfo> shared = Compiler::CompileEval(source, context, - true, - validate); + true); if (shared.is_null()) return Failure::Exception(); Handle<JSFunction> fun = Factory::NewFunctionFromSharedFunctionInfo(shared, context, NOT_TENURED); @@ -7157,8 +7168,7 @@ static ObjectPair CompileGlobalEval(Handle<String> source, Handle<SharedFunctionInfo> shared = Compiler::CompileEval( source, Handle<Context>(Top::context()), - Top::context()->IsGlobalContext(), - Compiler::DONT_VALIDATE_JSON); + Top::context()->IsGlobalContext()); if (shared.is_null()) return MakePair(Failure::Exception(), NULL); Handle<JSFunction> compiled = Factory::NewFunctionFromSharedFunctionInfo( shared, @@ -9370,8 +9380,7 @@ static MaybeObject* Runtime_DebugEvaluate(Arguments args) { Handle<SharedFunctionInfo> shared = Compiler::CompileEval(function_source, context, - context->IsGlobalContext(), - Compiler::DONT_VALIDATE_JSON); + context->IsGlobalContext()); if (shared.is_null()) return Failure::Exception(); Handle<JSFunction> compiled_function = Factory::NewFunctionFromSharedFunctionInfo(shared, context); @@ -9442,8 +9451,7 @@ static MaybeObject* Runtime_DebugEvaluateGlobal(Arguments args) { Handle<SharedFunctionInfo> shared = Compiler::CompileEval(source, context, - true, - Compiler::DONT_VALIDATE_JSON); + true); if (shared.is_null()) return Failure::Exception(); Handle<JSFunction> compiled_function = Handle<JSFunction>(Factory::NewFunctionFromSharedFunctionInfo(shared, diff --git a/deps/v8/src/runtime.h b/deps/v8/src/runtime.h index 8057d8bd30c..72a80379701 100644 --- a/deps/v8/src/runtime.h +++ b/deps/v8/src/runtime.h @@ -164,6 +164,9 @@ namespace internal { F(RegExpConstructResult, 3, 1) \ F(RegExpCloneResult, 1, 1) \ \ + /* JSON */ \ + F(ParseJson, 1, 1) \ + \ /* Strings */ \ F(StringCharCodeAt, 2, 1) \ F(StringIndexOf, 3, 1) \ @@ -222,7 +225,7 @@ namespace internal { /* Numbers */ \ \ /* Globals */ \ - F(CompileString, 2, 1) \ + F(CompileString, 1, 1) \ F(GlobalPrint, 1, 1) \ \ /* Eval */ \ diff --git a/deps/v8/src/scanner.h b/deps/v8/src/scanner.h index 6e5333bce1e..dab3d672815 100644 --- a/deps/v8/src/scanner.h +++ b/deps/v8/src/scanner.h @@ -296,6 +296,9 @@ class Scanner { // Returns the next token. Token::Value Next(); + // Returns the current token again. + Token::Value current_token() { return current_.token; } + // One token look-ahead (past the token returned by Next()). Token::Value peek() const { return next_.token; } diff --git a/deps/v8/src/stub-cache.h b/deps/v8/src/stub-cache.h index 07d21979bf5..9d947e404b1 100644 --- a/deps/v8/src/stub-cache.h +++ b/deps/v8/src/stub-cache.h @@ -241,13 +241,15 @@ class StubCache : public AllStatic { static void Clear(); // Generate code for probing the stub cache table. - // If extra != no_reg it might be used as am extra scratch register. + // Arguments extra and extra2 may be used to pass additional scratch + // registers. Set to no_reg if not needed. static void GenerateProbe(MacroAssembler* masm, Code::Flags flags, Register receiver, Register name, Register scratch, - Register extra); + Register extra, + Register extra2 = no_reg); enum Table { kPrimary, diff --git a/deps/v8/src/top.h b/deps/v8/src/top.h index e97289f3596..bc3a85e850c 100644 --- a/deps/v8/src/top.h +++ b/deps/v8/src/top.h @@ -105,7 +105,11 @@ class ThreadLocalTop BASE_EMBEDDED { Address handler_; // try-blocks are chained through the stack #ifdef USE_SIMULATOR +#ifdef V8_TARGET_ARCH_ARM assembler::arm::Simulator* simulator_; +#elif V8_TARGET_ARCH_MIPS + assembler::mips::Simulator* simulator_; +#endif #endif // USE_SIMULATOR #ifdef ENABLE_LOGGING_AND_PROFILING diff --git a/deps/v8/src/v8natives.js b/deps/v8/src/v8natives.js index 88aea9c1739..50a2774d122 100644 --- a/deps/v8/src/v8natives.js +++ b/deps/v8/src/v8natives.js @@ -140,7 +140,7 @@ function GlobalEval(x) { 'be the global object from which eval originated'); } - var f = %CompileString(x, false); + var f = %CompileString(x); if (!IS_FUNCTION(f)) return f; return f.call(this); @@ -151,7 +151,7 @@ function GlobalEval(x) { function GlobalExecScript(expr, lang) { // NOTE: We don't care about the character casing. if (!lang || /javascript/i.test(lang)) { - var f = %CompileString(ToString(expr), false); + var f = %CompileString(ToString(expr)); f.call(%GlobalReceiver(global)); } return null; @@ -1177,7 +1177,7 @@ function NewFunction(arg1) { // length == 1 // The call to SetNewFunctionAttributes will ensure the prototype // property of the resulting function is enumerable (ECMA262, 15.3.5.2). - var f = %CompileString(source, false)(); + var f = %CompileString(source)(); %FunctionSetName(f, "anonymous"); return %SetNewFunctionAttributes(f); } diff --git a/deps/v8/src/version.cc b/deps/v8/src/version.cc index 4017ae5e3d3..e27b9153fcc 100644 --- a/deps/v8/src/version.cc +++ b/deps/v8/src/version.cc @@ -34,7 +34,7 @@ // cannot be changed without changing the SCons build script. #define MAJOR_VERSION 2 #define MINOR_VERSION 5 -#define BUILD_NUMBER 2 +#define BUILD_NUMBER 3 #define PATCH_LEVEL 0 #define CANDIDATE_VERSION false diff --git a/deps/v8/src/x64/codegen-x64.cc b/deps/v8/src/x64/codegen-x64.cc index 9e6ef3b5240..0faf775d51c 100644 --- a/deps/v8/src/x64/codegen-x64.cc +++ b/deps/v8/src/x64/codegen-x64.cc @@ -4866,6 +4866,11 @@ void CodeGenerator::VisitObjectLiteral(ObjectLiteral* node) { } frame_->Push(&clone); + // Mark all computed expressions that are bound to a key that + // is shadowed by a later occurrence of the same key. For the + // marked expressions, no store code is emitted. + node->CalculateEmitStore(); + for (int i = 0; i < node->properties()->length(); i++) { ObjectLiteral::Property* property = node->properties()->at(i); switch (property->kind()) { @@ -4880,13 +4885,17 @@ void CodeGenerator::VisitObjectLiteral(ObjectLiteral* node) { // Duplicate the object as the IC receiver. frame_->Dup(); Load(property->value()); - Result ignored = - frame_->CallStoreIC(Handle<String>::cast(key), false); - // A test rax instruction following the store IC call would - // indicate the presence of an inlined version of the - // store. Add a nop to indicate that there is no such - // inlined version. - __ nop(); + if (property->emit_store()) { + Result ignored = + frame_->CallStoreIC(Handle<String>::cast(key), false); + // A test rax instruction following the store IC call would + // indicate the presence of an inlined version of the + // store. Add a nop to indicate that there is no such + // inlined version. + __ nop(); + } else { + frame_->Drop(2); + } break; } // Fall through @@ -4896,8 +4905,12 @@ void CodeGenerator::VisitObjectLiteral(ObjectLiteral* node) { frame_->Dup(); Load(property->key()); Load(property->value()); - Result ignored = frame_->CallRuntime(Runtime::kSetProperty, 3); - // Ignore the result. + if (property->emit_store()) { + // Ignore the result. + Result ignored = frame_->CallRuntime(Runtime::kSetProperty, 3); + } else { + frame_->Drop(3); + } break; } case ObjectLiteral::Property::SETTER: { diff --git a/deps/v8/src/x64/full-codegen-x64.cc b/deps/v8/src/x64/full-codegen-x64.cc index 32d624262fb..4e0f6d4b624 100644 --- a/deps/v8/src/x64/full-codegen-x64.cc +++ b/deps/v8/src/x64/full-codegen-x64.cc @@ -1158,6 +1158,11 @@ void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { // result_saved is false the result is in rax. bool result_saved = false; + // Mark all computed expressions that are bound to a key that + // is shadowed by a later occurrence of the same key. For the + // marked expressions, no store code is emitted. + expr->CalculateEmitStore(); + for (int i = 0; i < expr->properties()->length(); i++) { ObjectLiteral::Property* property = expr->properties()->at(i); if (property->IsCompileTimeValue()) continue; @@ -1179,8 +1184,10 @@ void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { VisitForAccumulatorValue(value); __ Move(rcx, key->handle()); __ movq(rdx, Operand(rsp, 0)); - Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); - EmitCallIC(ic, RelocInfo::CODE_TARGET); + if (property->emit_store()) { + Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); + EmitCallIC(ic, RelocInfo::CODE_TARGET); + } break; } // Fall through. @@ -1188,7 +1195,11 @@ void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { __ push(Operand(rsp, 0)); // Duplicate receiver. VisitForStackValue(key); VisitForStackValue(value); - __ CallRuntime(Runtime::kSetProperty, 3); + if (property->emit_store()) { + __ CallRuntime(Runtime::kSetProperty, 3); + } else { + __ Drop(3); + } break; case ObjectLiteral::Property::SETTER: case ObjectLiteral::Property::GETTER: diff --git a/deps/v8/src/x64/stub-cache-x64.cc b/deps/v8/src/x64/stub-cache-x64.cc index 3891e1d5a3b..24609bf642b 100644 --- a/deps/v8/src/x64/stub-cache-x64.cc +++ b/deps/v8/src/x64/stub-cache-x64.cc @@ -273,9 +273,11 @@ void StubCache::GenerateProbe(MacroAssembler* masm, Register receiver, Register name, Register scratch, - Register extra) { + Register extra, + Register extra2) { Label miss; - USE(extra); // The register extra is not used on the X64 platform. + USE(extra); // The register extra is not used on the X64 platform. + USE(extra2); // The register extra2 is not used on the X64 platform. // Make sure that code is valid. The shifting code relies on the // entry size being 16. ASSERT(sizeof(Entry) == 16); @@ -287,6 +289,10 @@ void StubCache::GenerateProbe(MacroAssembler* masm, ASSERT(!scratch.is(receiver)); ASSERT(!scratch.is(name)); + // Check scratch register is valid, extra and extra2 are unused. + ASSERT(!scratch.is(no_reg)); + ASSERT(extra2.is(no_reg)); + // Check that the receiver isn't a smi. __ JumpIfSmi(receiver, &miss); diff --git a/deps/v8/test/cctest/test-lock.cc b/deps/v8/test/cctest/test-lock.cc index 5eecfcee168..9039e022ec5 100644 --- a/deps/v8/test/cctest/test-lock.cc +++ b/deps/v8/test/cctest/test-lock.cc @@ -60,4 +60,5 @@ TEST(SemaphoreTimeout) { sem->Signal(); ok = sem->Wait(1000); CHECK(ok); + delete sem; } diff --git a/deps/v8/test/cctest/test-regexp.cc b/deps/v8/test/cctest/test-regexp.cc index 11a808e3699..3e6709aef43 100644 --- a/deps/v8/test/cctest/test-regexp.cc +++ b/deps/v8/test/cctest/test-regexp.cc @@ -64,7 +64,7 @@ static bool CheckParse(const char* input) { ZoneScope zone_scope(DELETE_ON_EXIT); FlatStringReader reader(CStrVector(input)); RegExpCompileData result; - return v8::internal::Parser::ParseRegExp(&reader, false, &result); + return v8::internal::RegExpParser::ParseRegExp(&reader, false, &result); } @@ -74,7 +74,7 @@ static SmartPointer<const char> Parse(const char* input) { ZoneScope zone_scope(DELETE_ON_EXIT); FlatStringReader reader(CStrVector(input)); RegExpCompileData result; - CHECK(v8::internal::Parser::ParseRegExp(&reader, false, &result)); + CHECK(v8::internal::RegExpParser::ParseRegExp(&reader, false, &result)); CHECK(result.tree != NULL); CHECK(result.error.is_null()); SmartPointer<const char> output = result.tree->ToString(); @@ -88,7 +88,7 @@ static bool CheckSimple(const char* input) { ZoneScope zone_scope(DELETE_ON_EXIT); FlatStringReader reader(CStrVector(input)); RegExpCompileData result; - CHECK(v8::internal::Parser::ParseRegExp(&reader, false, &result)); + CHECK(v8::internal::RegExpParser::ParseRegExp(&reader, false, &result)); CHECK(result.tree != NULL); CHECK(result.error.is_null()); return result.simple; @@ -106,7 +106,7 @@ static MinMaxPair CheckMinMaxMatch(const char* input) { ZoneScope zone_scope(DELETE_ON_EXIT); FlatStringReader reader(CStrVector(input)); RegExpCompileData result; - CHECK(v8::internal::Parser::ParseRegExp(&reader, false, &result)); + CHECK(v8::internal::RegExpParser::ParseRegExp(&reader, false, &result)); CHECK(result.tree != NULL); CHECK(result.error.is_null()); int min_match = result.tree->min_match(); @@ -365,7 +365,7 @@ static void ExpectError(const char* input, ZoneScope zone_scope(DELETE_ON_EXIT); FlatStringReader reader(CStrVector(input)); RegExpCompileData result; - CHECK_EQ(false, v8::internal::Parser::ParseRegExp(&reader, false, &result)); + CHECK(!v8::internal::RegExpParser::ParseRegExp(&reader, false, &result)); CHECK(result.tree == NULL); CHECK(!result.error.is_null()); SmartPointer<char> str = result.error->ToCString(ALLOW_NULLS); @@ -473,7 +473,8 @@ static RegExpNode* Compile(const char* input, bool multiline, bool is_ascii) { V8::Initialize(NULL); FlatStringReader reader(CStrVector(input)); RegExpCompileData compile_data; - if (!v8::internal::Parser::ParseRegExp(&reader, multiline, &compile_data)) + if (!v8::internal::RegExpParser::ParseRegExp(&reader, multiline, + &compile_data)) return NULL; Handle<String> pattern = Factory::NewStringFromUtf8(CStrVector(input)); RegExpEngine::Compile(&compile_data, false, multiline, pattern, is_ascii); diff --git a/deps/v8/test/cctest/test-serialize.cc b/deps/v8/test/cctest/test-serialize.cc index 6a513e5fa56..1cbaf2bf665 100644 --- a/deps/v8/test/cctest/test-serialize.cc +++ b/deps/v8/test/cctest/test-serialize.cc @@ -216,6 +216,7 @@ void FileByteSink::WriteSpaceUsed( Vector<char> name = Vector<char>::New(file_name_length + 1); OS::SNPrintF(name, "%s.size", file_name_); FILE* fp = OS::FOpen(name.start(), "w"); + name.Dispose(); fprintf(fp, "new %d\n", new_space_used); fprintf(fp, "pointer %d\n", pointer_space_used); fprintf(fp, "data %d\n", data_space_used); @@ -381,6 +382,7 @@ TEST(PartialSerialization) { env.Dispose(); FileByteSink startup_sink(startup_name.start()); + startup_name.Dispose(); StartupSerializer startup_serializer(&startup_sink); startup_serializer.SerializeStrongReferences(); @@ -403,6 +405,7 @@ static void ReserveSpaceForPartialSnapshot(const char* file_name) { Vector<char> name = Vector<char>::New(file_name_length + 1); OS::SNPrintF(name, "%s.size", file_name); FILE* fp = OS::FOpen(name.start(), "r"); + name.Dispose(); int new_size, pointer_size, data_size, code_size, map_size, cell_size; int large_size; #ifdef _MSC_VER @@ -438,6 +441,7 @@ DEPENDENT_TEST(PartialDeserialization, PartialSerialization) { OS::SNPrintF(startup_name, "%s.startup", FLAG_testing_serialization_file); CHECK(Snapshot::Initialize(startup_name.start())); + startup_name.Dispose(); const char* file_name = FLAG_testing_serialization_file; ReserveSpaceForPartialSnapshot(file_name); @@ -495,6 +499,7 @@ TEST(ContextSerialization) { env.Dispose(); FileByteSink startup_sink(startup_name.start()); + startup_name.Dispose(); StartupSerializer startup_serializer(&startup_sink); startup_serializer.SerializeStrongReferences(); @@ -519,6 +524,7 @@ DEPENDENT_TEST(ContextDeserialization, ContextSerialization) { OS::SNPrintF(startup_name, "%s.startup", FLAG_testing_serialization_file); CHECK(Snapshot::Initialize(startup_name.start())); + startup_name.Dispose(); const char* file_name = FLAG_testing_serialization_file; ReserveSpaceForPartialSnapshot(file_name); diff --git a/deps/v8/test/mjsunit/debug-compile-event.js b/deps/v8/test/mjsunit/debug-compile-event.js index e7ecf47ec98..b00a907a3cf 100644 --- a/deps/v8/test/mjsunit/debug-compile-event.js +++ b/deps/v8/test/mjsunit/debug-compile-event.js @@ -36,7 +36,6 @@ var current_source = ''; // Current source being compiled. var source_count = 0; // Total number of scources compiled. var host_compilations = 0; // Number of scources compiled through the API. var eval_compilations = 0; // Number of scources compiled through eval. -var json_compilations = 0; // Number of scources compiled through JSON.parse. function compileSource(source) { @@ -62,9 +61,6 @@ function listener(event, exec_state, event_data, data) { case Debug.ScriptCompilationType.Eval: eval_compilations++; break; - case Debug.ScriptCompilationType.JSON: - json_compilations++; - break; } } @@ -74,13 +70,6 @@ function listener(event, exec_state, event_data, data) { // For source with 'eval' there will be compile events with substrings // as well as with with the exact source. assertTrue(current_source.indexOf(event_data.script().source()) >= 0); - } else if (current_source.indexOf('JSON.parse') == 0) { - // For JSON the JSON source will be in parentheses. - var s = event_data.script().source(); - if (s[0] == '(') { - s = s.substring(1, s.length - 2); - } - assertTrue(current_source.indexOf(s) >= 0); } else { // For source without 'eval' there will be a compile events with the // exact source. @@ -113,7 +102,7 @@ source_count++; // Using eval causes additional compilation event. compileSource('eval("eval(\'(function(){return a;})\')")'); source_count += 2; // Using eval causes additional compilation event. compileSource('JSON.parse(\'{"a":1,"b":2}\')'); -source_count++; // Using JSON.parse causes additional compilation event. +// Using JSON.parse does not causes additional compilation events. compileSource('x=1; //@ sourceURL=myscript.js'); // Make sure that the debug event listener was invoked. @@ -123,10 +112,9 @@ assertFalse(exception, "exception in listener") assertEquals(before_compile_count, after_compile_count); // Check the actual number of events (no compilation through the API as all -// source compiled through eval except for one JSON.parse call). +// source compiled through eval). assertEquals(source_count, after_compile_count); assertEquals(0, host_compilations); -assertEquals(source_count - 1, eval_compilations); -assertEquals(1, json_compilations); +assertEquals(source_count, eval_compilations); Debug.setListener(null); diff --git a/deps/v8/test/mjsunit/mirror-script.js b/deps/v8/test/mjsunit/mirror-script.js index 8631028e4e3..71561701a23 100644 --- a/deps/v8/test/mjsunit/mirror-script.js +++ b/deps/v8/test/mjsunit/mirror-script.js @@ -83,12 +83,10 @@ function testScriptMirror(f, file_name, file_lines, type, compilation_type, // Test the script mirror for different functions. -testScriptMirror(function(){}, 'mirror-script.js', 100, 2, 0); +testScriptMirror(function(){}, 'mirror-script.js', 98, 2, 0); testScriptMirror(Math.sin, 'native math.js', -1, 0, 0); testScriptMirror(eval('(function(){})'), null, 1, 2, 1, '(function(){})', 87); testScriptMirror(eval('(function(){\n })'), null, 2, 2, 1, '(function(){\n })', 88); -testScriptMirror(%CompileString('{"a":1,"b":2}', true), null, 1, 2, 2, '{"a":1,"b":2}'); -testScriptMirror(%CompileString('{"a":1,\n "b":2}', true), null, 2, 2, 2, '{"a":1,\n "b":2}'); // Test taking slices of source. var mirror = debug.MakeMirror(eval('(function(){\n 1;\n})')).script(); diff --git a/deps/v8/test/mjsunit/mjsunit.status b/deps/v8/test/mjsunit/mjsunit.status index 3c8cbdbfe93..820dca7cd5b 100644 --- a/deps/v8/test/mjsunit/mjsunit.status +++ b/deps/v8/test/mjsunit/mjsunit.status @@ -45,6 +45,10 @@ unicode-case-overoptimization: PASS, TIMEOUT if ($arch == arm) # Skip long running test in debug and allow it to timeout in release mode. regress/regress-524: (PASS || TIMEOUT), SKIP if $mode == debug +# Stack manipulations in LiveEdit are buggy - see bug 915 +debug-liveedit-check-stack: SKIP +debug-liveedit-patch-positions-replace: SKIP + [ $arch == arm ] # Slow tests which times out in debug mode. @@ -61,14 +65,9 @@ array-splice: PASS || TIMEOUT # Skip long running test in debug mode on ARM. string-indexof-2: PASS, SKIP if $mode == debug -# Stack manipulations in LiveEdit is implemented for ia32 only. -debug-liveedit-check-stack: SKIP [ $arch == mips ] -# Stack manipulations in LiveEdit is implemented for ia32 only. -debug-liveedit-check-stack: SKIP - # Skip all tests on MIPS. *: SKIP diff --git a/deps/v8/test/mjsunit/object-literal-conversions.js b/deps/v8/test/mjsunit/object-literal-conversions.js new file mode 100644 index 00000000000..8540d93082d --- /dev/null +++ b/deps/v8/test/mjsunit/object-literal-conversions.js @@ -0,0 +1,46 @@ +// Copyright 2010 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 that the various conversions between property names are correctly +// used when overwriting initializers. + +var test1 = { 13: 6, "13": 7 }; +var test2 = { 13: 7, "13.0": 6 }; +var test3 = { "13": 6, 13.0000000000000000: 7 }; +var test4 = { 13.213000: 6, "13.213": 7 }; + +assertEquals(7, test1[13]); +assertEquals(7, test2[13]); +assertEquals(7, test3[13]); +assertEquals(7, test4[13.213]); + +var test5 = { 13: function() {}, "13": 7 }; +var test6 = { 17.31: function() {}, "17.31": 7 }; + +assertEquals(7, test5[13]); +assertEquals(7, test6[17.31]); +
\ No newline at end of file diff --git a/deps/v8/test/mjsunit/object-literal-overwrite.js b/deps/v8/test/mjsunit/object-literal-overwrite.js new file mode 100644 index 00000000000..5c58a2ddb68 --- /dev/null +++ b/deps/v8/test/mjsunit/object-literal-overwrite.js @@ -0,0 +1,118 @@ +// Copyright 2010 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. + +// Check that constants and computed properties are overwriting each other +// correctly, i.e., the last initializer for any name is stored in the object. + + +// Tests for the full code generator (if active). + +var foo1 = { + bar: 6, + bar: 7 +}; + +var foo2 = { + bar: function(a){}, + bar: 7 +}; + +var foo3 = { + bar: function(a){}, + bar: function(b){}, + bar: 7 +}; + +var foo4 = { + bar: function(b){}, + bar: 7, + bar: function(){return 7}, +}; + +var foo5 = { + 13: function(a){}, + 13: 7 +} + +var foo6 = { + 14.31: function(a){}, + 14.31: 7 +} + +var foo7 = { + 15: 6, + 15: 7 +} + +assertEquals(7, foo1.bar); +assertEquals(7, foo2.bar); +assertEquals(7, foo3.bar); +assertEquals(7, foo4.bar()); +assertEquals(7, foo5[13]); +assertEquals(7, foo6[14.31]); +assertEquals(7, foo7[15]); + +// Test for the classic code generator. + +function fun(x) { + var inner = { j: function(x) { return x; }, j: 7 }; + return inner.j; +} + +assertEquals(7, fun(7) ); + +// Check that the initializers of computed properties are executed, even if +// no store instructions are generated for the literals. + +var glob1 = 0; + +var bar1 = { x: glob1++, x: glob1++, x: glob1++, x: 7}; + +assertEquals(3, glob1); + + +var glob2 = 0; + +function fun2() { + var r = { y: glob2++, y: glob2++, y: glob2++, y: 7}; + return r.y; +} + +var y = fun2(); +assertEquals(7, y); +assertEquals(3, glob2); + +var glob3 = 0; + +function fun3() { + var r = { 113: glob3++, 113: glob3++, 113: glob3++, 113: 7}; + return r[113]; +} + +var y = fun3(); +assertEquals(7, y); +assertEquals(3, glob3);
\ No newline at end of file diff --git a/deps/v8/test/mjsunit/string-externalize.js b/deps/v8/test/mjsunit/string-externalize.js index 5b1f91709ee..da897869c55 100644 --- a/deps/v8/test/mjsunit/string-externalize.js +++ b/deps/v8/test/mjsunit/string-externalize.js @@ -25,7 +25,7 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// Flags: --expose-externalize-string +// Flags: --expose-externalize-string --expose-gc var size = 1024; @@ -93,3 +93,7 @@ function test() { for (var i = 0; i < 10; i++) { test(); } + +// Clean up string to make Valgrind happy. +gc(); +gc(); diff --git a/deps/v8/test/mjsunit/string-replace-with-empty.js b/deps/v8/test/mjsunit/string-replace-with-empty.js index 0e1e70a1f6e..aa97f27ac28 100644 --- a/deps/v8/test/mjsunit/string-replace-with-empty.js +++ b/deps/v8/test/mjsunit/string-replace-with-empty.js @@ -25,33 +25,45 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// Flags: --expose-externalize-string +// Flags: --expose-externalize-string --expose-gc -assertEquals("0123", "aa0bb1cc2dd3".replace(/[a-z]/g, "")); -assertEquals("0123", "\u1234a0bb1cc2dd3".replace(/[\u1234a-z]/g, "")); +function test() { + assertEquals("0123", "aa0bb1cc2dd3".replace(/[a-z]/g, "")); + assertEquals("0123", "\u1234a0bb1cc2dd3".replace(/[\u1234a-z]/g, "")); -var expected = "0123"; -var cons = "a0b1c2d3"; -for (var i = 0; i < 5; i++) { - expected += expected; - cons += cons; -} -assertEquals(expected, cons.replace(/[a-z]/g, "")); -cons = "\u12340b1c2d3"; -for (var i = 0; i < 5; i++) { - cons += cons; -} -assertEquals(expected, cons.replace(/[\u1234a-z]/g, "")); + var expected = "0123"; + var cons = "a0b1c2d3"; + for (var i = 0; i < 5; i++) { + expected += expected; + cons += cons; + } + assertEquals(expected, cons.replace(/[a-z]/g, "")); + cons = "\u12340b1c2d3"; + for (var i = 0; i < 5; i++) { + cons += cons; + } + assertEquals(expected, cons.replace(/[\u1234a-z]/g, "")); -cons = "a0b1c2d3"; -for (var i = 0; i < 5; i++) { - cons += cons; -} -externalizeString(cons, true/* force two-byte */); -assertEquals(expected, cons.replace(/[a-z]/g, "")); -cons = "\u12340b1c2d3"; -for (var i = 0; i < 5; i++) { - cons += cons; + cons = "a0b1c2d3"; + for (var i = 0; i < 5; i++) { + cons += cons; + } + externalizeString(cons, true/* force two-byte */); + assertEquals(expected, cons.replace(/[a-z]/g, "")); + cons = "\u12340b1c2d3"; + for (var i = 0; i < 5; i++) { + cons += cons; + } + externalizeString(cons); + assertEquals(expected, cons.replace(/[\u1234a-z]/g, "")); } -externalizeString(cons); -assertEquals(expected, cons.replace(/[\u1234a-z]/g, "")); + +test(); + +// Clear the regexp cache to allow the GC to work. +"foo".replace(/foo/g, ""); + +// GC in order to free up things on the C side so we don't get +// a memory leak. This makes valgrind happy. +gc(); +gc(); diff --git a/deps/v8/tools/ll_prof.py b/deps/v8/tools/ll_prof.py index 563084ddfca..8390d4afe36 100755 --- a/deps/v8/tools/ll_prof.py +++ b/deps/v8/tools/ll_prof.py @@ -353,7 +353,7 @@ class CodeLogReader(object): r"code-info,([^,]+),(\d+)") _CODE_CREATE_RE = re.compile( - r"code-creation,([^,]+),(0x[a-f0-9]+),(\d+),\"([^\"]*)\"(?:,(\d+))?") + r"code-creation,([^,]+),(0x[a-f0-9]+),(\d+),\"(.*)\"(?:,(\d+))?") _CODE_MOVE_RE = re.compile( r"code-move,(0x[a-f0-9]+),(0x[a-f0-9]+)") @@ -910,7 +910,7 @@ if __name__ == "__main__": start = time.time() mmap_info = trace_reader.ReadMmap(header, offset) if mmap_info.filename == V8_GC_FAKE_MMAP: - log_reader.ReadUpToGC() + log_reader.ReadUpToGC(code_info) else: library_repo.Load(mmap_info, code_map, options) mmap_time += time.time() - start |