diff options
author | Ben Murdoch <benm@google.com> | 2010-10-22 12:50:53 +0100 |
---|---|---|
committer | Ben Murdoch <benm@google.com> | 2010-10-22 20:03:06 +0100 |
commit | f87a203d89e1bbb6708282e0b64dbd13d59b723d (patch) | |
tree | d7658572059125113d4052a87e2e2c1251419c64 /src | |
parent | 0d5e116f6aee03185f237311a943491bb079a768 (diff) | |
download | android_external_v8-f87a203d89e1bbb6708282e0b64dbd13d59b723d.tar.gz android_external_v8-f87a203d89e1bbb6708282e0b64dbd13d59b723d.tar.bz2 android_external_v8-f87a203d89e1bbb6708282e0b64dbd13d59b723d.zip |
Update V8 to r5675 as required by WebKit r70209
Change-Id: Ib10adb470d41ca8c109ead5fc893b880e18d489f
Diffstat (limited to 'src')
133 files changed, 3934 insertions, 4991 deletions
diff --git a/src/SConscript b/src/SConscript index 7fae8d4b..8995d482 100755 --- a/src/SConscript +++ b/src/SConscript @@ -42,6 +42,7 @@ SOURCES = { ast.cc bootstrapper.cc builtins.cc + cached-powers.cc checks.cc circular-queue.cc code-stubs.cc @@ -100,7 +101,9 @@ SOURCES = { serialize.cc snapshot-common.cc spaces.cc + string-search.cc string-stream.cc + strtod.cc stub-cache.cc token.cc top.cc @@ -113,7 +116,6 @@ SOURCES = { variables.cc version.cc virtual-frame.cc - vm-state.cc zone.cc """), 'arch:arm': Split(""" @@ -1,4 +1,4 @@ -// Copyright 2009 the V8 project authors. All rights reserved. +// 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: @@ -28,6 +28,7 @@ #include "v8.h" #include "api.h" + #include "arguments.h" #include "bootstrapper.h" #include "compiler.h" @@ -36,6 +37,7 @@ #include "global-handles.h" #include "heap-profiler.h" #include "messages.h" +#include "parser.h" #include "platform.h" #include "profile-generator-inl.h" #include "serialize.h" @@ -134,27 +136,27 @@ void i::V8::FatalProcessOutOfMemory(const char* location, bool take_snapshot) { heap_stats.new_space_size = &new_space_size; int new_space_capacity; heap_stats.new_space_capacity = &new_space_capacity; - int old_pointer_space_size; + intptr_t old_pointer_space_size; heap_stats.old_pointer_space_size = &old_pointer_space_size; - int old_pointer_space_capacity; + intptr_t old_pointer_space_capacity; heap_stats.old_pointer_space_capacity = &old_pointer_space_capacity; - int old_data_space_size; + intptr_t old_data_space_size; heap_stats.old_data_space_size = &old_data_space_size; - int old_data_space_capacity; + intptr_t old_data_space_capacity; heap_stats.old_data_space_capacity = &old_data_space_capacity; - int code_space_size; + intptr_t code_space_size; heap_stats.code_space_size = &code_space_size; - int code_space_capacity; + intptr_t code_space_capacity; heap_stats.code_space_capacity = &code_space_capacity; - int map_space_size; + intptr_t map_space_size; heap_stats.map_space_size = &map_space_size; - int map_space_capacity; + intptr_t map_space_capacity; heap_stats.map_space_capacity = &map_space_capacity; - int cell_space_size; + intptr_t cell_space_size; heap_stats.cell_space_size = &cell_space_size; - int cell_space_capacity; + intptr_t cell_space_capacity; heap_stats.cell_space_capacity = &cell_space_capacity; - int lo_space_size; + intptr_t lo_space_size; heap_stats.lo_space_size = &lo_space_size; int global_handle_count; heap_stats.global_handle_count = &global_handle_count; @@ -166,9 +168,9 @@ void i::V8::FatalProcessOutOfMemory(const char* location, bool take_snapshot) { heap_stats.near_death_global_handle_count = &near_death_global_handle_count; int destroyed_global_handle_count; heap_stats.destroyed_global_handle_count = &destroyed_global_handle_count; - int memory_allocator_size; + intptr_t memory_allocator_size; heap_stats.memory_allocator_size = &memory_allocator_size; - int memory_allocator_capacity; + intptr_t memory_allocator_capacity; heap_stats.memory_allocator_capacity = &memory_allocator_capacity; int objects_per_type[LAST_TYPE + 1] = {0}; heap_stats.objects_per_type = objects_per_type; @@ -1135,13 +1137,13 @@ void ObjectTemplate::SetInternalFieldCount(int value) { ScriptData* ScriptData::PreCompile(const char* input, int length) { unibrow::Utf8InputBuffer<> buf(input, length); - return i::PreParse(i::Handle<i::String>(), &buf, NULL); + return i::Parser::PreParse(i::Handle<i::String>(), &buf, NULL); } ScriptData* ScriptData::PreCompile(v8::Handle<String> source) { i::Handle<i::String> str = Utils::OpenHandle(*source); - return i::PreParse(str, NULL, NULL); + return i::Parser::PreParse(str, NULL, NULL); } @@ -1677,6 +1679,21 @@ Local<String> StackFrame::GetScriptName() const { } +Local<String> StackFrame::GetScriptNameOrSourceURL() const { + if (IsDeadCheck("v8::StackFrame::GetScriptNameOrSourceURL()")) { + return Local<String>(); + } + ENTER_V8; + HandleScope scope; + i::Handle<i::JSObject> self = Utils::OpenHandle(this); + i::Handle<i::Object> name = GetProperty(self, "scriptNameOrSourceURL"); + if (!name->IsString()) { + return Local<String>(); + } + return scope.Close(Local<String>::Cast(Utils::ToLocal(name))); +} + + Local<String> StackFrame::GetFunctionName() const { if (IsDeadCheck("v8::StackFrame::GetFunctionName()")) return Local<String>(); ENTER_V8; @@ -1989,6 +2006,15 @@ void v8::Date::CheckCast(v8::Value* that) { } +void v8::RegExp::CheckCast(v8::Value* that) { + if (IsDeadCheck("v8::RegExp::Cast()")) return; + i::Handle<i::Object> obj = Utils::OpenHandle(that); + ApiCheck(obj->IsJSRegExp(), + "v8::RegExp::Cast()", + "Could not convert to regular expression"); +} + + bool Value::BooleanValue() const { if (IsDeadCheck("v8::Value::BooleanValue()")) return false; LOG_API("BooleanValue"); @@ -3710,6 +3736,57 @@ double v8::Date::NumberValue() const { } +static i::Handle<i::String> RegExpFlagsToString(RegExp::Flags flags) { + char flags_buf[3]; + int num_flags = 0; + if ((flags & RegExp::kGlobal) != 0) flags_buf[num_flags++] = 'g'; + if ((flags & RegExp::kMultiline) != 0) flags_buf[num_flags++] = 'm'; + if ((flags & RegExp::kIgnoreCase) != 0) flags_buf[num_flags++] = 'i'; + ASSERT(num_flags <= static_cast<int>(ARRAY_SIZE(flags_buf))); + return i::Factory::LookupSymbol( + i::Vector<const char>(flags_buf, num_flags)); +} + + +Local<v8::RegExp> v8::RegExp::New(Handle<String> pattern, + Flags flags) { + EnsureInitialized("v8::RegExp::New()"); + LOG_API("RegExp::New"); + ENTER_V8; + EXCEPTION_PREAMBLE(); + i::Handle<i::JSRegExp> obj = i::Execution::NewJSRegExp( + Utils::OpenHandle(*pattern), + RegExpFlagsToString(flags), + &has_pending_exception); + EXCEPTION_BAILOUT_CHECK(Local<v8::RegExp>()); + return Utils::ToLocal(i::Handle<i::JSRegExp>::cast(obj)); +} + + +Local<v8::String> v8::RegExp::GetSource() const { + if (IsDeadCheck("v8::RegExp::GetSource()")) return Local<v8::String>(); + i::Handle<i::JSRegExp> obj = Utils::OpenHandle(this); + return Utils::ToLocal(i::Handle<i::String>(obj->Pattern())); +} + + +// Assert that the static flags cast in GetFlags is valid. +#define REGEXP_FLAG_ASSERT_EQ(api_flag, internal_flag) \ + STATIC_ASSERT(static_cast<int>(v8::RegExp::api_flag) == \ + static_cast<int>(i::JSRegExp::internal_flag)) +REGEXP_FLAG_ASSERT_EQ(kNone, NONE); +REGEXP_FLAG_ASSERT_EQ(kGlobal, GLOBAL); +REGEXP_FLAG_ASSERT_EQ(kIgnoreCase, IGNORE_CASE); +REGEXP_FLAG_ASSERT_EQ(kMultiline, MULTILINE); +#undef REGEXP_FLAG_ASSERT_EQ + +v8::RegExp::Flags v8::RegExp::GetFlags() const { + if (IsDeadCheck("v8::RegExp::GetFlags()")) return v8::RegExp::kNone; + i::Handle<i::JSRegExp> obj = Utils::OpenHandle(this); + return static_cast<RegExp::Flags>(obj->GetFlags().value()); +} + + Local<v8::Array> v8::Array::New(int length) { EnsureInitialized("v8::Array::New()"); LOG_API("Array::New"); @@ -4265,6 +4342,11 @@ void Debug::DebugBreak() { } +void Debug::CancelDebugBreak() { + i::StackGuard::Continue(i::DEBUGBREAK); +} + + void Debug::DebugBreakForCommand(ClientData* data) { if (!i::V8::IsRunning()) return; i::Debugger::EnqueueDebugCommand(data); @@ -174,6 +174,8 @@ class Utils { v8::internal::Handle<v8::internal::JSFunction> obj); static inline Local<String> ToLocal( v8::internal::Handle<v8::internal::String> obj); + static inline Local<RegExp> ToLocal( + v8::internal::Handle<v8::internal::JSRegExp> obj); static inline Local<Object> ToLocal( v8::internal::Handle<v8::internal::JSObject> obj); static inline Local<Array> ToLocal( @@ -209,6 +211,8 @@ class Utils { OpenHandle(const ObjectTemplate* that); static inline v8::internal::Handle<v8::internal::Object> OpenHandle(const Data* data); + static inline v8::internal::Handle<v8::internal::JSRegExp> + OpenHandle(const RegExp* data); static inline v8::internal::Handle<v8::internal::JSObject> OpenHandle(const v8::Object* data); static inline v8::internal::Handle<v8::internal::JSArray> @@ -265,6 +269,7 @@ MAKE_TO_LOCAL(ToLocal, Context, Context) MAKE_TO_LOCAL(ToLocal, Object, Value) MAKE_TO_LOCAL(ToLocal, JSFunction, Function) MAKE_TO_LOCAL(ToLocal, String, String) +MAKE_TO_LOCAL(ToLocal, JSRegExp, RegExp) MAKE_TO_LOCAL(ToLocal, JSObject, Object) MAKE_TO_LOCAL(ToLocal, JSArray, Array) MAKE_TO_LOCAL(ToLocal, Proxy, External) @@ -297,6 +302,7 @@ MAKE_OPEN_HANDLE(ObjectTemplate, ObjectTemplateInfo) MAKE_OPEN_HANDLE(Signature, SignatureInfo) MAKE_OPEN_HANDLE(TypeSwitch, TypeSwitchInfo) MAKE_OPEN_HANDLE(Data, Object) +MAKE_OPEN_HANDLE(RegExp, JSRegExp) MAKE_OPEN_HANDLE(Object, JSObject) MAKE_OPEN_HANDLE(Array, JSArray) MAKE_OPEN_HANDLE(String, String) diff --git a/src/arm/code-stubs-arm.cc b/src/arm/code-stubs-arm.cc index 8f801cf9..b3b0766a 100644 --- a/src/arm/code-stubs-arm.cc +++ b/src/arm/code-stubs-arm.cc @@ -935,11 +935,8 @@ void CompareStub::Generate(MacroAssembler* masm) { __ orr(r2, r1, r0); __ tst(r2, Operand(kSmiTagMask)); __ b(ne, ¬_two_smis); - __ sub(r0, r1, r0); - __ b(vc, &smi_done); - // Correct the sign in case of overflow. - __ rsb(r0, r0, Operand(0, RelocInfo::NONE)); - __ bind(&smi_done); + __ mov(r1, Operand(r1, ASR, 1)); + __ sub(r0, r1, Operand(r0, ASR, 1)); __ Ret(); __ bind(¬_two_smis); } else if (FLAG_debug_code) { @@ -2300,13 +2297,7 @@ Runtime::FunctionId TranscendentalCacheStub::RuntimeFunction() { void StackCheckStub::Generate(MacroAssembler* masm) { - // Do tail-call to runtime routine. Runtime routines expect at least one - // argument, so give it a Smi. - __ mov(r0, Operand(Smi::FromInt(0))); - __ push(r0); - __ TailCallRuntime(Runtime::kStackGuard, 1, 1); - - __ Ret(); + __ TailCallRuntime(Runtime::kStackGuard, 0, 1); } diff --git a/src/arm/codegen-arm.cc b/src/arm/codegen-arm.cc index d273e759..684106c3 100644 --- a/src/arm/codegen-arm.cc +++ b/src/arm/codegen-arm.cc @@ -175,7 +175,7 @@ void CodeGenerator::Generate(CompilationInfo* info) { // Adjust for function-level loop nesting. ASSERT_EQ(0, loop_nesting_); - loop_nesting_ = info->loop_nesting(); + loop_nesting_ = info->is_in_loop() ? 1 : 0; { CodeGenState state(this); @@ -339,7 +339,7 @@ void CodeGenerator::Generate(CompilationInfo* info) { } // Adjust for function-level loop nesting. - ASSERT(loop_nesting_ == info->loop_nesting()); + ASSERT(loop_nesting_ == info->is_in_loop()? 1 : 0); loop_nesting_ = 0; // Code generation state must be reset. @@ -3132,9 +3132,9 @@ void CodeGenerator::VisitFunctionLiteral(FunctionLiteral* node) { // Build the function info and instantiate it. Handle<SharedFunctionInfo> function_info = - Compiler::BuildFunctionInfo(node, script(), this); - // Check for stack-overflow exception. - if (HasStackOverflow()) { + Compiler::BuildFunctionInfo(node, script()); + if (function_info.is_null()) { + SetStackOverflow(); ASSERT(frame_->height() == original_height); return; } diff --git a/src/arm/codegen-arm.h b/src/arm/codegen-arm.h index 1483c0b5..e6fd6071 100644 --- a/src/arm/codegen-arm.h +++ b/src/arm/codegen-arm.h @@ -207,9 +207,7 @@ enum NopMarkerTypes { class CodeGenerator: public AstVisitor { public: - // Takes a function literal, generates code for it. This function should only - // be called by compiler.cc. - static Handle<Code> MakeCode(CompilationInfo* info); + static bool MakeCode(CompilationInfo* info); // Printing of AST, etc. as requested by flags. static void MakeCodePrologue(CompilationInfo* info); @@ -449,9 +447,6 @@ class CodeGenerator: public AstVisitor { void Branch(bool if_true, JumpTarget* target); void CheckStack(); - static InlineFunctionGenerator FindInlineFunctionGenerator( - Runtime::FunctionId function_id); - bool CheckForInlineRuntimeCall(CallRuntime* node); static Handle<Code> ComputeLazyCompile(int argc); diff --git a/src/arm/full-codegen-arm.cc b/src/arm/full-codegen-arm.cc index 9fc0c096..2855ca4f 100644 --- a/src/arm/full-codegen-arm.cc +++ b/src/arm/full-codegen-arm.cc @@ -62,6 +62,13 @@ void FullCodeGenerator::Generate(CompilationInfo* info) { SetFunctionPosition(function()); Comment cmnt(masm_, "[ function compiled by full code generator"); +#ifdef DEBUG + if (strlen(FLAG_stop_at) > 0 && + info->function()->name()->IsEqualTo(CStrVector(FLAG_stop_at))) { + __ stop("stop-at"); + } +#endif + int locals_count = scope()->num_stack_slots(); __ Push(lr, fp, cp, r1); diff --git a/src/arm/ic-arm.cc b/src/arm/ic-arm.cc index d5a700cd..7f83d14a 100644 --- a/src/arm/ic-arm.cc +++ b/src/arm/ic-arm.cc @@ -969,7 +969,8 @@ bool LoadIC::PatchInlinedLoad(Address address, Object* map, int offset) { bool LoadIC::PatchInlinedContextualLoad(Address address, Object* map, - Object* cell) { + Object* cell, + bool is_dont_delete) { // TODO(<bug#>): implement this. return false; } @@ -1584,8 +1585,9 @@ void KeyedLoadIC::GenerateIndexedInterceptor(MacroAssembler* masm) { // Check that the receiver isn't a smi. __ BranchOnSmi(r1, &slow); - // Check that the key is a smi. - __ BranchOnNotSmi(r0, &slow); + // Check that the key is an array index, that is Uint32. + __ tst(r0, Operand(kSmiTagMask | kSmiSignMask)); + __ b(ne, &slow); // Get the map of the receiver. __ ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset)); diff --git a/src/arm/regexp-macro-assembler-arm.cc b/src/arm/regexp-macro-assembler-arm.cc index 8f45886d..37bb1f0a 100644 --- a/src/arm/regexp-macro-assembler-arm.cc +++ b/src/arm/regexp-macro-assembler-arm.cc @@ -142,7 +142,6 @@ int RegExpMacroAssemblerARM::stack_limit_slack() { void RegExpMacroAssemblerARM::AdvanceCurrentPosition(int by) { if (by != 0) { - Label inside_string; __ add(current_input_offset(), current_input_offset(), Operand(by * char_size())); } @@ -927,6 +926,19 @@ void RegExpMacroAssemblerARM::ReadStackPointerFromRegister(int reg) { } +void RegExpMacroAssemblerARM::SetCurrentPositionFromEnd(int by) { + Label after_position; + __ cmp(current_input_offset(), Operand(-by * char_size())); + __ b(ge, &after_position); + __ mov(current_input_offset(), Operand(-by * char_size())); + // On RegExp code entry (where this operation is used), the character before + // the current position is expected to be already loaded. + // We have advanced the position, so it's safe to read backwards. + LoadCurrentCharacterUnchecked(-1, 1); + __ bind(&after_position); +} + + void RegExpMacroAssemblerARM::SetRegister(int register_index, int to) { ASSERT(register_index >= num_saved_registers_); // Reserved for positions! __ mov(r0, Operand(to)); diff --git a/src/arm/regexp-macro-assembler-arm.h b/src/arm/regexp-macro-assembler-arm.h index 93a74d7c..4e09f671 100644 --- a/src/arm/regexp-macro-assembler-arm.h +++ b/src/arm/regexp-macro-assembler-arm.h @@ -100,6 +100,7 @@ class RegExpMacroAssemblerARM: public NativeRegExpMacroAssembler { StackCheckFlag check_stack_limit); virtual void ReadCurrentPositionFromRegister(int reg); virtual void ReadStackPointerFromRegister(int reg); + virtual void SetCurrentPositionFromEnd(int by); virtual void SetRegister(int register_index, int to); virtual void Succeed(); virtual void WriteCurrentPositionToRegister(int reg, int cp_offset); diff --git a/src/arm/simulator-arm.cc b/src/arm/simulator-arm.cc index 64262b2b..84d9d01d 100644 --- a/src/arm/simulator-arm.cc +++ b/src/arm/simulator-arm.cc @@ -37,7 +37,7 @@ #include "arm/constants-arm.h" #include "arm/simulator-arm.h" -#if !defined(__arm__) +#if !defined(__arm__) || defined(USE_SIMULATOR) // Only build the simulator if not compiling for real ARM hardware. namespace assembler { @@ -294,7 +294,7 @@ void Debugger::Debug() { } else if (GetVFPSingleValue(arg1, &svalue)) { PrintF("%s: %f \n", arg1, svalue); } else if (GetVFPDoubleValue(arg1, &dvalue)) { - PrintF("%s: %lf \n", arg1, dvalue); + PrintF("%s: %f \n", arg1, dvalue); } else { PrintF("%s unrecognized\n", arg1); } @@ -349,7 +349,8 @@ void Debugger::Debug() { end = cur + words; while (cur < end) { - PrintF(" 0x%08x: 0x%08x %10d\n", cur, *cur, *cur); + PrintF(" 0x%08x: 0x%08x %10d\n", + reinterpret_cast<intptr_t>(cur), *cur, *cur); cur++; } } else if (strcmp(cmd, "disasm") == 0) { @@ -382,7 +383,8 @@ void Debugger::Debug() { while (cur < end) { dasm.InstructionDecode(buffer, cur); - PrintF(" 0x%08x %s\n", cur, buffer.start()); + PrintF(" 0x%08x %s\n", + reinterpret_cast<intptr_t>(cur), buffer.start()); cur += Instr::kInstrSize; } } else if (strcmp(cmd, "gdb") == 0) { @@ -1061,7 +1063,7 @@ uintptr_t Simulator::StackLimit() const { // Unsupported instructions use Format to print an error and stop execution. void Simulator::Format(Instr* instr, const char* format) { PrintF("Simulator found unsupported instruction:\n 0x%08x: %s\n", - instr, format); + reinterpret_cast<intptr_t>(instr), format); UNIMPLEMENTED(); } @@ -2650,7 +2652,7 @@ void Simulator::InstructionDecode(Instr* instr) { v8::internal::EmbeddedVector<char, 256> buffer; dasm.InstructionDecode(buffer, reinterpret_cast<byte*>(instr)); - PrintF(" 0x%08x %s\n", instr, buffer.start()); + PrintF(" 0x%08x %s\n", reinterpret_cast<intptr_t>(instr), buffer.start()); } if (instr->ConditionField() == special_condition) { DecodeUnconditional(instr); @@ -2838,6 +2840,6 @@ uintptr_t Simulator::PopAddress() { } } // namespace assembler::arm -#endif // __arm__ +#endif // !__arm__ || USE_SIMULATOR #endif // V8_TARGET_ARCH_ARM diff --git a/src/arm/simulator-arm.h b/src/arm/simulator-arm.h index fee296e4..d4c8250b 100644 --- a/src/arm/simulator-arm.h +++ b/src/arm/simulator-arm.h @@ -38,7 +38,7 @@ #include "allocation.h" -#if defined(__arm__) +#if defined(__arm__) && !defined(USE_SIMULATOR) // When running without a simulator we call the entry directly. #define CALL_GENERATED_CODE(entry, p0, p1, p2, p3, p4) \ @@ -70,7 +70,7 @@ class SimulatorStack : public v8::internal::AllStatic { reinterpret_cast<TryCatch*>(try_catch_address) -#else // defined(__arm__) +#else // !defined(__arm__) || defined(USE_SIMULATOR) // When running with the simulator transition into simulated execution at this // point. @@ -356,6 +356,6 @@ class SimulatorStack : public v8::internal::AllStatic { }; -#endif // defined(__arm__) +#endif // !defined(__arm__) || defined(USE_SIMULATOR) #endif // V8_ARM_SIMULATOR_ARM_H_ diff --git a/src/arm/stub-cache-arm.cc b/src/arm/stub-cache-arm.cc index 659f29c3..97f94952 100644 --- a/src/arm/stub-cache-arm.cc +++ b/src/arm/stub-cache-arm.cc @@ -1643,6 +1643,108 @@ Object* CallStubCompiler::CompileMathFloorCall(Object* object, } +Object* CallStubCompiler::CompileMathAbsCall(Object* object, + JSObject* holder, + JSGlobalPropertyCell* cell, + JSFunction* function, + String* name) { + // ----------- S t a t e ------------- + // -- r2 : function name + // -- lr : return address + // -- sp[(argc - n - 1) * 4] : arg[n] (zero-based) + // -- ... + // -- sp[argc * 4] : receiver + // ----------------------------------- + + const int argc = arguments().immediate(); + + // If the object is not a JSObject or we got an unexpected number of + // arguments, bail out to the regular call. + if (!object->IsJSObject() || argc != 1) return Heap::undefined_value(); + + Label miss; + GenerateNameCheck(name, &miss); + + if (cell == NULL) { + __ ldr(r1, MemOperand(sp, 1 * kPointerSize)); + + STATIC_ASSERT(kSmiTag == 0); + __ tst(r1, Operand(kSmiTagMask)); + __ b(eq, &miss); + + CheckPrototypes(JSObject::cast(object), r1, holder, r0, r3, r4, name, + &miss); + } else { + ASSERT(cell->value() == function); + GenerateGlobalReceiverCheck(JSObject::cast(object), holder, name, &miss); + GenerateLoadFunctionFromCell(cell, function, &miss); + } + + // Load the (only) argument into r0. + __ ldr(r0, MemOperand(sp, 0 * kPointerSize)); + + // Check if the argument is a smi. + Label not_smi; + STATIC_ASSERT(kSmiTag == 0); + __ BranchOnNotSmi(r0, ¬_smi); + + // Do bitwise not or do nothing depending on the sign of the + // argument. + __ eor(r1, r0, Operand(r0, ASR, kBitsPerInt - 1)); + + // Add 1 or do nothing depending on the sign of the argument. + __ sub(r0, r1, Operand(r0, ASR, kBitsPerInt - 1), SetCC); + + // If the result is still negative, go to the slow case. + // This only happens for the most negative smi. + Label slow; + __ b(mi, &slow); + + // Smi case done. + __ Drop(argc + 1); + __ Ret(); + + // Check if the argument is a heap number and load its exponent and + // sign. + __ bind(¬_smi); + __ CheckMap(r0, r1, Heap::kHeapNumberMapRootIndex, &slow, true); + __ ldr(r1, FieldMemOperand(r0, HeapNumber::kExponentOffset)); + + // Check the sign of the argument. If the argument is positive, + // just return it. + Label negative_sign; + __ tst(r1, Operand(HeapNumber::kSignMask)); + __ b(ne, &negative_sign); + __ Drop(argc + 1); + __ Ret(); + + // If the argument is negative, clear the sign, and return a new + // number. + __ bind(&negative_sign); + __ eor(r1, r1, Operand(HeapNumber::kSignMask)); + __ ldr(r3, FieldMemOperand(r0, HeapNumber::kMantissaOffset)); + __ LoadRoot(r6, Heap::kHeapNumberMapRootIndex); + __ AllocateHeapNumber(r0, r4, r5, r6, &slow); + __ str(r1, FieldMemOperand(r0, HeapNumber::kExponentOffset)); + __ str(r3, FieldMemOperand(r0, HeapNumber::kMantissaOffset)); + __ Drop(argc + 1); + __ Ret(); + + // Tail call the full function. We do not have to patch the receiver + // because the function makes no use of it. + __ bind(&slow); + __ InvokeFunction(function, arguments(), JUMP_FUNCTION); + + __ bind(&miss); + // r2: function name. + Object* obj = GenerateMissBranch(); + if (obj->IsFailure()) return obj; + + // Return the generated code. + return (cell == NULL) ? GetCode(function) : GetCode(NORMAL, name); +} + + Object* CallStubCompiler::CompileCallConstant(Object* object, JSObject* holder, JSFunction* function, diff --git a/src/assembler.cc b/src/assembler.cc index 6a46f615..b6efdb97 100644 --- a/src/assembler.cc +++ b/src/assembler.cc @@ -465,7 +465,7 @@ const char* RelocInfo::RelocModeName(RelocInfo::Mode rmode) { void RelocInfo::Print() { PrintF("%p %s", pc_, RelocModeName(rmode_)); if (IsComment(rmode_)) { - PrintF(" (%s)", data_); + PrintF(" (%s)", reinterpret_cast<char*>(data_)); } else if (rmode_ == EMBEDDED_OBJECT) { PrintF(" ("); target_object()->ShortPrint(); @@ -479,7 +479,7 @@ void RelocInfo::Print() { Code* code = Code::GetCodeFromTargetAddress(target_address()); PrintF(" (%s) (%p)", Code::Kind2String(code->kind()), target_address()); } else if (IsPosition(rmode_)) { - PrintF(" (%d)", data()); + PrintF(" (%" V8_PTR_PREFIX "d)", data()); } PrintF("\n"); @@ -398,39 +398,70 @@ Interval RegExpQuantifier::CaptureRegisters() { } -bool RegExpAssertion::IsAnchored() { +bool RegExpAssertion::IsAnchoredAtStart() { return type() == RegExpAssertion::START_OF_INPUT; } -bool RegExpAlternative::IsAnchored() { +bool RegExpAssertion::IsAnchoredAtEnd() { + return type() == RegExpAssertion::END_OF_INPUT; +} + + +bool RegExpAlternative::IsAnchoredAtStart() { ZoneList<RegExpTree*>* nodes = this->nodes(); for (int i = 0; i < nodes->length(); i++) { RegExpTree* node = nodes->at(i); - if (node->IsAnchored()) { return true; } + if (node->IsAnchoredAtStart()) { return true; } + if (node->max_match() > 0) { return false; } + } + return false; +} + + +bool RegExpAlternative::IsAnchoredAtEnd() { + ZoneList<RegExpTree*>* nodes = this->nodes(); + for (int i = nodes->length() - 1; i >= 0; i--) { + RegExpTree* node = nodes->at(i); + if (node->IsAnchoredAtEnd()) { return true; } if (node->max_match() > 0) { return false; } } return false; } -bool RegExpDisjunction::IsAnchored() { +bool RegExpDisjunction::IsAnchoredAtStart() { ZoneList<RegExpTree*>* alternatives = this->alternatives(); for (int i = 0; i < alternatives->length(); i++) { - if (!alternatives->at(i)->IsAnchored()) + if (!alternatives->at(i)->IsAnchoredAtStart()) return false; } return true; } -bool RegExpLookahead::IsAnchored() { - return is_positive() && body()->IsAnchored(); +bool RegExpDisjunction::IsAnchoredAtEnd() { + ZoneList<RegExpTree*>* alternatives = this->alternatives(); + for (int i = 0; i < alternatives->length(); i++) { + if (!alternatives->at(i)->IsAnchoredAtEnd()) + return false; + } + return true; +} + + +bool RegExpLookahead::IsAnchoredAtStart() { + return is_positive() && body()->IsAnchoredAtStart(); +} + + +bool RegExpCapture::IsAnchoredAtStart() { + return body()->IsAnchoredAtStart(); } -bool RegExpCapture::IsAnchored() { - return body()->IsAnchored(); +bool RegExpCapture::IsAnchoredAtEnd() { + return body()->IsAnchoredAtEnd(); } @@ -118,35 +118,38 @@ typedef ZoneList<Handle<String> > ZoneStringList; typedef ZoneList<Handle<Object> > ZoneObjectList; +#define DECLARE_NODE_TYPE(type) \ + virtual void Accept(AstVisitor* v); \ + virtual AstNode::Type node_type() const { return AstNode::k##type; } \ + virtual type* As##type() { return this; } + + class AstNode: public ZoneObject { public: +#define DECLARE_TYPE_ENUM(type) k##type, + enum Type { + AST_NODE_LIST(DECLARE_TYPE_ENUM) + kInvalid = -1 + }; +#undef DECLARE_TYPE_ENUM + virtual ~AstNode() { } + virtual void Accept(AstVisitor* v) = 0; + virtual Type node_type() const { return kInvalid; } + + // Type testing & conversion functions overridden by concrete subclasses. +#define DECLARE_NODE_FUNCTIONS(type) \ + virtual type* As##type() { return NULL; } + AST_NODE_LIST(DECLARE_NODE_FUNCTIONS) +#undef DECLARE_NODE_FUNCTIONS - // Type testing & conversion. virtual Statement* AsStatement() { return NULL; } - virtual Block* AsBlock() { return NULL; } - virtual ExpressionStatement* AsExpressionStatement() { return NULL; } - virtual EmptyStatement* AsEmptyStatement() { return NULL; } virtual Expression* AsExpression() { return NULL; } - virtual Literal* AsLiteral() { return NULL; } - virtual Slot* AsSlot() { return NULL; } - virtual VariableProxy* AsVariableProxy() { return NULL; } - virtual Property* AsProperty() { return NULL; } - virtual Call* AsCall() { return NULL; } virtual TargetCollector* AsTargetCollector() { return NULL; } virtual BreakableStatement* AsBreakableStatement() { return NULL; } virtual IterationStatement* AsIterationStatement() { return NULL; } - virtual ForStatement* AsForStatement() { return NULL; } - virtual UnaryOperation* AsUnaryOperation() { return NULL; } - virtual CountOperation* AsCountOperation() { return NULL; } - virtual BinaryOperation* AsBinaryOperation() { return NULL; } - virtual Assignment* AsAssignment() { return NULL; } - virtual FunctionLiteral* AsFunctionLiteral() { return NULL; } virtual MaterializedLiteral* AsMaterializedLiteral() { return NULL; } - virtual ObjectLiteral* AsObjectLiteral() { return NULL; } - virtual ArrayLiteral* AsArrayLiteral() { return NULL; } - virtual CompareOperation* AsCompareOperation() { return NULL; } }; @@ -155,7 +158,6 @@ class Statement: public AstNode { Statement() : statement_pos_(RelocInfo::kNoPosition) {} virtual Statement* AsStatement() { return this; } - virtual ReturnStatement* AsReturnStatement() { return NULL; } virtual Assignment* StatementAsSimpleAssignment() { return NULL; } virtual CountOperation* StatementAsCountOperation() { return NULL; } @@ -313,9 +315,7 @@ class Block: public BreakableStatement { public: inline Block(ZoneStringList* labels, int capacity, bool is_initializer_block); - virtual void Accept(AstVisitor* v); - - virtual Block* AsBlock() { return this; } + DECLARE_NODE_TYPE(Block) virtual Assignment* StatementAsSimpleAssignment() { if (statements_.length() != 1) return NULL; @@ -349,7 +349,7 @@ class Declaration: public AstNode { ASSERT(fun == NULL || mode == Variable::VAR); } - virtual void Accept(AstVisitor* v); + DECLARE_NODE_TYPE(Declaration) VariableProxy* proxy() const { return proxy_; } Variable::Mode mode() const { return mode_; } @@ -390,13 +390,13 @@ class DoWhileStatement: public IterationStatement { public: explicit inline DoWhileStatement(ZoneStringList* labels); + DECLARE_NODE_TYPE(DoWhileStatement) + void Initialize(Expression* cond, Statement* body) { IterationStatement::Initialize(body); cond_ = cond; } - virtual void Accept(AstVisitor* v); - Expression* cond() const { return cond_; } // Position where condition expression starts. We need it to make @@ -414,13 +414,13 @@ class WhileStatement: public IterationStatement { public: explicit WhileStatement(ZoneStringList* labels); + DECLARE_NODE_TYPE(WhileStatement) + void Initialize(Expression* cond, Statement* body) { IterationStatement::Initialize(body); cond_ = cond; } - virtual void Accept(AstVisitor* v); - Expression* cond() const { return cond_; } bool may_have_function_literal() const { return may_have_function_literal_; @@ -440,7 +440,7 @@ class ForStatement: public IterationStatement { public: explicit inline ForStatement(ZoneStringList* labels); - virtual ForStatement* AsForStatement() { return this; } + DECLARE_NODE_TYPE(ForStatement) void Initialize(Statement* init, Expression* cond, @@ -452,8 +452,6 @@ class ForStatement: public IterationStatement { next_ = next; } - virtual void Accept(AstVisitor* v); - Statement* init() const { return init_; } void set_init(Statement* stmt) { init_ = stmt; } Expression* cond() const { return cond_; } @@ -486,14 +484,14 @@ class ForInStatement: public IterationStatement { public: explicit inline ForInStatement(ZoneStringList* labels); + DECLARE_NODE_TYPE(ForInStatement) + void Initialize(Expression* each, Expression* enumerable, Statement* body) { IterationStatement::Initialize(body); each_ = each; enumerable_ = enumerable; } - virtual void Accept(AstVisitor* v); - Expression* each() const { return each_; } Expression* enumerable() const { return enumerable_; } @@ -508,10 +506,7 @@ class ExpressionStatement: public Statement { explicit ExpressionStatement(Expression* expression) : expression_(expression) { } - virtual void Accept(AstVisitor* v); - - // Type testing & conversion. - virtual ExpressionStatement* AsExpressionStatement() { return this; } + DECLARE_NODE_TYPE(ExpressionStatement) virtual Assignment* StatementAsSimpleAssignment(); virtual CountOperation* StatementAsCountOperation(); @@ -529,7 +524,7 @@ class ContinueStatement: public Statement { explicit ContinueStatement(IterationStatement* target) : target_(target) { } - virtual void Accept(AstVisitor* v); + DECLARE_NODE_TYPE(ContinueStatement) IterationStatement* target() const { return target_; } @@ -543,7 +538,7 @@ class BreakStatement: public Statement { explicit BreakStatement(BreakableStatement* target) : target_(target) { } - virtual void Accept(AstVisitor* v); + DECLARE_NODE_TYPE(BreakStatement) BreakableStatement* target() const { return target_; } @@ -557,10 +552,7 @@ class ReturnStatement: public Statement { explicit ReturnStatement(Expression* expression) : expression_(expression) { } - virtual void Accept(AstVisitor* v); - - // Type testing & conversion. - virtual ReturnStatement* AsReturnStatement() { return this; } + DECLARE_NODE_TYPE(ReturnStatement) Expression* expression() { return expression_; } @@ -574,7 +566,7 @@ class WithEnterStatement: public Statement { explicit WithEnterStatement(Expression* expression, bool is_catch_block) : expression_(expression), is_catch_block_(is_catch_block) { } - virtual void Accept(AstVisitor* v); + DECLARE_NODE_TYPE(WithEnterStatement) Expression* expression() const { return expression_; } @@ -590,7 +582,7 @@ class WithExitStatement: public Statement { public: WithExitStatement() { } - virtual void Accept(AstVisitor* v); + DECLARE_NODE_TYPE(WithExitStatement) }; @@ -617,13 +609,13 @@ class SwitchStatement: public BreakableStatement { public: explicit inline SwitchStatement(ZoneStringList* labels); + DECLARE_NODE_TYPE(SwitchStatement) + void Initialize(Expression* tag, ZoneList<CaseClause*>* cases) { tag_ = tag; cases_ = cases; } - virtual void Accept(AstVisitor* v); - Expression* tag() const { return tag_; } ZoneList<CaseClause*>* cases() const { return cases_; } @@ -647,7 +639,7 @@ class IfStatement: public Statement { then_statement_(then_statement), else_statement_(else_statement) { } - virtual void Accept(AstVisitor* v); + DECLARE_NODE_TYPE(IfStatement) bool HasThenStatement() const { return !then_statement()->IsEmpty(); } bool HasElseStatement() const { return !else_statement()->IsEmpty(); } @@ -717,7 +709,7 @@ class TryCatchStatement: public TryStatement { catch_block_(catch_block) { } - virtual void Accept(AstVisitor* v); + DECLARE_NODE_TYPE(TryCatchStatement) VariableProxy* catch_var() const { return catch_var_; } Block* catch_block() const { return catch_block_; } @@ -734,7 +726,7 @@ class TryFinallyStatement: public TryStatement { : TryStatement(try_block), finally_block_(finally_block) { } - virtual void Accept(AstVisitor* v); + DECLARE_NODE_TYPE(TryFinallyStatement) Block* finally_block() const { return finally_block_; } @@ -745,18 +737,13 @@ class TryFinallyStatement: public TryStatement { class DebuggerStatement: public Statement { public: - virtual void Accept(AstVisitor* v); + DECLARE_NODE_TYPE(DebuggerStatement) }; class EmptyStatement: public Statement { public: - EmptyStatement() {} - - virtual void Accept(AstVisitor* v); - - // Type testing & conversion. - virtual EmptyStatement* AsEmptyStatement() { return this; } + DECLARE_NODE_TYPE(EmptyStatement) }; @@ -764,13 +751,11 @@ class Literal: public Expression { public: explicit Literal(Handle<Object> handle) : handle_(handle) { } - virtual void Accept(AstVisitor* v); + DECLARE_NODE_TYPE(Literal) + virtual bool IsTrivial() { return true; } virtual bool IsSmiLiteral() { return handle_->IsSmi(); } - // Type testing & conversion. - virtual Literal* AsLiteral() { return this; } - // Check if this literal is identical to the other literal. bool IsIdenticalTo(const Literal* other) const { return handle_.is_identical_to(other->handle_); @@ -864,8 +849,7 @@ class ObjectLiteral: public MaterializedLiteral { properties_(properties), fast_elements_(fast_elements) {} - virtual ObjectLiteral* AsObjectLiteral() { return this; } - virtual void Accept(AstVisitor* v); + DECLARE_NODE_TYPE(ObjectLiteral) Handle<FixedArray> constant_properties() const { return constant_properties_; @@ -891,7 +875,7 @@ class RegExpLiteral: public MaterializedLiteral { pattern_(pattern), flags_(flags) {} - virtual void Accept(AstVisitor* v); + DECLARE_NODE_TYPE(RegExpLiteral) Handle<String> pattern() const { return pattern_; } Handle<String> flags() const { return flags_; } @@ -914,8 +898,7 @@ class ArrayLiteral: public MaterializedLiteral { constant_elements_(constant_elements), values_(values) {} - virtual void Accept(AstVisitor* v); - virtual ArrayLiteral* AsArrayLiteral() { return this; } + DECLARE_NODE_TYPE(ArrayLiteral) Handle<FixedArray> constant_elements() const { return constant_elements_; } ZoneList<Expression*>* values() const { return values_; } @@ -935,7 +918,7 @@ class CatchExtensionObject: public Expression { : key_(key), value_(value) { } - virtual void Accept(AstVisitor* v); + DECLARE_NODE_TYPE(CatchExtensionObject) Literal* key() const { return key_; } VariableProxy* value() const { return value_; } @@ -950,17 +933,13 @@ class VariableProxy: public Expression { public: explicit VariableProxy(Variable* var); - virtual void Accept(AstVisitor* v); + DECLARE_NODE_TYPE(VariableProxy) // Type testing & conversion virtual Property* AsProperty() { return var_ == NULL ? NULL : var_->AsProperty(); } - virtual VariableProxy* AsVariableProxy() { - return this; - } - Variable* AsVariable() { if (this == NULL || var_ == NULL) return NULL; Expression* rewrite = var_->rewrite(); @@ -1055,10 +1034,7 @@ class Slot: public Expression { ASSERT(var != NULL); } - virtual void Accept(AstVisitor* v); - - // Type testing & conversion - virtual Slot* AsSlot() { return this; } + DECLARE_NODE_TYPE(Slot) bool IsStackAllocated() { return type_ == PARAMETER || type_ == LOCAL; } @@ -1085,10 +1061,7 @@ class Property: public Expression { Property(Expression* obj, Expression* key, int pos, Type type = NORMAL) : obj_(obj), key_(key), pos_(pos), type_(type) { } - virtual void Accept(AstVisitor* v); - - // Type testing & conversion - virtual Property* AsProperty() { return this; } + DECLARE_NODE_TYPE(Property) virtual bool IsValidLeftHandSide() { return true; } @@ -1117,10 +1090,7 @@ class Call: public Expression { Call(Expression* expression, ZoneList<Expression*>* arguments, int pos) : expression_(expression), arguments_(arguments), pos_(pos) { } - virtual void Accept(AstVisitor* v); - - // Type testing and conversion. - virtual Call* AsCall() { return this; } + DECLARE_NODE_TYPE(Call) Expression* expression() const { return expression_; } ZoneList<Expression*>* arguments() const { return arguments_; } @@ -1142,7 +1112,7 @@ class CallNew: public Expression { CallNew(Expression* expression, ZoneList<Expression*>* arguments, int pos) : expression_(expression), arguments_(arguments), pos_(pos) { } - virtual void Accept(AstVisitor* v); + DECLARE_NODE_TYPE(CallNew) Expression* expression() const { return expression_; } ZoneList<Expression*>* arguments() const { return arguments_; } @@ -1166,7 +1136,7 @@ class CallRuntime: public Expression { ZoneList<Expression*>* arguments) : name_(name), function_(function), arguments_(arguments) { } - virtual void Accept(AstVisitor* v); + DECLARE_NODE_TYPE(CallRuntime) Handle<String> name() const { return name_; } Runtime::Function* function() const { return function_; } @@ -1187,11 +1157,9 @@ class UnaryOperation: public Expression { ASSERT(Token::IsUnaryOp(op)); } - virtual void Accept(AstVisitor* v); - virtual bool ResultOverwriteAllowed(); + DECLARE_NODE_TYPE(UnaryOperation) - // Type testing & conversion - virtual UnaryOperation* AsUnaryOperation() { return this; } + virtual bool ResultOverwriteAllowed(); Token::Value op() const { return op_; } Expression* expression() const { return expression_; } @@ -1215,11 +1183,9 @@ class BinaryOperation: public Expression { // Create the binary operation corresponding to a compound assignment. explicit BinaryOperation(Assignment* assignment); - virtual void Accept(AstVisitor* v); - virtual bool ResultOverwriteAllowed(); + DECLARE_NODE_TYPE(BinaryOperation) - // Type testing & conversion - virtual BinaryOperation* AsBinaryOperation() { return this; } + virtual bool ResultOverwriteAllowed(); Token::Value op() const { return op_; } Expression* left() const { return left_; } @@ -1241,12 +1207,12 @@ class IncrementOperation: public Expression { ASSERT(Token::IsCountOp(op)); } + DECLARE_NODE_TYPE(IncrementOperation) + Token::Value op() const { return op_; } bool is_increment() { return op_ == Token::INC; } Expression* expression() const { return expression_; } - virtual void Accept(AstVisitor* v); - private: Token::Value op_; Expression* expression_; @@ -1259,9 +1225,7 @@ class CountOperation: public Expression { CountOperation(bool is_prefix, IncrementOperation* increment, int pos) : is_prefix_(is_prefix), increment_(increment), pos_(pos) { } - virtual void Accept(AstVisitor* v); - - virtual CountOperation* AsCountOperation() { return this; } + DECLARE_NODE_TYPE(CountOperation) bool is_prefix() const { return is_prefix_; } bool is_postfix() const { return !is_prefix_; } @@ -1294,16 +1258,13 @@ class CompareOperation: public Expression { ASSERT(Token::IsCompareOp(op)); } - virtual void Accept(AstVisitor* v); + DECLARE_NODE_TYPE(CompareOperation) Token::Value op() const { return op_; } Expression* left() const { return left_; } Expression* right() const { return right_; } int position() const { return pos_; } - // Type testing & conversion - virtual CompareOperation* AsCompareOperation() { return this; } - private: Token::Value op_; Expression* left_; @@ -1317,7 +1278,7 @@ class CompareToNull: public Expression { CompareToNull(bool is_strict, Expression* expression) : is_strict_(is_strict), expression_(expression) { } - virtual void Accept(AstVisitor* v); + DECLARE_NODE_TYPE(CompareToNull) bool is_strict() const { return is_strict_; } Token::Value op() const { return is_strict_ ? Token::EQ_STRICT : Token::EQ; } @@ -1342,7 +1303,7 @@ class Conditional: public Expression { then_expression_position_(then_expression_position), else_expression_position_(else_expression_position) { } - virtual void Accept(AstVisitor* v); + DECLARE_NODE_TYPE(Conditional) Expression* condition() const { return condition_; } Expression* then_expression() const { return then_expression_; } @@ -1368,8 +1329,7 @@ class Assignment: public Expression { ASSERT(Token::IsAssignmentOp(op)); } - virtual void Accept(AstVisitor* v); - virtual Assignment* AsAssignment() { return this; } + DECLARE_NODE_TYPE(Assignment) Assignment* AsSimpleAssignment() { return !is_compound() ? this : NULL; } @@ -1406,7 +1366,7 @@ class Throw: public Expression { Throw(Expression* exception, int pos) : exception_(exception), pos_(pos) {} - virtual void Accept(AstVisitor* v); + DECLARE_NODE_TYPE(Throw) Expression* exception() const { return exception_; } int position() const { return pos_; } @@ -1452,10 +1412,7 @@ class FunctionLiteral: public Expression { #endif } - virtual void Accept(AstVisitor* v); - - // Type testing & conversion - virtual FunctionLiteral* AsFunctionLiteral() { return this; } + DECLARE_NODE_TYPE(FunctionLiteral) Handle<String> name() const { return name_; } Scope* scope() const { return scope_; } @@ -1479,6 +1436,11 @@ class FunctionLiteral: public Expression { bool AllowsLazyCompilation(); + Handle<String> debug_name() const { + if (name_->length() > 0) return name_; + return inferred_name(); + } + Handle<String> inferred_name() const { return inferred_name_; } void set_inferred_name(Handle<String> inferred_name) { inferred_name_ = inferred_name; @@ -1522,12 +1484,12 @@ class SharedFunctionInfoLiteral: public Expression { Handle<SharedFunctionInfo> shared_function_info) : shared_function_info_(shared_function_info) { } + DECLARE_NODE_TYPE(SharedFunctionInfoLiteral) + Handle<SharedFunctionInfo> shared_function_info() const { return shared_function_info_; } - virtual void Accept(AstVisitor* v); - private: Handle<SharedFunctionInfo> shared_function_info_; }; @@ -1535,7 +1497,7 @@ class SharedFunctionInfoLiteral: public Expression { class ThisFunction: public Expression { public: - virtual void Accept(AstVisitor* v); + DECLARE_NODE_TYPE(ThisFunction) }; @@ -1561,7 +1523,8 @@ class RegExpTree: public ZoneObject { virtual RegExpNode* ToNode(RegExpCompiler* compiler, RegExpNode* on_success) = 0; virtual bool IsTextElement() { return false; } - virtual bool IsAnchored() { return false; } + virtual bool IsAnchoredAtStart() { return false; } + virtual bool IsAnchoredAtEnd() { return false; } virtual int min_match() = 0; virtual int max_match() = 0; // Returns the interval of registers used for captures within this @@ -1586,7 +1549,8 @@ class RegExpDisjunction: public RegExpTree { virtual RegExpDisjunction* AsDisjunction(); virtual Interval CaptureRegisters(); virtual bool IsDisjunction(); - virtual bool IsAnchored(); + virtual bool IsAnchoredAtStart(); + virtual bool IsAnchoredAtEnd(); virtual int min_match() { return min_match_; } virtual int max_match() { return max_match_; } ZoneList<RegExpTree*>* alternatives() { return alternatives_; } @@ -1606,7 +1570,8 @@ class RegExpAlternative: public RegExpTree { virtual RegExpAlternative* AsAlternative(); virtual Interval CaptureRegisters(); virtual bool IsAlternative(); - virtual bool IsAnchored(); + virtual bool IsAnchoredAtStart(); + virtual bool IsAnchoredAtEnd(); virtual int min_match() { return min_match_; } virtual int max_match() { return max_match_; } ZoneList<RegExpTree*>* nodes() { return nodes_; } @@ -1633,7 +1598,8 @@ class RegExpAssertion: public RegExpTree { RegExpNode* on_success); virtual RegExpAssertion* AsAssertion(); virtual bool IsAssertion(); - virtual bool IsAnchored(); + virtual bool IsAnchoredAtStart(); + virtual bool IsAnchoredAtEnd(); virtual int min_match() { return 0; } virtual int max_match() { return 0; } Type type() { return type_; } @@ -1806,7 +1772,8 @@ class RegExpCapture: public RegExpTree { RegExpCompiler* compiler, RegExpNode* on_success); virtual RegExpCapture* AsCapture(); - virtual bool IsAnchored(); + virtual bool IsAnchoredAtStart(); + virtual bool IsAnchoredAtEnd(); virtual Interval CaptureRegisters(); virtual bool IsCapture(); virtual int min_match() { return body_->min_match(); } @@ -1838,7 +1805,7 @@ class RegExpLookahead: public RegExpTree { virtual RegExpLookahead* AsLookahead(); virtual Interval CaptureRegisters(); virtual bool IsLookahead(); - virtual bool IsAnchored(); + virtual bool IsAnchoredAtStart(); virtual int min_match() { return 0; } virtual int max_match() { return 0; } RegExpTree* body() { return body_; } diff --git a/src/bootstrapper.cc b/src/bootstrapper.cc index aa8d8e5a..d7491e1f 100644 --- a/src/bootstrapper.cc +++ b/src/bootstrapper.cc @@ -1814,6 +1814,11 @@ Genesis::Genesis(Handle<Object> global_object, i::Counters::contexts_created_from_scratch.Increment(); } + // Add this context to the weak list of global contexts. + (*global_context_)->set(Context::NEXT_CONTEXT_LINK, + Heap::global_contexts_list()); + Heap::set_global_contexts_list(*global_context_); + result_ = global_context_; } diff --git a/src/bytecodes-irregexp.h b/src/bytecodes-irregexp.h index bcb34c89..93218ea9 100644 --- a/src/bytecodes-irregexp.h +++ b/src/bytecodes-irregexp.h @@ -88,7 +88,8 @@ V(CHECK_REGISTER_EQ_POS, 43, 8) /* bc8 reg_idx24 addr32 */ \ V(CHECK_AT_START, 44, 8) /* bc8 pad24 addr32 */ \ V(CHECK_NOT_AT_START, 45, 8) /* bc8 pad24 addr32 */ \ V(CHECK_GREEDY, 46, 8) /* bc8 pad24 addr32 */ \ -V(ADVANCE_CP_AND_GOTO, 47, 8) /* bc8 offset24 addr32 */ +V(ADVANCE_CP_AND_GOTO, 47, 8) /* bc8 offset24 addr32 */ \ +V(SET_CURRENT_POSITION_FROM_END, 48, 4) /* bc8 idx24 */ #define DECLARE_BYTECODES(name, code, length) \ static const int BC_##name = code; diff --git a/src/cached-powers.cc b/src/cached-powers.cc new file mode 100644 index 00000000..8f822862 --- /dev/null +++ b/src/cached-powers.cc @@ -0,0 +1,152 @@ +// Copyright 2006-2008 the V8 project authors. All rights reserved. +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include <stdarg.h> +#include <limits.h> + +#include "v8.h" + +#include "cached-powers.h" + +namespace v8 { +namespace internal { + +struct CachedPower { + uint64_t significand; + int16_t binary_exponent; + int16_t decimal_exponent; +}; + +static const CachedPower kCachedPowers[] = { + {V8_2PART_UINT64_C(0xe61acf03, 3d1a45df), -1087, -308}, + {V8_2PART_UINT64_C(0xab70fe17, c79ac6ca), -1060, -300}, + {V8_2PART_UINT64_C(0xff77b1fc, bebcdc4f), -1034, -292}, + {V8_2PART_UINT64_C(0xbe5691ef, 416bd60c), -1007, -284}, + {V8_2PART_UINT64_C(0x8dd01fad, 907ffc3c), -980, -276}, + {V8_2PART_UINT64_C(0xd3515c28, 31559a83), -954, -268}, + {V8_2PART_UINT64_C(0x9d71ac8f, ada6c9b5), -927, -260}, + {V8_2PART_UINT64_C(0xea9c2277, 23ee8bcb), -901, -252}, + {V8_2PART_UINT64_C(0xaecc4991, 4078536d), -874, -244}, + {V8_2PART_UINT64_C(0x823c1279, 5db6ce57), -847, -236}, + {V8_2PART_UINT64_C(0xc2109436, 4dfb5637), -821, -228}, + {V8_2PART_UINT64_C(0x9096ea6f, 3848984f), -794, -220}, + {V8_2PART_UINT64_C(0xd77485cb, 25823ac7), -768, -212}, + {V8_2PART_UINT64_C(0xa086cfcd, 97bf97f4), -741, -204}, + {V8_2PART_UINT64_C(0xef340a98, 172aace5), -715, -196}, + {V8_2PART_UINT64_C(0xb23867fb, 2a35b28e), -688, -188}, + {V8_2PART_UINT64_C(0x84c8d4df, d2c63f3b), -661, -180}, + {V8_2PART_UINT64_C(0xc5dd4427, 1ad3cdba), -635, -172}, + {V8_2PART_UINT64_C(0x936b9fce, bb25c996), -608, -164}, + {V8_2PART_UINT64_C(0xdbac6c24, 7d62a584), -582, -156}, + {V8_2PART_UINT64_C(0xa3ab6658, 0d5fdaf6), -555, -148}, + {V8_2PART_UINT64_C(0xf3e2f893, dec3f126), -529, -140}, + {V8_2PART_UINT64_C(0xb5b5ada8, aaff80b8), -502, -132}, + {V8_2PART_UINT64_C(0x87625f05, 6c7c4a8b), -475, -124}, + {V8_2PART_UINT64_C(0xc9bcff60, 34c13053), -449, -116}, + {V8_2PART_UINT64_C(0x964e858c, 91ba2655), -422, -108}, + {V8_2PART_UINT64_C(0xdff97724, 70297ebd), -396, -100}, + {V8_2PART_UINT64_C(0xa6dfbd9f, b8e5b88f), -369, -92}, + {V8_2PART_UINT64_C(0xf8a95fcf, 88747d94), -343, -84}, + {V8_2PART_UINT64_C(0xb9447093, 8fa89bcf), -316, -76}, + {V8_2PART_UINT64_C(0x8a08f0f8, bf0f156b), -289, -68}, + {V8_2PART_UINT64_C(0xcdb02555, 653131b6), -263, -60}, + {V8_2PART_UINT64_C(0x993fe2c6, d07b7fac), -236, -52}, + {V8_2PART_UINT64_C(0xe45c10c4, 2a2b3b06), -210, -44}, + {V8_2PART_UINT64_C(0xaa242499, 697392d3), -183, -36}, + {V8_2PART_UINT64_C(0xfd87b5f2, 8300ca0e), -157, -28}, + {V8_2PART_UINT64_C(0xbce50864, 92111aeb), -130, -20}, + {V8_2PART_UINT64_C(0x8cbccc09, 6f5088cc), -103, -12}, + {V8_2PART_UINT64_C(0xd1b71758, e219652c), -77, -4}, + {V8_2PART_UINT64_C(0x9c400000, 00000000), -50, 4}, + {V8_2PART_UINT64_C(0xe8d4a510, 00000000), -24, 12}, + {V8_2PART_UINT64_C(0xad78ebc5, ac620000), 3, 20}, + {V8_2PART_UINT64_C(0x813f3978, f8940984), 30, 28}, + {V8_2PART_UINT64_C(0xc097ce7b, c90715b3), 56, 36}, + {V8_2PART_UINT64_C(0x8f7e32ce, 7bea5c70), 83, 44}, + {V8_2PART_UINT64_C(0xd5d238a4, abe98068), 109, 52}, + {V8_2PART_UINT64_C(0x9f4f2726, 179a2245), 136, 60}, + {V8_2PART_UINT64_C(0xed63a231, d4c4fb27), 162, 68}, + {V8_2PART_UINT64_C(0xb0de6538, 8cc8ada8), 189, 76}, + {V8_2PART_UINT64_C(0x83c7088e, 1aab65db), 216, 84}, + {V8_2PART_UINT64_C(0xc45d1df9, 42711d9a), 242, 92}, + {V8_2PART_UINT64_C(0x924d692c, a61be758), 269, 100}, + {V8_2PART_UINT64_C(0xda01ee64, 1a708dea), 295, 108}, + {V8_2PART_UINT64_C(0xa26da399, 9aef774a), 322, 116}, + {V8_2PART_UINT64_C(0xf209787b, b47d6b85), 348, 124}, + {V8_2PART_UINT64_C(0xb454e4a1, 79dd1877), 375, 132}, + {V8_2PART_UINT64_C(0x865b8692, 5b9bc5c2), 402, 140}, + {V8_2PART_UINT64_C(0xc83553c5, c8965d3d), 428, 148}, + {V8_2PART_UINT64_C(0x952ab45c, fa97a0b3), 455, 156}, + {V8_2PART_UINT64_C(0xde469fbd, 99a05fe3), 481, 164}, + {V8_2PART_UINT64_C(0xa59bc234, db398c25), 508, 172}, + {V8_2PART_UINT64_C(0xf6c69a72, a3989f5c), 534, 180}, + {V8_2PART_UINT64_C(0xb7dcbf53, 54e9bece), 561, 188}, + {V8_2PART_UINT64_C(0x88fcf317, f22241e2), 588, 196}, + {V8_2PART_UINT64_C(0xcc20ce9b, d35c78a5), 614, 204}, + {V8_2PART_UINT64_C(0x98165af3, 7b2153df), 641, 212}, + {V8_2PART_UINT64_C(0xe2a0b5dc, 971f303a), 667, 220}, + {V8_2PART_UINT64_C(0xa8d9d153, 5ce3b396), 694, 228}, + {V8_2PART_UINT64_C(0xfb9b7cd9, a4a7443c), 720, 236}, + {V8_2PART_UINT64_C(0xbb764c4c, a7a44410), 747, 244}, + {V8_2PART_UINT64_C(0x8bab8eef, b6409c1a), 774, 252}, + {V8_2PART_UINT64_C(0xd01fef10, a657842c), 800, 260}, + {V8_2PART_UINT64_C(0x9b10a4e5, e9913129), 827, 268}, + {V8_2PART_UINT64_C(0xe7109bfb, a19c0c9d), 853, 276}, + {V8_2PART_UINT64_C(0xac2820d9, 623bf429), 880, 284}, + {V8_2PART_UINT64_C(0x80444b5e, 7aa7cf85), 907, 292}, + {V8_2PART_UINT64_C(0xbf21e440, 03acdd2d), 933, 300}, + {V8_2PART_UINT64_C(0x8e679c2f, 5e44ff8f), 960, 308}, + {V8_2PART_UINT64_C(0xd433179d, 9c8cb841), 986, 316}, + {V8_2PART_UINT64_C(0x9e19db92, b4e31ba9), 1013, 324}, + {V8_2PART_UINT64_C(0xeb96bf6e, badf77d9), 1039, 332}, + {V8_2PART_UINT64_C(0xaf87023b, 9bf0ee6b), 1066, 340}, +}; + +static const int kCachedPowersLength = ARRAY_SIZE(kCachedPowers); +static const int kCachedPowersOffset = -kCachedPowers[0].decimal_exponent; +static const double kD_1_LOG2_10 = 0.30102999566398114; // 1 / lg(10) +static const int kCachedPowersDecimalDistance = + kCachedPowers[1].decimal_exponent - kCachedPowers[0].decimal_exponent; + +void GetCachedPowerForBinaryExponentRange(int min_exponent, + int max_exponent, + DiyFp* power, + int* decimal_exponent) { + int kQ = DiyFp::kSignificandSize; + double k = ceiling((min_exponent + kQ - 1) * kD_1_LOG2_10); + int foo = kCachedPowersOffset; + int index = + (foo + static_cast<int>(k) - 1) / kCachedPowersDecimalDistance + 1; + ASSERT(0 <= index && index < kCachedPowersLength); + CachedPower cached_power = kCachedPowers[index]; + ASSERT(min_exponent <= cached_power.binary_exponent); + ASSERT(cached_power.binary_exponent <= max_exponent); + *decimal_exponent = cached_power.decimal_exponent; + *power = DiyFp(cached_power.significand, cached_power.binary_exponent); +} + +} } // namespace v8::internal diff --git a/src/cached-powers.h b/src/cached-powers.h index 314ccca3..0c783431 100644 --- a/src/cached-powers.h +++ b/src/cached-powers.h @@ -33,86 +33,10 @@ namespace v8 { namespace internal { -struct CachedPower { - uint64_t significand; - int16_t binary_exponent; - int16_t decimal_exponent; -}; - -// The following defines implement the interface between this file and the -// generated 'powers_ten.h'. -// GRISU_CACHE_NAME(1) contains all possible cached powers. -// GRISU_CACHE_NAME(i) contains GRISU_CACHE_NAME(1) where only every 'i'th -// element is kept. More formally GRISU_CACHE_NAME(i) contains the elements j*i -// with 0 <= j < k with k such that j*k < the size of GRISU_CACHE_NAME(1). -// The higher 'i' is the fewer elements we use. -// Given that there are less elements, the exponent-distance between two -// elements in the cache grows. The variable GRISU_CACHE_MAX_DISTANCE(i) stores -// the maximum distance between two elements. -#define GRISU_CACHE_STRUCT CachedPower -#define GRISU_CACHE_NAME(i) kCachedPowers##i -#define GRISU_CACHE_MAX_DISTANCE(i) kCachedPowersMaxDistance##i -#define GRISU_CACHE_OFFSET kCachedPowerOffset -#define GRISU_UINT64_C V8_2PART_UINT64_C -// The following include imports the precompiled cached powers. -#include "powers-ten.h" // NOLINT - -static const double kD_1_LOG2_10 = 0.30102999566398114; // 1 / lg(10) - -// We can't use a function since we reference variables depending on the 'i'. -// This way the compiler is able to see at compile time that only one -// cache-array variable is used and thus can remove all the others. -#define COMPUTE_FOR_CACHE(i) \ - if (!found && (gamma - alpha + 1 >= GRISU_CACHE_MAX_DISTANCE(i))) { \ - int kQ = DiyFp::kSignificandSize; \ - double k = ceiling((alpha - e + kQ - 1) * kD_1_LOG2_10); \ - int index = (GRISU_CACHE_OFFSET + static_cast<int>(k) - 1) / i + 1; \ - cached_power = GRISU_CACHE_NAME(i)[index]; \ - found = true; \ - } \ - -static void GetCachedPower(int e, int alpha, int gamma, int* mk, DiyFp* c_mk) { - // The following if statement should be optimized by the compiler so that only - // one array is referenced and the others are not included in the object file. - bool found = false; - CachedPower cached_power; - COMPUTE_FOR_CACHE(20); - COMPUTE_FOR_CACHE(19); - COMPUTE_FOR_CACHE(18); - COMPUTE_FOR_CACHE(17); - COMPUTE_FOR_CACHE(16); - COMPUTE_FOR_CACHE(15); - COMPUTE_FOR_CACHE(14); - COMPUTE_FOR_CACHE(13); - COMPUTE_FOR_CACHE(12); - COMPUTE_FOR_CACHE(11); - COMPUTE_FOR_CACHE(10); - COMPUTE_FOR_CACHE(9); - COMPUTE_FOR_CACHE(8); - COMPUTE_FOR_CACHE(7); - COMPUTE_FOR_CACHE(6); - COMPUTE_FOR_CACHE(5); - COMPUTE_FOR_CACHE(4); - COMPUTE_FOR_CACHE(3); - COMPUTE_FOR_CACHE(2); - COMPUTE_FOR_CACHE(1); - if (!found) { - UNIMPLEMENTED(); - // Silence compiler warnings. - cached_power.significand = 0; - cached_power.binary_exponent = 0; - cached_power.decimal_exponent = 0; - } - *c_mk = DiyFp(cached_power.significand, cached_power.binary_exponent); - *mk = cached_power.decimal_exponent; - ASSERT((alpha <= c_mk->e() + e) && (c_mk->e() + e <= gamma)); -} -#undef GRISU_REDUCTION -#undef GRISU_CACHE_STRUCT -#undef GRISU_CACHE_NAME -#undef GRISU_CACHE_MAX_DISTANCE -#undef GRISU_CACHE_OFFSET -#undef GRISU_UINT64_C +void GetCachedPowerForBinaryExponentRange(int min_exponent, + int max_exponent, + DiyFp* power, + int* decimal_exponent); } } // namespace v8::internal diff --git a/src/codegen.cc b/src/codegen.cc index 92241d1c..bda697ab 100644 --- a/src/codegen.cc +++ b/src/codegen.cc @@ -206,10 +206,9 @@ Handle<Code> CodeGenerator::MakeCodeEpilogue(MacroAssembler* masm, } -// Generate the code. Takes a function literal, generates code for it, assemble -// all the pieces into a Code object. This function is only to be called by -// the compiler.cc code. -Handle<Code> CodeGenerator::MakeCode(CompilationInfo* info) { +// Generate the code. Compile the AST and assemble all the pieces into a +// Code object. +bool CodeGenerator::MakeCode(CompilationInfo* info) { Handle<Script> script = info->script(); if (!script->IsUndefined() && !script->source()->IsUndefined()) { int len = String::cast(script->source())->length(); @@ -224,12 +223,14 @@ Handle<Code> CodeGenerator::MakeCode(CompilationInfo* info) { cgen.Generate(info); if (cgen.HasStackOverflow()) { ASSERT(!Top::has_pending_exception()); - return Handle<Code>::null(); + return false; } - InLoopFlag in_loop = (cgen.loop_nesting() != 0) ? IN_LOOP : NOT_IN_LOOP; + InLoopFlag in_loop = info->is_in_loop() ? IN_LOOP : NOT_IN_LOOP; Code::Flags flags = Code::ComputeFlags(Code::FUNCTION, in_loop); - return MakeCodeEpilogue(cgen.masm(), flags, info); + Handle<Code> code = MakeCodeEpilogue(cgen.masm(), flags, info); + info->SetCode(code); // May be an empty handle. + return !code.is_null(); } @@ -325,9 +326,12 @@ void CodeGenerator::ProcessDeclarations(ZoneList<Declaration*>* declarations) { } } else { Handle<SharedFunctionInfo> function = - Compiler::BuildFunctionInfo(node->fun(), script(), this); + Compiler::BuildFunctionInfo(node->fun(), script()); // Check for stack-overflow exception. - if (HasStackOverflow()) return; + if (function.is_null()) { + SetStackOverflow(); + return; + } array->set(j++, *function); } } @@ -357,24 +361,19 @@ const CodeGenerator::InlineFunctionGenerator #undef INLINE_FUNCTION_GENERATOR_ADDRESS -CodeGenerator::InlineFunctionGenerator - CodeGenerator::FindInlineFunctionGenerator(Runtime::FunctionId id) { - return kInlineFunctionGenerators[ - static_cast<int>(id) - static_cast<int>(Runtime::kFirstInlineFunction)]; -} - - bool CodeGenerator::CheckForInlineRuntimeCall(CallRuntime* node) { ZoneList<Expression*>* args = node->arguments(); Handle<String> name = node->name(); Runtime::Function* function = node->function(); if (function != NULL && function->intrinsic_type == Runtime::INLINE) { - InlineFunctionGenerator generator = - FindInlineFunctionGenerator(function->function_id); - if (generator != NULL) { - ((*this).*(generator))(args); - return true; - } + int lookup_index = static_cast<int>(function->function_id) - + static_cast<int>(Runtime::kFirstInlineFunction); + ASSERT(lookup_index >= 0); + ASSERT(static_cast<size_t>(lookup_index) < + ARRAY_SIZE(kInlineFunctionGenerators)); + InlineFunctionGenerator generator = kInlineFunctionGenerators[lookup_index]; + (this->*generator)(args); + return true; } return false; } diff --git a/src/codegen.h b/src/codegen.h index 2a4d9d4c..8f923dd3 100644 --- a/src/codegen.h +++ b/src/codegen.h @@ -62,7 +62,6 @@ // ComputeCallInitializeInLoop // ProcessDeclarations // DeclareGlobals -// FindInlineRuntimeLUT // CheckForInlineRuntimeCall // AnalyzeCondition // CodeForFunctionPosition diff --git a/src/compiler.cc b/src/compiler.cc index 825198ed..6cc09713 100755 --- a/src/compiler.cc +++ b/src/compiler.cc @@ -27,22 +27,58 @@ #include "v8.h" +#include "compiler.h" + #include "bootstrapper.h" #include "codegen-inl.h" #include "compilation-cache.h" -#include "compiler.h" #include "data-flow.h" #include "debug.h" #include "full-codegen.h" #include "liveedit.h" #include "oprofile-agent.h" +#include "parser.h" #include "rewriter.h" -#include "scopes.h" #include "scopeinfo.h" +#include "scopes.h" namespace v8 { namespace internal { + +CompilationInfo::CompilationInfo(Handle<Script> script) + : flags_(0), + function_(NULL), + scope_(NULL), + script_(script), + extension_(NULL), + pre_parse_data_(NULL) { +} + + +CompilationInfo::CompilationInfo(Handle<SharedFunctionInfo> shared_info) + : flags_(IsLazy::encode(true)), + function_(NULL), + scope_(NULL), + shared_info_(shared_info), + script_(Handle<Script>(Script::cast(shared_info->script()))), + extension_(NULL), + pre_parse_data_(NULL) { +} + + +CompilationInfo::CompilationInfo(Handle<JSFunction> closure) + : flags_(IsLazy::encode(true)), + function_(NULL), + scope_(NULL), + closure_(closure), + shared_info_(Handle<SharedFunctionInfo>(closure->shared())), + script_(Handle<Script>(Script::cast(shared_info_->script()))), + extension_(NULL), + pre_parse_data_(NULL) { +} + + // For normal operation the syntax checker is used to determine whether to // use the full compiler for top level code or not. However if the flag // --always-full-compiler is specified or debugging is active the full @@ -56,102 +92,74 @@ static bool AlwaysFullCompiler() { } -static Handle<Code> MakeCode(Handle<Context> context, CompilationInfo* info) { - FunctionLiteral* function = info->function(); - ASSERT(function != NULL); - // Rewrite the AST by introducing .result assignments where needed. - if (!Rewriter::Process(function)) { - // Signal a stack overflow by returning a null handle. The stack - // overflow exception will be thrown by the caller. - return Handle<Code>::null(); - } - - { - // Compute top scope and allocate variables. For lazy compilation - // the top scope only contains the single lazily compiled function, - // so this doesn't re-allocate variables repeatedly. - HistogramTimerScope timer(&Counters::variable_allocation); - Scope* top = info->scope(); - while (top->outer_scope() != NULL) top = top->outer_scope(); - top->AllocateVariables(context); - } - -#ifdef DEBUG - if (Bootstrapper::IsActive() ? - FLAG_print_builtin_scopes : - FLAG_print_scopes) { - info->scope()->Print(); - } -#endif - - // Optimize the AST. - if (!Rewriter::Optimize(function)) { - // Signal a stack overflow by returning a null handle. The stack - // overflow exception will be thrown by the caller. - return Handle<Code>::null(); - } - - // Generate code and return it. Code generator selection is governed by - // which backends are enabled and whether the function is considered - // run-once code or not: - // - // --full-compiler enables the dedicated backend for code we expect to be - // run once - // - // The normal choice of backend can be overridden with the flags - // --always-full-compiler. - Handle<SharedFunctionInfo> shared = info->shared_info(); - bool is_run_once = (shared.is_null()) - ? info->scope()->is_global_scope() - : (shared->is_toplevel() || shared->try_full_codegen()); - bool use_full = FLAG_full_compiler && !function->contains_loops(); - if (AlwaysFullCompiler() || (use_full && is_run_once)) { - return FullCodeGenerator::MakeCode(info); +static bool MakeCode(CompilationInfo* info) { + // Precondition: code has been parsed. Postcondition: the code field in + // the compilation info is set if compilation succeeded. + ASSERT(info->function() != NULL); + + if (Rewriter::Rewrite(info) && + Scope::Analyze(info) && + Rewriter::Analyze(info)) { + // Generate code and return it. Code generator selection is governed by + // which backends are enabled and whether the function is considered + // run-once code or not. + // + // --full-compiler enables the dedicated backend for code we expect to + // be run once + // + // The normal choice of backend can be overridden with the flags + // --always-full-compiler. + Handle<SharedFunctionInfo> shared = info->shared_info(); + bool is_run_once = (shared.is_null()) + ? info->scope()->is_global_scope() + : (shared->is_toplevel() || shared->try_full_codegen()); + bool can_use_full = + FLAG_full_compiler && !info->function()->contains_loops(); + if (AlwaysFullCompiler() || (is_run_once && can_use_full)) { + return FullCodeGenerator::MakeCode(info); + } else { + AssignedVariablesAnalyzer ava; + return ava.Analyze(info) && CodeGenerator::MakeCode(info); + } } - AssignedVariablesAnalyzer ava(function); - if (!ava.Analyze()) return Handle<Code>::null(); - return CodeGenerator::MakeCode(info); + return false; } #ifdef ENABLE_DEBUGGER_SUPPORT -Handle<Code> MakeCodeForLiveEdit(CompilationInfo* info) { - Handle<Context> context = Handle<Context>::null(); - Handle<Code> code = MakeCode(context, info); +bool Compiler::MakeCodeForLiveEdit(CompilationInfo* info) { + // Precondition: code has been parsed. Postcondition: the code field in + // the compilation info is set if compilation succeeded. + bool succeeded = MakeCode(info); if (!info->shared_info().is_null()) { Handle<SerializedScopeInfo> scope_info = SerializedScopeInfo::Create(info->scope()); info->shared_info()->set_scope_info(*scope_info); } - return code; + return succeeded; } #endif -static Handle<SharedFunctionInfo> MakeFunctionInfo(bool is_global, - bool is_eval, - Compiler::ValidationState validate, - Handle<Script> script, - Handle<Context> context, - v8::Extension* extension, - ScriptDataImpl* pre_data) { +static Handle<SharedFunctionInfo> MakeFunctionInfo(CompilationInfo* info) { CompilationZoneScope zone_scope(DELETE_ON_EXIT); PostponeInterruptsScope postpone; ASSERT(!i::Top::global_context().is_null()); + Handle<Script> script = info->script(); script->set_context_data((*i::Top::global_context())->data()); - bool is_json = (validate == Compiler::VALIDATE_JSON); #ifdef ENABLE_DEBUGGER_SUPPORT - if (is_eval || is_json) { - script->set_compilation_type( - is_json ? Smi::FromInt(Script::COMPILATION_TYPE_JSON) : - Smi::FromInt(Script::COMPILATION_TYPE_EVAL)); + if (info->is_eval() || info->is_json()) { + Script::CompilationType compilation_type = info->is_json() + ? Script::COMPILATION_TYPE_JSON + : 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. - if (is_eval) { + if (info->is_eval()) { StackTraceFrameIterator it; if (!it.done()) { script->set_eval_from_shared( @@ -168,54 +176,47 @@ static Handle<SharedFunctionInfo> MakeFunctionInfo(bool is_global, #endif // Only allow non-global compiles for eval. - ASSERT(is_eval || is_global); + ASSERT(info->is_eval() || info->is_global()); - // Build AST. - FunctionLiteral* lit = - MakeAST(is_global, script, extension, pre_data, is_json); - - LiveEditFunctionTracker live_edit_tracker(lit); - - // Check for parse errors. - if (lit == NULL) { - ASSERT(Top::has_pending_exception()); - return Handle<SharedFunctionInfo>::null(); - } + if (!Parser::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 // parsing statistics. - HistogramTimer* rate = is_eval + HistogramTimer* rate = info->is_eval() ? &Counters::compile_eval : &Counters::compile; HistogramTimerScope timer(rate); // Compile the code. - CompilationInfo info(lit, script, is_eval); - Handle<Code> code = MakeCode(context, &info); - - // Check for stack-overflow exceptions. - if (code.is_null()) { + FunctionLiteral* lit = info->function(); + LiveEditFunctionTracker live_edit_tracker(lit); + if (!MakeCode(info)) { Top::StackOverflow(); return Handle<SharedFunctionInfo>::null(); } + ASSERT(!info->code().is_null()); if (script->name()->IsString()) { PROFILE(CodeCreateEvent( - is_eval ? Logger::EVAL_TAG : - Logger::ToNativeByScript(Logger::SCRIPT_TAG, *script), - *code, String::cast(script->name()))); + info->is_eval() + ? Logger::EVAL_TAG + : Logger::ToNativeByScript(Logger::SCRIPT_TAG, *script), + *info->code(), + String::cast(script->name()))); OPROFILE(CreateNativeCodeRegion(String::cast(script->name()), - code->instruction_start(), - code->instruction_size())); + info->code()->instruction_start(), + info->code()->instruction_size())); } else { PROFILE(CodeCreateEvent( - is_eval ? Logger::EVAL_TAG : - Logger::ToNativeByScript(Logger::SCRIPT_TAG, *script), - *code, "")); - OPROFILE(CreateNativeCodeRegion(is_eval ? "Eval" : "Script", - code->instruction_start(), - code->instruction_size())); + info->is_eval() + ? Logger::EVAL_TAG + : Logger::ToNativeByScript(Logger::SCRIPT_TAG, *script), + *info->code(), + "")); + OPROFILE(CreateNativeCodeRegion(info->is_eval() ? "Eval" : "Script", + info->code()->instruction_start(), + info->code()->instruction_size())); } // Allocate function. @@ -223,8 +224,8 @@ static Handle<SharedFunctionInfo> MakeFunctionInfo(bool is_global, Factory::NewSharedFunctionInfo( lit->name(), lit->materialized_literal_count(), - code, - SerializedScopeInfo::Create(info.scope())); + info->code(), + SerializedScopeInfo::Create(info->scope())); ASSERT_EQ(RelocInfo::kNoPosition, lit->function_token_position()); Compiler::SetFunctionInfo(result, lit, true, script); @@ -282,7 +283,7 @@ Handle<SharedFunctionInfo> Compiler::Compile(Handle<String> source, if (pre_data == NULL && FLAG_lazy && source_length >= FLAG_min_preparse_length) { - pre_data = PartialPreParse(source, NULL, extension); + pre_data = Parser::PartialPreParse(source, NULL, extension); } // Create a script object describing the script to be compiled. @@ -300,13 +301,11 @@ Handle<SharedFunctionInfo> Compiler::Compile(Handle<String> source, : *script_data); // Compile the function and add it to the cache. - result = MakeFunctionInfo(true, - false, - DONT_VALIDATE_JSON, - script, - Handle<Context>::null(), - extension, - pre_data); + CompilationInfo info(script); + info.MarkAsGlobal(); + info.SetExtension(extension); + info.SetPreParseData(pre_data); + result = MakeFunctionInfo(&info); if (extension == NULL && !result.is_null()) { CompilationCache::PutScript(source, result); } @@ -326,9 +325,10 @@ 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. + // 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); int source_length = source->length(); Counters::total_eval_size.Increment(source_length); @@ -337,27 +337,27 @@ Handle<SharedFunctionInfo> Compiler::CompileEval(Handle<String> source, // The VM is in the COMPILER state until exiting this function. 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. + // 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. Handle<SharedFunctionInfo> result; - if (validate == DONT_VALIDATE_JSON) + if (!is_json) { result = CompilationCache::LookupEval(source, context, is_global); + } if (result.is_null()) { // Create a script object describing the script to be compiled. Handle<Script> script = Factory::NewScript(source); - result = MakeFunctionInfo(is_global, - true, - validate, - script, - context, - NULL, - NULL); - if (!result.is_null() && validate != VALIDATE_JSON) { - // For json it's unlikely that we'll ever see exactly the same - // string again so we don't use the compilation cache. + 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. CompilationCache::PutEval(source, context, is_global, result); } } @@ -374,140 +374,122 @@ bool Compiler::CompileLazy(CompilationInfo* info) { PostponeInterruptsScope postpone; - // Compute name, source code and script data. Handle<SharedFunctionInfo> shared = info->shared_info(); - Handle<String> name(String::cast(shared->name())); - - int start_position = shared->start_position(); - int end_position = shared->end_position(); - bool is_expression = shared->is_expression(); - Counters::total_compile_size.Increment(end_position - start_position); - - // Generate the AST for the lazily compiled function. The AST may be - // NULL in case of parser stack overflow. - FunctionLiteral* lit = MakeLazyAST(info->script(), - name, - start_position, - end_position, - is_expression); - - // Check for parse errors. - if (lit == NULL) { - ASSERT(Top::has_pending_exception()); - return false; - } - info->set_function(lit); - - // 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. - HistogramTimerScope timer(&Counters::compile_lazy); - - // Compile the code. - Handle<Code> code = MakeCode(Handle<Context>::null(), info); - - // Check for stack-overflow exception. - if (code.is_null()) { - Top::StackOverflow(); - return false; - } + int compiled_size = shared->end_position() - shared->start_position(); + Counters::total_compile_size.Increment(compiled_size); + + // Generate the AST for the lazily compiled function. + if (Parser::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. + HistogramTimerScope timer(&Counters::compile_lazy); + + // Compile the code. + if (!MakeCode(info)) { + Top::StackOverflow(); + } else { + ASSERT(!info->code().is_null()); + RecordFunctionCompilation(Logger::LAZY_COMPILE_TAG, + Handle<String>(shared->DebugName()), + shared->start_position(), + info); + + // Update the shared function info with the compiled code and the + // scope info. Please note, that the order of the sharedfunction + // initialization is important since SerializedScopeInfo::Create might + // trigger a GC, causing the ASSERT below to be invalid if the code + // was flushed. By setting the code object last we avoid this. + Handle<SerializedScopeInfo> scope_info = + SerializedScopeInfo::Create(info->scope()); + shared->set_scope_info(*scope_info); + shared->set_code(*info->code()); + if (!info->closure().is_null()) { + info->closure()->set_code(*info->code()); + } - RecordFunctionCompilation(Logger::LAZY_COMPILE_TAG, - name, - Handle<String>(shared->inferred_name()), - start_position, - info->script(), - code); - - // Update the shared function info with the compiled code and the scope info. - // Please note, that the order of the sharedfunction initialization is - // important since SerializedScopeInfo::Create might trigger a GC, causing - // the ASSERT below to be invalid if the code was flushed. By setting the code - // object last we avoid this. - Handle<SerializedScopeInfo> scope_info = - SerializedScopeInfo::Create(info->scope()); - shared->set_scope_info(*scope_info); - shared->set_code(*code); - if (!info->closure().is_null()) { - info->closure()->set_code(*code); + // Set the expected number of properties for instances. + FunctionLiteral* lit = info->function(); + SetExpectedNofPropertiesFromEstimate(shared, + lit->expected_property_count()); + + // Set the optimization hints after performing lazy compilation, as + // these are not set when the function is set up as a lazily compiled + // function. + shared->SetThisPropertyAssignmentsInfo( + lit->has_only_simple_this_property_assignments(), + *lit->this_property_assignments()); + + // Check the function has compiled code. + ASSERT(shared->is_compiled()); + shared->set_code_age(0); + ASSERT(!info->code().is_null()); + return true; + } } - // Set the expected number of properties for instances. - SetExpectedNofPropertiesFromEstimate(shared, lit->expected_property_count()); - - // Set the optimication hints after performing lazy compilation, as these are - // not set when the function is set up as a lazily compiled function. - shared->SetThisPropertyAssignmentsInfo( - lit->has_only_simple_this_property_assignments(), - *lit->this_property_assignments()); - - // Check the function has compiled code. - ASSERT(shared->is_compiled()); - shared->set_code_age(0); - return true; + ASSERT(info->code().is_null()); + return false; } Handle<SharedFunctionInfo> Compiler::BuildFunctionInfo(FunctionLiteral* literal, - Handle<Script> script, - AstVisitor* caller) { - LiveEditFunctionTracker live_edit_tracker(literal); + Handle<Script> script) { #ifdef DEBUG // We should not try to compile the same function literal more than // once. literal->mark_as_compiled(); #endif - // Determine if the function can be lazily compiled. This is - // necessary to allow some of our builtin JS files to be lazily - // compiled. These builtins cannot be handled lazily by the parser, - // since we have to know if a function uses the special natives - // syntax, which is something the parser records. + // Precondition: code has been parsed and scopes have been analyzed. + CompilationInfo info(script); + info.SetFunction(literal); + info.SetScope(literal->scope()); + + LiveEditFunctionTracker live_edit_tracker(literal); + // Determine if the function can be lazily compiled. This is necessary to + // allow some of our builtin JS files to be lazily compiled. These + // builtins cannot be handled lazily by the parser, since we have to know + // if a function uses the special natives syntax, which is something the + // parser records. bool allow_lazy = literal->AllowsLazyCompilation() && !LiveEditFunctionTracker::IsActive(); Handle<SerializedScopeInfo> scope_info(SerializedScopeInfo::Empty()); // Generate code - Handle<Code> code; if (FLAG_lazy && allow_lazy) { - code = Handle<Code>(Builtins::builtin(Builtins::LazyCompile)); + Handle<Code> code(Builtins::builtin(Builtins::LazyCompile)); + info.SetCode(code); } else { - // The bodies of function literals have not yet been visited by - // the AST optimizer/analyzer. - if (!Rewriter::Optimize(literal)) { - return Handle<SharedFunctionInfo>::null(); - } - // Generate code and return it. The way that the compilation mode // is controlled by the command-line flags is described in // the static helper function MakeCode. - CompilationInfo info(literal, script, false); + // + // The bodies of function literals have not yet been visited by + // the AST analyzer. + if (!Rewriter::Analyze(&info)) return Handle<SharedFunctionInfo>::null(); bool is_run_once = literal->try_full_codegen(); bool use_full = FLAG_full_compiler && !literal->contains_loops(); if (AlwaysFullCompiler() || (use_full && is_run_once)) { - code = FullCodeGenerator::MakeCode(&info); + if (!FullCodeGenerator::MakeCode(&info)) { + return Handle<SharedFunctionInfo>::null(); + } } else { // We fall back to the classic V8 code generator. - AssignedVariablesAnalyzer ava(literal); - if (!ava.Analyze()) return Handle<SharedFunctionInfo>::null(); - code = CodeGenerator::MakeCode(&info); - } - - // Check for stack-overflow exception. - if (code.is_null()) { - caller->SetStackOverflow(); - return Handle<SharedFunctionInfo>::null(); + AssignedVariablesAnalyzer ava; + if (!ava.Analyze(&info)) return Handle<SharedFunctionInfo>::null(); + if (!CodeGenerator::MakeCode(&info)) { + return Handle<SharedFunctionInfo>::null(); + } } // Function compilation complete. RecordFunctionCompilation(Logger::FUNCTION_TAG, - literal->name(), - literal->inferred_name(), + literal->debug_name(), literal->start_position(), - script, - code); + &info); scope_info = SerializedScopeInfo::Create(info.scope()); } @@ -515,7 +497,7 @@ Handle<SharedFunctionInfo> Compiler::BuildFunctionInfo(FunctionLiteral* literal, Handle<SharedFunctionInfo> result = Factory::NewSharedFunctionInfo(literal->name(), literal->materialized_literal_count(), - code, + info.code(), scope_info); SetFunctionInfo(result, literal, false, script); @@ -555,32 +537,34 @@ void Compiler::SetFunctionInfo(Handle<SharedFunctionInfo> function_info, void Compiler::RecordFunctionCompilation(Logger::LogEventsAndTags tag, Handle<String> name, - Handle<String> inferred_name, int start_position, - Handle<Script> script, - Handle<Code> code) { - // Log the code generation. If source information is available - // include script name and line number. Check explicitly whether - // logging is enabled as finding the line number is not free. - if (Logger::is_logging() - || OProfileAgent::is_enabled() - || CpuProfiler::is_profiling()) { - Handle<String> func_name(name->length() > 0 ? *name : *inferred_name); + CompilationInfo* info) { + // Log the code generation. If source information is available include + // script name and line number. Check explicitly whether logging is + // enabled as finding the line number is not free. + if (Logger::is_logging() || + OProfileAgent::is_enabled() || + CpuProfiler::is_profiling()) { + Handle<Script> script = info->script(); + Handle<Code> code = info->code(); if (script->name()->IsString()) { int line_num = GetScriptLineNumber(script, start_position) + 1; USE(line_num); PROFILE(CodeCreateEvent(Logger::ToNativeByScript(tag, *script), - *code, *func_name, - String::cast(script->name()), line_num)); - OPROFILE(CreateNativeCodeRegion(*func_name, + *code, + *name, + String::cast(script->name()), + line_num)); + OPROFILE(CreateNativeCodeRegion(*name, String::cast(script->name()), line_num, code->instruction_start(), code->instruction_size())); } else { PROFILE(CodeCreateEvent(Logger::ToNativeByScript(tag, *script), - *code, *func_name)); - OPROFILE(CreateNativeCodeRegion(*func_name, + *code, + *name)); + OPROFILE(CreateNativeCodeRegion(*name, code->instruction_start(), code->instruction_size())); } diff --git a/src/compiler.h b/src/compiler.h index ed26603f..d6f4e69d 100644 --- a/src/compiler.h +++ b/src/compiler.h @@ -1,4 +1,4 @@ -// Copyright 2006-2008 the V8 project authors. All rights reserved. +// 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: @@ -30,127 +30,111 @@ #include "ast.h" #include "frame-element.h" -#include "parser.h" #include "register-allocator.h" #include "zone.h" namespace v8 { namespace internal { +class ScriptDataImpl; + // CompilationInfo encapsulates some information known at compile time. It // is constructed based on the resources available at compile-time. class CompilationInfo BASE_EMBEDDED { public: - // Lazy compilation of a JSFunction. - CompilationInfo(Handle<JSFunction> closure, - int loop_nesting, - Handle<Object> receiver) - : closure_(closure), - function_(NULL), - is_eval_(false), - loop_nesting_(loop_nesting), - receiver_(receiver) { - Initialize(); - ASSERT(!closure_.is_null() && - shared_info_.is_null() && - script_.is_null()); + explicit CompilationInfo(Handle<Script> script); + explicit CompilationInfo(Handle<SharedFunctionInfo> shared_info); + explicit CompilationInfo(Handle<JSFunction> closure); + + 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_; } + Handle<Code> code() const { return code_; } + Handle<JSFunction> closure() const { return closure_; } + Handle<SharedFunctionInfo> shared_info() const { return shared_info_; } + Handle<Script> script() const { return script_; } + v8::Extension* extension() const { return extension_; } + ScriptDataImpl* pre_parse_data() const { return pre_parse_data_; } + Handle<Context> calling_context() const { return calling_context_; } + + void MarkAsEval() { + ASSERT(!is_lazy()); + flags_ |= IsEval::encode(true); } - - // Lazy compilation based on SharedFunctionInfo. - explicit CompilationInfo(Handle<SharedFunctionInfo> shared_info) - : shared_info_(shared_info), - function_(NULL), - is_eval_(false), - loop_nesting_(0) { - Initialize(); - ASSERT(closure_.is_null() && - !shared_info_.is_null() && - script_.is_null()); + void MarkAsGlobal() { + ASSERT(!is_lazy()); + flags_ |= IsGlobal::encode(true); } - - // Eager compilation. - CompilationInfo(FunctionLiteral* literal, Handle<Script> script, bool is_eval) - : script_(script), - function_(literal), - is_eval_(is_eval), - loop_nesting_(0) { - Initialize(); - ASSERT(closure_.is_null() && - shared_info_.is_null() && - !script_.is_null()); + void MarkAsJson() { + ASSERT(!is_lazy()); + flags_ |= IsJson::encode(true); } - - // We can only get a JSFunction if we actually have one. - Handle<JSFunction> closure() { return closure_; } - - // We can get a SharedFunctionInfo from a JSFunction or if we actually - // have one. - Handle<SharedFunctionInfo> shared_info() { - if (!closure().is_null()) { - return Handle<SharedFunctionInfo>(closure()->shared()); - } else { - return shared_info_; - } + void MarkAsInLoop() { + ASSERT(is_lazy()); + flags_ |= IsInLoop::encode(true); } - - // We can always get a script. Either we have one or we can get a shared - // function info. - Handle<Script> script() { - if (!script_.is_null()) { - return script_; - } else { - ASSERT(shared_info()->script()->IsScript()); - return Handle<Script>(Script::cast(shared_info()->script())); - } + void SetFunction(FunctionLiteral* literal) { + ASSERT(function_ == NULL); + function_ = literal; } - - // There should always be a function literal, but it may be set after - // construction (for lazy compilation). - FunctionLiteral* function() { return function_; } - void set_function(FunctionLiteral* literal) { function_ = literal; } - - // Simple accessors. - bool is_eval() { return is_eval_; } - int loop_nesting() { return loop_nesting_; } - bool has_receiver() { return !receiver_.is_null(); } - Handle<Object> receiver() { return receiver_; } - - bool has_this_properties() { return has_this_properties_; } - void set_has_this_properties(bool flag) { has_this_properties_ = flag; } - - bool has_global_object() { - return !closure().is_null() && (closure()->context()->global() != NULL); + void SetScope(Scope* scope) { + ASSERT(scope_ == NULL); + scope_ = scope; } - - GlobalObject* global_object() { - return has_global_object() ? closure()->context()->global() : NULL; + void SetCode(Handle<Code> code) { code_ = code; } + void SetExtension(v8::Extension* extension) { + ASSERT(!is_lazy()); + extension_ = extension; + } + void SetPreParseData(ScriptDataImpl* pre_parse_data) { + ASSERT(!is_lazy()); + pre_parse_data_ = pre_parse_data; + } + void SetCallingContext(Handle<Context> context) { + ASSERT(is_eval()); + calling_context_ = context; } - - bool has_globals() { return has_globals_; } - void set_has_globals(bool flag) { has_globals_ = flag; } - - // Derived accessors. - Scope* scope() { return function()->scope(); } private: - void Initialize() { - has_this_properties_ = false; - has_globals_ = false; - } + // Flags using template class BitField<type, start, length>. All are + // false by default. + // + // Compilation is either eager or lazy. + class IsLazy: public BitField<bool, 0, 1> {}; + // 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> {}; + + 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 + // that scopes have been analyzed. + Scope* scope_; + // The compiled code. + Handle<Code> code_; + // Possible initial inputs to the compilation process. Handle<JSFunction> closure_; Handle<SharedFunctionInfo> shared_info_; Handle<Script> script_; - FunctionLiteral* function_; - - bool is_eval_; - int loop_nesting_; - - Handle<Object> receiver_; + // Fields possibly needed for eager compilation, NULL by default. + v8::Extension* extension_; + ScriptDataImpl* pre_parse_data_; - bool has_this_properties_; - bool has_globals_; + // The context of the caller is needed for eval code, and will be a null + // handle otherwise. + Handle<Context> calling_context_; DISALLOW_COPY_AND_ASSIGN(CompilationInfo); }; @@ -163,13 +147,13 @@ class CompilationInfo BASE_EMBEDDED { // functions, they will be compiled and allocated as part of the compilation // of the source code. -// Please note this interface returns shared function infos. -// This means you need to call Factory::NewFunctionFromSharedFunctionInfo -// before you have a real function with a context. +// Please note this interface returns shared function infos. This means you +// need to call Factory::NewFunctionFromSharedFunctionInfo before you have a +// real function with a context. class Compiler : public AllStatic { public: - enum ValidationState { VALIDATE_JSON, DONT_VALIDATE_JSON }; + enum ValidationState { DONT_VALIDATE_JSON, VALIDATE_JSON }; // All routines return a JSFunction. // If an error occurs an exception is raised and @@ -191,17 +175,14 @@ class Compiler : public AllStatic { bool is_global, ValidationState validation); - // Compile from function info (used for lazy compilation). Returns - // true on success and false if the compilation resulted in a stack - // overflow. + // Compile from function info (used for lazy compilation). Returns true on + // success and false if the compilation resulted in a stack overflow. static bool CompileLazy(CompilationInfo* info); - // Compile a shared function info object (the function is possibly - // lazily compiled). Called recursively from a backend code - // generator 'caller' to build the shared function info. + // Compile a shared function info object (the function is possibly lazily + // compiled). static Handle<SharedFunctionInfo> BuildFunctionInfo(FunctionLiteral* node, - Handle<Script> script, - AstVisitor* caller); + Handle<Script> script); // Set the function info for a newly compiled function. static void SetFunctionInfo(Handle<SharedFunctionInfo> function_info, @@ -209,23 +190,18 @@ class Compiler : public AllStatic { bool is_toplevel, Handle<Script> script); +#ifdef ENABLE_DEBUGGER_SUPPORT + static bool MakeCodeForLiveEdit(CompilationInfo* info); +#endif + private: static void RecordFunctionCompilation(Logger::LogEventsAndTags tag, Handle<String> name, - Handle<String> inferred_name, int start_position, - Handle<Script> script, - Handle<Code> code); + CompilationInfo* info); }; -#ifdef ENABLE_DEBUGGER_SUPPORT - -Handle<Code> MakeCodeForLiveEdit(CompilationInfo* info); - -#endif - - // During compilation we need a global list of handles to constants // for frame elements. When the zone gets deleted, we make sure to // clear this list of handles as well. diff --git a/src/contexts.cc b/src/contexts.cc index 723354fc..1ce5007d 100644 --- a/src/contexts.cc +++ b/src/contexts.cc @@ -90,7 +90,7 @@ Handle<Object> Context::Lookup(Handle<String> name, ContextLookupFlags flags, do { if (FLAG_trace_contexts) { - PrintF(" - looking in context %p", *context); + PrintF(" - looking in context %p", reinterpret_cast<void*>(*context)); if (context->IsGlobalContext()) PrintF(" (global context)"); PrintF("\n"); } @@ -110,7 +110,8 @@ Handle<Object> Context::Lookup(Handle<String> name, ContextLookupFlags flags, if (*attributes != ABSENT) { // property found if (FLAG_trace_contexts) { - PrintF("=> found property in context object %p\n", *extension); + PrintF("=> found property in context object %p\n", + reinterpret_cast<void*>(*extension)); } return extension; } diff --git a/src/contexts.h b/src/contexts.h index 78dda6a6..9722a938 100644 --- a/src/contexts.h +++ b/src/contexts.h @@ -225,7 +225,15 @@ class Context: public FixedArray { OUT_OF_MEMORY_INDEX, MAP_CACHE_INDEX, CONTEXT_DATA_INDEX, - GLOBAL_CONTEXT_SLOTS + + // Properties from here are treated as weak references by the full GC. + // Scavenge treats them as strong references. + NEXT_CONTEXT_LINK, + + // Total number of slots. + GLOBAL_CONTEXT_SLOTS, + + FIRST_WEAK_SLOT = NEXT_CONTEXT_LINK }; // Direct slot access. @@ -333,6 +341,17 @@ class Context: public FixedArray { return kHeaderSize + index * kPointerSize - kHeapObjectTag; } + static const int kSize = kHeaderSize + GLOBAL_CONTEXT_SLOTS * kPointerSize; + + // GC support. + typedef FixedBodyDescriptor< + kHeaderSize, kSize, kSize> ScavengeBodyDescriptor; + + typedef FixedBodyDescriptor< + kHeaderSize, + kHeaderSize + FIRST_WEAK_SLOT * kPointerSize, + kSize> MarkCompactBodyDescriptor; + private: // Unchecked access to the slots. Object* unchecked_previous() { return get(PREVIOUS_INDEX); } diff --git a/src/conversions.cc b/src/conversions.cc index f15a804e..790e807a 100644 --- a/src/conversions.cc +++ b/src/conversions.cc @@ -34,6 +34,7 @@ #include "dtoa.h" #include "factory.h" #include "scanner.h" +#include "strtod.h" namespace v8 { namespace internal { @@ -103,8 +104,6 @@ static bool SubStringEquals(Iterator* current, } -extern "C" double gay_strtod(const char* s00, const char** se); - // Maximum number of significant digits in decimal representation. // The longest possible double in decimal representation is // (2^53 - 1) * 2 ^ -1074 that is (2 ^ 53 - 1) * 5 ^ 1074 / 10 ^ 1074 @@ -353,8 +352,9 @@ static double InternalStringToInt(Iterator current, EndMark end, int radix) { } ASSERT(buffer_pos < kBufferSize); - buffer[buffer_pos++] = '\0'; - return sign ? -gay_strtod(buffer, NULL) : gay_strtod(buffer, NULL); + buffer[buffer_pos] = '\0'; + Vector<const char> buffer_vector(buffer, buffer_pos); + return sign ? -Strtod(buffer_vector, 0) : Strtod(buffer_vector, 0); } // The following code causes accumulating rounding error for numbers greater @@ -462,7 +462,6 @@ static double InternalStringToDouble(Iterator current, ++current; if (!AdvanceToNonspace(¤t, end)) return JUNK_STRING_VALUE; } else if (*current == '-') { - buffer[buffer_pos++] = '-'; ++current; if (!AdvanceToNonspace(¤t, end)) return JUNK_STRING_VALUE; sign = true; @@ -478,8 +477,8 @@ static double InternalStringToDouble(Iterator current, return JUNK_STRING_VALUE; } - ASSERT(buffer_pos == 0 || buffer[0] == '-'); - return buffer_pos > 0 ? -V8_INFINITY : V8_INFINITY; + ASSERT(buffer_pos == 0); + return sign ? -V8_INFINITY : V8_INFINITY; } bool leading_zero = false; @@ -496,7 +495,6 @@ static double InternalStringToDouble(Iterator current, return JUNK_STRING_VALUE; // "0x". } - bool sign = (buffer_pos > 0 && buffer[0] == '-'); return InternalStringToIntDouble<4>(current, end, sign, @@ -533,6 +531,9 @@ static double InternalStringToDouble(Iterator current, } if (*current == '.') { + if (octal && !allow_trailing_junk) return JUNK_STRING_VALUE; + if (octal) goto parsing_done; + ++current; if (current == end) { if (significant_digits == 0 && !leading_zero) { @@ -553,16 +554,16 @@ static double InternalStringToDouble(Iterator current, } } - ASSERT(buffer_pos < kBufferSize); - buffer[buffer_pos++] = '.'; + // We don't emit a '.', but adjust the exponent instead. fractional_part = true; - // There is the fractional part. + // There is a fractional part. while (*current >= '0' && *current <= '9') { if (significant_digits < kMaxSignificantDigits) { ASSERT(buffer_pos < kBufferSize); buffer[buffer_pos++] = static_cast<char>(*current); significant_digits++; + exponent--; } else { // Ignore insignificant digits in the fractional part. nonzero_digit_dropped = nonzero_digit_dropped || *current != '0'; @@ -638,60 +639,25 @@ static double InternalStringToDouble(Iterator current, exponent += insignificant_digits; if (octal) { - bool sign = buffer[0] == '-'; - int start_pos = (sign ? 1 : 0); - - return InternalStringToIntDouble<3>(buffer + start_pos, + return InternalStringToIntDouble<3>(buffer, buffer + buffer_pos, sign, allow_trailing_junk); } if (nonzero_digit_dropped) { - if (insignificant_digits) buffer[buffer_pos++] = '.'; buffer[buffer_pos++] = '1'; - } - - // If the number has no more than kMaxDigitsInInt digits and doesn't have - // fractional part it could be parsed faster (without checks for - // spaces, overflow, etc.). - const int kMaxDigitsInInt = 9 * sizeof(int) / 4; // NOLINT - - if (exponent != 0) { - ASSERT(buffer_pos < kBufferSize); - buffer[buffer_pos++] = 'e'; - if (exponent < 0) { - ASSERT(buffer_pos < kBufferSize); - buffer[buffer_pos++] = '-'; - exponent = -exponent; - } - if (exponent > 999) exponent = 999; // Result will be Infinity or 0 or -0. - - const int exp_digits = 3; - for (int i = 0; i < exp_digits; i++) { - buffer[buffer_pos + exp_digits - 1 - i] = '0' + exponent % 10; - exponent /= 10; - } - ASSERT(exponent == 0); - buffer_pos += exp_digits; - } else if (!fractional_part && significant_digits <= kMaxDigitsInInt) { - if (significant_digits == 0) return SignedZero(sign); - ASSERT(buffer_pos > 0); - int num = 0; - int start_pos = (buffer[0] == '-' ? 1 : 0); - for (int i = start_pos; i < buffer_pos; i++) { - ASSERT(buffer[i] >= '0' && buffer[i] <= '9'); - num = 10 * num + (buffer[i] - '0'); - } - return static_cast<double>(start_pos == 0 ? num : -num); + exponent--; } ASSERT(buffer_pos < kBufferSize); buffer[buffer_pos] = '\0'; - return gay_strtod(buffer, NULL); + double converted = Strtod(Vector<const char>(buffer, buffer_pos), exponent); + return sign? -converted: converted; } + double StringToDouble(String* str, int flags, double empty_string_val) { StringShape shape(str); if (shape.IsSequentialAscii()) { diff --git a/src/cpu-profiler.cc b/src/cpu-profiler.cc index acf3349b..da19a450 100644 --- a/src/cpu-profiler.cc +++ b/src/cpu-profiler.cc @@ -188,6 +188,20 @@ bool ProfilerEventsProcessor::IsKnownFunction(Address start) { } +void ProfilerEventsProcessor::ProcessMovedFunctions() { + for (int i = 0; i < moved_functions_.length(); ++i) { + JSFunction* function = moved_functions_[i]; + CpuProfiler::FunctionCreateEvent(function); + } + moved_functions_.Clear(); +} + + +void ProfilerEventsProcessor::RememberMovedFunction(JSFunction* function) { + moved_functions_.Add(function); +} + + void ProfilerEventsProcessor::RegExpCodeCreateEvent( Logger::LogEventsAndTags tag, const char* prefix, @@ -426,8 +440,12 @@ void CpuProfiler::FunctionCreateEvent(JSFunction* function) { } -void CpuProfiler::FunctionCreateEventFromMove(JSFunction* function, - HeapObject* source) { +void CpuProfiler::ProcessMovedFunctions() { + singleton_->processor_->ProcessMovedFunctions(); +} + + +void CpuProfiler::FunctionCreateEventFromMove(JSFunction* function) { // This function is called from GC iterators (during Scavenge, // MC, and MS), so marking bits can be set on objects. That's // why unchecked accessors are used here. @@ -436,27 +454,7 @@ void CpuProfiler::FunctionCreateEventFromMove(JSFunction* function, if (function->unchecked_code() == Builtins::builtin(Builtins::LazyCompile) || singleton_->processor_->IsKnownFunction(function->address())) return; - int security_token_id = TokenEnumerator::kNoSecurityToken; - // In debug mode, assertions may fail for contexts, - // and we can live without security tokens in debug mode. -#ifndef DEBUG - if (function->unchecked_context()->IsContext()) { - security_token_id = singleton_->token_enumerator_->GetTokenId( - function->context()->global_context()->security_token()); - } - // Security token may not be moved yet. - if (security_token_id == TokenEnumerator::kNoSecurityToken) { - JSFunction* old_function = reinterpret_cast<JSFunction*>(source); - if (old_function->unchecked_context()->IsContext()) { - security_token_id = singleton_->token_enumerator_->GetTokenId( - old_function->context()->global_context()->security_token()); - } - } -#endif - singleton_->processor_->FunctionCreateEvent( - function->address(), - function->unchecked_code()->address(), - security_token_id); + singleton_->processor_->RememberMovedFunction(function); } diff --git a/src/cpu-profiler.h b/src/cpu-profiler.h index 86f9f671..d3158d7a 100644 --- a/src/cpu-profiler.h +++ b/src/cpu-profiler.h @@ -165,6 +165,8 @@ class ProfilerEventsProcessor : public Thread { // Puts current stack into tick sample events buffer. void AddCurrentStack(); bool IsKnownFunction(Address start); + void ProcessMovedFunctions(); + void RememberMovedFunction(JSFunction* function); // Tick sample events are filled directly in the buffer of the circular // queue (because the structure is of fixed width, but usually not all @@ -202,6 +204,7 @@ class ProfilerEventsProcessor : public Thread { // Used from the VM thread. HashMap* known_functions_; + List<JSFunction*> moved_functions_; }; } } // namespace v8::internal @@ -251,17 +254,18 @@ class CpuProfiler { String* source, int line); static void CodeCreateEvent(Logger::LogEventsAndTags tag, Code* code, int args_count); + static void CodeMovingGCEvent() {} static void CodeMoveEvent(Address from, Address to); static void CodeDeleteEvent(Address from); static void FunctionCreateEvent(JSFunction* function); // Reports function creation in case we had missed it (e.g. // if it was created from compiled code). - static void FunctionCreateEventFromMove(JSFunction* function, - HeapObject* source); + static void FunctionCreateEventFromMove(JSFunction* function); static void FunctionMoveEvent(Address from, Address to); static void FunctionDeleteEvent(Address from); static void GetterCallbackEvent(String* name, Address entry_point); static void RegExpCodeCreateEvent(Code* code, String* source); + static void ProcessMovedFunctions(); static void SetterCallbackEvent(String* name, Address entry_point); static INLINE(bool is_profiling()) { @@ -949,7 +949,7 @@ function DebugResponseDetails(response) { case 'suspend': details.text = 'stopped'; break; - + case 'setbreakpoint': result = 'set breakpoint #'; result += body.breakpoint; @@ -961,7 +961,7 @@ function DebugResponseDetails(response) { result += body.breakpoint; details.text = result; break; - + case 'listbreakpoints': result = 'breakpoints: (' + body.breakpoints.length + ')'; for (var i = 0; i < body.breakpoints.length; i++) { diff --git a/src/data-flow.cc b/src/data-flow.cc index 44a10506..be824460 100644 --- a/src/data-flow.cc +++ b/src/data-flow.cc @@ -42,7 +42,7 @@ void BitVector::Print() { if (Contains(i)) { if (!first) PrintF(","); first = false; - PrintF("%d"); + PrintF("%d", i); } } PrintF("}"); @@ -50,12 +50,13 @@ void BitVector::Print() { #endif -bool AssignedVariablesAnalyzer::Analyze() { - Scope* scope = fun_->scope(); +bool AssignedVariablesAnalyzer::Analyze(CompilationInfo* info) { + info_ = info; + Scope* scope = info->scope(); int variables = scope->num_parameters() + scope->num_stack_slots(); if (variables == 0) return true; av_.ExpandTo(variables); - VisitStatements(fun_->body()); + VisitStatements(info->function()->body()); return !HasStackOverflow(); } @@ -129,7 +130,7 @@ int AssignedVariablesAnalyzer::BitIndex(Variable* var) { if (slot->type() == Slot::PARAMETER) { return slot->index(); } else { - return fun_->scope()->num_parameters() + slot->index(); + return info_->scope()->num_parameters() + slot->index(); } } diff --git a/src/data-flow.h b/src/data-flow.h index 540db162..efce1ea7 100644 --- a/src/data-flow.h +++ b/src/data-flow.h @@ -198,8 +198,8 @@ class WorkList BASE_EMBEDDED { // is guaranteed to be a smi. class AssignedVariablesAnalyzer : public AstVisitor { public: - explicit AssignedVariablesAnalyzer(FunctionLiteral* fun) : fun_(fun) { } - bool Analyze(); + explicit AssignedVariablesAnalyzer() : info_(NULL) { } + bool Analyze(CompilationInfo* info); private: Variable* FindSmiLoopVariable(ForStatement* stmt); @@ -219,7 +219,7 @@ class AssignedVariablesAnalyzer : public AstVisitor { AST_NODE_LIST(DECLARE_VISIT) #undef DECLARE_VISIT - FunctionLiteral* fun_; + CompilationInfo* info_; // Accumulator for assigned variables set. BitVector av_; diff --git a/src/date.js b/src/date.js index b101ea66..96014707 100644 --- a/src/date.js +++ b/src/date.js @@ -246,7 +246,7 @@ function LocalTime(time) { var ltcache = { - key: null, + key: null, val: null }; diff --git a/src/debug-debugger.js b/src/debug-debugger.js index 34eb0f0e..a0c68081 100644 --- a/src/debug-debugger.js +++ b/src/debug-debugger.js @@ -2118,7 +2118,7 @@ DebugCommandProcessor.prototype.changeLiveRequest_ = function(request, response) } var script_id = request.arguments.script_id; var preview_only = !!request.arguments.preview_only; - + var scripts = %DebugGetLoadedScripts(); var the_script = null; @@ -2139,11 +2139,11 @@ DebugCommandProcessor.prototype.changeLiveRequest_ = function(request, response) } var new_source = request.arguments.new_source; - + var result_description = Debug.LiveEdit.SetScriptSource(the_script, new_source, preview_only, change_log); response.body = {change_log: change_log, result: result_description}; - + if (!preview_only && !this.running_ && result_description.stack_modified) { response.body.stepin_recommended = true; } diff --git a/src/disassembler.cc b/src/disassembler.cc index e79421fe..2a4ea74e 100644 --- a/src/disassembler.cc +++ b/src/disassembler.cc @@ -44,7 +44,10 @@ namespace internal { void Disassembler::Dump(FILE* f, byte* begin, byte* end) { for (byte* pc = begin; pc < end; pc++) { if (f == NULL) { - PrintF("%" V8PRIxPTR " %4" V8PRIdPTR " %02x\n", pc, pc - begin, *pc); + PrintF("%" V8PRIxPTR " %4" V8PRIdPTR " %02x\n", + reinterpret_cast<intptr_t>(pc), + pc - begin, + *pc); } else { fprintf(f, "%" V8PRIxPTR " %4" V8PRIdPTR " %02x\n", reinterpret_cast<uintptr_t>(pc), pc - begin, *pc); diff --git a/src/execution.cc b/src/execution.cc index 54216784..68623247 100644 --- a/src/execution.cc +++ b/src/execution.cc @@ -473,6 +473,19 @@ Handle<Object> Execution::NewDate(double time, bool* exc) { #undef RETURN_NATIVE_CALL +Handle<JSRegExp> Execution::NewJSRegExp(Handle<String> pattern, + Handle<String> flags, + bool* exc) { + Handle<Object> re_obj = RegExpImpl::CreateRegExpLiteral( + Handle<JSFunction>(Top::global_context()->regexp_function()), + pattern, + flags, + exc); + if (*exc) return Handle<JSRegExp>(); + return Handle<JSRegExp>::cast(re_obj); +} + + Handle<Object> Execution::CharAt(Handle<String> string, uint32_t index) { int int_index = static_cast<int>(index); if (int_index < 0 || int_index >= string->length()) { diff --git a/src/execution.h b/src/execution.h index 28235033..15d85ef4 100644 --- a/src/execution.h +++ b/src/execution.h @@ -105,6 +105,11 @@ class Execution : public AllStatic { // Create a new date object from 'time'. static Handle<Object> NewDate(double time, bool* exc); + // Create a new regular expression object from 'pattern' and 'flags'. + static Handle<JSRegExp> NewJSRegExp(Handle<String> pattern, + Handle<String> flags, + bool* exc); + // Used to implement [] notation on strings (calls JS code) static Handle<Object> CharAt(Handle<String> str, uint32_t index); diff --git a/src/fast-dtoa.cc b/src/fast-dtoa.cc index d2a00cc6..ce825f9d 100644 --- a/src/fast-dtoa.cc +++ b/src/fast-dtoa.cc @@ -609,8 +609,13 @@ static bool Grisu3(double v, ASSERT(boundary_plus.e() == w.e()); DiyFp ten_mk; // Cached power of ten: 10^-k int mk; // -k - GetCachedPower(w.e() + DiyFp::kSignificandSize, kMinimalTargetExponent, - kMaximalTargetExponent, &mk, &ten_mk); + int ten_mk_minimal_binary_exponent = + kMinimalTargetExponent - (w.e() + DiyFp::kSignificandSize); + int ten_mk_maximal_binary_exponent = + kMaximalTargetExponent - (w.e() + DiyFp::kSignificandSize); + GetCachedPowerForBinaryExponentRange(ten_mk_minimal_binary_exponent, + ten_mk_maximal_binary_exponent, + &ten_mk, &mk); ASSERT((kMinimalTargetExponent <= w.e() + ten_mk.e() + DiyFp::kSignificandSize) && (kMaximalTargetExponent >= w.e() + ten_mk.e() + @@ -662,8 +667,13 @@ static bool Grisu3Counted(double v, DiyFp w = Double(v).AsNormalizedDiyFp(); DiyFp ten_mk; // Cached power of ten: 10^-k int mk; // -k - GetCachedPower(w.e() + DiyFp::kSignificandSize, kMinimalTargetExponent, - kMaximalTargetExponent, &mk, &ten_mk); + int ten_mk_minimal_binary_exponent = + kMinimalTargetExponent - (w.e() + DiyFp::kSignificandSize); + int ten_mk_maximal_binary_exponent = + kMaximalTargetExponent - (w.e() + DiyFp::kSignificandSize); + GetCachedPowerForBinaryExponentRange(ten_mk_minimal_binary_exponent, + ten_mk_maximal_binary_exponent, + &ten_mk, &mk); ASSERT((kMinimalTargetExponent <= w.e() + ten_mk.e() + DiyFp::kSignificandSize) && (kMaximalTargetExponent >= w.e() + ten_mk.e() + diff --git a/src/flag-definitions.h b/src/flag-definitions.h index 263a2a40..2474c62b 100644 --- a/src/flag-definitions.h +++ b/src/flag-definitions.h @@ -108,6 +108,8 @@ DEFINE_bool(enable_sse2, true, "enable use of SSE2 instructions if available") DEFINE_bool(enable_sse3, true, "enable use of SSE3 instructions if available") +DEFINE_bool(enable_sse4_1, true, + "enable use of SSE4.1 instructions if available") DEFINE_bool(enable_cmov, true, "enable use of CMOV instruction if available") DEFINE_bool(enable_rdtsc, true, @@ -179,8 +181,8 @@ DEFINE_bool(always_inline_smi_code, false, "always inline smi code in non-opt code") // heap.cc -DEFINE_int(max_new_space_size, 0, "max size of the new generation") -DEFINE_int(max_old_space_size, 0, "max size of the old generation") +DEFINE_int(max_new_space_size, 0, "max size of the new generation (in kBytes)") +DEFINE_int(max_old_space_size, 0, "max size of the old generation (in Mbytes)") DEFINE_bool(gc_global, false, "always perform global GCs") DEFINE_int(gc_interval, -1, "garbage collect after <n> allocations") DEFINE_bool(trace_gc, false, @@ -410,6 +412,7 @@ DEFINE_bool(sliding_state_window, false, "Update sliding state window counters.") DEFINE_string(logfile, "v8.log", "Specify the name of the log file.") DEFINE_bool(oprofile, false, "Enable JIT agent for OProfile.") +DEFINE_bool(ll_prof, false, "Enable low-level linux profiler.") // // Heap protection flags diff --git a/src/full-codegen.cc b/src/full-codegen.cc index fa835cb0..97987c27 100644 --- a/src/full-codegen.cc +++ b/src/full-codegen.cc @@ -277,7 +277,7 @@ void BreakableStatementChecker::VisitThisFunction(ThisFunction* expr) { #define __ ACCESS_MASM(masm()) -Handle<Code> FullCodeGenerator::MakeCode(CompilationInfo* info) { +bool FullCodeGenerator::MakeCode(CompilationInfo* info) { Handle<Script> script = info->script(); if (!script->IsUndefined() && !script->source()->IsUndefined()) { int len = String::cast(script->source())->length(); @@ -291,10 +291,13 @@ Handle<Code> FullCodeGenerator::MakeCode(CompilationInfo* info) { cgen.Generate(info); if (cgen.HasStackOverflow()) { ASSERT(!Top::has_pending_exception()); - return Handle<Code>::null(); + return false; } + Code::Flags flags = Code::ComputeFlags(Code::FUNCTION, NOT_IN_LOOP); - return CodeGenerator::MakeCodeEpilogue(&masm, flags, info); + Handle<Code> code = CodeGenerator::MakeCodeEpilogue(&masm, flags, info); + info->SetCode(code); // may be an empty handle. + return !code.is_null(); } @@ -462,9 +465,12 @@ void FullCodeGenerator::VisitDeclarations( } } else { Handle<SharedFunctionInfo> function = - Compiler::BuildFunctionInfo(decl->fun(), script(), this); + Compiler::BuildFunctionInfo(decl->fun(), script()); // Check for stack-overflow exception. - if (HasStackOverflow()) return; + if (function.is_null()) { + SetStackOverflow(); + return; + } array->set(j++, *function); } } @@ -1122,9 +1128,14 @@ void FullCodeGenerator::VisitConditional(Conditional* expr) { __ bind(&true_case); SetExpressionPosition(expr->then_expression(), expr->then_expression_position()); - Visit(expr->then_expression()); - // If control flow falls through Visit, jump to done. - if (!context()->IsTest()) { + if (context()->IsTest()) { + const TestContext* for_test = TestContext::cast(context()); + VisitForControl(expr->then_expression(), + for_test->true_label(), + for_test->false_label(), + NULL); + } else { + Visit(expr->then_expression()); __ jmp(&done); } @@ -1156,8 +1167,11 @@ void FullCodeGenerator::VisitFunctionLiteral(FunctionLiteral* expr) { // Build the function boilerplate and instantiate it. Handle<SharedFunctionInfo> function_info = - Compiler::BuildFunctionInfo(expr, script(), this); - if (HasStackOverflow()) return; + Compiler::BuildFunctionInfo(expr, script()); + if (function_info.is_null()) { + SetStackOverflow(); + return; + } EmitNewClosure(function_info); } diff --git a/src/full-codegen.h b/src/full-codegen.h index 03024e19..201507b2 100644 --- a/src/full-codegen.h +++ b/src/full-codegen.h @@ -74,7 +74,7 @@ class FullCodeGenerator: public AstVisitor { context_(NULL) { } - static Handle<Code> MakeCode(CompilationInfo* info); + static bool MakeCode(CompilationInfo* info); void Generate(CompilationInfo* info); @@ -604,6 +604,15 @@ class FullCodeGenerator: public AstVisitor { false_label_(false_label), fall_through_(fall_through) { } + static const TestContext* cast(const ExpressionContext* context) { + ASSERT(context->IsTest()); + return reinterpret_cast<const TestContext*>(context); + } + + Label* true_label() const { return true_label_; } + Label* false_label() const { return false_label_; } + Label* fall_through() const { return fall_through_; } + virtual void Plug(bool flag) const; virtual void Plug(Register reg) const; virtual void Plug(Label* materialize_true, Label* materialize_false) const; diff --git a/src/global-handles.cc b/src/global-handles.cc index a909caf3..02073227 100644 --- a/src/global-handles.cc +++ b/src/global-handles.cc @@ -486,7 +486,7 @@ void GlobalHandles::PrintStats() { } PrintF("Global Handle Statistics:\n"); - PrintF(" allocated memory = %dB\n", sizeof(Node) * total); + PrintF(" allocated memory = %" V8_PTR_PREFIX "dB\n", sizeof(Node) * total); PrintF(" # weak = %d\n", weak); PrintF(" # pending = %d\n", pending); PrintF(" # near_death = %d\n", near_death); @@ -497,8 +497,10 @@ void GlobalHandles::PrintStats() { void GlobalHandles::Print() { PrintF("Global handles:\n"); for (Node* current = head_; current != NULL; current = current->next()) { - PrintF(" handle %p to %p (weak=%d)\n", current->handle().location(), - *current->handle(), current->state_ == Node::WEAK); + PrintF(" handle %p to %p (weak=%d)\n", + reinterpret_cast<void*>(current->handle().location()), + reinterpret_cast<void*>(*current->handle()), + current->state_ == Node::WEAK); } } diff --git a/src/handles.cc b/src/handles.cc index 78a7fcf9..8fe29bb7 100644 --- a/src/handles.cc +++ b/src/handles.cc @@ -175,7 +175,7 @@ static int ExpectedNofPropertiesFromEstimate(int estimate) { // Inobject slack tracking will reclaim redundant inobject space later, // so we can afford to adjust the estimate generously. - return estimate + 6; + return estimate + 8; } @@ -635,8 +635,19 @@ v8::Handle<v8::Array> GetKeysForIndexedInterceptor(Handle<JSObject> receiver, } +static bool ContainsOnlyValidKeys(Handle<FixedArray> array) { + int len = array->length(); + for (int i = 0; i < len; i++) { + Object* e = array->get(i); + if (!(e->IsString() || e->IsNumber())) return false; + } + return true; +} + + Handle<FixedArray> GetKeysInFixedArrayFor(Handle<JSObject> object, KeyCollectionType type) { + USE(ContainsOnlyValidKeys); Handle<FixedArray> content = Factory::empty_fixed_array(); Handle<JSObject> arguments_boilerplate = Handle<JSObject>( @@ -664,6 +675,7 @@ Handle<FixedArray> GetKeysInFixedArrayFor(Handle<JSObject> object, Factory::NewFixedArray(current->NumberOfEnumElements()); current->GetEnumElementKeys(*element_keys); content = UnionOfKeys(content, element_keys); + ASSERT(ContainsOnlyValidKeys(content)); // Add the element keys from the interceptor. if (current->HasIndexedInterceptor()) { @@ -671,6 +683,7 @@ Handle<FixedArray> GetKeysInFixedArrayFor(Handle<JSObject> object, GetKeysForIndexedInterceptor(object, current); if (!result.IsEmpty()) content = AddKeysFromJSArray(content, v8::Utils::OpenHandle(*result)); + ASSERT(ContainsOnlyValidKeys(content)); } // We can cache the computed property keys if access checks are @@ -692,6 +705,7 @@ Handle<FixedArray> GetKeysInFixedArrayFor(Handle<JSObject> object, // Compute the property keys and cache them if possible. content = UnionOfKeys(content, GetEnumPropertyKeys(current, cache_enum_keys)); + ASSERT(ContainsOnlyValidKeys(content)); // Add the property keys from the interceptor. if (current->HasNamedInterceptor()) { @@ -699,6 +713,7 @@ Handle<FixedArray> GetKeysInFixedArrayFor(Handle<JSObject> object, GetKeysForNamedInterceptor(object, current); if (!result.IsEmpty()) content = AddKeysFromJSArray(content, v8::Utils::OpenHandle(*result)); + ASSERT(ContainsOnlyValidKeys(content)); } // If we only want local properties we bail out after the first @@ -785,15 +800,16 @@ bool CompileLazyShared(Handle<SharedFunctionInfo> shared, bool CompileLazy(Handle<JSFunction> function, - Handle<Object> receiver, ClearExceptionFlag flag) { if (function->shared()->is_compiled()) { function->set_code(function->shared()->code()); + PROFILE(FunctionCreateEvent(*function)); function->shared()->set_code_age(0); return true; } else { - CompilationInfo info(function, 0, receiver); + CompilationInfo info(function); bool result = CompileLazyHelper(&info, flag); + ASSERT(!result || function->is_compiled()); PROFILE(FunctionCreateEvent(*function)); return result; } @@ -801,15 +817,17 @@ bool CompileLazy(Handle<JSFunction> function, bool CompileLazyInLoop(Handle<JSFunction> function, - Handle<Object> receiver, ClearExceptionFlag flag) { if (function->shared()->is_compiled()) { function->set_code(function->shared()->code()); + PROFILE(FunctionCreateEvent(*function)); function->shared()->set_code_age(0); return true; } else { - CompilationInfo info(function, 1, receiver); + CompilationInfo info(function); + info.MarkAsInLoop(); bool result = CompileLazyHelper(&info, flag); + ASSERT(!result || function->is_compiled()); PROFILE(FunctionCreateEvent(*function)); return result; } diff --git a/src/handles.h b/src/handles.h index 135dbfb5..69170ff2 100644 --- a/src/handles.h +++ b/src/handles.h @@ -345,13 +345,9 @@ bool EnsureCompiled(Handle<SharedFunctionInfo> shared, bool CompileLazyShared(Handle<SharedFunctionInfo> shared, ClearExceptionFlag flag); -bool CompileLazy(Handle<JSFunction> function, - Handle<Object> receiver, - ClearExceptionFlag flag); +bool CompileLazy(Handle<JSFunction> function, ClearExceptionFlag flag); -bool CompileLazyInLoop(Handle<JSFunction> function, - Handle<Object> receiver, - ClearExceptionFlag flag); +bool CompileLazyInLoop(Handle<JSFunction> function, ClearExceptionFlag flag); class NoHandleAllocation BASE_EMBEDDED { public: diff --git a/src/heap-inl.h b/src/heap-inl.h index b68f5c1c..104292df 100644 --- a/src/heap-inl.h +++ b/src/heap-inl.h @@ -36,7 +36,7 @@ namespace v8 { namespace internal { void Heap::UpdateOldSpaceLimits() { - int old_gen_size = PromotedSpaceSize(); + intptr_t old_gen_size = PromotedSpaceSize(); old_gen_promotion_limit_ = old_gen_size + Max(kMinimumPromotionLimit, old_gen_size / 3); old_gen_allocation_limit_ = @@ -76,7 +76,7 @@ Object* Heap::AllocateRaw(int size_in_bytes, if (FLAG_gc_interval >= 0 && !disallow_allocation_failure_ && Heap::allocation_timeout_-- <= 0) { - return Failure::RetryAfterGC(size_in_bytes, space); + return Failure::RetryAfterGC(space); } Counters::objs_since_last_full.Increment(); Counters::objs_since_last_young.Increment(); @@ -389,8 +389,12 @@ void Heap::SetLastScriptId(Object* last_script_id) { } +#ifdef DEBUG #define GC_GREEDY_CHECK() \ - ASSERT(!FLAG_gc_greedy || v8::internal::Heap::GarbageCollectionGreedyCheck()) + if (FLAG_gc_greedy) v8::internal::Heap::GarbageCollectionGreedyCheck() +#else +#define GC_GREEDY_CHECK() { } +#endif // Calls the FUNCTION_CALL function and retries it up to three times @@ -409,8 +413,7 @@ void Heap::SetLastScriptId(Object* last_script_id) { v8::internal::V8::FatalProcessOutOfMemory("CALL_AND_RETRY_0", true);\ } \ if (!__object__->IsRetryAfterGC()) RETURN_EMPTY; \ - Heap::CollectGarbage(Failure::cast(__object__)->requested(), \ - Failure::cast(__object__)->allocation_space()); \ + Heap::CollectGarbage(Failure::cast(__object__)->allocation_space()); \ __object__ = FUNCTION_CALL; \ if (!__object__->IsFailure()) RETURN_VALUE; \ if (__object__->IsOutOfMemoryFailure()) { \ diff --git a/src/heap.cc b/src/heap.cc index 047e3316..675639a3 100644 --- a/src/heap.cc +++ b/src/heap.cc @@ -54,6 +54,7 @@ namespace internal { String* Heap::hidden_symbol_; Object* Heap::roots_[Heap::kRootListLength]; +Object* Heap::global_contexts_list_; NewSpace Heap::new_space_; OldSpace* Heap::old_pointer_space_ = NULL; @@ -63,8 +64,8 @@ MapSpace* Heap::map_space_ = NULL; CellSpace* Heap::cell_space_ = NULL; LargeObjectSpace* Heap::lo_space_ = NULL; -int Heap::old_gen_promotion_limit_ = kMinimumPromotionLimit; -int Heap::old_gen_allocation_limit_ = kMinimumAllocationLimit; +intptr_t Heap::old_gen_promotion_limit_ = kMinimumPromotionLimit; +intptr_t Heap::old_gen_allocation_limit_ = kMinimumAllocationLimit; int Heap::old_gen_exhausted_ = false; @@ -75,19 +76,19 @@ int Heap::amount_of_external_allocated_memory_at_last_global_gc_ = 0; // a multiple of Page::kPageSize. #if defined(ANDROID) int Heap::max_semispace_size_ = 2*MB; -int Heap::max_old_generation_size_ = 192*MB; +intptr_t Heap::max_old_generation_size_ = 192*MB; int Heap::initial_semispace_size_ = 128*KB; -size_t Heap::code_range_size_ = 0; +intptr_t Heap::code_range_size_ = 0; #elif defined(V8_TARGET_ARCH_X64) int Heap::max_semispace_size_ = 16*MB; -int Heap::max_old_generation_size_ = 1*GB; +intptr_t Heap::max_old_generation_size_ = 1*GB; int Heap::initial_semispace_size_ = 1*MB; -size_t Heap::code_range_size_ = 512*MB; +intptr_t Heap::code_range_size_ = 512*MB; #else int Heap::max_semispace_size_ = 8*MB; -int Heap::max_old_generation_size_ = 512*MB; +intptr_t Heap::max_old_generation_size_ = 512*MB; int Heap::initial_semispace_size_ = 512*KB; -size_t Heap::code_range_size_ = 0; +intptr_t Heap::code_range_size_ = 0; #endif // The snapshot semispace size will be the default semispace size if @@ -108,7 +109,7 @@ HeapObjectCallback Heap::gc_safe_size_of_old_object_ = NULL; // Will be 4 * reserved_semispace_size_ to ensure that young // generation can be aligned to its size. int Heap::survived_since_last_expansion_ = 0; -int Heap::external_allocation_limit_ = 0; +intptr_t Heap::external_allocation_limit_ = 0; Heap::HeapState Heap::gc_state_ = NOT_IN_GC; @@ -137,13 +138,13 @@ int Heap::allocation_timeout_ = 0; bool Heap::disallow_allocation_failure_ = false; #endif // DEBUG -int GCTracer::alive_after_last_gc_ = 0; +intptr_t GCTracer::alive_after_last_gc_ = 0; double GCTracer::last_gc_end_timestamp_ = 0.0; int GCTracer::max_gc_pause_ = 0; -int GCTracer::max_alive_after_gc_ = 0; +intptr_t GCTracer::max_alive_after_gc_ = 0; int GCTracer::min_in_mutator_ = kMaxInt; -int Heap::Capacity() { +intptr_t Heap::Capacity() { if (!HasBeenSetup()) return 0; return new_space_.Capacity() + @@ -155,7 +156,7 @@ int Heap::Capacity() { } -int Heap::CommittedMemory() { +intptr_t Heap::CommittedMemory() { if (!HasBeenSetup()) return 0; return new_space_.CommittedMemory() + @@ -168,7 +169,7 @@ int Heap::CommittedMemory() { } -int Heap::Available() { +intptr_t Heap::Available() { if (!HasBeenSetup()) return 0; return new_space_.Available() + @@ -289,33 +290,46 @@ void Heap::ReportStatisticsBeforeGC() { #if defined(ENABLE_LOGGING_AND_PROFILING) void Heap::PrintShortHeapStatistics() { if (!FLAG_trace_gc_verbose) return; - PrintF("Memory allocator, used: %8d, available: %8d\n", + PrintF("Memory allocator, used: %8" V8_PTR_PREFIX "d" + ", available: %8" V8_PTR_PREFIX "d\n", MemoryAllocator::Size(), MemoryAllocator::Available()); - PrintF("New space, used: %8d, available: %8d\n", + PrintF("New space, used: %8" V8_PTR_PREFIX "d" + ", available: %8" V8_PTR_PREFIX "d\n", Heap::new_space_.Size(), new_space_.Available()); - PrintF("Old pointers, used: %8d, available: %8d, waste: %8d\n", + PrintF("Old pointers, used: %8" V8_PTR_PREFIX "d" + ", available: %8" V8_PTR_PREFIX "d" + ", waste: %8" V8_PTR_PREFIX "d\n", old_pointer_space_->Size(), old_pointer_space_->Available(), old_pointer_space_->Waste()); - PrintF("Old data space, used: %8d, available: %8d, waste: %8d\n", + PrintF("Old data space, used: %8" V8_PTR_PREFIX "d" + ", available: %8" V8_PTR_PREFIX "d" + ", waste: %8" V8_PTR_PREFIX "d\n", old_data_space_->Size(), old_data_space_->Available(), old_data_space_->Waste()); - PrintF("Code space, used: %8d, available: %8d, waste: %8d\n", + PrintF("Code space, used: %8" V8_PTR_PREFIX "d" + ", available: %8" V8_PTR_PREFIX "d" + ", waste: %8" V8_PTR_PREFIX "d\n", code_space_->Size(), code_space_->Available(), code_space_->Waste()); - PrintF("Map space, used: %8d, available: %8d, waste: %8d\n", + PrintF("Map space, used: %8" V8_PTR_PREFIX "d" + ", available: %8" V8_PTR_PREFIX "d" + ", waste: %8" V8_PTR_PREFIX "d\n", map_space_->Size(), map_space_->Available(), map_space_->Waste()); - PrintF("Cell space, used: %8d, available: %8d, waste: %8d\n", + PrintF("Cell space, used: %8" V8_PTR_PREFIX "d" + ", available: %8" V8_PTR_PREFIX "d" + ", waste: %8" V8_PTR_PREFIX "d\n", cell_space_->Size(), cell_space_->Available(), cell_space_->Waste()); - PrintF("Large object space, used: %8d, avaialble: %8d\n", + PrintF("Large object space, used: %8" V8_PTR_PREFIX "d" + ", available: %8" V8_PTR_PREFIX "d\n", lo_space_->Size(), lo_space_->Available()); } @@ -364,8 +378,8 @@ void Heap::GarbageCollectionPrologue() { #endif } -int Heap::SizeOfObjects() { - int total = 0; +intptr_t Heap::SizeOfObjects() { + intptr_t total = 0; AllSpaces spaces; for (Space* space = spaces.next(); space != NULL; space = spaces.next()) { total += space->Size(); @@ -388,7 +402,7 @@ void Heap::GarbageCollectionEpilogue() { if (FLAG_code_stats) ReportCodeStatistics("After GC"); #endif - Counters::alive_after_last_gc.Set(SizeOfObjects()); + Counters::alive_after_last_gc.Set(static_cast<int>(SizeOfObjects())); Counters::symbol_table_capacity.Set(symbol_table()->Capacity()); Counters::number_of_symbols.Set(symbol_table()->NumberOfElements()); @@ -407,7 +421,7 @@ void Heap::CollectAllGarbage(bool force_compaction, // not matter, so long as we do not specify NEW_SPACE, which would not // cause a full GC. MarkCompactCollector::SetForceCompaction(force_compaction); - CollectGarbage(0, OLD_POINTER_SPACE, collectionPolicy); + CollectGarbage(OLD_POINTER_SPACE, collectionPolicy); MarkCompactCollector::SetForceCompaction(false); } @@ -418,8 +432,7 @@ void Heap::CollectAllAvailableGarbage() { } -bool Heap::CollectGarbage(int requested_size, - AllocationSpace space, +void Heap::CollectGarbage(AllocationSpace space, CollectionPolicy collectionPolicy) { // The VM is in the GC state until exiting this function. VMState state(GC); @@ -456,25 +469,8 @@ bool Heap::CollectGarbage(int requested_size, #ifdef ENABLE_LOGGING_AND_PROFILING if (FLAG_log_gc) HeapProfiler::WriteSample(); + if (CpuProfiler::is_profiling()) CpuProfiler::ProcessMovedFunctions(); #endif - - switch (space) { - case NEW_SPACE: - return new_space_.Available() >= requested_size; - case OLD_POINTER_SPACE: - return old_pointer_space_->Available() >= requested_size; - case OLD_DATA_SPACE: - return old_data_space_->Available() >= requested_size; - case CODE_SPACE: - return code_space_->Available() >= requested_size; - case MAP_SPACE: - return map_space_->Available() >= requested_size; - case CELL_SPACE: - return cell_space_->Available() >= requested_size; - case LO_SPACE: - return lo_space_->Available() >= requested_size; - } - return false; } @@ -529,27 +525,27 @@ void Heap::ReserveSpace( while (gc_performed) { gc_performed = false; if (!new_space->ReserveSpace(new_space_size)) { - Heap::CollectGarbage(new_space_size, NEW_SPACE); + Heap::CollectGarbage(NEW_SPACE); gc_performed = true; } if (!old_pointer_space->ReserveSpace(pointer_space_size)) { - Heap::CollectGarbage(pointer_space_size, OLD_POINTER_SPACE); + Heap::CollectGarbage(OLD_POINTER_SPACE); gc_performed = true; } if (!(old_data_space->ReserveSpace(data_space_size))) { - Heap::CollectGarbage(data_space_size, OLD_DATA_SPACE); + Heap::CollectGarbage(OLD_DATA_SPACE); gc_performed = true; } if (!(code_space->ReserveSpace(code_space_size))) { - Heap::CollectGarbage(code_space_size, CODE_SPACE); + Heap::CollectGarbage(CODE_SPACE); gc_performed = true; } if (!(map_space->ReserveSpace(map_space_size))) { - Heap::CollectGarbage(map_space_size, MAP_SPACE); + Heap::CollectGarbage(MAP_SPACE); gc_performed = true; } if (!(cell_space->ReserveSpace(cell_space_size))) { - Heap::CollectGarbage(cell_space_size, CELL_SPACE); + Heap::CollectGarbage(CELL_SPACE); gc_performed = true; } // We add a slack-factor of 2 in order to have space for a series of @@ -561,7 +557,7 @@ void Heap::ReserveSpace( large_object_size += cell_space_size + map_space_size + code_space_size + data_space_size + pointer_space_size; if (!(lo_space->ReserveSpace(large_object_size))) { - Heap::CollectGarbage(large_object_size, LO_SPACE); + Heap::CollectGarbage(LO_SPACE); gc_performed = true; } } @@ -611,19 +607,14 @@ void Heap::ClearJSFunctionResultCaches() { } -class ClearThreadNormalizedMapCachesVisitor: public ThreadVisitor { - virtual void VisitThread(ThreadLocalTop* top) { - Context* context = top->context_; - if (context == NULL) return; - context->global()->global_context()->normalized_map_cache()->Clear(); - } -}; - - void Heap::ClearNormalizedMapCaches() { if (Bootstrapper::IsActive()) return; - ClearThreadNormalizedMapCachesVisitor visitor; - ThreadManager::IterateArchivedThreads(&visitor); + + Object* context = global_contexts_list_; + while (!context->IsUndefined()) { + Context::cast(context)->normalized_map_cache()->Clear(); + context = Context::cast(context)->get(Context::NEXT_CONTEXT_LINK); + } } @@ -672,6 +663,10 @@ void Heap::UpdateSurvivalRateTrend(int start_new_space_size) { void Heap::PerformGarbageCollection(GarbageCollector collector, GCTracer* tracer, CollectionPolicy collectionPolicy) { + if (collector != SCAVENGER) { + PROFILE(CodeMovingGCEvent()); + } + VerifySymbolTable(); if (collector == MARK_COMPACTOR && global_gc_prologue_callback_) { ASSERT(!allocation_allowed_); @@ -690,7 +685,7 @@ void Heap::PerformGarbageCollection(GarbageCollector collector, EnsureFromSpaceIsCommitted(); - int start_new_space_size = Heap::new_space()->Size(); + int start_new_space_size = Heap::new_space()->SizeAsInt(); if (collector == MARK_COMPACTOR) { // Perform mark-sweep with optional compaction. @@ -962,7 +957,7 @@ void Heap::Scavenge() { DescriptorLookupCache::Clear(); // Used for updating survived_since_last_expansion_ at function end. - int survived_watermark = PromotedSpaceSize(); + intptr_t survived_watermark = PromotedSpaceSize(); CheckNewSpaceExpansionCriteria(); @@ -1021,6 +1016,9 @@ void Heap::Scavenge() { } } + // Scavenge object reachable from the global contexts list directly. + scavenge_visitor.VisitPointer(BitCast<Object**>(&global_contexts_list_)); + new_space_front = DoScavenge(&scavenge_visitor, new_space_front); UpdateNewSpaceReferencesInExternalStringTable( @@ -1032,8 +1030,8 @@ void Heap::Scavenge() { new_space_.set_age_mark(new_space_.top()); // Update how much has survived scavenge. - IncrementYoungSurvivorsCounter( - (PromotedSpaceSize() - survived_watermark) + new_space_.Size()); + IncrementYoungSurvivorsCounter(static_cast<int>( + (PromotedSpaceSize() - survived_watermark) + new_space_.Size())); LOG(ResourceEvent("scavenge", "end")); @@ -1088,6 +1086,44 @@ void Heap::UpdateNewSpaceReferencesInExternalStringTable( } +void Heap::ProcessWeakReferences(WeakObjectRetainer* retainer) { + Object* head = undefined_value(); + Context* tail = NULL; + Object* candidate = global_contexts_list_; + while (!candidate->IsUndefined()) { + // Check whether to keep the candidate in the list. + Context* candidate_context = reinterpret_cast<Context*>(candidate); + Object* retain = retainer->RetainAs(candidate); + if (retain != NULL) { + if (head->IsUndefined()) { + // First element in the list. + head = candidate_context; + } else { + // Subsequent elements in the list. + ASSERT(tail != NULL); + tail->set_unchecked(Context::NEXT_CONTEXT_LINK, + candidate_context, + UPDATE_WRITE_BARRIER); + } + // Retained context is new tail. + tail = candidate_context; + } + // Move to next element in the list. + candidate = candidate_context->get(Context::NEXT_CONTEXT_LINK); + } + + // Terminate the list if there is one or more elements. + if (tail != NULL) { + tail->set_unchecked(Context::NEXT_CONTEXT_LINK, + Heap::undefined_value(), + UPDATE_WRITE_BARRIER); + } + + // Update the head of the list of contexts. + Heap::global_contexts_list_ = head; +} + + class NewSpaceScavenger : public StaticNewSpaceVisitor<NewSpaceScavenger> { public: static inline void VisitPointer(Object** p) { @@ -1144,6 +1180,9 @@ class ScavengingVisitor : public StaticVisitorBase { table_.Register(kVisitShortcutCandidate, &EvacuateShortcutCandidate); table_.Register(kVisitByteArray, &EvacuateByteArray); table_.Register(kVisitFixedArray, &EvacuateFixedArray); + table_.Register(kVisitGlobalContext, + &ObjectEvacuationStrategy<POINTER_OBJECT>:: + VisitSpecialized<Context::kSize>); typedef ObjectEvacuationStrategy<POINTER_OBJECT> PointerObject; @@ -1222,7 +1261,7 @@ class ScavengingVisitor : public StaticVisitorBase { if (Logger::is_logging() || CpuProfiler::is_profiling()) { if (target->IsJSFunction()) { PROFILE(FunctionMoveEvent(source->address(), target->address())); - PROFILE(FunctionCreateEventFromMove(JSFunction::cast(target), source)); + PROFILE(FunctionCreateEventFromMove(JSFunction::cast(target))); } } #endif @@ -1634,7 +1673,9 @@ bool Heap::CreateInitialMaps() { obj = AllocateMap(FIXED_ARRAY_TYPE, kVariableSizeSentinel); if (obj->IsFailure()) return false; - set_global_context_map(Map::cast(obj)); + Map* global_context_map = Map::cast(obj); + global_context_map->set_visitor_id(StaticVisitorBase::kVisitGlobalContext); + set_global_context_map(global_context_map); obj = AllocateMap(SHARED_FUNCTION_INFO_TYPE, SharedFunctionInfo::kAlignedSize); @@ -3418,7 +3459,7 @@ bool Heap::IdleNotification() { HistogramTimerScope scope(&Counters::gc_context); CollectAllGarbage(false); } else { - CollectGarbage(0, NEW_SPACE); + CollectGarbage(NEW_SPACE); } new_space_.Shrink(); last_gc_count = gc_count_; @@ -3496,8 +3537,10 @@ void Heap::ReportHeapStatistics(const char* title) { PrintF(">>>>>> =============== %s (%d) =============== >>>>>>\n", title, gc_count_); PrintF("mark-compact GC : %d\n", mc_count_); - PrintF("old_gen_promotion_limit_ %d\n", old_gen_promotion_limit_); - PrintF("old_gen_allocation_limit_ %d\n", old_gen_allocation_limit_); + PrintF("old_gen_promotion_limit_ %" V8_PTR_PREFIX "d\n", + old_gen_promotion_limit_); + PrintF("old_gen_allocation_limit_ %" V8_PTR_PREFIX "d\n", + old_gen_allocation_limit_); PrintF("\n"); PrintF("Number of handles : %d\n", HandleScope::NumberOfHandles()); @@ -4069,15 +4112,16 @@ bool Heap::ConfigureHeap(int max_semispace_size, int max_old_gen_size) { bool Heap::ConfigureHeapDefault() { - return ConfigureHeap(FLAG_max_new_space_size / 2, FLAG_max_old_space_size); + return ConfigureHeap( + FLAG_max_new_space_size * (KB / 2), FLAG_max_old_space_size * MB); } void Heap::RecordStats(HeapStats* stats, bool take_snapshot) { *stats->start_marker = HeapStats::kStartMarker; *stats->end_marker = HeapStats::kEndMarker; - *stats->new_space_size = new_space_.Size(); - *stats->new_space_capacity = new_space_.Capacity(); + *stats->new_space_size = new_space_.SizeAsInt(); + *stats->new_space_capacity = static_cast<int>(new_space_.Capacity()); *stats->old_pointer_space_size = old_pointer_space_->Size(); *stats->old_pointer_space_capacity = old_pointer_space_->Capacity(); *stats->old_data_space_size = old_data_space_->Size(); @@ -4111,7 +4155,7 @@ void Heap::RecordStats(HeapStats* stats, bool take_snapshot) { } -int Heap::PromotedSpaceSize() { +intptr_t Heap::PromotedSpaceSize() { return old_pointer_space_->Size() + old_data_space_->Size() + code_space_->Size() @@ -4220,10 +4264,12 @@ bool Heap::Setup(bool create_heap_objects) { // Create initial objects if (!CreateInitialObjects()) return false; + + global_contexts_list_ = undefined_value(); } - LOG(IntEvent("heap-capacity", Capacity())); - LOG(IntEvent("heap-available", Available())); + LOG(IntPtrTEvent("heap-capacity", Capacity())); + LOG(IntPtrTEvent("heap-available", Available())); #ifdef ENABLE_LOGGING_AND_PROFILING // This should be called only after initial objects have been created. @@ -4257,7 +4303,8 @@ void Heap::TearDown() { PrintF("mark_compact_count=%d ", mc_count_); PrintF("max_gc_pause=%d ", GCTracer::get_max_gc_pause()); PrintF("min_in_mutator=%d ", GCTracer::get_min_in_mutator()); - PrintF("max_alive_after_gc=%d ", GCTracer::get_max_alive_after_gc()); + PrintF("max_alive_after_gc=%" V8_PTR_PREFIX "d ", + GCTracer::get_max_alive_after_gc()); PrintF("\n\n"); } @@ -4383,7 +4430,9 @@ class PrintHandleVisitor: public ObjectVisitor { public: void VisitPointers(Object** start, Object** end) { for (Object** p = start; p < end; p++) - PrintF(" handle %p to %p\n", p, *p); + PrintF(" handle %p to %p\n", + reinterpret_cast<void*>(p), + reinterpret_cast<void*>(*p)); } }; @@ -4736,8 +4785,8 @@ void Heap::TracePathToGlobal() { #endif -static int CountTotalHolesSize() { - int holes_size = 0; +static intptr_t CountTotalHolesSize() { + intptr_t holes_size = 0; OldSpaces spaces; for (OldSpace* space = spaces.next(); space != NULL; @@ -4835,13 +4884,14 @@ GCTracer::~GCTracer() { PrintF("sweepns=%d ", static_cast<int>(scopes_[Scope::MC_SWEEP_NEWSPACE])); PrintF("compact=%d ", static_cast<int>(scopes_[Scope::MC_COMPACT])); - PrintF("total_size_before=%d ", start_size_); - PrintF("total_size_after=%d ", Heap::SizeOfObjects()); - PrintF("holes_size_before=%d ", in_free_list_or_wasted_before_gc_); - PrintF("holes_size_after=%d ", CountTotalHolesSize()); + PrintF("total_size_before=%" V8_PTR_PREFIX "d ", start_size_); + PrintF("total_size_after=%" V8_PTR_PREFIX "d ", Heap::SizeOfObjects()); + PrintF("holes_size_before=%" V8_PTR_PREFIX "d ", + in_free_list_or_wasted_before_gc_); + PrintF("holes_size_after=%" V8_PTR_PREFIX "d ", CountTotalHolesSize()); - PrintF("allocated=%d ", allocated_since_last_gc_); - PrintF("promoted=%d ", promoted_objects_size_); + PrintF("allocated=%" V8_PTR_PREFIX "d ", allocated_since_last_gc_); + PrintF("promoted=%" V8_PTR_PREFIX "d ", promoted_objects_size_); PrintF("\n"); } @@ -4917,11 +4967,11 @@ int DescriptorLookupCache::results_[DescriptorLookupCache::kLength]; #ifdef DEBUG -bool Heap::GarbageCollectionGreedyCheck() { +void Heap::GarbageCollectionGreedyCheck() { ASSERT(FLAG_gc_greedy); - if (Bootstrapper::IsActive()) return true; - if (disallow_allocation_failure()) return true; - return CollectGarbage(0, NEW_SPACE); + if (Bootstrapper::IsActive()) return; + if (disallow_allocation_failure()) return; + CollectGarbage(NEW_SPACE); } #endif @@ -202,9 +202,10 @@ namespace internal { V(closure_symbol, "(closure)") -// Forward declaration of the GCTracer class. +// Forward declarations. class GCTracer; class HeapStats; +class WeakObjectRetainer; typedef String* (*ExternalStringTableUpdaterCallback)(Object** pointer); @@ -245,31 +246,31 @@ class Heap : public AllStatic { // semi space. The young generation consists of two semi spaces and // we reserve twice the amount needed for those in order to ensure // that new space can be aligned to its size. - static int MaxReserved() { + static intptr_t MaxReserved() { return 4 * reserved_semispace_size_ + max_old_generation_size_; } static int MaxSemiSpaceSize() { return max_semispace_size_; } static int ReservedSemiSpaceSize() { return reserved_semispace_size_; } static int InitialSemiSpaceSize() { return initial_semispace_size_; } - static int MaxOldGenerationSize() { return max_old_generation_size_; } + static intptr_t MaxOldGenerationSize() { return max_old_generation_size_; } // Returns the capacity of the heap in bytes w/o growing. Heap grows when // more spaces are needed until it reaches the limit. - static int Capacity(); + static intptr_t Capacity(); // Returns the amount of memory currently committed for the heap. - static int CommittedMemory(); + static intptr_t CommittedMemory(); // Returns the available bytes in space w/o growing. // Heap doesn't guarantee that it can allocate an object that requires // all available bytes. Check MaxHeapObjectSize() instead. - static int Available(); + static intptr_t Available(); // Returns the maximum object size in paged space. static inline int MaxObjectSizeInPagedSpace(); // Returns of size of all objects residing in the heap. - static int SizeOfObjects(); + static intptr_t SizeOfObjects(); // Return the starting address and a mask for the new space. And-masking an // address with the mask will result in the start address of the new space @@ -696,8 +697,7 @@ class Heap : public AllStatic { // Performs garbage collection operation. // Returns whether required_space bytes are available after the collection. - static bool CollectGarbage(int required_space, - AllocationSpace space, + static void CollectGarbage(AllocationSpace space, CollectionPolicy collectionPolicy = NORMAL); // Performs a full garbage collection. Force compaction if the @@ -717,7 +717,7 @@ class Heap : public AllStatic { #ifdef DEBUG // Utility used with flag gc-greedy. - static bool GarbageCollectionGreedyCheck(); + static void GarbageCollectionGreedyCheck(); #endif static void AddGCPrologueCallback( @@ -767,6 +767,11 @@ class Heap : public AllStatic { // not match the empty string. static String* hidden_symbol() { return hidden_symbol_; } + static void set_global_contexts_list(Object* object) { + global_contexts_list_ = object; + } + static Object* global_contexts_list() { return global_contexts_list_; } + // Iterates over all roots in the heap. static void IterateRoots(ObjectVisitor* v, VisitMode mode); // Iterates over all strong roots in the heap. @@ -870,6 +875,11 @@ class Heap : public AllStatic { // Generated code can embed this address to get access to the roots. static Object** roots_address() { return roots_; } + // Get address of global contexts list for serialization support. + static Object** global_contexts_list_address() { + return &global_contexts_list_; + } + #ifdef DEBUG static void Print(); static void PrintHandles(); @@ -1051,6 +1061,8 @@ class Heap : public AllStatic { static void UpdateNewSpaceReferencesInExternalStringTable( ExternalStringTableUpdaterCallback updater_func); + static void ProcessWeakReferences(WeakObjectRetainer* retainer); + // Helper function that governs the promotion policy from new space to // old. If the object's old address lies below the new space's age // mark or if we've already filled the bottom 1/16th of the to space, @@ -1069,8 +1081,8 @@ class Heap : public AllStatic { static int reserved_semispace_size_; static int max_semispace_size_; static int initial_semispace_size_; - static int max_old_generation_size_; - static size_t code_range_size_; + static intptr_t max_old_generation_size_; + static intptr_t code_range_size_; // For keeping track of how much data has survived // scavenge since last new space expansion. @@ -1098,7 +1110,7 @@ class Heap : public AllStatic { static HeapState gc_state_; // Returns the size of object residing in non new spaces. - static int PromotedSpaceSize(); + static intptr_t PromotedSpaceSize(); // Returns the amount of external memory registered since last global gc. static int PromotedExternalMemorySize(); @@ -1133,16 +1145,16 @@ class Heap : public AllStatic { // Limit that triggers a global GC on the next (normally caused) GC. This // is checked when we have already decided to do a GC to help determine // which collector to invoke. - static int old_gen_promotion_limit_; + static intptr_t old_gen_promotion_limit_; // Limit that triggers a global GC as soon as is reasonable. This is // checked before expanding a paged space in the old generation and on // every allocation in large object space. - static int old_gen_allocation_limit_; + static intptr_t old_gen_allocation_limit_; // Limit on the amount of externally allocated memory allowed // between global GCs. If reached a global GC is forced. - static int external_allocation_limit_; + static intptr_t external_allocation_limit_; // The amount of external memory registered through the API kept alive // by global handles @@ -1157,6 +1169,8 @@ class Heap : public AllStatic { static Object* roots_[kRootListLength]; + static Object* global_contexts_list_; + struct StringTypeTable { InstanceType type; int size; @@ -1231,8 +1245,8 @@ class Heap : public AllStatic { GCTracer* tracer, CollectionPolicy collectionPolicy); - static const int kMinimumPromotionLimit = 2 * MB; - static const int kMinimumAllocationLimit = 8 * MB; + static const intptr_t kMinimumPromotionLimit = 2 * MB; + static const intptr_t kMinimumAllocationLimit = 8 * MB; inline static void UpdateOldSpaceLimits(); @@ -1385,24 +1399,24 @@ class HeapStats { int* start_marker; // 0 int* new_space_size; // 1 int* new_space_capacity; // 2 - int* old_pointer_space_size; // 3 - int* old_pointer_space_capacity; // 4 - int* old_data_space_size; // 5 - int* old_data_space_capacity; // 6 - int* code_space_size; // 7 - int* code_space_capacity; // 8 - int* map_space_size; // 9 - int* map_space_capacity; // 10 - int* cell_space_size; // 11 - int* cell_space_capacity; // 12 - int* lo_space_size; // 13 + intptr_t* old_pointer_space_size; // 3 + intptr_t* old_pointer_space_capacity; // 4 + intptr_t* old_data_space_size; // 5 + intptr_t* old_data_space_capacity; // 6 + intptr_t* code_space_size; // 7 + intptr_t* code_space_capacity; // 8 + intptr_t* map_space_size; // 9 + intptr_t* map_space_capacity; // 10 + intptr_t* cell_space_size; // 11 + intptr_t* cell_space_capacity; // 12 + intptr_t* lo_space_size; // 13 int* global_handle_count; // 14 int* weak_global_handle_count; // 15 int* pending_global_handle_count; // 16 int* near_death_global_handle_count; // 17 int* destroyed_global_handle_count; // 18 - int* memory_allocator_size; // 19 - int* memory_allocator_capacity; // 20 + intptr_t* memory_allocator_size; // 19 + intptr_t* memory_allocator_capacity; // 20 int* objects_per_type; // 21 int* size_per_type; // 22 int* os_error; // 23 @@ -1837,7 +1851,7 @@ class GCTracer BASE_EMBEDDED { static int get_max_gc_pause() { return max_gc_pause_; } // Returns maximum size of objects alive after GC. - static int get_max_alive_after_gc() { return max_alive_after_gc_; } + static intptr_t get_max_alive_after_gc() { return max_alive_after_gc_; } // Returns minimal interval between two subsequent collections. static int get_min_in_mutator() { return min_in_mutator_; } @@ -1852,7 +1866,7 @@ class GCTracer BASE_EMBEDDED { } double start_time_; // Timestamp set in the constructor. - int start_size_; // Size of objects in heap set in constructor. + intptr_t start_size_; // Size of objects in heap set in constructor. GarbageCollector collector_; // Type of collector. // A count (including this one, eg, the first collection is 1) of the @@ -1884,30 +1898,30 @@ class GCTracer BASE_EMBEDDED { // Total amount of space either wasted or contained in one of free lists // before the current GC. - int in_free_list_or_wasted_before_gc_; + intptr_t in_free_list_or_wasted_before_gc_; // Difference between space used in the heap at the beginning of the current // collection and the end of the previous collection. - int allocated_since_last_gc_; + intptr_t allocated_since_last_gc_; // Amount of time spent in mutator that is time elapsed between end of the // previous collection and the beginning of the current one. double spent_in_mutator_; // Size of objects promoted during the current collection. - int promoted_objects_size_; + intptr_t promoted_objects_size_; // Maximum GC pause. static int max_gc_pause_; // Maximum size of objects alive after GC. - static int max_alive_after_gc_; + static intptr_t max_alive_after_gc_; // Minimal interval between two subsequent collections. static int min_in_mutator_; // Size of objects alive after last GC. - static int alive_after_last_gc_; + static intptr_t alive_after_last_gc_; static double last_gc_end_timestamp_; }; @@ -2043,6 +2057,19 @@ class ExternalStringTable : public AllStatic { static List<Object*> old_space_strings_; }; + +// Abstract base class for checking whether a weak object should be retained. +class WeakObjectRetainer { + public: + virtual ~WeakObjectRetainer() {} + + // Return whether this object should be retained. If NULL is returned the + // object has no references. Otherwise the address of the retained object + // should be returned as in some GC situations the object has been moved. + virtual Object* RetainAs(Object* object) = 0; +}; + + } } // namespace v8::internal #endif // V8_HEAP_H_ diff --git a/src/ia32/assembler-ia32.cc b/src/ia32/assembler-ia32.cc index e2f45470..e201179c 100644 --- a/src/ia32/assembler-ia32.cc +++ b/src/ia32/assembler-ia32.cc @@ -2414,7 +2414,7 @@ void Assembler::pxor(XMMRegister dst, XMMRegister src) { void Assembler::ptest(XMMRegister dst, XMMRegister src) { - ASSERT(CpuFeatures::IsEnabled(SSE2)); + ASSERT(CpuFeatures::IsEnabled(SSE4_1)); EnsureSpace ensure_space(this); last_pc_ = pc_; EMIT(0x66); diff --git a/src/ia32/assembler-ia32.h b/src/ia32/assembler-ia32.h index 1dab0a60..d8051c87 100644 --- a/src/ia32/assembler-ia32.h +++ b/src/ia32/assembler-ia32.h @@ -376,6 +376,7 @@ class CpuFeatures : public AllStatic { static bool IsSupported(CpuFeature f) { if (f == SSE2 && !FLAG_enable_sse2) return false; if (f == SSE3 && !FLAG_enable_sse3) return false; + if (f == SSE4_1 && !FLAG_enable_sse4_1) return false; if (f == CMOV && !FLAG_enable_cmov) return false; if (f == RDTSC && !FLAG_enable_rdtsc) return false; return (supported_ & (static_cast<uint64_t>(1) << f)) != 0; diff --git a/src/ia32/code-stubs-ia32.cc b/src/ia32/code-stubs-ia32.cc index 3e2b7ae1..348bb148 100644 --- a/src/ia32/code-stubs-ia32.cc +++ b/src/ia32/code-stubs-ia32.cc @@ -2638,7 +2638,7 @@ void CompareStub::Generate(MacroAssembler* masm) { __ j(not_zero, &non_smi, not_taken); __ sub(edx, Operand(eax)); // Return on the result of the subtraction. __ j(no_overflow, &smi_done); - __ neg(edx); // Correct sign in case of overflow. + __ not_(edx); // Correct sign in case of overflow. edx is never 0 here. __ bind(&smi_done); __ mov(eax, edx); __ ret(0); @@ -2964,16 +2964,7 @@ void CompareStub::BranchIfNonSymbol(MacroAssembler* masm, void StackCheckStub::Generate(MacroAssembler* masm) { - // Because builtins always remove the receiver from the stack, we - // have to fake one to avoid underflowing the stack. The receiver - // must be inserted below the return address on the stack so we - // temporarily store that in a register. - __ pop(eax); - __ push(Immediate(Smi::FromInt(0))); - __ push(eax); - - // Do tail-call to runtime routine. - __ TailCallRuntime(Runtime::kStackGuard, 1, 1); + __ TailCallRuntime(Runtime::kStackGuard, 0, 1); } diff --git a/src/ia32/codegen-ia32.cc b/src/ia32/codegen-ia32.cc index 9c8573ce..f2ac7f70 100644 --- a/src/ia32/codegen-ia32.cc +++ b/src/ia32/codegen-ia32.cc @@ -179,20 +179,11 @@ void CodeGenerator::Generate(CompilationInfo* info) { // Adjust for function-level loop nesting. ASSERT_EQ(0, loop_nesting_); - loop_nesting_ = info->loop_nesting(); + loop_nesting_ = info->is_in_loop() ? 1 : 0; JumpTarget::set_compiling_deferred_code(false); -#ifdef DEBUG - if (strlen(FLAG_stop_at) > 0 && - info->function()->name()->IsEqualTo(CStrVector(FLAG_stop_at))) { - frame_->SpillAll(); - __ int3(); - } -#endif - - // New scope to get automatic timing calculation. - { HistogramTimerScope codegen_timer(&Counters::code_generation); + { CodeGenState state(this); // Entry: @@ -203,6 +194,14 @@ void CodeGenerator::Generate(CompilationInfo* info) { // esi: callee's context allocator_->Initialize(); +#ifdef DEBUG + if (strlen(FLAG_stop_at) > 0 && + info->function()->name()->IsEqualTo(CStrVector(FLAG_stop_at))) { + frame_->SpillAll(); + __ int3(); + } +#endif + frame_->Enter(); // Allocate space for locals and initialize them. @@ -358,7 +357,7 @@ void CodeGenerator::Generate(CompilationInfo* info) { } // Adjust for function-level loop nesting. - ASSERT_EQ(loop_nesting_, info->loop_nesting()); + ASSERT_EQ(loop_nesting_, info->is_in_loop() ? 1 : 0); loop_nesting_ = 0; // Code generation state must be reset. @@ -369,7 +368,6 @@ void CodeGenerator::Generate(CompilationInfo* info) { // Process any deferred code using the register allocator. if (!HasStackOverflow()) { - HistogramTimerScope deferred_timer(&Counters::deferred_code_generation); JumpTarget::set_compiling_deferred_code(true); ProcessDeferred(); JumpTarget::set_compiling_deferred_code(false); @@ -4925,9 +4923,12 @@ void CodeGenerator::VisitFunctionLiteral(FunctionLiteral* node) { ASSERT(!in_safe_int32_mode()); // Build the function info and instantiate it. Handle<SharedFunctionInfo> function_info = - Compiler::BuildFunctionInfo(node, script(), this); + Compiler::BuildFunctionInfo(node, script()); // Check for stack-overflow exception. - if (HasStackOverflow()) return; + if (function_info.is_null()) { + SetStackOverflow(); + return; + } Result result = InstantiateFunction(function_info); frame()->Push(&result); } @@ -9149,7 +9150,8 @@ class DeferredReferenceGetNamedValue: public DeferredCode { : dst_(dst), receiver_(receiver), name_(name), - is_contextual_(is_contextual) { + is_contextual_(is_contextual), + is_dont_delete_(false) { set_comment(is_contextual ? "[ DeferredReferenceGetNamedValue (contextual)" : "[ DeferredReferenceGetNamedValue"); @@ -9159,12 +9161,18 @@ class DeferredReferenceGetNamedValue: public DeferredCode { Label* patch_site() { return &patch_site_; } + void set_is_dont_delete(bool value) { + ASSERT(is_contextual_); + is_dont_delete_ = value; + } + private: Label patch_site_; Register dst_; Register receiver_; Handle<String> name_; bool is_contextual_; + bool is_dont_delete_; }; @@ -9181,8 +9189,8 @@ void DeferredReferenceGetNamedValue::Generate() { // The call must be followed by: // - a test eax instruction to indicate that the inobject property // case was inlined. - // - a mov ecx instruction to indicate that the contextual property - // load was inlined. + // - a mov ecx or mov edx instruction to indicate that the + // contextual property load was inlined. // // Store the delta to the map check instruction here in the test // instruction. Use masm_-> instead of the __ macro since the @@ -9191,8 +9199,11 @@ void DeferredReferenceGetNamedValue::Generate() { // Here we use masm_-> instead of the __ macro because this is the // instruction that gets patched and coverage code gets in the way. if (is_contextual_) { - masm_->mov(ecx, -delta_to_patch_site); + masm_->mov(is_dont_delete_ ? edx : ecx, -delta_to_patch_site); __ IncrementCounter(&Counters::named_load_global_inline_miss, 1); + if (is_dont_delete_) { + __ IncrementCounter(&Counters::dont_delete_hint_miss, 1); + } } else { masm_->test(eax, Immediate(-delta_to_patch_site)); __ IncrementCounter(&Counters::named_load_inline_miss, 1); @@ -9436,9 +9447,34 @@ Result CodeGenerator::EmitNamedLoad(Handle<String> name, bool is_contextual) { } __ mov(result.reg(), FieldOperand(result.reg(), JSGlobalPropertyCell::kValueOffset)); - __ cmp(result.reg(), Factory::the_hole_value()); - deferred->Branch(equal); + bool is_dont_delete = false; + if (!info_->closure().is_null()) { + // When doing lazy compilation we can check if the global cell + // already exists and use its "don't delete" status as a hint. + AssertNoAllocation no_gc; + v8::internal::GlobalObject* global_object = + info_->closure()->context()->global(); + LookupResult lookup; + global_object->LocalLookupRealNamedProperty(*name, &lookup); + if (lookup.IsProperty() && lookup.type() == NORMAL) { + ASSERT(lookup.holder() == global_object); + ASSERT(global_object->property_dictionary()->ValueAt( + lookup.GetDictionaryEntry())->IsJSGlobalPropertyCell()); + is_dont_delete = lookup.IsDontDelete(); + } + } + deferred->set_is_dont_delete(is_dont_delete); + if (!is_dont_delete) { + __ cmp(result.reg(), Factory::the_hole_value()); + deferred->Branch(equal); + } else if (FLAG_debug_code) { + __ cmp(result.reg(), Factory::the_hole_value()); + __ Check(not_equal, "DontDelete cells can't contain the hole"); + } __ IncrementCounter(&Counters::named_load_global_inline, 1); + if (is_dont_delete) { + __ IncrementCounter(&Counters::dont_delete_hint_hit, 1); + } } else { // The initial (invalid) offset has to be large enough to force a 32-bit // instruction encoding to allow patching with an arbitrary offset. Use diff --git a/src/ia32/codegen-ia32.h b/src/ia32/codegen-ia32.h index c4a03d11..b0724092 100644 --- a/src/ia32/codegen-ia32.h +++ b/src/ia32/codegen-ia32.h @@ -300,9 +300,7 @@ enum ArgumentsAllocationMode { class CodeGenerator: public AstVisitor { public: - // Takes a function literal, generates code for it. This function should only - // be called by compiler.cc. - static Handle<Code> MakeCode(CompilationInfo* info); + static bool MakeCode(CompilationInfo* info); // Printing of AST, etc. as requested by flags. static void MakeCodePrologue(CompilationInfo* info); @@ -626,9 +624,6 @@ class CodeGenerator: public AstVisitor { void CheckStack(); - static InlineFunctionGenerator FindInlineFunctionGenerator( - Runtime::FunctionId function_id); - bool CheckForInlineRuntimeCall(CallRuntime* node); void ProcessDeclarations(ZoneList<Declaration*>* declarations); diff --git a/src/ia32/full-codegen-ia32.cc b/src/ia32/full-codegen-ia32.cc index cf53f4b8..150df995 100644 --- a/src/ia32/full-codegen-ia32.cc +++ b/src/ia32/full-codegen-ia32.cc @@ -61,6 +61,13 @@ void FullCodeGenerator::Generate(CompilationInfo* info) { SetFunctionPosition(function()); Comment cmnt(masm_, "[ function compiled by full code generator"); +#ifdef DEBUG + if (strlen(FLAG_stop_at) > 0 && + info->function()->name()->IsEqualTo(CStrVector(FLAG_stop_at))) { + __ int3(); + } +#endif + __ push(ebp); // Caller's frame pointer. __ mov(ebp, esp); __ push(esi); // Callee's context. diff --git a/src/ia32/ic-ia32.cc b/src/ia32/ic-ia32.cc index 413c36e9..b5f4deef 100644 --- a/src/ia32/ic-ia32.cc +++ b/src/ia32/ic-ia32.cc @@ -885,8 +885,8 @@ void KeyedLoadIC::GenerateIndexedInterceptor(MacroAssembler* masm) { __ test(edx, Immediate(kSmiTagMask)); __ j(zero, &slow, not_taken); - // Check that the key is a smi. - __ test(eax, Immediate(kSmiTagMask)); + // Check that the key is an array index, that is Uint32. + __ test(eax, Immediate(kSmiTagMask | kSmiSignMask)); __ j(not_zero, &slow, not_taken); // Get the map of the receiver. @@ -1662,17 +1662,37 @@ bool LoadIC::PatchInlinedLoad(Address address, Object* map, int offset) { // One byte opcode for mov ecx,0xXXXXXXXX. +// Marks inlined contextual loads using all kinds of cells. Generated +// code has the hole check: +// mov reg, <cell> +// mov reg, (<cell>, value offset) +// cmp reg, <the hole> +// je slow +// ;; use reg static const byte kMovEcxByte = 0xB9; +// One byte opcode for mov edx,0xXXXXXXXX. +// Marks inlined contextual loads using only "don't delete" +// cells. Generated code doesn't have the hole check: +// mov reg, <cell> +// mov reg, (<cell>, value offset) +// ;; use reg +static const byte kMovEdxByte = 0xBA; + bool LoadIC::PatchInlinedContextualLoad(Address address, Object* map, - Object* cell) { + Object* cell, + bool is_dont_delete) { // The address of the instruction following the call. Address mov_instruction_address = address + Assembler::kCallTargetAddressOffset; - // If the instruction following the call is not a cmp eax, nothing - // was inlined. - if (*mov_instruction_address != kMovEcxByte) return false; + // If the instruction following the call is not a mov ecx/edx, + // nothing was inlined. + byte b = *mov_instruction_address; + if (b != kMovEcxByte && b != kMovEdxByte) return false; + // If we don't have the hole check generated, we can only support + // "don't delete" cells. + if (b == kMovEdxByte && !is_dont_delete) return false; Address delta_address = mov_instruction_address + 1; // The delta to the start of the map check instruction. diff --git a/src/ia32/regexp-macro-assembler-ia32.cc b/src/ia32/regexp-macro-assembler-ia32.cc index 2aab7a8d..e2853e88 100644 --- a/src/ia32/regexp-macro-assembler-ia32.cc +++ b/src/ia32/regexp-macro-assembler-ia32.cc @@ -133,7 +133,6 @@ int RegExpMacroAssemblerIA32::stack_limit_slack() { void RegExpMacroAssemblerIA32::AdvanceCurrentPosition(int by) { if (by != 0) { - Label inside_string; __ add(Operand(edi), Immediate(by * char_size())); } } @@ -964,6 +963,17 @@ void RegExpMacroAssemblerIA32::ReadStackPointerFromRegister(int reg) { __ add(backtrack_stackpointer(), Operand(ebp, kStackHighEnd)); } +void RegExpMacroAssemblerIA32::SetCurrentPositionFromEnd(int by) { + NearLabel after_position; + __ cmp(edi, -by * char_size()); + __ j(greater_equal, &after_position); + __ mov(edi, -by * char_size()); + // On RegExp code entry (where this operation is used), the character before + // the current position is expected to be already loaded. + // We have advanced the position, so it's safe to read backwards. + LoadCurrentCharacterUnchecked(-1, 1); + __ bind(&after_position); +} void RegExpMacroAssemblerIA32::SetRegister(int register_index, int to) { ASSERT(register_index >= num_saved_registers_); // Reserved for positions! diff --git a/src/ia32/regexp-macro-assembler-ia32.h b/src/ia32/regexp-macro-assembler-ia32.h index 8b8eeed6..51e2cb01 100644 --- a/src/ia32/regexp-macro-assembler-ia32.h +++ b/src/ia32/regexp-macro-assembler-ia32.h @@ -98,6 +98,7 @@ class RegExpMacroAssemblerIA32: public NativeRegExpMacroAssembler { StackCheckFlag check_stack_limit); virtual void ReadCurrentPositionFromRegister(int reg); virtual void ReadStackPointerFromRegister(int reg); + virtual void SetCurrentPositionFromEnd(int by); virtual void SetRegister(int register_index, int to); virtual void Succeed(); virtual void WriteCurrentPositionToRegister(int reg, int cp_offset); diff --git a/src/ia32/stub-cache-ia32.cc b/src/ia32/stub-cache-ia32.cc index dd0d6364..bb0a46cd 100644 --- a/src/ia32/stub-cache-ia32.cc +++ b/src/ia32/stub-cache-ia32.cc @@ -1944,6 +1944,109 @@ Object* CallStubCompiler::CompileMathFloorCall(Object* object, } +Object* CallStubCompiler::CompileMathAbsCall(Object* object, + JSObject* holder, + JSGlobalPropertyCell* cell, + JSFunction* function, + String* name) { + // ----------- S t a t e ------------- + // -- ecx : name + // -- esp[0] : return address + // -- esp[(argc - n) * 4] : arg[n] (zero-based) + // -- ... + // -- esp[(argc + 1) * 4] : receiver + // ----------------------------------- + + const int argc = arguments().immediate(); + + // If the object is not a JSObject or we got an unexpected number of + // arguments, bail out to the regular call. + if (!object->IsJSObject() || argc != 1) return Heap::undefined_value(); + + Label miss; + GenerateNameCheck(name, &miss); + + if (cell == NULL) { + __ mov(edx, Operand(esp, 2 * kPointerSize)); + + STATIC_ASSERT(kSmiTag == 0); + __ test(edx, Immediate(kSmiTagMask)); + __ j(zero, &miss); + + CheckPrototypes(JSObject::cast(object), edx, holder, ebx, eax, edi, name, + &miss); + } else { + ASSERT(cell->value() == function); + GenerateGlobalReceiverCheck(JSObject::cast(object), holder, name, &miss); + GenerateLoadFunctionFromCell(cell, function, &miss); + } + + // Load the (only) argument into eax. + __ mov(eax, Operand(esp, 1 * kPointerSize)); + + // Check if the argument is a smi. + Label not_smi; + STATIC_ASSERT(kSmiTag == 0); + __ test(eax, Immediate(kSmiTagMask)); + __ j(not_zero, ¬_smi); + + // Set ebx to 1...1 (== -1) if the argument is negative, or to 0...0 + // otherwise. + __ mov(ebx, eax); + __ sar(ebx, kBitsPerInt - 1); + + // Do bitwise not or do nothing depending on ebx. + __ xor_(eax, Operand(ebx)); + + // Add 1 or do nothing depending on ebx. + __ sub(eax, Operand(ebx)); + + // If the result is still negative, go to the slow case. + // This only happens for the most negative smi. + Label slow; + __ j(negative, &slow); + + // Smi case done. + __ ret(2 * kPointerSize); + + // Check if the argument is a heap number and load its exponent and + // sign into ebx. + __ bind(¬_smi); + __ CheckMap(eax, Factory::heap_number_map(), &slow, true); + __ mov(ebx, FieldOperand(eax, HeapNumber::kExponentOffset)); + + // Check the sign of the argument. If the argument is positive, + // just return it. + Label negative_sign; + __ test(ebx, Immediate(HeapNumber::kSignMask)); + __ j(not_zero, &negative_sign); + __ ret(2 * kPointerSize); + + // If the argument is negative, clear the sign, and return a new + // number. + __ bind(&negative_sign); + __ and_(ebx, ~HeapNumber::kSignMask); + __ mov(ecx, FieldOperand(eax, HeapNumber::kMantissaOffset)); + __ AllocateHeapNumber(eax, edi, edx, &slow); + __ mov(FieldOperand(eax, HeapNumber::kExponentOffset), ebx); + __ mov(FieldOperand(eax, HeapNumber::kMantissaOffset), ecx); + __ ret(2 * kPointerSize); + + // Tail call the full function. We do not have to patch the receiver + // because the function makes no use of it. + __ bind(&slow); + __ InvokeFunction(function, arguments(), JUMP_FUNCTION); + + __ bind(&miss); + // ecx: function name. + Object* obj = GenerateMissBranch(); + if (obj->IsFailure()) return obj; + + // Return the generated code. + return (cell == NULL) ? GetCode(function) : GetCode(NORMAL, name); +} + + Object* CallStubCompiler::CompileCallConstant(Object* object, JSObject* holder, JSFunction* function, @@ -299,7 +299,10 @@ void LoadIC::ClearInlinedVersion(Address address) { // present) to guarantee failure by holding an invalid map (the null // value). The offset can be patched to anything. PatchInlinedLoad(address, Heap::null_value(), 0); - PatchInlinedContextualLoad(address, Heap::null_value(), Heap::null_value()); + PatchInlinedContextualLoad(address, + Heap::null_value(), + Heap::null_value(), + true); } @@ -848,7 +851,10 @@ Object* LoadIC::Load(State state, Handle<Object> object, Handle<String> name) { JSGlobalPropertyCell* cell = JSGlobalPropertyCell::cast( lookup.holder()->property_dictionary()->ValueAt( lookup.GetDictionaryEntry())); - if (PatchInlinedContextualLoad(address(), map, cell)) { + if (PatchInlinedContextualLoad(address(), + map, + cell, + lookup.IsDontDelete())) { set_target(megamorphic_stub()); TRACE_IC_NAMED("[LoadIC : inline contextual patch %s]\n", name); ASSERT(cell->value() != Heap::the_hole_value()); @@ -1541,18 +1547,17 @@ void KeyedStoreIC::UpdateCaches(LookupResult* lookup, // Static IC stub generators. // -static Object* CompileFunction(Object* result, - Handle<Object> object, - InLoopFlag in_loop) { +static JSFunction* CompileFunction(JSFunction* function, + InLoopFlag in_loop) { // Compile now with optimization. HandleScope scope; - Handle<JSFunction> function = Handle<JSFunction>(JSFunction::cast(result)); + Handle<JSFunction> function_handle(function); if (in_loop == IN_LOOP) { - CompileLazyInLoop(function, object, CLEAR_EXCEPTION); + CompileLazyInLoop(function_handle, CLEAR_EXCEPTION); } else { - CompileLazy(function, object, CLEAR_EXCEPTION); + CompileLazy(function_handle, CLEAR_EXCEPTION); } - return *function; + return *function_handle; } @@ -1575,7 +1580,7 @@ Object* CallIC_Miss(Arguments args) { if (!result->IsJSFunction() || JSFunction::cast(result)->is_compiled()) { return result; } - return CompileFunction(result, args.at<Object>(0), ic.target()->ic_in_loop()); + return CompileFunction(JSFunction::cast(result), ic.target()->ic_in_loop()); } @@ -1591,7 +1596,7 @@ Object* KeyedCallIC_Miss(Arguments args) { if (!result->IsJSFunction() || JSFunction::cast(result)->is_compiled()) { return result; } - return CompileFunction(result, args.at<Object>(0), ic.target()->ic_in_loop()); + return CompileFunction(JSFunction::cast(result), ic.target()->ic_in_loop()); } @@ -300,7 +300,8 @@ class LoadIC: public IC { static bool PatchInlinedContextualLoad(Address address, Object* map, - Object* cell); + Object* cell, + bool is_dont_delete); friend class IC; }; diff --git a/src/interpreter-irregexp.cc b/src/interpreter-irregexp.cc index a904447f..c9c3cc4c 100644 --- a/src/interpreter-irregexp.cc +++ b/src/interpreter-irregexp.cc @@ -607,6 +607,15 @@ static bool RawMatch(const byte* code_base, pc = code_base + Load32Aligned(pc + 4); } break; + BYTECODE(SET_CURRENT_POSITION_FROM_END) { + int by = static_cast<uint32_t>(insn) >> BYTECODE_SHIFT; + if (subject.length() - current > by) { + current = subject.length() - by; + current_char = subject[current - 1]; + } + pc += BC_SET_CURRENT_POSITION_FROM_END_LENGTH; + break; + } default: UNREACHABLE(); break; diff --git a/src/jsregexp.cc b/src/jsregexp.cc index 30d4dcbf..3c5ddfbe 100644 --- a/src/jsregexp.cc +++ b/src/jsregexp.cc @@ -125,7 +125,7 @@ Handle<Object> RegExpImpl::Compile(Handle<JSRegExp> re, PostponeInterruptsScope postpone; RegExpCompileData parse_result; FlatStringReader reader(pattern); - if (!ParseRegExp(&reader, flags.is_multiline(), &parse_result)) { + if (!Parser::ParseRegExp(&reader, flags.is_multiline(), &parse_result)) { // Throw an exception if we fail to parse the pattern. ThrowRegExpException(re, pattern, @@ -267,7 +267,7 @@ bool RegExpImpl::CompileIrregexp(Handle<JSRegExp> re, bool is_ascii) { RegExpCompileData compile_data; FlatStringReader reader(pattern); - if (!ParseRegExp(&reader, flags.is_multiline(), &compile_data)) { + if (!Parser::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, @@ -5180,7 +5180,10 @@ RegExpEngine::CompilationResult RegExpEngine::Compile(RegExpCompileData* data, &compiler, compiler.accept()); RegExpNode* node = captured_body; - if (!data->tree->IsAnchored()) { + bool is_end_anchored = data->tree->IsAnchoredAtEnd(); + bool is_start_anchored = data->tree->IsAnchoredAtStart(); + int max_length = data->tree->max_match(); + if (!is_start_anchored) { // Add a .*? at the beginning, outside the body capture, unless // this expression is anchored at the beginning. RegExpNode* loop_node = @@ -5236,6 +5239,15 @@ RegExpEngine::CompilationResult RegExpEngine::Compile(RegExpCompileData* data, RegExpMacroAssemblerIrregexp macro_assembler(codes); #endif // V8_INTERPRETED_REGEXP + // Inserted here, instead of in Assembler, because it depends on information + // in the AST that isn't replicated in the Node structure. + static const int kMaxBacksearchLimit = 1024; + if (is_end_anchored && + !is_start_anchored && + max_length < kMaxBacksearchLimit) { + macro_assembler.SetCurrentPositionFromEnd(max_length); + } + return compiler.Assemble(¯o_assembler, node, data->capture_count, diff --git a/src/liveedit-debugger.js b/src/liveedit-debugger.js index be97989b..83b703f8 100644 --- a/src/liveedit-debugger.js +++ b/src/liveedit-debugger.js @@ -46,8 +46,7 @@ Debug.LiveEdit = new function() { // Forward declaration for minifier. var FunctionStatus; - - + // Applies the change to the script. // The change is in form of list of chunks encoded in a single array as // a series of triplets (pos1_start, pos1_end, pos2_end) @@ -58,7 +57,7 @@ Debug.LiveEdit = new function() { // Gather compile information about old version of script. var old_compile_info = GatherCompileInfo(old_source, script); - + // Build tree structures for old and new versions of the script. var root_old_node = BuildCodeInfoTree(old_compile_info); @@ -69,7 +68,7 @@ Debug.LiveEdit = new function() { // Find all SharedFunctionInfo's that were compiled from this script. FindLiveSharedInfos(root_old_node, script); - + // Gather compile information about new version of script. var new_compile_info; try { @@ -81,7 +80,7 @@ Debug.LiveEdit = new function() { // Link recompiled script data with other data. FindCorrespondingFunctions(root_old_node, root_new_node); - + // Prepare to-do lists. var replace_code_list = new Array(); var link_to_old_script_list = new Array(); @@ -104,7 +103,7 @@ Debug.LiveEdit = new function() { CollectNew(node_list[i].children); } } - + if (old_node.status == FunctionStatus.DAMAGED) { CollectDamaged(old_node); return; @@ -131,17 +130,17 @@ Debug.LiveEdit = new function() { }, updated: false }; - + if (preview_only) { return preview_description; } - + HarvestTodo(root_old_node); - + // Collect shared infos for functions whose code need to be patched. var replaced_function_infos = new Array(); for (var i = 0; i < replace_code_list.length; i++) { - var info_wrapper = replace_code_list[i].live_shared_info_wrapper; + var info_wrapper = replace_code_list[i].live_shared_info_wrapper; if (info_wrapper) { replaced_function_infos.push(info_wrapper); } @@ -149,14 +148,14 @@ Debug.LiveEdit = new function() { // We haven't changed anything before this line yet. // Committing all changes. - + // Check that function being patched is not currently on stack or drop them. var dropped_functions_number = CheckStackActivations(replaced_function_infos, change_log); - - preview_description.stack_modified = dropped_functions_number != 0; - - // Start with breakpoints. Convert their line/column positions and + + preview_description.stack_modified = dropped_functions_number != 0; + + // Start with breakpoints. Convert their line/column positions and // temporary remove. var break_points_restorer = TemporaryRemoveBreakPoints(script, change_log); @@ -169,24 +168,24 @@ Debug.LiveEdit = new function() { old_script = void 0; } else { var old_script_name = CreateNameForOldScript(script); - + // Update the script text and create a new script representing an old // version of the script. old_script = %LiveEditReplaceScript(script, new_source, old_script_name); - + var link_to_old_script_report = new Array(); change_log.push( { linked_to_old_script: link_to_old_script_report } ); - + // We need to link to old script all former nested functions. for (var i = 0; i < link_to_old_script_list.length; i++) { LinkToOldScript(link_to_old_script_list[i], old_script, link_to_old_script_report); } - + preview_description.created_script_name = old_script_name; } - + // Link to an actual script all the functions that we are going to use. for (var i = 0; i < link_to_original_script_list.length; i++) { %LiveEditFunctionSetScript( @@ -196,26 +195,26 @@ Debug.LiveEdit = new function() { for (var i = 0; i < replace_code_list.length; i++) { PatchFunctionCode(replace_code_list[i], change_log); } - + var position_patch_report = new Array(); change_log.push( {position_patched: position_patch_report} ); - + for (var i = 0; i < update_positions_list.length; i++) { // TODO(LiveEdit): take into account wether it's source_changed or // unchanged and whether positions changed at all. PatchPositions(update_positions_list[i], diff_array, position_patch_report); } - + break_points_restorer(pos_translator, old_script); - + preview_description.updated = true; return preview_description; } // Function is public. this.ApplyPatchMultiChunk = ApplyPatchMultiChunk; - + // Fully compiles source string as a script. Returns Array of // FunctionCompileInfo -- a descriptions of all functions of the script. // Elements of array are ordered by start positions of functions (from top @@ -224,7 +223,7 @@ Debug.LiveEdit = new function() { // // All functions get compiled linked to script provided as parameter script. // TODO(LiveEdit): consider not using actual scripts as script, because - // we have to manually erase all links right after compile. + // we have to manually erase all links right after compile. function GatherCompileInfo(source, script) { // Get function info, elements are partially sorted (it is a tree of // nested functions serialized as parent followed by serialized children. @@ -291,7 +290,7 @@ Debug.LiveEdit = new function() { return compile_info; } - + // Replaces function's Code. function PatchFunctionCode(old_node, change_log) { var new_info = old_node.corresponding_node.info; @@ -318,7 +317,7 @@ Debug.LiveEdit = new function() { } } } - + change_log.push( {function_patched: new_info.function_name} ); } else { change_log.push( {function_patched: new_info.function_name, @@ -326,7 +325,7 @@ Debug.LiveEdit = new function() { } } - + // Makes a function associated with another instance of a script (the // one representing its old version). This way the function still // may access its own text. @@ -340,12 +339,12 @@ Debug.LiveEdit = new function() { { name: old_info_node.info.function_name, not_found: true } ); } } - + // Returns function that restores breakpoints. function TemporaryRemoveBreakPoints(original_script, change_log) { var script_break_points = GetScriptBreakPoints(original_script); - + var break_points_update_report = []; change_log.push( { break_points_update: break_points_update_report } ); @@ -354,11 +353,11 @@ Debug.LiveEdit = new function() { var break_point = script_break_points[i]; break_point.clear(); - - // TODO(LiveEdit): be careful with resource offset here. + + // TODO(LiveEdit): be careful with resource offset here. var break_point_position = Debug.findScriptSourcePosition(original_script, break_point.line(), break_point.column()); - + var old_position_description = { position: break_point_position, line: break_point.line(), @@ -366,8 +365,8 @@ Debug.LiveEdit = new function() { } break_point_old_positions.push(old_position_description); } - - + + // Restores breakpoints and creates their copies in the "old" copy of // the script. return function (pos_translator, old_script_copy_opt) { @@ -378,19 +377,19 @@ Debug.LiveEdit = new function() { if (old_script_copy_opt) { var clone = break_point.cloneForOtherScript(old_script_copy_opt); clone.set(old_script_copy_opt); - + break_points_update_report.push( { type: "copied_to_old", id: break_point.number(), - new_id: clone.number(), + new_id: clone.number(), positions: break_point_old_positions[i] } ); } - + var updated_position = pos_translator.Translate( break_point_old_positions[i].position, PosTranslator.ShiftWithTopInsideChunkHandler); - + var new_location = original_script.locationFromPosition(updated_position, false); @@ -401,9 +400,9 @@ Debug.LiveEdit = new function() { line: new_location.line, column: new_location.column } - + break_point.set(original_script); - + break_points_update_report.push( { type: "position_changed", id: break_point.number(), old_positions: break_point_old_positions[i], @@ -413,7 +412,7 @@ Debug.LiveEdit = new function() { } } - + function Assert(condition, message) { if (!condition) { if (message) { @@ -430,7 +429,7 @@ Debug.LiveEdit = new function() { this.len1 = len1; this.len2 = len2; } - + function PosTranslator(diff_array) { var chunks = new Array(); var current_diff = 0; @@ -441,16 +440,16 @@ Debug.LiveEdit = new function() { var pos2_end = diff_array[i + 2]; chunks.push(new DiffChunk(pos1_begin, pos2_begin, pos1_end - pos1_begin, pos2_end - pos2_begin)); - current_diff = pos2_end - pos1_end; + current_diff = pos2_end - pos1_end; } this.chunks = chunks; } PosTranslator.prototype.GetChunks = function() { return this.chunks; } - + PosTranslator.prototype.Translate = function(pos, inside_chunk_handler) { - var array = this.chunks; + var array = this.chunks; if (array.length == 0 || pos < array[0].pos1) { return pos; } @@ -467,9 +466,9 @@ Debug.LiveEdit = new function() { } var chunk = array[chunk_index1]; if (pos >= chunk.pos1 + chunk.len1) { - return pos + chunk.pos2 + chunk.len2 - chunk.pos1 - chunk.len1; + return pos + chunk.pos2 + chunk.len2 - chunk.pos1 - chunk.len1; } - + if (!inside_chunk_handler) { inside_chunk_handler = PosTranslator.DefaultInsideChunkHandler; } @@ -479,17 +478,17 @@ Debug.LiveEdit = new function() { PosTranslator.DefaultInsideChunkHandler = function(pos, diff_chunk) { Assert(false, "Cannot translate position in changed area"); } - + PosTranslator.ShiftWithTopInsideChunkHandler = function(pos, diff_chunk) { // We carelessly do not check whether we stay inside the chunk after // translation. - return pos - diff_chunk.pos1 + diff_chunk.pos2; + return pos - diff_chunk.pos1 + diff_chunk.pos2; } - + var FunctionStatus = { // No change to function or its inner functions; however its positions - // in script may have been shifted. + // in script may have been shifted. UNCHANGED: "unchanged", // The code of a function remains unchanged, but something happened inside // some inner functions. @@ -500,14 +499,14 @@ Debug.LiveEdit = new function() { // Function is changed but cannot be patched. DAMAGED: "damaged" } - + function CodeInfoTreeNode(code_info, children, array_index) { this.info = code_info; this.children = children; // an index in array of compile_info - this.array_index = array_index; + this.array_index = array_index; this.parent = void 0; - + this.status = FunctionStatus.UNCHANGED; // Status explanation is used for debugging purposes and will be shown // in user UI if some explanations are needed. @@ -516,26 +515,26 @@ Debug.LiveEdit = new function() { this.new_end_pos = void 0; this.corresponding_node = void 0; this.unmatched_new_nodes = void 0; - + // 'Textual' correspondence/matching is weaker than 'pure' // correspondence/matching. We need 'textual' level for visual presentation // in UI, we use 'pure' level for actual code manipulation. // Sometimes only function body is changed (functions in old and new script // textually correspond), but we cannot patch the code, so we see them - // as an old function deleted and new function created. + // as an old function deleted and new function created. this.textual_corresponding_node = void 0; this.textually_unmatched_new_nodes = void 0; - + this.live_shared_info_wrapper = void 0; } - + // From array of function infos that is implicitly a tree creates // an actual tree of functions in script. function BuildCodeInfoTree(code_info_array) { // Throughtout all function we iterate over input array. var index = 0; - // Recursive function that builds a branch of tree. + // Recursive function that builds a branch of tree. function BuildNode() { var my_index = index; index++; @@ -551,7 +550,7 @@ Debug.LiveEdit = new function() { } return node; } - + var root = BuildNode(); Assert(index == code_info_array.length); return root; @@ -570,7 +569,7 @@ Debug.LiveEdit = new function() { this.current = function() { return chunks[chunk_index]; } this.next = function() { var chunk = chunks[chunk_index]; - pos_diff = chunk.pos2 + chunk.len2 - (chunk.pos1 + chunk.len1); + pos_diff = chunk.pos2 + chunk.len2 - (chunk.pos1 + chunk.len1); chunk_index++; } this.done = function() { return chunk_index >= chunks.length; } @@ -582,7 +581,7 @@ Debug.LiveEdit = new function() { // below function start. function ProcessInternals(info_node) { info_node.new_start_pos = chunk_it.TranslatePos( - info_node.info.start_position); + info_node.info.start_position); var child_index = 0; var code_changed = false; var source_changed = false; @@ -591,7 +590,7 @@ Debug.LiveEdit = new function() { chunk_it.current().pos1 < info_node.info.end_position) { if (child_index < info_node.children.length) { var child = info_node.children[child_index]; - + if (child.info.end_position <= chunk_it.current().pos1) { ProcessUnchangedChild(child); child_index++; @@ -620,7 +619,7 @@ Debug.LiveEdit = new function() { continue; } } else { - if (chunk_it.current().pos1 + chunk_it.current().len1 <= + if (chunk_it.current().pos1 + chunk_it.current().len1 <= info_node.info.end_position) { info_node.status = FunctionStatus.CHANGED; chunk_it.next(); @@ -645,14 +644,14 @@ Debug.LiveEdit = new function() { info_node.status = FunctionStatus.SOURCE_CHANGED; } info_node.new_end_pos = - chunk_it.TranslatePos(info_node.info.end_position); + chunk_it.TranslatePos(info_node.info.end_position); } - + function ProcessUnchangedChild(node) { node.new_start_pos = chunk_it.TranslatePos(node.info.start_position); node.new_end_pos = chunk_it.TranslatePos(node.info.end_position); } - + ProcessInternals(code_info_tree); } @@ -670,7 +669,7 @@ Debug.LiveEdit = new function() { function ProcessChildren(old_node, new_node) { var old_children = old_node.children; var new_children = new_node.children; - + var unmatched_new_nodes_list = []; var textually_unmatched_new_nodes_list = []; @@ -728,13 +727,13 @@ Debug.LiveEdit = new function() { old_index++; } } - + while (new_index < new_children.length) { unmatched_new_nodes_list.push(new_children[new_index]); textually_unmatched_new_nodes_list.push(new_children[new_index]); new_index++; } - + if (old_node.status == FunctionStatus.CHANGED) { var why_wrong_expectations = WhyFunctionExpectationsDiffer(old_node.info, new_node.info); @@ -749,23 +748,23 @@ Debug.LiveEdit = new function() { } ProcessChildren(old_code_tree, new_code_tree); - + old_code_tree.corresponding_node = new_code_tree; old_code_tree.textual_corresponding_node = new_code_tree; Assert(old_code_tree.status != FunctionStatus.DAMAGED, "Script became damaged"); } - + function FindLiveSharedInfos(old_code_tree, script) { var shared_raw_list = %LiveEditFindSharedFunctionInfosForScript(script); - + var shared_infos = new Array(); - + for (var i = 0; i < shared_raw_list.length; i++) { shared_infos.push(new SharedInfoWrapper(shared_raw_list[i])); } - + // Finds SharedFunctionInfo that corresponds compile info with index // in old version of the script. function FindFunctionInfo(compile_info) { @@ -777,7 +776,7 @@ Debug.LiveEdit = new function() { } } } - + function TraverseTree(node) { var info_wrapper = FindFunctionInfo(node.info); if (info_wrapper) { @@ -791,7 +790,7 @@ Debug.LiveEdit = new function() { TraverseTree(old_code_tree); } - + // An object describing function compilation details. Its index fields // apply to indexes inside array that stores these objects. function FunctionCompileInfo(raw_array) { @@ -807,7 +806,7 @@ Debug.LiveEdit = new function() { this.next_sibling_index = null; this.raw_array = raw_array; } - + function SharedInfoWrapper(raw_array) { this.function_name = raw_array[0]; this.start_position = raw_array[1]; @@ -821,7 +820,7 @@ Debug.LiveEdit = new function() { var shared_info_wrapper = old_info_node.live_shared_info_wrapper; if (!shared_info_wrapper) { // TODO(LiveEdit): function is not compiled yet or is already collected. - report_array.push( + report_array.push( { name: old_info_node.info.function_name, info_not_found: true } ); return; } @@ -835,44 +834,44 @@ Debug.LiveEdit = new function() { // TODO(635): try better than this; support several changes. return script.name + " (old)"; } - + // Compares a function interface old and new version, whether it // changed or not. Returns explanation if they differ. function WhyFunctionExpectationsDiffer(function_info1, function_info2) { // Check that function has the same number of parameters (there may exist // an adapter, that won't survive function parameter number change). if (function_info1.param_num != function_info2.param_num) { - return "Changed parameter number: " + function_info1.param_num + + return "Changed parameter number: " + function_info1.param_num + " and " + function_info2.param_num; } var scope_info1 = function_info1.scope_info; var scope_info2 = function_info2.scope_info; - var scope_info1_text; - var scope_info2_text; - + var scope_info1_text; + var scope_info2_text; + if (scope_info1) { - scope_info1_text = scope_info1.toString(); + scope_info1_text = scope_info1.toString(); } else { scope_info1_text = ""; } if (scope_info2) { - scope_info2_text = scope_info2.toString(); + scope_info2_text = scope_info2.toString(); } else { scope_info2_text = ""; } - + if (scope_info1_text != scope_info2_text) { return "Incompatible variable maps: [" + scope_info1_text + - "] and [" + scope_info2_text + "]"; + "] and [" + scope_info2_text + "]"; } // No differences. Return undefined. return; } - + // Minifier forward declaration. var FunctionPatchabilityStatus; - + // For array of wrapped shared function infos checks that none of them // have activations on stack (of any thread). Throws a Failure exception // if this proves to be false. @@ -886,7 +885,7 @@ Debug.LiveEdit = new function() { // Extra array element may contain error message. throw new Failure(result[shared_list.length]); } - + var problems = new Array(); var dropped = new Array(); for (var i = 0; i < shared_list.length; i++) { @@ -896,7 +895,7 @@ Debug.LiveEdit = new function() { } else if (result[i] != FunctionPatchabilityStatus.AVAILABLE_FOR_PATCH) { var description = { name: shared.function_name, - start_pos: shared.start_position, + start_pos: shared.start_position, end_pos: shared.end_position, replace_problem: FunctionPatchabilityStatus.SymbolName(result[i]) @@ -911,10 +910,10 @@ Debug.LiveEdit = new function() { change_log.push( { functions_on_stack: problems } ); throw new Failure("Blocked by functions on stack"); } - + return dropped.length; } - + // A copy of the FunctionPatchabilityStatus enum from liveedit.h var FunctionPatchabilityStatus = { AVAILABLE_FOR_PATCH: 1, @@ -923,17 +922,17 @@ Debug.LiveEdit = new function() { BLOCKED_UNDER_NATIVE_CODE: 4, REPLACED_ON_ACTIVE_STACK: 5 } - + FunctionPatchabilityStatus.SymbolName = function(code) { var enum = FunctionPatchabilityStatus; for (name in enum) { if (enum[name] == code) { return name; } - } + } } - - + + // A logical failure in liveedit process. This means that change_log // is valid and consistent description of what happened. function Failure(message) { @@ -941,11 +940,11 @@ Debug.LiveEdit = new function() { } // Function (constructor) is public. this.Failure = Failure; - + Failure.prototype.toString = function() { return "LiveEdit Failure: " + this.message; } - + // A testing entry. function GetPcFromSourcePos(func, source_pos) { return %GetFunctionCodePositionFromSource(func, source_pos); @@ -962,7 +961,7 @@ Debug.LiveEdit = new function() { } // Function is public. this.SetScriptSource = SetScriptSource; - + function CompareStringsLinewise(s1, s2) { return %LiveEditCompareStringsLinewise(s1, s2); } @@ -978,19 +977,19 @@ Debug.LiveEdit = new function() { function ApplySingleChunkPatch(script, change_pos, change_len, new_str, change_log) { var old_source = script.source; - + // Prepare new source string. var new_source = old_source.substring(0, change_pos) + new_str + old_source.substring(change_pos + change_len); - + return ApplyPatchMultiChunk(script, [ change_pos, change_pos + change_len, change_pos + new_str.length], new_source, false, change_log); } - + // Creates JSON description for a change tree. function DescribeChangeTree(old_code_tree) { - + function ProcessOldNode(node) { var child_infos = []; for (var i = 0; i < node.children.length; i++) { @@ -1011,7 +1010,7 @@ Debug.LiveEdit = new function() { positions: DescribePositions(node), status: node.status, children: child_infos, - new_children: new_child_infos + new_children: new_child_infos }; if (node.status_explanation) { res.status_explanation = node.status_explanation; @@ -1021,7 +1020,7 @@ Debug.LiveEdit = new function() { } return res; } - + function ProcessNewNode(node) { var child_infos = []; // Do not list ancestors. @@ -1037,18 +1036,18 @@ Debug.LiveEdit = new function() { }; return res; } - + function DescribePositions(node) { return { start_position: node.info.start_position, end_position: node.info.end_position }; } - + return ProcessOldNode(old_code_tree); } - + // Functions are public for tests. this.TestApi = { PosTranslator: PosTranslator, diff --git a/src/liveedit.cc b/src/liveedit.cc index c07e83f6..3cbd2446 100644 --- a/src/liveedit.cc +++ b/src/liveedit.cc @@ -29,13 +29,15 @@ #include "v8.h" #include "liveedit.h" + #include "compiler.h" -#include "oprofile-agent.h" -#include "scopes.h" -#include "scopeinfo.h" -#include "global-handles.h" #include "debug.h" +#include "global-handles.h" #include "memory.h" +#include "oprofile-agent.h" +#include "parser.h" +#include "scopeinfo.h" +#include "scopes.h" namespace v8 { namespace internal { @@ -396,45 +398,31 @@ Handle<JSArray> LiveEdit::CompareStringsLinewise(Handle<String> s1, static void CompileScriptForTracker(Handle<Script> script) { - const bool is_eval = false; - const bool is_global = true; // TODO(635): support extensions. - Extension* extension = NULL; - PostponeInterruptsScope postpone; - // Only allow non-global compiles for eval. - ASSERT(is_eval || is_global); - // Build AST. - ScriptDataImpl* pre_data = NULL; - FunctionLiteral* lit = MakeAST(is_global, script, extension, pre_data); - - // Check for parse errors. - if (lit == NULL) { - ASSERT(Top::has_pending_exception()); - return; - } - - // Compile the code. - CompilationInfo info(lit, script, is_eval); - - LiveEditFunctionTracker tracker(lit); - Handle<Code> code = MakeCodeForLiveEdit(&info); - - // Check for stack-overflow exceptions. - if (code.is_null()) { - Top::StackOverflow(); - return; + CompilationInfo info(script); + info.MarkAsGlobal(); + if (Parser::Parse(&info)) { + // Compile the code. + LiveEditFunctionTracker tracker(info.function()); + if (Compiler::MakeCodeForLiveEdit(&info)) { + ASSERT(!info.code().is_null()); + tracker.RecordRootFunctionInfo(info.code()); + } else { + Top::StackOverflow(); + } } - tracker.RecordRootFunctionInfo(code); } + // Unwraps JSValue object, returning its field "value" static Handle<Object> UnwrapJSValue(Handle<JSValue> jsValue) { return Handle<Object>(jsValue->value()); } + // Wraps any object into a OpaqueReference, that will hide the object // from JavaScript. static Handle<JSValue> WrapInJSValue(Object* object) { @@ -445,6 +433,7 @@ static Handle<JSValue> WrapInJSValue(Object* object) { return result; } + // Simple helper class that creates more or less typed structures over // JSArray object. This is an adhoc method of passing structures from C++ // to JavaScript. @@ -465,6 +454,7 @@ class JSArrayBasedStruct { Handle<JSArray> GetJSArray() { return array_; } + protected: void SetField(int field_position, Handle<Object> value) { SetElement(array_, field_position, value); @@ -479,6 +469,7 @@ class JSArrayBasedStruct { Object* res = GetField(field_position); return Smi::cast(res)->value(); } + private: Handle<JSArray> array_; }; @@ -551,6 +542,7 @@ class FunctionInfoWrapper : public JSArrayBasedStruct<FunctionInfoWrapper> { friend class JSArrayBasedStruct<FunctionInfoWrapper>; }; + // Wraps SharedFunctionInfo along with some of its fields for passing it // back to JavaScript. SharedFunctionInfo object itself is additionally // wrapped into BlindReference for sanitizing reasons. @@ -591,6 +583,7 @@ class SharedInfoWrapper : public JSArrayBasedStruct<SharedInfoWrapper> { friend class JSArrayBasedStruct<SharedInfoWrapper>; }; + class FunctionInfoListener { public: FunctionInfoListener() { @@ -617,7 +610,6 @@ class FunctionInfoListener { current_parent_index_ = info.GetParentIndex(); } - public: // Saves only function code, because for a script function we // may never create a SharedFunctionInfo object. void FunctionCode(Handle<Code> function_code) { @@ -705,6 +697,7 @@ class FunctionInfoListener { int current_parent_index_; }; + static FunctionInfoListener* active_function_info_listener = NULL; JSArray* LiveEdit::GatherCompileInfo(Handle<Script> script, diff --git a/src/log-utils.cc b/src/log-utils.cc index 62f0ca62..d6d8754b 100644 --- a/src/log-utils.cc +++ b/src/log-utils.cc @@ -122,6 +122,7 @@ int LogDynamicBuffer::WriteInternal(const char* data, int data_size) { bool Log::is_stopped_ = false; Log::WritePtr Log::Write = NULL; FILE* Log::output_handle_ = NULL; +FILE* Log::output_code_handle_ = NULL; LogDynamicBuffer* Log::output_buffer_ = NULL; // Must be the same message as in Logger::PauseProfiler. const char* Log::kDynamicBufferSeal = "profiler,\"pause\"\n"; @@ -143,9 +144,22 @@ void Log::OpenStdout() { } +static const char kCodeLogExt[] = ".code"; + + void Log::OpenFile(const char* name) { ASSERT(!IsEnabled()); output_handle_ = OS::FOpen(name, OS::LogFileOpenMode); + if (FLAG_ll_prof) { + // Open a file for logging the contents of code objects so that + // they can be disassembled later. + size_t name_len = strlen(name); + ScopedVector<char> code_name( + static_cast<int>(name_len + sizeof(kCodeLogExt))); + memcpy(code_name.start(), name, name_len); + memcpy(code_name.start() + name_len, kCodeLogExt, sizeof(kCodeLogExt)); + output_code_handle_ = OS::FOpen(code_name.start(), OS::LogFileOpenMode); + } Write = WriteToFile; Init(); } @@ -165,6 +179,8 @@ void Log::Close() { if (Write == WriteToFile) { if (output_handle_ != NULL) fclose(output_handle_); output_handle_ = NULL; + if (output_code_handle_ != NULL) fclose(output_code_handle_); + output_code_handle_ = NULL; } else if (Write == WriteToMemory) { delete output_buffer_; output_buffer_ = NULL; diff --git a/src/log-utils.h b/src/log-utils.h index 8889f1b7..ffea9282 100644 --- a/src/log-utils.h +++ b/src/log-utils.h @@ -132,6 +132,7 @@ class Log : public AllStatic { size_t rv = fwrite(msg, 1, length, output_handle_); ASSERT(static_cast<size_t>(length) == rv); USE(rv); + fflush(output_handle_); return length; } @@ -151,6 +152,9 @@ class Log : public AllStatic { // mutex_ should be acquired before using output_handle_ or output_buffer_. static FILE* output_handle_; + // Used when low-level profiling is active to save code object contents. + static FILE* output_code_handle_; + static LogDynamicBuffer* output_buffer_; // Size of dynamic buffer block (and dynamic buffer initial size). @@ -170,6 +174,7 @@ class Log : public AllStatic { // mutex_ should be acquired before using it. static char* message_buffer_; + friend class Logger; friend class LogMessageBuilder; friend class LogRecordCompressor; }; @@ -191,11 +191,12 @@ class Ticker: public Sampler { ~Ticker() { if (IsActive()) Stop(); } - void SampleStack(TickSample* sample) { + virtual void SampleStack(TickSample* sample) { + ASSERT(IsSynchronous()); StackTracer::Trace(sample); } - void Tick(TickSample* sample) { + virtual void Tick(TickSample* sample) { if (profiler_) profiler_->Insert(sample); if (window_) window_->AddState(sample->state); } @@ -393,6 +394,13 @@ void Logger::IntEvent(const char* name, int value) { } +void Logger::IntPtrTEvent(const char* name, intptr_t value) { +#ifdef ENABLE_LOGGING_AND_PROFILING + if (FLAG_log) UncheckedIntPtrTEvent(name, value); +#endif +} + + #ifdef ENABLE_LOGGING_AND_PROFILING void Logger::UncheckedIntEvent(const char* name, int value) { if (!Log::IsEnabled()) return; @@ -403,6 +411,16 @@ void Logger::UncheckedIntEvent(const char* name, int value) { #endif +#ifdef ENABLE_LOGGING_AND_PROFILING +void Logger::UncheckedIntPtrTEvent(const char* name, intptr_t value) { + if (!Log::IsEnabled()) return; + LogMessageBuilder msg; + msg.Append("%s,%" V8_PTR_PREFIX "d\n", name, value); + msg.WriteToLogFile(); +} +#endif + + void Logger::HandleEvent(const char* name, Object** location) { #ifdef ENABLE_LOGGING_AND_PROFILING if (!Log::IsEnabled() || !FLAG_log_handles) return; @@ -748,6 +766,7 @@ void Logger::CodeCreateEvent(LogEventsAndTags tag, msg.Append(*p); } msg.Append('"'); + LowLevelCodeCreateEvent(code, &msg); if (FLAG_compress_log) { ASSERT(compression_helper_ != NULL); if (!compression_helper_->HandleMessage(&msg)) return; @@ -767,6 +786,7 @@ void Logger::CodeCreateEvent(LogEventsAndTags tag, Code* code, String* name) { msg.Append("%s,%s,", log_events_[CODE_CREATION_EVENT], log_events_[tag]); msg.AppendAddress(code->address()); msg.Append(",%d,\"%s\"", code->ExecutableSize(), *str); + LowLevelCodeCreateEvent(code, &msg); if (FLAG_compress_log) { ASSERT(compression_helper_ != NULL); if (!compression_helper_->HandleMessage(&msg)) return; @@ -791,6 +811,7 @@ void Logger::CodeCreateEvent(LogEventsAndTags tag, msg.AppendAddress(code->address()); msg.Append(",%d,\"%s %s:%d\"", code->ExecutableSize(), *str, *sourcestr, line); + LowLevelCodeCreateEvent(code, &msg); if (FLAG_compress_log) { ASSERT(compression_helper_ != NULL); if (!compression_helper_->HandleMessage(&msg)) return; @@ -808,6 +829,7 @@ void Logger::CodeCreateEvent(LogEventsAndTags tag, Code* code, int args_count) { msg.Append("%s,%s,", log_events_[CODE_CREATION_EVENT], log_events_[tag]); msg.AppendAddress(code->address()); msg.Append(",%d,\"args_count: %d\"", code->ExecutableSize(), args_count); + LowLevelCodeCreateEvent(code, &msg); if (FLAG_compress_log) { ASSERT(compression_helper_ != NULL); if (!compression_helper_->HandleMessage(&msg)) return; @@ -818,6 +840,17 @@ void Logger::CodeCreateEvent(LogEventsAndTags tag, Code* code, int args_count) { } +void Logger::CodeMovingGCEvent() { +#ifdef ENABLE_LOGGING_AND_PROFILING + if (!Log::IsEnabled() || !FLAG_log_code || !FLAG_ll_prof) return; + LogMessageBuilder msg; + msg.Append("%s\n", log_events_[CODE_MOVING_GC]); + msg.WriteToLogFile(); + OS::SignalCodeMovingGC(); +#endif +} + + void Logger::RegExpCodeCreateEvent(Code* code, String* source) { #ifdef ENABLE_LOGGING_AND_PROFILING if (!Log::IsEnabled() || !FLAG_log_code) return; @@ -828,6 +861,7 @@ void Logger::RegExpCodeCreateEvent(Code* code, String* source) { msg.Append(",%d,\"", code->ExecutableSize()); msg.AppendDetailed(source, false); msg.Append('\"'); + LowLevelCodeCreateEvent(code, &msg); if (FLAG_compress_log) { ASSERT(compression_helper_ != NULL); if (!compression_helper_->HandleMessage(&msg)) return; @@ -892,8 +926,7 @@ void Logger::FunctionCreateEvent(JSFunction* function) { } -void Logger::FunctionCreateEventFromMove(JSFunction* function, - HeapObject*) { +void Logger::FunctionCreateEventFromMove(JSFunction* function) { #ifdef ENABLE_LOGGING_AND_PROFILING if (function->unchecked_code() != Builtins::builtin(Builtins::LazyCompile)) { FunctionCreateEvent(function); @@ -1005,11 +1038,12 @@ void Logger::HeapSampleBeginEvent(const char* space, const char* kind) { void Logger::HeapSampleStats(const char* space, const char* kind, - int capacity, int used) { + intptr_t capacity, intptr_t used) { #ifdef ENABLE_LOGGING_AND_PROFILING if (!Log::IsEnabled() || !FLAG_log_gc) return; LogMessageBuilder msg; - msg.Append("heap-sample-stats,\"%s\",\"%s\",%d,%d\n", + msg.Append("heap-sample-stats,\"%s\",\"%s\"," + "%" V8_PTR_PREFIX "d,%" V8_PTR_PREFIX "d\n", space, kind, capacity, used); msg.WriteToLogFile(); #endif @@ -1322,6 +1356,34 @@ void Logger::LogCodeObject(Object* object) { } +void Logger::LogCodeInfo() { +#ifdef ENABLE_LOGGING_AND_PROFILING + if (!Log::IsEnabled() || !FLAG_log_code || !FLAG_ll_prof) return; +#if V8_TARGET_ARCH_IA32 + const char arch[] = "ia32"; +#elif V8_TARGET_ARCH_X64 + const char arch[] = "x64"; +#elif V8_TARGET_ARCH_ARM + const char arch[] = "arm"; +#else + const char arch[] = "unknown"; +#endif + LogMessageBuilder msg; + msg.Append("code-info,%s,%d\n", arch, Code::kHeaderSize); + msg.WriteToLogFile(); +#endif // ENABLE_LOGGING_AND_PROFILING +} + + +void Logger::LowLevelCodeCreateEvent(Code* code, LogMessageBuilder* msg) { + if (!FLAG_ll_prof || Log::output_code_handle_ == NULL) return; + int pos = static_cast<int>(ftell(Log::output_code_handle_)); + fwrite(code->instruction_start(), 1, code->instruction_size(), + Log::output_code_handle_); + msg->Append(",%d", pos); +} + + void Logger::LogCodeObjects() { AssertNoAllocation no_alloc; HeapIterator iterator; @@ -1433,6 +1495,12 @@ bool Logger::Setup() { // --prof implies --log-code. if (FLAG_prof) FLAG_log_code = true; + // --ll-prof implies --log-code and --log-snapshot-positions. + if (FLAG_ll_prof) { + FLAG_log_code = true; + FLAG_log_snapshot_positions = true; + } + // --prof_lazy controls --log-code, implies --noprof_auto. if (FLAG_prof_lazy) { FLAG_log_code = false; @@ -1494,6 +1562,8 @@ bool Logger::Setup() { ASSERT(VMState::is_outermost_external()); + if (FLAG_ll_prof) LogCodeInfo(); + ticker_ = new Ticker(kSamplingIntervalMs); if (FLAG_sliding_state_window && sliding_state_window_ == NULL) { @@ -91,6 +91,7 @@ class CompressionHelper; V(CODE_CREATION_EVENT, "code-creation", "cc") \ V(CODE_MOVE_EVENT, "code-move", "cm") \ V(CODE_DELETE_EVENT, "code-delete", "cd") \ + V(CODE_MOVING_GC, "code-moving-gc", "cg") \ V(FUNCTION_CREATION_EVENT, "function-creation", "fc") \ V(FUNCTION_MOVE_EVENT, "function-move", "fm") \ V(FUNCTION_DELETE_EVENT, "function-delete", "fd") \ @@ -159,6 +160,7 @@ class Logger { // Emits an event with an int value -> (name, value). static void IntEvent(const char* name, int value); + static void IntPtrTEvent(const char* name, intptr_t value); // Emits an event with an handle value -> (name, location). static void HandleEvent(const char* name, Object** location); @@ -208,6 +210,7 @@ class Logger { static void CodeCreateEvent(LogEventsAndTags tag, Code* code, String* name, String* source, int line); static void CodeCreateEvent(LogEventsAndTags tag, Code* code, int args_count); + static void CodeMovingGCEvent(); // Emits a code create event for a RegExp. static void RegExpCodeCreateEvent(Code* code, String* source); // Emits a code move event. @@ -216,8 +219,7 @@ class Logger { static void CodeDeleteEvent(Address from); // Emits a function object create event. static void FunctionCreateEvent(JSFunction* function); - static void FunctionCreateEventFromMove(JSFunction* function, - HeapObject*); + static void FunctionCreateEventFromMove(JSFunction* function); // Emits a function move event. static void FunctionMoveEvent(Address from, Address to); // Emits a function delete event. @@ -237,7 +239,7 @@ class Logger { static void HeapSampleJSProducerEvent(const char* constructor, Address* stack); static void HeapSampleStats(const char* space, const char* kind, - int capacity, int used); + intptr_t capacity, intptr_t used); static void SharedLibraryEvent(const char* library_path, uintptr_t start, @@ -316,6 +318,12 @@ class Logger { // Used for logging stubs found in the snapshot. static void LogCodeObject(Object* code_object); + // Emits general information about generated code. + static void LogCodeInfo(); + + // Handles code creation when low-level profiling is active. + static void LowLevelCodeCreateEvent(Code* code, LogMessageBuilder* msg); + // Emits a profiler tick event. Used by the profiler thread. static void TickEvent(TickSample* sample, bool overflow); @@ -326,6 +334,7 @@ class Logger { // Logs an IntEvent regardless of whether FLAG_log is true. static void UncheckedIntEvent(const char* name, int value); + static void UncheckedIntPtrTEvent(const char* name, intptr_t value); // Stops logging and profiling in case of insufficient resources. static void StopLoggingAndProfiling(); diff --git a/src/mark-compact.cc b/src/mark-compact.cc index c847b842..ad928ea3 100644 --- a/src/mark-compact.cc +++ b/src/mark-compact.cc @@ -167,8 +167,8 @@ void MarkCompactCollector::Finish() { // reclaiming the waste and free list blocks). static const int kFragmentationLimit = 15; // Percent. static const int kFragmentationAllowed = 1 * MB; // Absolute. - int old_gen_recoverable = 0; - int old_gen_used = 0; + intptr_t old_gen_recoverable = 0; + intptr_t old_gen_used = 0; OldSpaces spaces; for (OldSpace* space = spaces.next(); space != NULL; space = spaces.next()) { @@ -282,6 +282,11 @@ class StaticMarkingVisitor : public StaticVisitorBase { FixedArray::BodyDescriptor, void>::Visit); + table_.Register(kVisitGlobalContext, + &FixedBodyVisitor<StaticMarkingVisitor, + Context::MarkCompactBodyDescriptor, + void>::Visit); + table_.Register(kVisitSharedFunctionInfo, &VisitSharedFunctionInfo); table_.Register(kVisitByteArray, &DataObjectVisitor::Visit); @@ -578,6 +583,7 @@ class StaticMarkingVisitor : public StaticVisitorBase { VisitPointers(SLOT_ADDR(object, JSFunction::kCodeEntryOffset + kPointerSize), SLOT_ADDR(object, JSFunction::kSize)); + #undef SLOT_ADDR } @@ -738,6 +744,21 @@ class SymbolTableCleaner : public ObjectVisitor { }; +// Implementation of WeakObjectRetainer for mark compact GCs. All marked objects +// are retained. +class MarkCompactWeakObjectRetainer : public WeakObjectRetainer { + public: + virtual Object* RetainAs(Object* object) { + MapWord first_word = HeapObject::cast(object)->map_word(); + if (first_word.IsMarked()) { + return object; + } else { + return NULL; + } + } +}; + + void MarkCompactCollector::MarkUnmarkedObject(HeapObject* object) { ASSERT(!object->IsMarked()); ASSERT(Heap::Contains(object)); @@ -1069,6 +1090,10 @@ void MarkCompactCollector::MarkLiveObjects() { ExternalStringTable::Iterate(&v); ExternalStringTable::CleanUp(); + // Process the weak references. + MarkCompactWeakObjectRetainer mark_compact_object_retainer; + Heap::ProcessWeakReferences(&mark_compact_object_retainer); + // Remove object groups after marking phase. GlobalHandles::RemoveObjectGroups(); } @@ -1639,6 +1664,9 @@ static void SweepNewSpace(NewSpace* space) { } } + // Update pointer from the global contexts list. + updating_visitor.VisitPointer(Heap::global_contexts_list_address()); + // Update pointers from external string table. Heap::UpdateNewSpaceReferencesInExternalStringTable( &UpdateNewSpaceReferenceInExternalStringTableEntry); @@ -2008,8 +2036,10 @@ class MapCompact { #ifdef DEBUG if (FLAG_gc_verbose) { - PrintF("update %p : %p -> %p\n", obj->address(), - map, new_map); + PrintF("update %p : %p -> %p\n", + obj->address(), + reinterpret_cast<void*>(map), + reinterpret_cast<void*>(new_map)); } #endif } @@ -2068,8 +2098,8 @@ void MarkCompactCollector::SweepSpaces() { &UpdatePointerToNewGen, Heap::WATERMARK_SHOULD_BE_VALID); - int live_maps_size = Heap::map_space()->Size(); - int live_maps = live_maps_size / Map::kSize; + intptr_t live_maps_size = Heap::map_space()->Size(); + int live_maps = static_cast<int>(live_maps_size / Map::kSize); ASSERT(live_map_objects_size_ == live_maps_size); if (Heap::map_space()->NeedsCompaction(live_maps)) { @@ -2243,6 +2273,9 @@ void MarkCompactCollector::UpdatePointers() { Heap::IterateRoots(&updating_visitor, VISIT_ONLY_STRONG); GlobalHandles::IterateWeakRoots(&updating_visitor); + // Update the pointer to the head of the weak list of global contexts. + updating_visitor.VisitPointer(&Heap::global_contexts_list_); + int live_maps_size = IterateLiveObjects(Heap::map_space(), &UpdatePointersInOldObject); int live_pointer_olds_size = IterateLiveObjects(Heap::old_pointer_space(), @@ -2520,7 +2553,7 @@ int MarkCompactCollector::RelocateOldNonCodeObject(HeapObject* obj, HeapObject* copied_to = HeapObject::FromAddress(new_addr); if (copied_to->IsJSFunction()) { PROFILE(FunctionMoveEvent(old_addr, new_addr)); - PROFILE(FunctionCreateEventFromMove(JSFunction::cast(copied_to), obj)); + PROFILE(FunctionCreateEventFromMove(JSFunction::cast(copied_to))); } HEAP_PROFILE(ObjectMoveEvent(old_addr, new_addr)); @@ -2613,7 +2646,7 @@ int MarkCompactCollector::RelocateNewObject(HeapObject* obj) { HeapObject* copied_to = HeapObject::FromAddress(new_addr); if (copied_to->IsJSFunction()) { PROFILE(FunctionMoveEvent(old_addr, new_addr)); - PROFILE(FunctionCreateEventFromMove(JSFunction::cast(copied_to), obj)); + PROFILE(FunctionCreateEventFromMove(JSFunction::cast(copied_to))); } HEAP_PROFILE(ObjectMoveEvent(old_addr, new_addr)); diff --git a/src/messages.js b/src/messages.js index 4f492bc5..7f9c0f8d 100644 --- a/src/messages.js +++ b/src/messages.js @@ -438,18 +438,18 @@ Script.prototype.lineCount = function() { /** * Returns the name of script if available, contents of sourceURL comment - * otherwise. See + * otherwise. See * http://fbug.googlecode.com/svn/branches/firebug1.1/docs/ReleaseNotes_1.1.txt * for details on using //@ sourceURL comment to identify scritps that don't * have name. - * + * * @return {?string} script name if present, value for //@ sourceURL comment * otherwise. */ Script.prototype.nameOrSourceURL = function() { if (this.name) return this.name; - // TODO(608): the spaces in a regexp below had to be escaped as \040 + // TODO(608): the spaces in a regexp below had to be escaped as \040 // because this file is being processed by js2c whose handling of spaces // in regexps is broken. Also, ['"] are excluded from allowed URLs to // avoid matches against sources that invoke evals with sourceURL. diff --git a/src/mips/simulator-mips.cc b/src/mips/simulator-mips.cc index 57bed6a0..59a53732 100644 --- a/src/mips/simulator-mips.cc +++ b/src/mips/simulator-mips.cc @@ -39,7 +39,7 @@ namespace v8i = v8::internal; -#if !defined(__mips) +#if !defined(__mips) || defined(USE_SIMULATOR) // Only build the simulator if not compiling for real MIPS hardware. namespace assembler { @@ -1645,6 +1645,6 @@ uintptr_t Simulator::PopAddress() { } } // namespace assembler::mips -#endif // __mips +#endif // !__mips || USE_SIMULATOR #endif // V8_TARGET_ARCH_MIPS diff --git a/src/mips/simulator-mips.h b/src/mips/simulator-mips.h index d5dfc301..6e42683a 100644 --- a/src/mips/simulator-mips.h +++ b/src/mips/simulator-mips.h @@ -38,7 +38,7 @@ #include "allocation.h" -#if defined(__mips) +#if defined(__mips) && !defined(USE_SIMULATOR) // When running without a simulator we call the entry directly. #define CALL_GENERATED_CODE(entry, p0, p1, p2, p3, p4) \ @@ -79,7 +79,7 @@ class SimulatorStack : public v8::internal::AllStatic { reinterpret_cast<TryCatch*>(try_catch_address) -#else // #if defined(__mips) +#else // #if !defined(__mips) || defined(USE_SIMULATOR) // When running with the simulator transition into simulated execution at this // point. @@ -305,7 +305,7 @@ class SimulatorStack : public v8::internal::AllStatic { } }; -#endif // defined(__mips) +#endif // !defined(__mips) || defined(USE_SIMULATOR) #endif // V8_MIPS_SIMULATOR_MIPS_H_ diff --git a/src/mirror-debugger.js b/src/mirror-debugger.js index 761b9b31..6b9e9655 100644 --- a/src/mirror-debugger.js +++ b/src/mirror-debugger.js @@ -1611,7 +1611,7 @@ FrameMirror.prototype.invocationText = function() { result += ' returning '; result += this.returnValue().toText(); } - + return result; } diff --git a/src/objects-debug.cc b/src/objects-debug.cc index ed08468e..5883f8b3 100644 --- a/src/objects-debug.cc +++ b/src/objects-debug.cc @@ -89,7 +89,7 @@ void Failure::FailureVerify() { void HeapObject::PrintHeader(const char* id) { - PrintF("%p: [%s]\n", this, id); + PrintF("%p: [%s]\n", reinterpret_cast<void*>(this), id); } @@ -522,9 +522,9 @@ void JSObject::PrintElements() { void JSObject::JSObjectPrint() { - PrintF("%p: [JSObject]\n", this); - PrintF(" - map = %p\n", map()); - PrintF(" - prototype = %p\n", GetPrototype()); + PrintF("%p: [JSObject]\n", reinterpret_cast<void*>(this)); + PrintF(" - map = %p\n", reinterpret_cast<void*>(map())); + PrintF(" - prototype = %p\n", reinterpret_cast<void*>(GetPrototype())); PrintF(" {\n"); PrintProperties(); PrintElements(); @@ -744,7 +744,7 @@ void String::StringVerify() { void JSFunction::JSFunctionPrint() { HeapObject::PrintHeader("Function"); - PrintF(" - map = 0x%p\n", map()); + PrintF(" - map = 0x%p\n", reinterpret_cast<void*>(map())); PrintF(" - initial_map = "); if (has_initial_map()) { initial_map()->ShortPrint(); @@ -1224,9 +1224,9 @@ void BreakPointInfo::BreakPointInfoVerify() { void BreakPointInfo::BreakPointInfoPrint() { HeapObject::PrintHeader("BreakPointInfo"); - PrintF("\n - code_position: %d", code_position()); - PrintF("\n - source_position: %d", source_position()); - PrintF("\n - statement_position: %d", statement_position()); + PrintF("\n - code_position: %d", code_position()->value()); + PrintF("\n - source_position: %d", source_position()->value()); + PrintF("\n - statement_position: %d", statement_position()->value()); PrintF("\n - break_point_objects: "); break_point_objects()->ShortPrint(); } diff --git a/src/objects-inl.h b/src/objects-inl.h index f63d6725..11f9d348 100644 --- a/src/objects-inl.h +++ b/src/objects-inl.h @@ -844,15 +844,6 @@ bool Failure::IsOutOfMemoryException() const { } -int Failure::requested() const { - const int kShiftBits = - kFailureTypeTagSize + kSpaceTagSize - kObjectAlignmentBits; - STATIC_ASSERT(kShiftBits >= 0); - ASSERT(type() == RETRY_AFTER_GC); - return static_cast<int>(value() >> kShiftBits); -} - - AllocationSpace Failure::allocation_space() const { ASSERT_EQ(RETRY_AFTER_GC, type()); return static_cast<AllocationSpace>((value() >> kFailureTypeTagSize) @@ -881,20 +872,14 @@ intptr_t Failure::value() const { } -Failure* Failure::RetryAfterGC(int requested_bytes) { - // Assert that the space encoding fits in the three bytes allotted for it. - ASSERT((LAST_SPACE & ~kSpaceTagMask) == 0); - uintptr_t requested = - static_cast<uintptr_t>(requested_bytes >> kObjectAlignmentBits); - int tag_bits = kSpaceTagSize + kFailureTypeTagSize + kFailureTagSize; - if (((requested << tag_bits) >> tag_bits) != requested) { - // No room for entire requested size in the bits. Round down to - // maximally representable size. - requested = static_cast<intptr_t>( - (~static_cast<uintptr_t>(0)) >> (tag_bits + 1)); - } - int value = static_cast<int>(requested << kSpaceTagSize) | NEW_SPACE; - return Construct(RETRY_AFTER_GC, value); +Failure* Failure::RetryAfterGC() { + return RetryAfterGC(NEW_SPACE); +} + + +Failure* Failure::RetryAfterGC(AllocationSpace space) { + ASSERT((space & ~kSpaceTagMask) == 0); + return Construct(RETRY_AFTER_GC, space); } @@ -1485,6 +1470,15 @@ void FixedArray::set_unchecked(int index, Smi* value) { } +void FixedArray::set_unchecked(int index, + Object* value, + WriteBarrierMode mode) { + int offset = kHeaderSize + index * kPointerSize; + WRITE_FIELD(this, offset, value); + CONDITIONAL_WRITE_BARRIER(this, offset, mode); +} + + void FixedArray::set_null_unchecked(int index) { ASSERT(index >= 0 && index < this->length()); ASSERT(!Heap::InNewSpace(Heap::null_value())); diff --git a/src/objects-visiting.h b/src/objects-visiting.h index a6d6b12c..ed76cb97 100644 --- a/src/objects-visiting.h +++ b/src/objects-visiting.h @@ -25,8 +25,8 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -#ifndef V8_OBJECTS_ITERATION_H_ -#define V8_OBJECTS_ITERATION_H_ +#ifndef V8_OBJECTS_VISITING_H_ +#define V8_OBJECTS_VISITING_H_ // This file provides base classes and auxiliary methods for defining // static object visitors used during GC. @@ -50,6 +50,7 @@ class StaticVisitorBase : public AllStatic { kVisitShortcutCandidate, kVisitByteArray, kVisitFixedArray, + kVisitGlobalContext, // For data objects, JS objects and structs along with generic visitor which // can visit object of any size we provide visitors specialized by @@ -263,6 +264,11 @@ class StaticNewSpaceVisitor : public StaticVisitorBase { FixedArray::BodyDescriptor, int>::Visit); + table_.Register(kVisitGlobalContext, + &FixedBodyVisitor<StaticVisitor, + Context::ScavengeBodyDescriptor, + int>::Visit); + table_.Register(kVisitByteArray, &VisitByteArray); table_.Register(kVisitSharedFunctionInfo, @@ -389,4 +395,4 @@ void Code::CodeIterateBody() { } } // namespace v8::internal -#endif // V8_OBJECTS_ITERATION_H_ +#endif // V8_OBJECTS_VISITING_H_ diff --git a/src/objects.cc b/src/objects.cc index 737bf572..ac20b2e6 100644 --- a/src/objects.cc +++ b/src/objects.cc @@ -1,4 +1,4 @@ -// Copyright 2006-2009 the V8 project authors. All rights reserved. +// 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: @@ -574,28 +574,6 @@ void Failure::FailurePrint() { } -Failure* Failure::RetryAfterGC(int requested_bytes, AllocationSpace space) { - ASSERT((space & ~kSpaceTagMask) == 0); - // TODO(X64): Stop using Smi validation for non-smi checks, even if they - // happen to be identical at the moment. - - int requested = requested_bytes >> kObjectAlignmentBits; - int value = (requested << kSpaceTagSize) | space; - // We can't very well allocate a heap number in this situation, and if the - // requested memory is so large it seems reasonable to say that this is an - // out of memory situation. This fixes a crash in - // js1_5/Regress/regress-303213.js. - if (value >> kSpaceTagSize != requested || - !Smi::IsValid(value) || - value != ((value << kFailureTypeTagSize) >> kFailureTypeTagSize) || - !Smi::IsValid(value << kFailureTypeTagSize)) { - Top::context()->mark_out_of_memory(); - return Failure::OutOfMemoryException(); - } - return Construct(RETRY_AFTER_GC, value); -} - - // Should a word be prefixed by 'a' or 'an' in order to read naturally in // English? Returns false for non-ASCII or words that don't start with // a capital letter. The a/an rule follows pronunciation in English. @@ -1180,7 +1158,11 @@ String* JSObject::constructor_name() { if (map()->constructor()->IsJSFunction()) { JSFunction* constructor = JSFunction::cast(map()->constructor()); String* name = String::cast(constructor->shared()->name()); - return name->length() > 0 ? name : constructor->shared()->inferred_name(); + if (name->length() > 0) return name; + String* inferred_name = constructor->shared()->inferred_name(); + if (inferred_name->length() > 0) return inferred_name; + Object* proto = GetPrototype(); + if (proto->IsJSObject()) return JSObject::cast(proto)->constructor_name(); } // If the constructor is not present, return "Object". return Heap::Object_symbol(); @@ -3601,9 +3583,17 @@ Object* FixedArray::AddKeysFromJSArray(JSArray* array) { Object* FixedArray::UnionOfKeys(FixedArray* other) { int len0 = length(); +#ifdef DEBUG + if (FLAG_enable_slow_asserts) { + for (int i = 0; i < len0; i++) { + ASSERT(get(i)->IsString() || get(i)->IsNumber()); + } + } +#endif int len1 = other->length(); - // Optimize if either is empty. - if (len0 == 0) return other; + // Optimize if 'other' is empty. + // We cannot optimize if 'this' is empty, as other may have holes + // or non keys. if (len1 == 0) return this; // Compute how many elements are not in this. @@ -3623,14 +3613,18 @@ Object* FixedArray::UnionOfKeys(FixedArray* other) { FixedArray* result = FixedArray::cast(obj); WriteBarrierMode mode = result->GetWriteBarrierMode(no_gc); for (int i = 0; i < len0; i++) { - result->set(i, get(i), mode); + Object* e = get(i); + ASSERT(e->IsString() || e->IsNumber()); + result->set(i, e, mode); } // Fill in the extra keys. int index = 0; for (int y = 0; y < len1; y++) { Object* value = other->get(y); if (!value->IsTheHole() && !HasKey(this, value)) { - result->set(len0 + index, other->get(y), mode); + Object* e = other->get(y); + ASSERT(e->IsString() || e->IsNumber()); + result->set(len0 + index, e, mode); index++; } } @@ -5227,6 +5221,13 @@ Object* Oddball::Initialize(const char* to_string, Object* to_number) { } +String* SharedFunctionInfo::DebugName() { + Object* n = name(); + if (!n->IsString() || String::cast(n)->length() == 0) return inferred_name(); + return String::cast(n); +} + + bool SharedFunctionInfo::HasSourceCode() { return !script()->IsUndefined() && !reinterpret_cast<Script*>(script())->source()->IsUndefined(); @@ -6454,7 +6455,7 @@ Object* JSObject::SetElementWithoutInterceptor(uint32_t index, Object* value) { // When we set the is_extensible flag to false we always force // the element into dictionary mode (and force them to stay there). if (!map()->is_extensible()) { - Handle<Object> number(Heap::NumberFromUint32(index)); + Handle<Object> number(Factory::NewNumberFromUint(index)); Handle<String> index_string(Factory::NumberToString(number)); Handle<Object> args[1] = { index_string }; return Top::Throw(*Factory::NewTypeError("object_not_extensible", @@ -8568,7 +8569,9 @@ Object* NumberDictionary::Set(uint32_t key, details = PropertyDetails(details.attributes(), details.type(), DetailsAt(entry).index()); - SetEntry(entry, NumberDictionaryShape::AsObject(key), value, details); + Object* object_key = NumberDictionaryShape::AsObject(key); + if (object_key->IsFailure()) return object_key; + SetEntry(entry, object_key, value, details); return this; } @@ -8719,6 +8722,11 @@ Object* StringDictionary::TransformPropertiesToFastFor( int inobject_props = obj->map()->inobject_properties(); int number_of_allocated_fields = number_of_fields + unused_property_fields - inobject_props; + if (number_of_allocated_fields < 0) { + // There is enough inobject space for all fields (including unused). + number_of_allocated_fields = 0; + unused_property_fields = inobject_props - number_of_fields; + } // Allocate the fixed array for the fields. Object* fields = Heap::AllocateFixedArray(number_of_allocated_fields); diff --git a/src/objects.h b/src/objects.h index 7f301b5c..d917a575 100644 --- a/src/objects.h +++ b/src/objects.h @@ -1,4 +1,4 @@ -// Copyright 2006-2009 the V8 project authors. All rights reserved. +// 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: @@ -794,7 +794,7 @@ class Smi: public Object { // // Failures are a single word, encoded as follows: // +-------------------------+---+--+--+ -// |...rrrrrrrrrrrrrrrrrrrrrr|sss|tt|11| +// |.........unused..........|sss|tt|11| // +-------------------------+---+--+--+ // 7 6 4 32 10 // @@ -810,11 +810,6 @@ class Smi: public Object { // allocation space tag is 000 for all failure types except // RETRY_AFTER_GC. For RETRY_AFTER_GC, the possible values are the // allocation spaces (the encoding is found in globals.h). -// -// The remaining bits is the size of the allocation request in units -// of the pointer size, and is zeroed except for RETRY_AFTER_GC -// failures. The 25 bits (on a 32 bit platform) gives a representable -// range of 2^27 bytes (128MB). // Failure type tag info. const int kFailureTypeTagSize = 2; @@ -836,15 +831,11 @@ class Failure: public Object { // Returns the space that needs to be collected for RetryAfterGC failures. inline AllocationSpace allocation_space() const; - // Returns the number of bytes requested (up to the representable maximum) - // for RetryAfterGC failures. - inline int requested() const; - inline bool IsInternalError() const; inline bool IsOutOfMemoryException() const; - static Failure* RetryAfterGC(int requested_bytes, AllocationSpace space); - static inline Failure* RetryAfterGC(int requested_bytes); // NEW_SPACE + static inline Failure* RetryAfterGC(AllocationSpace space); + static inline Failure* RetryAfterGC(); // NEW_SPACE static inline Failure* Exception(); static inline Failure* InternalError(); static inline Failure* OutOfMemoryException(); @@ -1760,6 +1751,7 @@ class FixedArray: public HeapObject { // Setters with less debug checks for the GC to use. inline void set_unchecked(int index, Smi* value); inline void set_null_unchecked(int index); + inline void set_unchecked(int index, Object* value, WriteBarrierMode mode); // Gives access to raw memory which stores the array's data. inline Object** data_start(); @@ -3537,7 +3529,7 @@ class SharedFunctionInfo: public HeapObject { // Important: inobject slack tracking is not attempted during the snapshot // creation. - static const int kGenerousAllocationCount = 16; + static const int kGenerousAllocationCount = 8; // [construction_count]: Counter for constructor calls made during // the tracking phase. @@ -3621,6 +3613,9 @@ class SharedFunctionInfo: public HeapObject { // properties. DECL_ACCESSORS(inferred_name, String) + // The function's name if it is non-empty, otherwise the inferred name. + String* DebugName(); + // Position of the 'function' token in the script source. inline int function_token_position(); inline void set_function_token_position(int function_token_position); diff --git a/src/parser.cc b/src/parser.cc index a3f469af..7690e92d 100644 --- a/src/parser.cc +++ b/src/parser.cc @@ -47,14 +47,6 @@ namespace v8 { namespace internal { -class ParserFactory; -class ParserLog; -class TemporaryScope; -class Target; - -template <typename T> class ZoneListWrapper; - - // PositionStack is used for on-stack allocation of token positions for // new expressions. Please look at ParseNewExpression. @@ -95,254 +87,6 @@ class PositionStack { }; -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); - - void ReportMessage(const char* message, Vector<const char*> args); - virtual void ReportMessageAt(Scanner::Location loc, - const char* message, - Vector<const char*> args) = 0; - - - // Returns NULL if parsing failed. - FunctionLiteral* ParseProgram(Handle<String> source, - bool in_global_context); - FunctionLiteral* ParseLazy(Handle<String> source, - Handle<String> name, - int start_position, - int end_position, - bool is_expression); - FunctionLiteral* ParseJson(Handle<String> source); - - // The minimum number of contiguous assignment that will - // be treated as an initialization block. Benchmarks show that - // the overhead exceeds the savings below this limit. - static const int kMinInitializationBlock = 3; - - protected: - - enum Mode { - PARSE_LAZILY, - PARSE_EAGERLY - }; - - // Report syntax error - void ReportUnexpectedToken(Token::Value token); - void ReportInvalidPreparseData(Handle<String> name, bool* ok); - - Handle<Script> script_; - Scanner scanner_; - - Scope* top_scope_; - int with_nesting_level_; - - TemporaryScope* temp_scope_; - Mode mode_; - - Target* target_stack_; // for break, continue statements - bool allow_natives_syntax_; - v8::Extension* extension_; - ParserFactory* factory_; - ParserLog* log_; - bool is_pre_parsing_; - ScriptDataImpl* pre_data_; - FuncNameInferrer* fni_; - - bool inside_with() const { return with_nesting_level_ > 0; } - ParserFactory* factory() const { return factory_; } - ParserLog* log() const { return log_; } - Scanner& scanner() { return scanner_; } - Mode mode() const { return mode_; } - ScriptDataImpl* pre_data() const { return pre_data_; } - - // All ParseXXX functions take as the last argument an *ok parameter - // which is set to false if parsing failed; it is unchanged otherwise. - // By making the 'exception handling' explicit, we are forced to check - // for failure at the call sites. - void* ParseSourceElements(ZoneListWrapper<Statement>* processor, - int end_token, bool* ok); - Statement* ParseStatement(ZoneStringList* labels, bool* ok); - Statement* ParseFunctionDeclaration(bool* ok); - Statement* ParseNativeDeclaration(bool* ok); - Block* ParseBlock(ZoneStringList* labels, bool* ok); - Block* ParseVariableStatement(bool* ok); - Block* ParseVariableDeclarations(bool accept_IN, Expression** var, bool* ok); - Statement* ParseExpressionOrLabelledStatement(ZoneStringList* labels, - bool* ok); - IfStatement* ParseIfStatement(ZoneStringList* labels, bool* ok); - Statement* ParseContinueStatement(bool* ok); - Statement* ParseBreakStatement(ZoneStringList* labels, bool* ok); - Statement* ParseReturnStatement(bool* ok); - Block* WithHelper(Expression* obj, - ZoneStringList* labels, - bool is_catch_block, - bool* ok); - Statement* ParseWithStatement(ZoneStringList* labels, bool* ok); - CaseClause* ParseCaseClause(bool* default_seen_ptr, bool* ok); - SwitchStatement* ParseSwitchStatement(ZoneStringList* labels, bool* ok); - DoWhileStatement* ParseDoWhileStatement(ZoneStringList* labels, bool* ok); - WhileStatement* ParseWhileStatement(ZoneStringList* labels, bool* ok); - Statement* ParseForStatement(ZoneStringList* labels, bool* ok); - Statement* ParseThrowStatement(bool* ok); - Expression* MakeCatchContext(Handle<String> id, VariableProxy* value); - TryStatement* ParseTryStatement(bool* ok); - DebuggerStatement* ParseDebuggerStatement(bool* ok); - - Expression* ParseExpression(bool accept_IN, bool* ok); - Expression* ParseAssignmentExpression(bool accept_IN, bool* ok); - Expression* ParseConditionalExpression(bool accept_IN, bool* ok); - Expression* ParseBinaryExpression(int prec, bool accept_IN, bool* ok); - Expression* ParseUnaryExpression(bool* ok); - Expression* ParsePostfixExpression(bool* ok); - Expression* ParseLeftHandSideExpression(bool* ok); - Expression* ParseNewExpression(bool* ok); - Expression* ParseMemberExpression(bool* ok); - Expression* ParseNewPrefix(PositionStack* stack, bool* ok); - Expression* ParseMemberWithNewPrefixesExpression(PositionStack* stack, - bool* ok); - Expression* ParsePrimaryExpression(bool* ok); - Expression* ParseArrayLiteral(bool* ok); - Expression* ParseObjectLiteral(bool* ok); - ObjectLiteral::Property* ParseObjectLiteralGetSet(bool is_getter, bool* ok); - Expression* ParseRegExpLiteral(bool seen_equal, bool* ok); - - Expression* NewCompareNode(Token::Value op, - Expression* x, - Expression* y, - int position); - - // Populate the constant properties fixed array for a materialized object - // literal. - void BuildObjectLiteralConstantProperties( - ZoneList<ObjectLiteral::Property*>* properties, - Handle<FixedArray> constants, - bool* is_simple, - bool* fast_elements, - int* depth); - - // Populate the literals fixed array for a materialized array literal. - void BuildArrayLiteralBoilerplateLiterals(ZoneList<Expression*>* properties, - Handle<FixedArray> constants, - bool* is_simple, - int* depth); - - // Decide if a property should be in the object boilerplate. - bool IsBoilerplateProperty(ObjectLiteral::Property* property); - // If the expression is a literal, return the literal value; - // if the expression is a materialized literal and is simple return a - // compile time value as encoded by CompileTimeValue::GetValue(). - // Otherwise, return undefined literal as the placeholder - // in the object literal boilerplate. - Handle<Object> GetBoilerplateValue(Expression* expression); - - enum FunctionLiteralType { - EXPRESSION, - DECLARATION, - NESTED - }; - - ZoneList<Expression*>* ParseArguments(bool* ok); - FunctionLiteral* ParseFunctionLiteral(Handle<String> var_name, - int function_token_position, - FunctionLiteralType type, - bool* ok); - - - // Magical syntax support. - Expression* ParseV8Intrinsic(bool* ok); - - INLINE(Token::Value peek()) { return scanner_.peek(); } - INLINE(Token::Value Next()) { return scanner_.Next(); } - INLINE(void Consume(Token::Value token)); - void Expect(Token::Value token, bool* ok); - bool Check(Token::Value token); - void ExpectSemicolon(bool* ok); - - Handle<String> GetSymbol(bool* ok); - - // Get odd-ball literals. - Literal* GetLiteralUndefined(); - Literal* GetLiteralTheHole(); - Literal* GetLiteralNumber(double value); - - Handle<String> ParseIdentifier(bool* ok); - Handle<String> ParseIdentifierName(bool* ok); - Handle<String> ParseIdentifierOrGetOrSet(bool* is_get, - bool* is_set, - bool* ok); - - // Parser support - virtual VariableProxy* Declare(Handle<String> name, Variable::Mode mode, - FunctionLiteral* fun, - bool resolve, - bool* ok) = 0; - - bool TargetStackContainsLabel(Handle<String> label); - BreakableStatement* LookupBreakTarget(Handle<String> label, bool* ok); - IterationStatement* LookupContinueTarget(Handle<String> label, bool* ok); - - void RegisterTargetUse(BreakTarget* target, Target* stop); - - // Create a number literal. - Literal* NewNumberLiteral(double value); - - // Generate AST node that throw a ReferenceError with the given type. - Expression* NewThrowReferenceError(Handle<String> type); - - // Generate AST node that throw a SyntaxError with the given - // type. The first argument may be null (in the handle sense) in - // which case no arguments are passed to the constructor. - Expression* NewThrowSyntaxError(Handle<String> type, Handle<Object> first); - - // Generate AST node that throw a TypeError with the given - // type. Both arguments must be non-null (in the handle sense). - Expression* NewThrowTypeError(Handle<String> type, - Handle<Object> first, - Handle<Object> second); - - // Generic AST generator for throwing errors from compiled code. - 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; -}; - - template <typename T, int initial_size> class BufferedZoneList { public: @@ -877,12 +621,30 @@ class ParserLog BASE_EMBEDDED { virtual int function_position() { return 0; } virtual int symbol_position() { return 0; } virtual int symbol_ids() { return 0; } + virtual void PauseRecording() {} + virtual void ResumeRecording() {} virtual Vector<unsigned> ExtractData() { return Vector<unsigned>(); }; }; + +class ConditionalLogPauseScope { + public: + ConditionalLogPauseScope(bool pause, ParserLog* log) + : log_(log), pause_(pause) { + if (pause) log->PauseRecording(); + } + ~ConditionalLogPauseScope() { + if (pause_) log_->ResumeRecording(); + } + private: + ParserLog* log_; + bool pause_; +}; + + class AstBuildingParserFactory : public ParserFactory { public: explicit AstBuildingParserFactory(int expected_symbols) @@ -970,15 +732,31 @@ class PartialParserRecorder: public ParserLog { return data; } + virtual void PauseRecording() { + pause_count_++; + is_recording_ = false; + } + + virtual void ResumeRecording() { + ASSERT(pause_count_ > 0); + if (--pause_count_ == 0) is_recording_ = !has_error(); + } + protected: bool has_error() { return static_cast<bool>(preamble_[ScriptDataImpl::kHasErrorOffset]); } + bool is_recording() { + return is_recording_; + } void WriteString(Vector<const char> str); Collector<unsigned> function_store_; unsigned preamble_[ScriptDataImpl::kHeaderSize]; + bool is_recording_; + int pause_count_; + #ifdef DEBUG int prev_start; #endif @@ -991,6 +769,7 @@ class CompleteParserRecorder: public PartialParserRecorder { CompleteParserRecorder(); virtual void LogSymbol(int start, Vector<const char> literal) { + if (!is_recording_) return; int hash = vector_hash(literal); HashMap::Entry* entry = symbol_table_.Lookup(&literal, hash, true); int id = static_cast<int>(reinterpret_cast<intptr_t>(entry->value)); @@ -1061,13 +840,6 @@ class CompleteParserRecorder: public PartialParserRecorder { }; -void ScriptDataImpl::SkipFunctionEntry(int start) { - ASSERT(function_index_ + FunctionEntry::kSize <= store_.length()); - ASSERT(static_cast<int>(store_[function_index_]) == start); - function_index_ += FunctionEntry::kSize; -} - - FunctionEntry ScriptDataImpl::GetFunctionEntry(int start) { // The current pre-data entry must be a FunctionEntry with the given // start position. @@ -1126,7 +898,10 @@ bool ScriptDataImpl::SanityCheck() { -PartialParserRecorder::PartialParserRecorder() : function_store_(0) { +PartialParserRecorder::PartialParserRecorder() + : function_store_(0), + is_recording_(true), + pause_count_(0) { preamble_[ScriptDataImpl::kMagicOffset] = ScriptDataImpl::kMagicNumber; preamble_[ScriptDataImpl::kVersionOffset] = ScriptDataImpl::kCurrentVersion; preamble_[ScriptDataImpl::kHasErrorOffset] = false; @@ -1202,6 +977,7 @@ void PartialParserRecorder::LogMessage(Scanner::Location loc, for (int i = 0; i < args.length(); i++) { WriteString(CStrVector(args[i])); } + is_recording_ = false; } @@ -1248,7 +1024,7 @@ FunctionEntry PartialParserRecorder::LogFunction(int start) { ASSERT(start > prev_start); prev_start = start; #endif - if (has_error()) return FunctionEntry(); + if (!is_recording_) return FunctionEntry(); FunctionEntry result(function_store_.AddBlock(FunctionEntry::kSize, 0)); result.set_start_pos(start); return result; @@ -1343,6 +1119,8 @@ Scope* ParserFactory::NewScope(Scope* parent, Scope::Type type, bool inside_with) { ASSERT(parent != NULL); parent->type_ = type; + // Initialize function is hijacked by DummyScope to increment scope depth. + parent->Initialize(inside_with); return parent; } @@ -1415,6 +1193,7 @@ class LexicalScope BASE_EMBEDDED { } ~LexicalScope() { + parser_->top_scope_->Leave(); parser_->top_scope_ = prev_scope_; parser_->with_nesting_level_ = prev_level_; } @@ -1480,7 +1259,8 @@ bool Parser::PreParseProgram(Handle<String> source, NoHandleAllocation no_handle_allocation; scanner_.Initialize(source, stream, JAVASCRIPT); ASSERT(target_stack_ == NULL); - mode_ = PARSE_EAGERLY; + 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); @@ -1551,21 +1331,20 @@ FunctionLiteral* Parser::ParseProgram(Handle<String> source, } -FunctionLiteral* Parser::ParseLazy(Handle<String> source, - Handle<String> name, - int start_position, - int end_position, - bool is_expression) { +FunctionLiteral* Parser::ParseLazy(Handle<SharedFunctionInfo> info) { CompilationZoneScope zone_scope(DONT_DELETE_ON_EXIT); HistogramTimerScope timer(&Counters::parse_lazy); + Handle<String> source(String::cast(script_->source())); Counters::total_parse_size.Increment(source->length()); + Handle<String> name(String::cast(info->name())); fni_ = new FuncNameInferrer(); fni_->PushEnclosingName(name); // Initialize parser state. source->TryFlatten(); - scanner_.Initialize(source, start_position, end_position, JAVASCRIPT); + scanner_.Initialize(source, info->start_position(), info->end_position(), + JAVASCRIPT); ASSERT(target_stack_ == NULL); mode_ = PARSE_EAGERLY; @@ -1580,7 +1359,8 @@ FunctionLiteral* Parser::ParseLazy(Handle<String> source, LexicalScope lexical_scope(this, scope); TemporaryScope temp_scope(this); - FunctionLiteralType type = is_expression ? EXPRESSION : DECLARATION; + FunctionLiteralType type = + info->is_expression() ? EXPRESSION : DECLARATION; bool ok = true; result = ParseFunctionLiteral(name, RelocInfo::kNoPosition, type, &ok); // Make sure the results agree. @@ -1601,6 +1381,7 @@ FunctionLiteral* Parser::ParseLazy(Handle<String> source, return result; } + FunctionLiteral* Parser::ParseJson(Handle<String> source) { CompilationZoneScope zone_scope(DONT_DELETE_ON_EXIT); @@ -1658,7 +1439,10 @@ void Parser::ReportMessage(const char* type, Vector<const char*> args) { Handle<String> Parser::GetSymbol(bool* ok) { - log()->LogSymbol(scanner_.location().beg_pos, scanner_.literal()); + if (is_pre_parsing_) { + log()->LogSymbol(scanner_.location().beg_pos, scanner_.literal()); + return Handle<String>::null(); + } int symbol_id = -1; if (pre_data() != NULL) { symbol_id = pre_data()->GetSymbolIdentifier(); @@ -1971,7 +1755,7 @@ void* Parser::ParseSourceElements(ZoneListWrapper<Statement>* processor, } // Propagate the collected information on this property assignments. - if (top_scope_->is_function_scope()) { + if (!is_pre_parsing_ && top_scope_->is_function_scope()) { bool only_simple_this_property_assignments = this_property_assignment_finder.only_simple_this_property_assignments() && top_scope_->declarations()->length() == 0; @@ -4123,8 +3907,8 @@ FunctionLiteral* Parser::ParseFunctionLiteral(Handle<String> var_name, int num_parameters = 0; // Parse function body. - { Scope::Type type = Scope::FUNCTION_SCOPE; - Scope* scope = factory()->NewScope(top_scope_, type, inside_with()); + { Scope* scope = + factory()->NewScope(top_scope_, Scope::FUNCTION_SCOPE, inside_with()); LexicalScope lexical_scope(this, scope); TemporaryScope temp_scope(this); top_scope_->SetScopeName(name); @@ -4155,7 +3939,9 @@ FunctionLiteral* Parser::ParseFunctionLiteral(Handle<String> var_name, // NOTE: We create a proxy and resolve it here so that in the // future we can change the AST to only refer to VariableProxies // instead of Variables and Proxis as is the case now. - if (!function_name.is_null() && function_name->length() > 0) { + if (!is_pre_parsing_ + && !function_name.is_null() + && function_name->length() > 0) { Variable* fvar = top_scope_->DeclareFunctionVar(function_name); VariableProxy* fproxy = top_scope_->NewUnresolved(function_name, inside_with()); @@ -4189,22 +3975,18 @@ FunctionLiteral* Parser::ParseFunctionLiteral(Handle<String> var_name, } Counters::total_preparse_skipped.Increment(end_pos - function_block_pos); scanner_.SeekForward(end_pos); - pre_data()->Skip(entry.predata_function_skip(), - entry.predata_symbol_skip()); materialized_literal_count = entry.literal_count(); expected_property_count = entry.property_count(); only_simple_this_property_assignments = false; this_property_assignments = Factory::empty_fixed_array(); Expect(Token::RBRACE, CHECK_OK); } else { - if (pre_data() != NULL) { - // Skip pre-data entry for non-lazily compiled function. - pre_data()->SkipFunctionEntry(function_block_pos); + FunctionEntry entry; + if (is_lazily_compiled) entry = log()->LogFunction(function_block_pos); + { + ConditionalLogPauseScope pause_if(is_lazily_compiled, log()); + ParseSourceElements(&body, Token::RBRACE, CHECK_OK); } - FunctionEntry entry = log()->LogFunction(function_block_pos); - int predata_function_position_before = log()->function_position(); - int predata_symbol_position_before = log()->symbol_position(); - ParseSourceElements(&body, Token::RBRACE, CHECK_OK); materialized_literal_count = temp_scope.materialized_literal_count(); expected_property_count = temp_scope.expected_property_count(); only_simple_this_property_assignments = @@ -4214,13 +3996,11 @@ FunctionLiteral* Parser::ParseFunctionLiteral(Handle<String> var_name, Expect(Token::RBRACE, CHECK_OK); end_pos = scanner_.location().end_pos; if (entry.is_valid()) { + ASSERT(is_lazily_compiled); + ASSERT(is_pre_parsing_); entry.set_end_pos(end_pos); entry.set_literal_count(materialized_literal_count); entry.set_property_count(expected_property_count); - entry.set_predata_function_skip( - log()->function_position() - predata_function_position_before); - entry.set_predata_symbol_skip( - log()->symbol_position() - predata_symbol_position_before); } } @@ -5440,12 +5220,6 @@ RegExpTree* RegExpParser::ParseCharacterClass() { // ---------------------------------------------------------------------------- // The Parser interface. -// MakeAST() is just a wrapper for the corresponding Parser calls -// so we don't have to expose the entire Parser class in the .h file. - -static bool always_allow_natives_syntax = false; - - ParserMessage::~ParserMessage() { for (int i = 0; i < args().length(); i++) DeleteArray(args()[i]); @@ -5475,14 +5249,12 @@ bool ScriptDataImpl::HasError() { // Preparse, but only collect data that is immediately useful, // even if the preparser data is only used once. -ScriptDataImpl* PartialPreParse(Handle<String> source, - unibrow::CharacterStream* stream, - v8::Extension* extension) { +ScriptDataImpl* Parser::PartialPreParse(Handle<String> source, + unibrow::CharacterStream* stream, + v8::Extension* extension) { Handle<Script> no_script; bool allow_natives_syntax = - always_allow_natives_syntax || - FLAG_allow_natives_syntax || - Bootstrapper::IsActive(); + FLAG_allow_natives_syntax || Bootstrapper::IsActive(); PartialPreParser parser(no_script, allow_natives_syntax, extension); if (!parser.PreParseProgram(source, stream)) return NULL; // Extract the accumulated data from the recorder as a single @@ -5535,14 +5307,12 @@ int ScriptDataImpl::ReadNumber(byte** source) { } -ScriptDataImpl* PreParse(Handle<String> source, - unibrow::CharacterStream* stream, - v8::Extension* extension) { +ScriptDataImpl* Parser::PreParse(Handle<String> source, + unibrow::CharacterStream* stream, + v8::Extension* extension) { Handle<Script> no_script; bool allow_natives_syntax = - always_allow_natives_syntax || - FLAG_allow_natives_syntax || - Bootstrapper::IsActive(); + FLAG_allow_natives_syntax || Bootstrapper::IsActive(); CompletePreParser parser(no_script, allow_natives_syntax, extension); if (!parser.PreParseProgram(source, stream)) return NULL; // Extract the accumulated data from the recorder as a single @@ -5552,9 +5322,9 @@ ScriptDataImpl* PreParse(Handle<String> source, } -bool ParseRegExp(FlatStringReader* input, - bool multiline, - RegExpCompileData* result) { +bool Parser::ParseRegExp(FlatStringReader* input, + bool multiline, + RegExpCompileData* result) { ASSERT(result != NULL); RegExpParser parser(input, &result->error, multiline); RegExpTree* tree = parser.ParsePattern(); @@ -5574,59 +5344,44 @@ bool ParseRegExp(FlatStringReader* input, } -FunctionLiteral* MakeAST(bool compile_in_global_context, - Handle<Script> script, - v8::Extension* extension, - ScriptDataImpl* pre_data, - bool is_json) { - bool allow_natives_syntax = - always_allow_natives_syntax || - FLAG_allow_natives_syntax || - Bootstrapper::IsActive(); - AstBuildingParser parser(script, allow_natives_syntax, extension, pre_data); - if (pre_data != NULL && pre_data->has_error()) { - Scanner::Location loc = pre_data->MessageLocation(); - const char* message = pre_data->BuildMessage(); - Vector<const char*> args = pre_data->BuildArgs(); - parser.ReportMessageAt(loc, message, args); - DeleteArray(message); - for (int i = 0; i < args.length(); i++) { - DeleteArray(args[i]); - } - DeleteArray(args.start()); - return NULL; - } - Handle<String> source = Handle<String>(String::cast(script->source())); - FunctionLiteral* result; - if (is_json) { - ASSERT(compile_in_global_context); - result = parser.ParseJson(source); +bool Parser::Parse(CompilationInfo* info) { + ASSERT(info->function() == NULL); + FunctionLiteral* result = NULL; + Handle<Script> script = info->script(); + if (info->is_lazy()) { + AstBuildingParser parser(script, true, NULL, NULL); + result = parser.ParseLazy(info->shared_info()); } else { - result = parser.ParseProgram(source, compile_in_global_context); + bool allow_natives_syntax = + FLAG_allow_natives_syntax || Bootstrapper::IsActive(); + ScriptDataImpl* pre_data = info->pre_parse_data(); + AstBuildingParser parser(script, allow_natives_syntax, info->extension(), + pre_data); + if (pre_data != NULL && pre_data->has_error()) { + Scanner::Location loc = pre_data->MessageLocation(); + const char* message = pre_data->BuildMessage(); + Vector<const char*> args = pre_data->BuildArgs(); + parser.ReportMessageAt(loc, message, args); + DeleteArray(message); + for (int i = 0; i < args.length(); i++) { + DeleteArray(args[i]); + } + DeleteArray(args.start()); + 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()); + } } - return result; -} - -FunctionLiteral* MakeLazyAST(Handle<Script> script, - Handle<String> name, - int start_position, - int end_position, - bool is_expression) { - bool allow_natives_syntax_before = always_allow_natives_syntax; - always_allow_natives_syntax = true; - AstBuildingParser parser(script, true, NULL, NULL); // always allow - always_allow_natives_syntax = allow_natives_syntax_before; - // Parse the function by pointing to the function source in the script source. - Handle<String> script_source(String::cast(script->source())); - FunctionLiteral* result = - parser.ParseLazy(script_source, name, - start_position, end_position, is_expression); - return result; + info->SetFunction(result); + return (result != NULL); } - #undef NEW - } } // namespace v8::internal diff --git a/src/parser.h b/src/parser.h index 8c008572..7142551c 100644 --- a/src/parser.h +++ b/src/parser.h @@ -1,4 +1,4 @@ -// Copyright 2006-2008 the V8 project authors. All rights reserved. +// 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: @@ -28,12 +28,23 @@ #ifndef V8_PARSER_H_ #define V8_PARSER_H_ -#include "scanner.h" #include "allocation.h" +#include "ast.h" +#include "scanner.h" namespace v8 { namespace internal { +class CompilationInfo; +class FuncNameInferrer; +class ParserFactory; +class ParserLog; +class PositionStack; +class Target; +class TemporaryScope; + +template <typename T> class ZoneListWrapper; + class ParserMessage : public Malloced { public: @@ -72,19 +83,9 @@ class FunctionEntry BASE_EMBEDDED { backing_[kPropertyCountOffset] = value; } - int predata_function_skip() { return backing_[kPredataFunctionSkipOffset]; } - void set_predata_function_skip(int value) { - backing_[kPredataFunctionSkipOffset] = value; - } - - int predata_symbol_skip() { return backing_[kPredataSymbolSkipOffset]; } - void set_predata_symbol_skip(int value) { - backing_[kPredataSymbolSkipOffset] = value; - } - bool is_valid() { return backing_.length() > 0; } - static const int kSize = 6; + static const int kSize = 4; private: Vector<unsigned> backing_; @@ -92,8 +93,6 @@ class FunctionEntry BASE_EMBEDDED { static const int kEndPosOffset = 1; static const int kLiteralCountOffset = 2; static const int kPropertyCountOffset = 3; - static const int kPredataFunctionSkipOffset = 4; - static const int kPredataSymbolSkipOffset = 5; }; @@ -117,7 +116,6 @@ class ScriptDataImpl : public ScriptData { FunctionEntry GetFunctionEntry(int start); int GetSymbolIdentifier(); - void SkipFunctionEntry(int start); bool SanityCheck(); Scanner::Location MessageLocation(); @@ -133,28 +131,8 @@ class ScriptDataImpl : public ScriptData { unsigned magic() { return store_[kMagicOffset]; } unsigned version() { return store_[kVersionOffset]; } - // Skip forward in the preparser data by the given number - // of unsigned ints of function entries and the given number of bytes of - // symbol id encoding. - void Skip(int function_entries, int symbol_entries) { - ASSERT(function_entries >= 0); - ASSERT(function_entries - <= (static_cast<int>(store_[kFunctionsSizeOffset]) - - (function_index_ - kHeaderSize))); - ASSERT(symbol_entries >= 0); - ASSERT(symbol_entries <= symbol_data_end_ - symbol_data_); - - unsigned max_function_skip = store_[kFunctionsSizeOffset] - - static_cast<unsigned>(function_index_ - kHeaderSize); - function_index_ += - Min(static_cast<unsigned>(function_entries), max_function_skip); - symbol_data_ += - Min(static_cast<unsigned>(symbol_entries), - static_cast<unsigned>(symbol_data_end_ - symbol_data_)); - } - static const unsigned kMagicNumber = 0xBadDead; - static const unsigned kCurrentVersion = 3; + static const unsigned kCurrentVersion = 4; static const int kMagicOffset = 0; static const int kVersionOffset = 1; @@ -186,9 +164,10 @@ class ScriptDataImpl : public ScriptData { ScriptDataImpl(const char* backing_store, int length) : store_(reinterpret_cast<unsigned*>(const_cast<char*>(backing_store)), - length / sizeof(unsigned)), + length / static_cast<int>(sizeof(unsigned))), owns_store_(false) { - ASSERT_EQ(0, reinterpret_cast<intptr_t>(backing_store) % sizeof(unsigned)); + ASSERT_EQ(0, static_cast<int>( + reinterpret_cast<intptr_t>(backing_store) % sizeof(unsigned))); } // Read strings written by ParserRecorder::WriteString. @@ -198,46 +177,268 @@ class ScriptDataImpl : public ScriptData { }; -// The parser: Takes a script and and context information, and builds a -// FunctionLiteral AST node. Returns NULL and deallocates any allocated -// AST nodes if parsing failed. -FunctionLiteral* MakeAST(bool compile_in_global_context, - Handle<Script> script, - v8::Extension* extension, - ScriptDataImpl* pre_data, - bool is_json = false); - -// Generic preparser generating full preparse data. -ScriptDataImpl* PreParse(Handle<String> source, - unibrow::CharacterStream* stream, - v8::Extension* extension); - -// Preparser that only does preprocessing that makes sense if only used -// immediately after. -ScriptDataImpl* PartialPreParse(Handle<String> source, - unibrow::CharacterStream* stream, - v8::Extension* extension); - - -bool ParseRegExp(FlatStringReader* input, - bool multiline, - RegExpCompileData* result); +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() { } + + // 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. + static bool Parse(CompilationInfo* info); + + // Generic preparser generating full preparse data. + static ScriptDataImpl* PreParse(Handle<String> source, + unibrow::CharacterStream* stream, + v8::Extension* extension); + + // Preparser that only does preprocessing that makes sense if only used + // immediately after. + static ScriptDataImpl* PartialPreParse(Handle<String> source, + unibrow::CharacterStream* stream, + v8::Extension* extension); + + static bool ParseRegExp(FlatStringReader* input, + bool multiline, + RegExpCompileData* result); + + // 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); + + void ReportMessage(const char* message, Vector<const char*> args); + virtual void ReportMessageAt(Scanner::Location loc, + const char* message, + Vector<const char*> args) = 0; + + + // Returns NULL if parsing failed. + 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 + // the overhead exceeds the savings below this limit. + static const int kMinInitializationBlock = 3; + + protected: + + enum Mode { + PARSE_LAZILY, + PARSE_EAGERLY + }; + // Report syntax error + void ReportUnexpectedToken(Token::Value token); + void ReportInvalidPreparseData(Handle<String> name, bool* ok); + + Handle<Script> script_; + Scanner scanner_; + + Scope* top_scope_; + int with_nesting_level_; + + TemporaryScope* temp_scope_; + Mode mode_; + + Target* target_stack_; // for break, continue statements + bool allow_natives_syntax_; + v8::Extension* extension_; + ParserFactory* factory_; + ParserLog* log_; + bool is_pre_parsing_; + ScriptDataImpl* pre_data_; + FuncNameInferrer* fni_; + + bool inside_with() const { return with_nesting_level_ > 0; } + ParserFactory* factory() const { return factory_; } + ParserLog* log() const { return log_; } + Scanner& scanner() { return scanner_; } + Mode mode() const { return mode_; } + ScriptDataImpl* pre_data() const { return pre_data_; } + + // All ParseXXX functions take as the last argument an *ok parameter + // which is set to false if parsing failed; it is unchanged otherwise. + // By making the 'exception handling' explicit, we are forced to check + // for failure at the call sites. + void* ParseSourceElements(ZoneListWrapper<Statement>* processor, + int end_token, bool* ok); + Statement* ParseStatement(ZoneStringList* labels, bool* ok); + Statement* ParseFunctionDeclaration(bool* ok); + Statement* ParseNativeDeclaration(bool* ok); + Block* ParseBlock(ZoneStringList* labels, bool* ok); + Block* ParseVariableStatement(bool* ok); + Block* ParseVariableDeclarations(bool accept_IN, Expression** var, bool* ok); + Statement* ParseExpressionOrLabelledStatement(ZoneStringList* labels, + bool* ok); + IfStatement* ParseIfStatement(ZoneStringList* labels, bool* ok); + Statement* ParseContinueStatement(bool* ok); + Statement* ParseBreakStatement(ZoneStringList* labels, bool* ok); + Statement* ParseReturnStatement(bool* ok); + Block* WithHelper(Expression* obj, + ZoneStringList* labels, + bool is_catch_block, + bool* ok); + Statement* ParseWithStatement(ZoneStringList* labels, bool* ok); + CaseClause* ParseCaseClause(bool* default_seen_ptr, bool* ok); + SwitchStatement* ParseSwitchStatement(ZoneStringList* labels, bool* ok); + DoWhileStatement* ParseDoWhileStatement(ZoneStringList* labels, bool* ok); + WhileStatement* ParseWhileStatement(ZoneStringList* labels, bool* ok); + Statement* ParseForStatement(ZoneStringList* labels, bool* ok); + Statement* ParseThrowStatement(bool* ok); + Expression* MakeCatchContext(Handle<String> id, VariableProxy* value); + TryStatement* ParseTryStatement(bool* ok); + DebuggerStatement* ParseDebuggerStatement(bool* ok); + + Expression* ParseExpression(bool accept_IN, bool* ok); + Expression* ParseAssignmentExpression(bool accept_IN, bool* ok); + Expression* ParseConditionalExpression(bool accept_IN, bool* ok); + Expression* ParseBinaryExpression(int prec, bool accept_IN, bool* ok); + Expression* ParseUnaryExpression(bool* ok); + Expression* ParsePostfixExpression(bool* ok); + Expression* ParseLeftHandSideExpression(bool* ok); + Expression* ParseNewExpression(bool* ok); + Expression* ParseMemberExpression(bool* ok); + Expression* ParseNewPrefix(PositionStack* stack, bool* ok); + Expression* ParseMemberWithNewPrefixesExpression(PositionStack* stack, + bool* ok); + Expression* ParsePrimaryExpression(bool* ok); + Expression* ParseArrayLiteral(bool* ok); + Expression* ParseObjectLiteral(bool* ok); + ObjectLiteral::Property* ParseObjectLiteralGetSet(bool is_getter, bool* ok); + Expression* ParseRegExpLiteral(bool seen_equal, bool* ok); + + Expression* NewCompareNode(Token::Value op, + Expression* x, + Expression* y, + int position); + + // Populate the constant properties fixed array for a materialized object + // literal. + void BuildObjectLiteralConstantProperties( + ZoneList<ObjectLiteral::Property*>* properties, + Handle<FixedArray> constants, + bool* is_simple, + bool* fast_elements, + int* depth); + + // Populate the literals fixed array for a materialized array literal. + void BuildArrayLiteralBoilerplateLiterals(ZoneList<Expression*>* properties, + Handle<FixedArray> constants, + bool* is_simple, + int* depth); + + // Decide if a property should be in the object boilerplate. + bool IsBoilerplateProperty(ObjectLiteral::Property* property); + // If the expression is a literal, return the literal value; + // if the expression is a materialized literal and is simple return a + // compile time value as encoded by CompileTimeValue::GetValue(). + // Otherwise, return undefined literal as the placeholder + // in the object literal boilerplate. + Handle<Object> GetBoilerplateValue(Expression* expression); + + enum FunctionLiteralType { + EXPRESSION, + DECLARATION, + NESTED + }; -// Support for doing lazy compilation. The script is the script containing full -// source of the script where the function is declared. The start_position and -// end_position specifies the part of the script source which has the source -// for the function declaration in the form: -// -// (<formal parameters>) { <function body> } -// -// without any function keyword or name. -// -FunctionLiteral* MakeLazyAST(Handle<Script> script, - Handle<String> name, - int start_position, - int end_position, - bool is_expression); + ZoneList<Expression*>* ParseArguments(bool* ok); + FunctionLiteral* ParseFunctionLiteral(Handle<String> var_name, + int function_token_position, + FunctionLiteralType type, + bool* ok); + + + // Magical syntax support. + Expression* ParseV8Intrinsic(bool* ok); + + INLINE(Token::Value peek()) { return scanner_.peek(); } + INLINE(Token::Value Next()) { return scanner_.Next(); } + INLINE(void Consume(Token::Value token)); + void Expect(Token::Value token, bool* ok); + bool Check(Token::Value token); + void ExpectSemicolon(bool* ok); + + Handle<String> GetSymbol(bool* ok); + + // Get odd-ball literals. + Literal* GetLiteralUndefined(); + Literal* GetLiteralTheHole(); + Literal* GetLiteralNumber(double value); + + Handle<String> ParseIdentifier(bool* ok); + Handle<String> ParseIdentifierName(bool* ok); + Handle<String> ParseIdentifierOrGetOrSet(bool* is_get, + bool* is_set, + bool* ok); + + // Parser support + virtual VariableProxy* Declare(Handle<String> name, Variable::Mode mode, + FunctionLiteral* fun, + bool resolve, + bool* ok) = 0; + + bool TargetStackContainsLabel(Handle<String> label); + BreakableStatement* LookupBreakTarget(Handle<String> label, bool* ok); + IterationStatement* LookupContinueTarget(Handle<String> label, bool* ok); + + void RegisterTargetUse(BreakTarget* target, Target* stop); + + // Create a number literal. + Literal* NewNumberLiteral(double value); + + // Generate AST node that throw a ReferenceError with the given type. + Expression* NewThrowReferenceError(Handle<String> type); + + // Generate AST node that throw a SyntaxError with the given + // type. The first argument may be null (in the handle sense) in + // which case no arguments are passed to the constructor. + Expression* NewThrowSyntaxError(Handle<String> type, Handle<Object> first); + + // Generate AST node that throw a TypeError with the given + // type. Both arguments must be non-null (in the handle sense). + Expression* NewThrowTypeError(Handle<String> type, + Handle<Object> first, + Handle<Object> second); + + // Generic AST generator for throwing errors from compiled code. + 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; +}; // Support for handling complex values (array and object literals) that diff --git a/src/platform-freebsd.cc b/src/platform-freebsd.cc index ae44944f..1003de15 100644 --- a/src/platform-freebsd.cc +++ b/src/platform-freebsd.cc @@ -291,6 +291,10 @@ void OS::LogSharedLibraryAddresses() { } +void OS::SignalCodeMovingGC() { +} + + int OS::StackWalk(Vector<OS::StackFrame> frames) { int frames_size = frames.length(); ScopedVector<void*> addresses(frames_size); diff --git a/src/platform-linux.cc b/src/platform-linux.cc index f7d8609b..c01c0d24 100644 --- a/src/platform-linux.cc +++ b/src/platform-linux.cc @@ -397,6 +397,30 @@ void OS::LogSharedLibraryAddresses() { } +static const char kGCFakeMmap[] = "/tmp/__v8_gc__"; + + +void OS::SignalCodeMovingGC() { +#ifdef ENABLE_LOGGING_AND_PROFILING + // Support for ll_prof.py. + // + // The Linux profiler built into the kernel logs all mmap's with + // PROT_EXEC so that analysis tools can properly attribute ticks. We + // do a mmap with a name known by ll_prof.py and immediately munmap + // it. This injects a GC marker into the stream of events generated + // by the kernel and allows us to synchronize V8 code log and the + // kernel log. + int size = sysconf(_SC_PAGESIZE); + FILE* f = fopen(kGCFakeMmap, "w+"); + void* addr = mmap(NULL, size, PROT_READ | PROT_EXEC, MAP_PRIVATE, + fileno(f), 0); + ASSERT(addr != MAP_FAILED); + munmap(addr, size); + fclose(f); +#endif +} + + int OS::StackWalk(Vector<OS::StackFrame> frames) { // backtrace is a glibc extension. #ifdef __GLIBC__ @@ -748,6 +772,7 @@ static void ProfilerSignalHandler(int signal, siginfo_t* info, void* context) { USE(info); if (signal != SIGPROF) return; if (active_sampler_ == NULL) return; + if (!IsVmThread()) return; TickSample sample_obj; TickSample* sample = CpuProfiler::TickSampleEvent(); @@ -755,6 +780,7 @@ static void ProfilerSignalHandler(int signal, siginfo_t* info, void* context) { // We always sample the VM state. sample->state = VMState::current_state(); + // If profiling, we extract the current pc and sp. if (active_sampler_->IsProfiling()) { // Extracting the sample from the context is extremely machine dependent. @@ -783,9 +809,7 @@ static void ProfilerSignalHandler(int signal, siginfo_t* info, void* context) { // Implement this on MIPS. UNIMPLEMENTED(); #endif - if (IsVmThread()) { - active_sampler_->SampleStack(sample); - } + active_sampler_->SampleStack(sample); } active_sampler_->Tick(sample); @@ -806,7 +830,10 @@ class Sampler::PlatformData : public Malloced { Sampler::Sampler(int interval, bool profiling) - : interval_(interval), profiling_(profiling), active_(false) { + : interval_(interval), + profiling_(profiling), + synchronous_(profiling), + active_(false) { data_ = new PlatformData(); } diff --git a/src/platform-macos.cc b/src/platform-macos.cc index 47193de7..3e4daf3b 100644 --- a/src/platform-macos.cc +++ b/src/platform-macos.cc @@ -245,6 +245,10 @@ void OS::LogSharedLibraryAddresses() { } +void OS::SignalCodeMovingGC() { +} + + uint64_t OS::CpuFeaturesImpliedByPlatform() { // MacOSX requires all these to install so we can assume they are present. // These constants are defined by the CPUid instructions. @@ -549,17 +553,24 @@ class Sampler::PlatformData : public Malloced { // Sampler thread handler. void Runner() { - // Loop until the sampler is disengaged, keeping the specified samling freq. + // Loop until the sampler is disengaged, keeping the specified + // sampling frequency. for ( ; sampler_->IsActive(); OS::Sleep(sampler_->interval_)) { TickSample sample_obj; TickSample* sample = CpuProfiler::TickSampleEvent(); if (sample == NULL) sample = &sample_obj; + // If the sampler runs in sync with the JS thread, we try to + // suspend it. If we fail, we skip the current sample. + if (sampler_->IsSynchronous()) { + if (KERN_SUCCESS != thread_suspend(profiled_thread_)) continue; + } + // We always sample the VM state. sample->state = VMState::current_state(); + // If profiling, we record the pc and sp of the profiled thread. - if (sampler_->IsProfiling() - && KERN_SUCCESS == thread_suspend(profiled_thread_)) { + if (sampler_->IsProfiling()) { #if V8_HOST_ARCH_X64 thread_state_flavor_t flavor = x86_THREAD_STATE64; x86_thread_state64_t state; @@ -591,11 +602,14 @@ class Sampler::PlatformData : public Malloced { sample->fp = reinterpret_cast<Address>(state.REGISTER_FIELD(bp)); sampler_->SampleStack(sample); } - thread_resume(profiled_thread_); } // Invoke tick handler with program counter and stack pointer. sampler_->Tick(sample); + + // If the sampler runs in sync with the JS thread, we have to + // remember to resume it. + if (sampler_->IsSynchronous()) thread_resume(profiled_thread_); } } }; @@ -613,7 +627,10 @@ static void* SamplerEntry(void* arg) { Sampler::Sampler(int interval, bool profiling) - : interval_(interval), profiling_(profiling), active_(false) { + : interval_(interval), + profiling_(profiling), + synchronous_(profiling), + active_(false) { data_ = new PlatformData(this); } @@ -624,9 +641,9 @@ Sampler::~Sampler() { void Sampler::Start() { - // If we are profiling, we need to be able to access the calling - // thread. - if (IsProfiling()) { + // If we are starting a synchronous sampler, we need to be able to + // access the calling thread. + if (IsSynchronous()) { data_->profiled_thread_ = mach_thread_self(); } @@ -655,7 +672,7 @@ void Sampler::Stop() { pthread_join(data_->sampler_thread_, NULL); // Deallocate Mach port for thread. - if (IsProfiling()) { + if (IsSynchronous()) { mach_port_deallocate(data_->task_self_, data_->profiled_thread_); } } diff --git a/src/platform-nullos.cc b/src/platform-nullos.cc index b8392e88..b5caa5e1 100644 --- a/src/platform-nullos.cc +++ b/src/platform-nullos.cc @@ -240,6 +240,11 @@ void OS::LogSharedLibraryAddresses() { } +void OS::SignalCodeMovingGC() { + UNIMPLEMENTED(); +} + + int OS::StackWalk(Vector<OS::StackFrame> frames) { UNIMPLEMENTED(); return 0; diff --git a/src/platform-openbsd.cc b/src/platform-openbsd.cc index 05ed9eee..e03059ad 100644 --- a/src/platform-openbsd.cc +++ b/src/platform-openbsd.cc @@ -289,6 +289,10 @@ void OS::LogSharedLibraryAddresses() { } +void OS::SignalCodeMovingGC() { +} + + int OS::StackWalk(Vector<OS::StackFrame> frames) { UNIMPLEMENTED(); return 1; diff --git a/src/platform-solaris.cc b/src/platform-solaris.cc index 6d97ed7e..fcd69deb 100644 --- a/src/platform-solaris.cc +++ b/src/platform-solaris.cc @@ -256,6 +256,10 @@ void OS::LogSharedLibraryAddresses() { } +void OS::SignalCodeMovingGC() { +} + + struct StackWalker { Vector<OS::StackFrame>& frames; int index; @@ -598,7 +602,10 @@ class Sampler::PlatformData : public Malloced { Sampler::Sampler(int interval, bool profiling) - : interval_(interval), profiling_(profiling), active_(false) { + : interval_(interval), + profiling_(profiling), + synchronous_(profiling), + active_(false) { data_ = new PlatformData(); } diff --git a/src/platform-win32.cc b/src/platform-win32.cc index 86314a80..caea16cb 100644 --- a/src/platform-win32.cc +++ b/src/platform-win32.cc @@ -845,14 +845,15 @@ void* OS::Allocate(const size_t requested, bool is_executable) { // The address range used to randomize RWX allocations in OS::Allocate // Try not to map pages into the default range that windows loads DLLs + // Use a multiple of 64k to prevent committing unused memory. // Note: This does not guarantee RWX regions will be within the // range kAllocationRandomAddressMin to kAllocationRandomAddressMax #ifdef V8_HOST_ARCH_64_BIT static const intptr_t kAllocationRandomAddressMin = 0x0000000080000000; - static const intptr_t kAllocationRandomAddressMax = 0x000004FFFFFFFFFF; + static const intptr_t kAllocationRandomAddressMax = 0x000003FFFFFF0000; #else static const intptr_t kAllocationRandomAddressMin = 0x04000000; - static const intptr_t kAllocationRandomAddressMax = 0x4FFFFFFF; + static const intptr_t kAllocationRandomAddressMax = 0x3FFF0000; #endif // VirtualAlloc rounds allocated size to page size automatically. @@ -1217,6 +1218,10 @@ void OS::LogSharedLibraryAddresses() { } +void OS::SignalCodeMovingGC() { +} + + // Walk the stack using the facilities in dbghelp.dll and tlhelp32.dll // Switch off warning 4748 (/GS can not protect parameters and local variables @@ -1838,17 +1843,25 @@ class Sampler::PlatformData : public Malloced { // Context used for sampling the register state of the profiled thread. CONTEXT context; memset(&context, 0, sizeof(context)); - // Loop until the sampler is disengaged, keeping the specified samling freq. + // Loop until the sampler is disengaged, keeping the specified + // sampling frequency. for ( ; sampler_->IsActive(); Sleep(sampler_->interval_)) { TickSample sample_obj; TickSample* sample = CpuProfiler::TickSampleEvent(); if (sample == NULL) sample = &sample_obj; + // If the sampler runs in sync with the JS thread, we try to + // suspend it. If we fail, we skip the current sample. + if (sampler_->IsSynchronous()) { + static const DWORD kSuspendFailed = static_cast<DWORD>(-1); + if (SuspendThread(profiled_thread_) == kSuspendFailed) continue; + } + // We always sample the VM state. sample->state = VMState::current_state(); + // If profiling, we record the pc and sp of the profiled thread. - if (sampler_->IsProfiling() - && SuspendThread(profiled_thread_) != (DWORD)-1) { + if (sampler_->IsProfiling()) { context.ContextFlags = CONTEXT_FULL; if (GetThreadContext(profiled_thread_, &context) != 0) { #if V8_HOST_ARCH_X64 @@ -1862,11 +1875,14 @@ class Sampler::PlatformData : public Malloced { #endif sampler_->SampleStack(sample); } - ResumeThread(profiled_thread_); } // Invoke tick handler with program counter and stack pointer. sampler_->Tick(sample); + + // If the sampler runs in sync with the JS thread, we have to + // remember to resume it. + if (sampler_->IsSynchronous()) ResumeThread(profiled_thread_); } } }; @@ -1883,7 +1899,10 @@ static unsigned int __stdcall SamplerEntry(void* arg) { // Initialize a profile sampler. Sampler::Sampler(int interval, bool profiling) - : interval_(interval), profiling_(profiling), active_(false) { + : interval_(interval), + profiling_(profiling), + synchronous_(profiling), + active_(false) { data_ = new PlatformData(this); } @@ -1895,9 +1914,9 @@ Sampler::~Sampler() { // Start profiling. void Sampler::Start() { - // If we are profiling, we need to be able to access the calling - // thread. - if (IsProfiling()) { + // If we are starting a synchronous sampler, we need to be able to + // access the calling thread. + if (IsSynchronous()) { // Get a handle to the calling thread. This is the thread that we are // going to profile. We need to make a copy of the handle because we are // going to use it in the sampler thread. Using GetThreadHandle() will diff --git a/src/platform.h b/src/platform.h index e9e7c223..42e6eae9 100644 --- a/src/platform.h +++ b/src/platform.h @@ -257,11 +257,16 @@ class OS { static char* StrChr(char* str, int c); static void StrNCpy(Vector<char> dest, const char* src, size_t n); - // Support for profiler. Can do nothing, in which case ticks - // occuring in shared libraries will not be properly accounted - // for. + // Support for the profiler. Can do nothing, in which case ticks + // occuring in shared libraries will not be properly accounted for. static void LogSharedLibraryAddresses(); + // Support for the profiler. Notifies the external profiling + // process that a code moving garbage collection starts. Can do + // nothing, in which case the code objects must not move (e.g., by + // using --never-compact) if accurate profiling is desired. + static void SignalCodeMovingGC(); + // The return value indicates the CPU features we are sure of because of the // OS. For example MacOSX doesn't run on any x86 CPUs that don't have SSE2 // instructions. @@ -563,17 +568,24 @@ class Sampler { void Start(); void Stop(); - // Is the sampler used for profiling. - inline bool IsProfiling() { return profiling_; } + // Is the sampler used for profiling? + bool IsProfiling() const { return profiling_; } + + // Is the sampler running in sync with the JS thread? On platforms + // where the sampler is implemented with a thread that wakes up + // every now and then, having a synchronous sampler implies + // suspending/resuming the JS thread. + bool IsSynchronous() const { return synchronous_; } // Whether the sampler is running (that is, consumes resources). - inline bool IsActive() { return active_; } + bool IsActive() const { return active_; } class PlatformData; private: const int interval_; const bool profiling_; + const bool synchronous_; bool active_; PlatformData* data_; // Platform specific data. DISALLOW_IMPLICIT_CONSTRUCTORS(Sampler); diff --git a/src/powers-ten.h b/src/powers-ten.h deleted file mode 100644 index 93d92d91..00000000 --- a/src/powers-ten.h +++ /dev/null @@ -1,2461 +0,0 @@ -// Copyright 2010 the V8 project authors. All rights reserved. -// ------------ GENERATED FILE ---------------- -// command used: -// tools/generate-ten-powers --from -308 --to 342 --mantissa-size 64 --round round -o src/powers-ten.h // NOLINT - -// This file is intended to be included inside another .h or .cc files -// with the following defines set: -// GRISU_CACHE_STRUCT: should expand to the name of a struct that will -// hold the cached powers of ten. Each entry will hold a 64-bit -// significand, a 16-bit signed binary exponent, and a 16-bit -// signed decimal exponent. Each entry will be constructed as follows: -// { significand, binary_exponent, decimal_exponent }. -// GRISU_CACHE_NAME(i): generates the name for the different caches. -// The parameter i will be a number in the range 1-20. A cache will -// hold every i'th element of a full cache. GRISU_CACHE_NAME(1) will -// thus hold all elements. The higher i the fewer elements it has. -// Ideally the user should only reference one cache and let the -// compiler remove the unused ones. -// GRISU_CACHE_MAX_DISTANCE(i): generates the name for the maximum -// binary exponent distance between all elements of a given cache. -// GRISU_CACHE_OFFSET: is used as variable name for the decimal -// exponent offset. It is equal to -cache[0].decimal_exponent. -// GRISU_UINT64_C: used to construct 64-bit values in a platform -// independent way. In order to encode 0x123456789ABCDEF0 the macro -// will be invoked as follows: GRISU_UINT64_C(0x12345678,9ABCDEF0). - - -static const GRISU_CACHE_STRUCT GRISU_CACHE_NAME(1)[] = { - {GRISU_UINT64_C(0xe61acf03, 3d1a45df), -1087, -308}, - {GRISU_UINT64_C(0x8fd0c162, 06306bac), -1083, -307}, - {GRISU_UINT64_C(0xb3c4f1ba, 87bc8697), -1080, -306}, - {GRISU_UINT64_C(0xe0b62e29, 29aba83c), -1077, -305}, - {GRISU_UINT64_C(0x8c71dcd9, ba0b4926), -1073, -304}, - {GRISU_UINT64_C(0xaf8e5410, 288e1b6f), -1070, -303}, - {GRISU_UINT64_C(0xdb71e914, 32b1a24b), -1067, -302}, - {GRISU_UINT64_C(0x892731ac, 9faf056f), -1063, -301}, - {GRISU_UINT64_C(0xab70fe17, c79ac6ca), -1060, -300}, - {GRISU_UINT64_C(0xd64d3d9d, b981787d), -1057, -299}, - {GRISU_UINT64_C(0x85f04682, 93f0eb4e), -1053, -298}, - {GRISU_UINT64_C(0xa76c5823, 38ed2622), -1050, -297}, - {GRISU_UINT64_C(0xd1476e2c, 07286faa), -1047, -296}, - {GRISU_UINT64_C(0x82cca4db, 847945ca), -1043, -295}, - {GRISU_UINT64_C(0xa37fce12, 6597973d), -1040, -294}, - {GRISU_UINT64_C(0xcc5fc196, fefd7d0c), -1037, -293}, - {GRISU_UINT64_C(0xff77b1fc, bebcdc4f), -1034, -292}, - {GRISU_UINT64_C(0x9faacf3d, f73609b1), -1030, -291}, - {GRISU_UINT64_C(0xc795830d, 75038c1e), -1027, -290}, - {GRISU_UINT64_C(0xf97ae3d0, d2446f25), -1024, -289}, - {GRISU_UINT64_C(0x9becce62, 836ac577), -1020, -288}, - {GRISU_UINT64_C(0xc2e801fb, 244576d5), -1017, -287}, - {GRISU_UINT64_C(0xf3a20279, ed56d48a), -1014, -286}, - {GRISU_UINT64_C(0x9845418c, 345644d7), -1010, -285}, - {GRISU_UINT64_C(0xbe5691ef, 416bd60c), -1007, -284}, - {GRISU_UINT64_C(0xedec366b, 11c6cb8f), -1004, -283}, - {GRISU_UINT64_C(0x94b3a202, eb1c3f39), -1000, -282}, - {GRISU_UINT64_C(0xb9e08a83, a5e34f08), -997, -281}, - {GRISU_UINT64_C(0xe858ad24, 8f5c22ca), -994, -280}, - {GRISU_UINT64_C(0x91376c36, d99995be), -990, -279}, - {GRISU_UINT64_C(0xb5854744, 8ffffb2e), -987, -278}, - {GRISU_UINT64_C(0xe2e69915, b3fff9f9), -984, -277}, - {GRISU_UINT64_C(0x8dd01fad, 907ffc3c), -980, -276}, - {GRISU_UINT64_C(0xb1442798, f49ffb4b), -977, -275}, - {GRISU_UINT64_C(0xdd95317f, 31c7fa1d), -974, -274}, - {GRISU_UINT64_C(0x8a7d3eef, 7f1cfc52), -970, -273}, - {GRISU_UINT64_C(0xad1c8eab, 5ee43b67), -967, -272}, - {GRISU_UINT64_C(0xd863b256, 369d4a41), -964, -271}, - {GRISU_UINT64_C(0x873e4f75, e2224e68), -960, -270}, - {GRISU_UINT64_C(0xa90de353, 5aaae202), -957, -269}, - {GRISU_UINT64_C(0xd3515c28, 31559a83), -954, -268}, - {GRISU_UINT64_C(0x8412d999, 1ed58092), -950, -267}, - {GRISU_UINT64_C(0xa5178fff, 668ae0b6), -947, -266}, - {GRISU_UINT64_C(0xce5d73ff, 402d98e4), -944, -265}, - {GRISU_UINT64_C(0x80fa687f, 881c7f8e), -940, -264}, - {GRISU_UINT64_C(0xa139029f, 6a239f72), -937, -263}, - {GRISU_UINT64_C(0xc9874347, 44ac874f), -934, -262}, - {GRISU_UINT64_C(0xfbe91419, 15d7a922), -931, -261}, - {GRISU_UINT64_C(0x9d71ac8f, ada6c9b5), -927, -260}, - {GRISU_UINT64_C(0xc4ce17b3, 99107c23), -924, -259}, - {GRISU_UINT64_C(0xf6019da0, 7f549b2b), -921, -258}, - {GRISU_UINT64_C(0x99c10284, 4f94e0fb), -917, -257}, - {GRISU_UINT64_C(0xc0314325, 637a193a), -914, -256}, - {GRISU_UINT64_C(0xf03d93ee, bc589f88), -911, -255}, - {GRISU_UINT64_C(0x96267c75, 35b763b5), -907, -254}, - {GRISU_UINT64_C(0xbbb01b92, 83253ca3), -904, -253}, - {GRISU_UINT64_C(0xea9c2277, 23ee8bcb), -901, -252}, - {GRISU_UINT64_C(0x92a1958a, 7675175f), -897, -251}, - {GRISU_UINT64_C(0xb749faed, 14125d37), -894, -250}, - {GRISU_UINT64_C(0xe51c79a8, 5916f485), -891, -249}, - {GRISU_UINT64_C(0x8f31cc09, 37ae58d3), -887, -248}, - {GRISU_UINT64_C(0xb2fe3f0b, 8599ef08), -884, -247}, - {GRISU_UINT64_C(0xdfbdcece, 67006ac9), -881, -246}, - {GRISU_UINT64_C(0x8bd6a141, 006042be), -877, -245}, - {GRISU_UINT64_C(0xaecc4991, 4078536d), -874, -244}, - {GRISU_UINT64_C(0xda7f5bf5, 90966849), -871, -243}, - {GRISU_UINT64_C(0x888f9979, 7a5e012d), -867, -242}, - {GRISU_UINT64_C(0xaab37fd7, d8f58179), -864, -241}, - {GRISU_UINT64_C(0xd5605fcd, cf32e1d7), -861, -240}, - {GRISU_UINT64_C(0x855c3be0, a17fcd26), -857, -239}, - {GRISU_UINT64_C(0xa6b34ad8, c9dfc070), -854, -238}, - {GRISU_UINT64_C(0xd0601d8e, fc57b08c), -851, -237}, - {GRISU_UINT64_C(0x823c1279, 5db6ce57), -847, -236}, - {GRISU_UINT64_C(0xa2cb1717, b52481ed), -844, -235}, - {GRISU_UINT64_C(0xcb7ddcdd, a26da269), -841, -234}, - {GRISU_UINT64_C(0xfe5d5415, 0b090b03), -838, -233}, - {GRISU_UINT64_C(0x9efa548d, 26e5a6e2), -834, -232}, - {GRISU_UINT64_C(0xc6b8e9b0, 709f109a), -831, -231}, - {GRISU_UINT64_C(0xf867241c, 8cc6d4c1), -828, -230}, - {GRISU_UINT64_C(0x9b407691, d7fc44f8), -824, -229}, - {GRISU_UINT64_C(0xc2109436, 4dfb5637), -821, -228}, - {GRISU_UINT64_C(0xf294b943, e17a2bc4), -818, -227}, - {GRISU_UINT64_C(0x979cf3ca, 6cec5b5b), -814, -226}, - {GRISU_UINT64_C(0xbd8430bd, 08277231), -811, -225}, - {GRISU_UINT64_C(0xece53cec, 4a314ebe), -808, -224}, - {GRISU_UINT64_C(0x940f4613, ae5ed137), -804, -223}, - {GRISU_UINT64_C(0xb9131798, 99f68584), -801, -222}, - {GRISU_UINT64_C(0xe757dd7e, c07426e5), -798, -221}, - {GRISU_UINT64_C(0x9096ea6f, 3848984f), -794, -220}, - {GRISU_UINT64_C(0xb4bca50b, 065abe63), -791, -219}, - {GRISU_UINT64_C(0xe1ebce4d, c7f16dfc), -788, -218}, - {GRISU_UINT64_C(0x8d3360f0, 9cf6e4bd), -784, -217}, - {GRISU_UINT64_C(0xb080392c, c4349ded), -781, -216}, - {GRISU_UINT64_C(0xdca04777, f541c568), -778, -215}, - {GRISU_UINT64_C(0x89e42caa, f9491b61), -774, -214}, - {GRISU_UINT64_C(0xac5d37d5, b79b6239), -771, -213}, - {GRISU_UINT64_C(0xd77485cb, 25823ac7), -768, -212}, - {GRISU_UINT64_C(0x86a8d39e, f77164bd), -764, -211}, - {GRISU_UINT64_C(0xa8530886, b54dbdec), -761, -210}, - {GRISU_UINT64_C(0xd267caa8, 62a12d67), -758, -209}, - {GRISU_UINT64_C(0x8380dea9, 3da4bc60), -754, -208}, - {GRISU_UINT64_C(0xa4611653, 8d0deb78), -751, -207}, - {GRISU_UINT64_C(0xcd795be8, 70516656), -748, -206}, - {GRISU_UINT64_C(0x806bd971, 4632dff6), -744, -205}, - {GRISU_UINT64_C(0xa086cfcd, 97bf97f4), -741, -204}, - {GRISU_UINT64_C(0xc8a883c0, fdaf7df0), -738, -203}, - {GRISU_UINT64_C(0xfad2a4b1, 3d1b5d6c), -735, -202}, - {GRISU_UINT64_C(0x9cc3a6ee, c6311a64), -731, -201}, - {GRISU_UINT64_C(0xc3f490aa, 77bd60fd), -728, -200}, - {GRISU_UINT64_C(0xf4f1b4d5, 15acb93c), -725, -199}, - {GRISU_UINT64_C(0x99171105, 2d8bf3c5), -721, -198}, - {GRISU_UINT64_C(0xbf5cd546, 78eef0b7), -718, -197}, - {GRISU_UINT64_C(0xef340a98, 172aace5), -715, -196}, - {GRISU_UINT64_C(0x9580869f, 0e7aac0f), -711, -195}, - {GRISU_UINT64_C(0xbae0a846, d2195713), -708, -194}, - {GRISU_UINT64_C(0xe998d258, 869facd7), -705, -193}, - {GRISU_UINT64_C(0x91ff8377, 5423cc06), -701, -192}, - {GRISU_UINT64_C(0xb67f6455, 292cbf08), -698, -191}, - {GRISU_UINT64_C(0xe41f3d6a, 7377eeca), -695, -190}, - {GRISU_UINT64_C(0x8e938662, 882af53e), -691, -189}, - {GRISU_UINT64_C(0xb23867fb, 2a35b28e), -688, -188}, - {GRISU_UINT64_C(0xdec681f9, f4c31f31), -685, -187}, - {GRISU_UINT64_C(0x8b3c113c, 38f9f37f), -681, -186}, - {GRISU_UINT64_C(0xae0b158b, 4738705f), -678, -185}, - {GRISU_UINT64_C(0xd98ddaee, 19068c76), -675, -184}, - {GRISU_UINT64_C(0x87f8a8d4, cfa417ca), -671, -183}, - {GRISU_UINT64_C(0xa9f6d30a, 038d1dbc), -668, -182}, - {GRISU_UINT64_C(0xd47487cc, 8470652b), -665, -181}, - {GRISU_UINT64_C(0x84c8d4df, d2c63f3b), -661, -180}, - {GRISU_UINT64_C(0xa5fb0a17, c777cf0a), -658, -179}, - {GRISU_UINT64_C(0xcf79cc9d, b955c2cc), -655, -178}, - {GRISU_UINT64_C(0x81ac1fe2, 93d599c0), -651, -177}, - {GRISU_UINT64_C(0xa21727db, 38cb0030), -648, -176}, - {GRISU_UINT64_C(0xca9cf1d2, 06fdc03c), -645, -175}, - {GRISU_UINT64_C(0xfd442e46, 88bd304b), -642, -174}, - {GRISU_UINT64_C(0x9e4a9cec, 15763e2f), -638, -173}, - {GRISU_UINT64_C(0xc5dd4427, 1ad3cdba), -635, -172}, - {GRISU_UINT64_C(0xf7549530, e188c129), -632, -171}, - {GRISU_UINT64_C(0x9a94dd3e, 8cf578ba), -628, -170}, - {GRISU_UINT64_C(0xc13a148e, 3032d6e8), -625, -169}, - {GRISU_UINT64_C(0xf18899b1, bc3f8ca2), -622, -168}, - {GRISU_UINT64_C(0x96f5600f, 15a7b7e5), -618, -167}, - {GRISU_UINT64_C(0xbcb2b812, db11a5de), -615, -166}, - {GRISU_UINT64_C(0xebdf6617, 91d60f56), -612, -165}, - {GRISU_UINT64_C(0x936b9fce, bb25c996), -608, -164}, - {GRISU_UINT64_C(0xb84687c2, 69ef3bfb), -605, -163}, - {GRISU_UINT64_C(0xe65829b3, 046b0afa), -602, -162}, - {GRISU_UINT64_C(0x8ff71a0f, e2c2e6dc), -598, -161}, - {GRISU_UINT64_C(0xb3f4e093, db73a093), -595, -160}, - {GRISU_UINT64_C(0xe0f218b8, d25088b8), -592, -159}, - {GRISU_UINT64_C(0x8c974f73, 83725573), -588, -158}, - {GRISU_UINT64_C(0xafbd2350, 644eead0), -585, -157}, - {GRISU_UINT64_C(0xdbac6c24, 7d62a584), -582, -156}, - {GRISU_UINT64_C(0x894bc396, ce5da772), -578, -155}, - {GRISU_UINT64_C(0xab9eb47c, 81f5114f), -575, -154}, - {GRISU_UINT64_C(0xd686619b, a27255a3), -572, -153}, - {GRISU_UINT64_C(0x8613fd01, 45877586), -568, -152}, - {GRISU_UINT64_C(0xa798fc41, 96e952e7), -565, -151}, - {GRISU_UINT64_C(0xd17f3b51, fca3a7a1), -562, -150}, - {GRISU_UINT64_C(0x82ef8513, 3de648c5), -558, -149}, - {GRISU_UINT64_C(0xa3ab6658, 0d5fdaf6), -555, -148}, - {GRISU_UINT64_C(0xcc963fee, 10b7d1b3), -552, -147}, - {GRISU_UINT64_C(0xffbbcfe9, 94e5c620), -549, -146}, - {GRISU_UINT64_C(0x9fd561f1, fd0f9bd4), -545, -145}, - {GRISU_UINT64_C(0xc7caba6e, 7c5382c9), -542, -144}, - {GRISU_UINT64_C(0xf9bd690a, 1b68637b), -539, -143}, - {GRISU_UINT64_C(0x9c1661a6, 51213e2d), -535, -142}, - {GRISU_UINT64_C(0xc31bfa0f, e5698db8), -532, -141}, - {GRISU_UINT64_C(0xf3e2f893, dec3f126), -529, -140}, - {GRISU_UINT64_C(0x986ddb5c, 6b3a76b8), -525, -139}, - {GRISU_UINT64_C(0xbe895233, 86091466), -522, -138}, - {GRISU_UINT64_C(0xee2ba6c0, 678b597f), -519, -137}, - {GRISU_UINT64_C(0x94db4838, 40b717f0), -515, -136}, - {GRISU_UINT64_C(0xba121a46, 50e4ddec), -512, -135}, - {GRISU_UINT64_C(0xe896a0d7, e51e1566), -509, -134}, - {GRISU_UINT64_C(0x915e2486, ef32cd60), -505, -133}, - {GRISU_UINT64_C(0xb5b5ada8, aaff80b8), -502, -132}, - {GRISU_UINT64_C(0xe3231912, d5bf60e6), -499, -131}, - {GRISU_UINT64_C(0x8df5efab, c5979c90), -495, -130}, - {GRISU_UINT64_C(0xb1736b96, b6fd83b4), -492, -129}, - {GRISU_UINT64_C(0xddd0467c, 64bce4a1), -489, -128}, - {GRISU_UINT64_C(0x8aa22c0d, bef60ee4), -485, -127}, - {GRISU_UINT64_C(0xad4ab711, 2eb3929e), -482, -126}, - {GRISU_UINT64_C(0xd89d64d5, 7a607745), -479, -125}, - {GRISU_UINT64_C(0x87625f05, 6c7c4a8b), -475, -124}, - {GRISU_UINT64_C(0xa93af6c6, c79b5d2e), -472, -123}, - {GRISU_UINT64_C(0xd389b478, 79823479), -469, -122}, - {GRISU_UINT64_C(0x843610cb, 4bf160cc), -465, -121}, - {GRISU_UINT64_C(0xa54394fe, 1eedb8ff), -462, -120}, - {GRISU_UINT64_C(0xce947a3d, a6a9273e), -459, -119}, - {GRISU_UINT64_C(0x811ccc66, 8829b887), -455, -118}, - {GRISU_UINT64_C(0xa163ff80, 2a3426a9), -452, -117}, - {GRISU_UINT64_C(0xc9bcff60, 34c13053), -449, -116}, - {GRISU_UINT64_C(0xfc2c3f38, 41f17c68), -446, -115}, - {GRISU_UINT64_C(0x9d9ba783, 2936edc1), -442, -114}, - {GRISU_UINT64_C(0xc5029163, f384a931), -439, -113}, - {GRISU_UINT64_C(0xf64335bc, f065d37d), -436, -112}, - {GRISU_UINT64_C(0x99ea0196, 163fa42e), -432, -111}, - {GRISU_UINT64_C(0xc06481fb, 9bcf8d3a), -429, -110}, - {GRISU_UINT64_C(0xf07da27a, 82c37088), -426, -109}, - {GRISU_UINT64_C(0x964e858c, 91ba2655), -422, -108}, - {GRISU_UINT64_C(0xbbe226ef, b628afeb), -419, -107}, - {GRISU_UINT64_C(0xeadab0ab, a3b2dbe5), -416, -106}, - {GRISU_UINT64_C(0x92c8ae6b, 464fc96f), -412, -105}, - {GRISU_UINT64_C(0xb77ada06, 17e3bbcb), -409, -104}, - {GRISU_UINT64_C(0xe5599087, 9ddcaabe), -406, -103}, - {GRISU_UINT64_C(0x8f57fa54, c2a9eab7), -402, -102}, - {GRISU_UINT64_C(0xb32df8e9, f3546564), -399, -101}, - {GRISU_UINT64_C(0xdff97724, 70297ebd), -396, -100}, - {GRISU_UINT64_C(0x8bfbea76, c619ef36), -392, -99}, - {GRISU_UINT64_C(0xaefae514, 77a06b04), -389, -98}, - {GRISU_UINT64_C(0xdab99e59, 958885c5), -386, -97}, - {GRISU_UINT64_C(0x88b402f7, fd75539b), -382, -96}, - {GRISU_UINT64_C(0xaae103b5, fcd2a882), -379, -95}, - {GRISU_UINT64_C(0xd59944a3, 7c0752a2), -376, -94}, - {GRISU_UINT64_C(0x857fcae6, 2d8493a5), -372, -93}, - {GRISU_UINT64_C(0xa6dfbd9f, b8e5b88f), -369, -92}, - {GRISU_UINT64_C(0xd097ad07, a71f26b2), -366, -91}, - {GRISU_UINT64_C(0x825ecc24, c8737830), -362, -90}, - {GRISU_UINT64_C(0xa2f67f2d, fa90563b), -359, -89}, - {GRISU_UINT64_C(0xcbb41ef9, 79346bca), -356, -88}, - {GRISU_UINT64_C(0xfea126b7, d78186bd), -353, -87}, - {GRISU_UINT64_C(0x9f24b832, e6b0f436), -349, -86}, - {GRISU_UINT64_C(0xc6ede63f, a05d3144), -346, -85}, - {GRISU_UINT64_C(0xf8a95fcf, 88747d94), -343, -84}, - {GRISU_UINT64_C(0x9b69dbe1, b548ce7d), -339, -83}, - {GRISU_UINT64_C(0xc24452da, 229b021c), -336, -82}, - {GRISU_UINT64_C(0xf2d56790, ab41c2a3), -333, -81}, - {GRISU_UINT64_C(0x97c560ba, 6b0919a6), -329, -80}, - {GRISU_UINT64_C(0xbdb6b8e9, 05cb600f), -326, -79}, - {GRISU_UINT64_C(0xed246723, 473e3813), -323, -78}, - {GRISU_UINT64_C(0x9436c076, 0c86e30c), -319, -77}, - {GRISU_UINT64_C(0xb9447093, 8fa89bcf), -316, -76}, - {GRISU_UINT64_C(0xe7958cb8, 7392c2c3), -313, -75}, - {GRISU_UINT64_C(0x90bd77f3, 483bb9ba), -309, -74}, - {GRISU_UINT64_C(0xb4ecd5f0, 1a4aa828), -306, -73}, - {GRISU_UINT64_C(0xe2280b6c, 20dd5232), -303, -72}, - {GRISU_UINT64_C(0x8d590723, 948a535f), -299, -71}, - {GRISU_UINT64_C(0xb0af48ec, 79ace837), -296, -70}, - {GRISU_UINT64_C(0xdcdb1b27, 98182245), -293, -69}, - {GRISU_UINT64_C(0x8a08f0f8, bf0f156b), -289, -68}, - {GRISU_UINT64_C(0xac8b2d36, eed2dac6), -286, -67}, - {GRISU_UINT64_C(0xd7adf884, aa879177), -283, -66}, - {GRISU_UINT64_C(0x86ccbb52, ea94baeb), -279, -65}, - {GRISU_UINT64_C(0xa87fea27, a539e9a5), -276, -64}, - {GRISU_UINT64_C(0xd29fe4b1, 8e88640f), -273, -63}, - {GRISU_UINT64_C(0x83a3eeee, f9153e89), -269, -62}, - {GRISU_UINT64_C(0xa48ceaaa, b75a8e2b), -266, -61}, - {GRISU_UINT64_C(0xcdb02555, 653131b6), -263, -60}, - {GRISU_UINT64_C(0x808e1755, 5f3ebf12), -259, -59}, - {GRISU_UINT64_C(0xa0b19d2a, b70e6ed6), -256, -58}, - {GRISU_UINT64_C(0xc8de0475, 64d20a8c), -253, -57}, - {GRISU_UINT64_C(0xfb158592, be068d2f), -250, -56}, - {GRISU_UINT64_C(0x9ced737b, b6c4183d), -246, -55}, - {GRISU_UINT64_C(0xc428d05a, a4751e4d), -243, -54}, - {GRISU_UINT64_C(0xf5330471, 4d9265e0), -240, -53}, - {GRISU_UINT64_C(0x993fe2c6, d07b7fac), -236, -52}, - {GRISU_UINT64_C(0xbf8fdb78, 849a5f97), -233, -51}, - {GRISU_UINT64_C(0xef73d256, a5c0f77d), -230, -50}, - {GRISU_UINT64_C(0x95a86376, 27989aae), -226, -49}, - {GRISU_UINT64_C(0xbb127c53, b17ec159), -223, -48}, - {GRISU_UINT64_C(0xe9d71b68, 9dde71b0), -220, -47}, - {GRISU_UINT64_C(0x92267121, 62ab070e), -216, -46}, - {GRISU_UINT64_C(0xb6b00d69, bb55c8d1), -213, -45}, - {GRISU_UINT64_C(0xe45c10c4, 2a2b3b06), -210, -44}, - {GRISU_UINT64_C(0x8eb98a7a, 9a5b04e3), -206, -43}, - {GRISU_UINT64_C(0xb267ed19, 40f1c61c), -203, -42}, - {GRISU_UINT64_C(0xdf01e85f, 912e37a3), -200, -41}, - {GRISU_UINT64_C(0x8b61313b, babce2c6), -196, -40}, - {GRISU_UINT64_C(0xae397d8a, a96c1b78), -193, -39}, - {GRISU_UINT64_C(0xd9c7dced, 53c72256), -190, -38}, - {GRISU_UINT64_C(0x881cea14, 545c7575), -186, -37}, - {GRISU_UINT64_C(0xaa242499, 697392d3), -183, -36}, - {GRISU_UINT64_C(0xd4ad2dbf, c3d07788), -180, -35}, - {GRISU_UINT64_C(0x84ec3c97, da624ab5), -176, -34}, - {GRISU_UINT64_C(0xa6274bbd, d0fadd62), -173, -33}, - {GRISU_UINT64_C(0xcfb11ead, 453994ba), -170, -32}, - {GRISU_UINT64_C(0x81ceb32c, 4b43fcf5), -166, -31}, - {GRISU_UINT64_C(0xa2425ff7, 5e14fc32), -163, -30}, - {GRISU_UINT64_C(0xcad2f7f5, 359a3b3e), -160, -29}, - {GRISU_UINT64_C(0xfd87b5f2, 8300ca0e), -157, -28}, - {GRISU_UINT64_C(0x9e74d1b7, 91e07e48), -153, -27}, - {GRISU_UINT64_C(0xc6120625, 76589ddb), -150, -26}, - {GRISU_UINT64_C(0xf79687ae, d3eec551), -147, -25}, - {GRISU_UINT64_C(0x9abe14cd, 44753b53), -143, -24}, - {GRISU_UINT64_C(0xc16d9a00, 95928a27), -140, -23}, - {GRISU_UINT64_C(0xf1c90080, baf72cb1), -137, -22}, - {GRISU_UINT64_C(0x971da050, 74da7bef), -133, -21}, - {GRISU_UINT64_C(0xbce50864, 92111aeb), -130, -20}, - {GRISU_UINT64_C(0xec1e4a7d, b69561a5), -127, -19}, - {GRISU_UINT64_C(0x9392ee8e, 921d5d07), -123, -18}, - {GRISU_UINT64_C(0xb877aa32, 36a4b449), -120, -17}, - {GRISU_UINT64_C(0xe69594be, c44de15b), -117, -16}, - {GRISU_UINT64_C(0x901d7cf7, 3ab0acd9), -113, -15}, - {GRISU_UINT64_C(0xb424dc35, 095cd80f), -110, -14}, - {GRISU_UINT64_C(0xe12e1342, 4bb40e13), -107, -13}, - {GRISU_UINT64_C(0x8cbccc09, 6f5088cc), -103, -12}, - {GRISU_UINT64_C(0xafebff0b, cb24aaff), -100, -11}, - {GRISU_UINT64_C(0xdbe6fece, bdedd5bf), -97, -10}, - {GRISU_UINT64_C(0x89705f41, 36b4a597), -93, -9}, - {GRISU_UINT64_C(0xabcc7711, 8461cefd), -90, -8}, - {GRISU_UINT64_C(0xd6bf94d5, e57a42bc), -87, -7}, - {GRISU_UINT64_C(0x8637bd05, af6c69b6), -83, -6}, - {GRISU_UINT64_C(0xa7c5ac47, 1b478423), -80, -5}, - {GRISU_UINT64_C(0xd1b71758, e219652c), -77, -4}, - {GRISU_UINT64_C(0x83126e97, 8d4fdf3b), -73, -3}, - {GRISU_UINT64_C(0xa3d70a3d, 70a3d70a), -70, -2}, - {GRISU_UINT64_C(0xcccccccc, cccccccd), -67, -1}, - {GRISU_UINT64_C(0x80000000, 00000000), -63, 0}, - {GRISU_UINT64_C(0xa0000000, 00000000), -60, 1}, - {GRISU_UINT64_C(0xc8000000, 00000000), -57, 2}, - {GRISU_UINT64_C(0xfa000000, 00000000), -54, 3}, - {GRISU_UINT64_C(0x9c400000, 00000000), -50, 4}, - {GRISU_UINT64_C(0xc3500000, 00000000), -47, 5}, - {GRISU_UINT64_C(0xf4240000, 00000000), -44, 6}, - {GRISU_UINT64_C(0x98968000, 00000000), -40, 7}, - {GRISU_UINT64_C(0xbebc2000, 00000000), -37, 8}, - {GRISU_UINT64_C(0xee6b2800, 00000000), -34, 9}, - {GRISU_UINT64_C(0x9502f900, 00000000), -30, 10}, - {GRISU_UINT64_C(0xba43b740, 00000000), -27, 11}, - {GRISU_UINT64_C(0xe8d4a510, 00000000), -24, 12}, - {GRISU_UINT64_C(0x9184e72a, 00000000), -20, 13}, - {GRISU_UINT64_C(0xb5e620f4, 80000000), -17, 14}, - {GRISU_UINT64_C(0xe35fa931, a0000000), -14, 15}, - {GRISU_UINT64_C(0x8e1bc9bf, 04000000), -10, 16}, - {GRISU_UINT64_C(0xb1a2bc2e, c5000000), -7, 17}, - {GRISU_UINT64_C(0xde0b6b3a, 76400000), -4, 18}, - {GRISU_UINT64_C(0x8ac72304, 89e80000), 0, 19}, - {GRISU_UINT64_C(0xad78ebc5, ac620000), 3, 20}, - {GRISU_UINT64_C(0xd8d726b7, 177a8000), 6, 21}, - {GRISU_UINT64_C(0x87867832, 6eac9000), 10, 22}, - {GRISU_UINT64_C(0xa968163f, 0a57b400), 13, 23}, - {GRISU_UINT64_C(0xd3c21bce, cceda100), 16, 24}, - {GRISU_UINT64_C(0x84595161, 401484a0), 20, 25}, - {GRISU_UINT64_C(0xa56fa5b9, 9019a5c8), 23, 26}, - {GRISU_UINT64_C(0xcecb8f27, f4200f3a), 26, 27}, - {GRISU_UINT64_C(0x813f3978, f8940984), 30, 28}, - {GRISU_UINT64_C(0xa18f07d7, 36b90be5), 33, 29}, - {GRISU_UINT64_C(0xc9f2c9cd, 04674edf), 36, 30}, - {GRISU_UINT64_C(0xfc6f7c40, 45812296), 39, 31}, - {GRISU_UINT64_C(0x9dc5ada8, 2b70b59e), 43, 32}, - {GRISU_UINT64_C(0xc5371912, 364ce305), 46, 33}, - {GRISU_UINT64_C(0xf684df56, c3e01bc7), 49, 34}, - {GRISU_UINT64_C(0x9a130b96, 3a6c115c), 53, 35}, - {GRISU_UINT64_C(0xc097ce7b, c90715b3), 56, 36}, - {GRISU_UINT64_C(0xf0bdc21a, bb48db20), 59, 37}, - {GRISU_UINT64_C(0x96769950, b50d88f4), 63, 38}, - {GRISU_UINT64_C(0xbc143fa4, e250eb31), 66, 39}, - {GRISU_UINT64_C(0xeb194f8e, 1ae525fd), 69, 40}, - {GRISU_UINT64_C(0x92efd1b8, d0cf37be), 73, 41}, - {GRISU_UINT64_C(0xb7abc627, 050305ae), 76, 42}, - {GRISU_UINT64_C(0xe596b7b0, c643c719), 79, 43}, - {GRISU_UINT64_C(0x8f7e32ce, 7bea5c70), 83, 44}, - {GRISU_UINT64_C(0xb35dbf82, 1ae4f38c), 86, 45}, - {GRISU_UINT64_C(0xe0352f62, a19e306f), 89, 46}, - {GRISU_UINT64_C(0x8c213d9d, a502de45), 93, 47}, - {GRISU_UINT64_C(0xaf298d05, 0e4395d7), 96, 48}, - {GRISU_UINT64_C(0xdaf3f046, 51d47b4c), 99, 49}, - {GRISU_UINT64_C(0x88d8762b, f324cd10), 103, 50}, - {GRISU_UINT64_C(0xab0e93b6, efee0054), 106, 51}, - {GRISU_UINT64_C(0xd5d238a4, abe98068), 109, 52}, - {GRISU_UINT64_C(0x85a36366, eb71f041), 113, 53}, - {GRISU_UINT64_C(0xa70c3c40, a64e6c52), 116, 54}, - {GRISU_UINT64_C(0xd0cf4b50, cfe20766), 119, 55}, - {GRISU_UINT64_C(0x82818f12, 81ed44a0), 123, 56}, - {GRISU_UINT64_C(0xa321f2d7, 226895c8), 126, 57}, - {GRISU_UINT64_C(0xcbea6f8c, eb02bb3a), 129, 58}, - {GRISU_UINT64_C(0xfee50b70, 25c36a08), 132, 59}, - {GRISU_UINT64_C(0x9f4f2726, 179a2245), 136, 60}, - {GRISU_UINT64_C(0xc722f0ef, 9d80aad6), 139, 61}, - {GRISU_UINT64_C(0xf8ebad2b, 84e0d58c), 142, 62}, - {GRISU_UINT64_C(0x9b934c3b, 330c8577), 146, 63}, - {GRISU_UINT64_C(0xc2781f49, ffcfa6d5), 149, 64}, - {GRISU_UINT64_C(0xf316271c, 7fc3908b), 152, 65}, - {GRISU_UINT64_C(0x97edd871, cfda3a57), 156, 66}, - {GRISU_UINT64_C(0xbde94e8e, 43d0c8ec), 159, 67}, - {GRISU_UINT64_C(0xed63a231, d4c4fb27), 162, 68}, - {GRISU_UINT64_C(0x945e455f, 24fb1cf9), 166, 69}, - {GRISU_UINT64_C(0xb975d6b6, ee39e437), 169, 70}, - {GRISU_UINT64_C(0xe7d34c64, a9c85d44), 172, 71}, - {GRISU_UINT64_C(0x90e40fbe, ea1d3a4b), 176, 72}, - {GRISU_UINT64_C(0xb51d13ae, a4a488dd), 179, 73}, - {GRISU_UINT64_C(0xe264589a, 4dcdab15), 182, 74}, - {GRISU_UINT64_C(0x8d7eb760, 70a08aed), 186, 75}, - {GRISU_UINT64_C(0xb0de6538, 8cc8ada8), 189, 76}, - {GRISU_UINT64_C(0xdd15fe86, affad912), 192, 77}, - {GRISU_UINT64_C(0x8a2dbf14, 2dfcc7ab), 196, 78}, - {GRISU_UINT64_C(0xacb92ed9, 397bf996), 199, 79}, - {GRISU_UINT64_C(0xd7e77a8f, 87daf7fc), 202, 80}, - {GRISU_UINT64_C(0x86f0ac99, b4e8dafd), 206, 81}, - {GRISU_UINT64_C(0xa8acd7c0, 222311bd), 209, 82}, - {GRISU_UINT64_C(0xd2d80db0, 2aabd62c), 212, 83}, - {GRISU_UINT64_C(0x83c7088e, 1aab65db), 216, 84}, - {GRISU_UINT64_C(0xa4b8cab1, a1563f52), 219, 85}, - {GRISU_UINT64_C(0xcde6fd5e, 09abcf27), 222, 86}, - {GRISU_UINT64_C(0x80b05e5a, c60b6178), 226, 87}, - {GRISU_UINT64_C(0xa0dc75f1, 778e39d6), 229, 88}, - {GRISU_UINT64_C(0xc913936d, d571c84c), 232, 89}, - {GRISU_UINT64_C(0xfb587849, 4ace3a5f), 235, 90}, - {GRISU_UINT64_C(0x9d174b2d, cec0e47b), 239, 91}, - {GRISU_UINT64_C(0xc45d1df9, 42711d9a), 242, 92}, - {GRISU_UINT64_C(0xf5746577, 930d6501), 245, 93}, - {GRISU_UINT64_C(0x9968bf6a, bbe85f20), 249, 94}, - {GRISU_UINT64_C(0xbfc2ef45, 6ae276e9), 252, 95}, - {GRISU_UINT64_C(0xefb3ab16, c59b14a3), 255, 96}, - {GRISU_UINT64_C(0x95d04aee, 3b80ece6), 259, 97}, - {GRISU_UINT64_C(0xbb445da9, ca61281f), 262, 98}, - {GRISU_UINT64_C(0xea157514, 3cf97227), 265, 99}, - {GRISU_UINT64_C(0x924d692c, a61be758), 269, 100}, - {GRISU_UINT64_C(0xb6e0c377, cfa2e12e), 272, 101}, - {GRISU_UINT64_C(0xe498f455, c38b997a), 275, 102}, - {GRISU_UINT64_C(0x8edf98b5, 9a373fec), 279, 103}, - {GRISU_UINT64_C(0xb2977ee3, 00c50fe7), 282, 104}, - {GRISU_UINT64_C(0xdf3d5e9b, c0f653e1), 285, 105}, - {GRISU_UINT64_C(0x8b865b21, 5899f46d), 289, 106}, - {GRISU_UINT64_C(0xae67f1e9, aec07188), 292, 107}, - {GRISU_UINT64_C(0xda01ee64, 1a708dea), 295, 108}, - {GRISU_UINT64_C(0x884134fe, 908658b2), 299, 109}, - {GRISU_UINT64_C(0xaa51823e, 34a7eedf), 302, 110}, - {GRISU_UINT64_C(0xd4e5e2cd, c1d1ea96), 305, 111}, - {GRISU_UINT64_C(0x850fadc0, 9923329e), 309, 112}, - {GRISU_UINT64_C(0xa6539930, bf6bff46), 312, 113}, - {GRISU_UINT64_C(0xcfe87f7c, ef46ff17), 315, 114}, - {GRISU_UINT64_C(0x81f14fae, 158c5f6e), 319, 115}, - {GRISU_UINT64_C(0xa26da399, 9aef774a), 322, 116}, - {GRISU_UINT64_C(0xcb090c80, 01ab551c), 325, 117}, - {GRISU_UINT64_C(0xfdcb4fa0, 02162a63), 328, 118}, - {GRISU_UINT64_C(0x9e9f11c4, 014dda7e), 332, 119}, - {GRISU_UINT64_C(0xc646d635, 01a1511e), 335, 120}, - {GRISU_UINT64_C(0xf7d88bc2, 4209a565), 338, 121}, - {GRISU_UINT64_C(0x9ae75759, 6946075f), 342, 122}, - {GRISU_UINT64_C(0xc1a12d2f, c3978937), 345, 123}, - {GRISU_UINT64_C(0xf209787b, b47d6b85), 348, 124}, - {GRISU_UINT64_C(0x9745eb4d, 50ce6333), 352, 125}, - {GRISU_UINT64_C(0xbd176620, a501fc00), 355, 126}, - {GRISU_UINT64_C(0xec5d3fa8, ce427b00), 358, 127}, - {GRISU_UINT64_C(0x93ba47c9, 80e98ce0), 362, 128}, - {GRISU_UINT64_C(0xb8a8d9bb, e123f018), 365, 129}, - {GRISU_UINT64_C(0xe6d3102a, d96cec1e), 368, 130}, - {GRISU_UINT64_C(0x9043ea1a, c7e41393), 372, 131}, - {GRISU_UINT64_C(0xb454e4a1, 79dd1877), 375, 132}, - {GRISU_UINT64_C(0xe16a1dc9, d8545e95), 378, 133}, - {GRISU_UINT64_C(0x8ce2529e, 2734bb1d), 382, 134}, - {GRISU_UINT64_C(0xb01ae745, b101e9e4), 385, 135}, - {GRISU_UINT64_C(0xdc21a117, 1d42645d), 388, 136}, - {GRISU_UINT64_C(0x899504ae, 72497eba), 392, 137}, - {GRISU_UINT64_C(0xabfa45da, 0edbde69), 395, 138}, - {GRISU_UINT64_C(0xd6f8d750, 9292d603), 398, 139}, - {GRISU_UINT64_C(0x865b8692, 5b9bc5c2), 402, 140}, - {GRISU_UINT64_C(0xa7f26836, f282b733), 405, 141}, - {GRISU_UINT64_C(0xd1ef0244, af2364ff), 408, 142}, - {GRISU_UINT64_C(0x8335616a, ed761f1f), 412, 143}, - {GRISU_UINT64_C(0xa402b9c5, a8d3a6e7), 415, 144}, - {GRISU_UINT64_C(0xcd036837, 130890a1), 418, 145}, - {GRISU_UINT64_C(0x80222122, 6be55a65), 422, 146}, - {GRISU_UINT64_C(0xa02aa96b, 06deb0fe), 425, 147}, - {GRISU_UINT64_C(0xc83553c5, c8965d3d), 428, 148}, - {GRISU_UINT64_C(0xfa42a8b7, 3abbf48d), 431, 149}, - {GRISU_UINT64_C(0x9c69a972, 84b578d8), 435, 150}, - {GRISU_UINT64_C(0xc38413cf, 25e2d70e), 438, 151}, - {GRISU_UINT64_C(0xf46518c2, ef5b8cd1), 441, 152}, - {GRISU_UINT64_C(0x98bf2f79, d5993803), 445, 153}, - {GRISU_UINT64_C(0xbeeefb58, 4aff8604), 448, 154}, - {GRISU_UINT64_C(0xeeaaba2e, 5dbf6785), 451, 155}, - {GRISU_UINT64_C(0x952ab45c, fa97a0b3), 455, 156}, - {GRISU_UINT64_C(0xba756174, 393d88e0), 458, 157}, - {GRISU_UINT64_C(0xe912b9d1, 478ceb17), 461, 158}, - {GRISU_UINT64_C(0x91abb422, ccb812ef), 465, 159}, - {GRISU_UINT64_C(0xb616a12b, 7fe617aa), 468, 160}, - {GRISU_UINT64_C(0xe39c4976, 5fdf9d95), 471, 161}, - {GRISU_UINT64_C(0x8e41ade9, fbebc27d), 475, 162}, - {GRISU_UINT64_C(0xb1d21964, 7ae6b31c), 478, 163}, - {GRISU_UINT64_C(0xde469fbd, 99a05fe3), 481, 164}, - {GRISU_UINT64_C(0x8aec23d6, 80043bee), 485, 165}, - {GRISU_UINT64_C(0xada72ccc, 20054aea), 488, 166}, - {GRISU_UINT64_C(0xd910f7ff, 28069da4), 491, 167}, - {GRISU_UINT64_C(0x87aa9aff, 79042287), 495, 168}, - {GRISU_UINT64_C(0xa99541bf, 57452b28), 498, 169}, - {GRISU_UINT64_C(0xd3fa922f, 2d1675f2), 501, 170}, - {GRISU_UINT64_C(0x847c9b5d, 7c2e09b7), 505, 171}, - {GRISU_UINT64_C(0xa59bc234, db398c25), 508, 172}, - {GRISU_UINT64_C(0xcf02b2c2, 1207ef2f), 511, 173}, - {GRISU_UINT64_C(0x8161afb9, 4b44f57d), 515, 174}, - {GRISU_UINT64_C(0xa1ba1ba7, 9e1632dc), 518, 175}, - {GRISU_UINT64_C(0xca28a291, 859bbf93), 521, 176}, - {GRISU_UINT64_C(0xfcb2cb35, e702af78), 524, 177}, - {GRISU_UINT64_C(0x9defbf01, b061adab), 528, 178}, - {GRISU_UINT64_C(0xc56baec2, 1c7a1916), 531, 179}, - {GRISU_UINT64_C(0xf6c69a72, a3989f5c), 534, 180}, - {GRISU_UINT64_C(0x9a3c2087, a63f6399), 538, 181}, - {GRISU_UINT64_C(0xc0cb28a9, 8fcf3c80), 541, 182}, - {GRISU_UINT64_C(0xf0fdf2d3, f3c30b9f), 544, 183}, - {GRISU_UINT64_C(0x969eb7c4, 7859e744), 548, 184}, - {GRISU_UINT64_C(0xbc4665b5, 96706115), 551, 185}, - {GRISU_UINT64_C(0xeb57ff22, fc0c795a), 554, 186}, - {GRISU_UINT64_C(0x9316ff75, dd87cbd8), 558, 187}, - {GRISU_UINT64_C(0xb7dcbf53, 54e9bece), 561, 188}, - {GRISU_UINT64_C(0xe5d3ef28, 2a242e82), 564, 189}, - {GRISU_UINT64_C(0x8fa47579, 1a569d11), 568, 190}, - {GRISU_UINT64_C(0xb38d92d7, 60ec4455), 571, 191}, - {GRISU_UINT64_C(0xe070f78d, 3927556b), 574, 192}, - {GRISU_UINT64_C(0x8c469ab8, 43b89563), 578, 193}, - {GRISU_UINT64_C(0xaf584166, 54a6babb), 581, 194}, - {GRISU_UINT64_C(0xdb2e51bf, e9d0696a), 584, 195}, - {GRISU_UINT64_C(0x88fcf317, f22241e2), 588, 196}, - {GRISU_UINT64_C(0xab3c2fdd, eeaad25b), 591, 197}, - {GRISU_UINT64_C(0xd60b3bd5, 6a5586f2), 594, 198}, - {GRISU_UINT64_C(0x85c70565, 62757457), 598, 199}, - {GRISU_UINT64_C(0xa738c6be, bb12d16d), 601, 200}, - {GRISU_UINT64_C(0xd106f86e, 69d785c8), 604, 201}, - {GRISU_UINT64_C(0x82a45b45, 0226b39d), 608, 202}, - {GRISU_UINT64_C(0xa34d7216, 42b06084), 611, 203}, - {GRISU_UINT64_C(0xcc20ce9b, d35c78a5), 614, 204}, - {GRISU_UINT64_C(0xff290242, c83396ce), 617, 205}, - {GRISU_UINT64_C(0x9f79a169, bd203e41), 621, 206}, - {GRISU_UINT64_C(0xc75809c4, 2c684dd1), 624, 207}, - {GRISU_UINT64_C(0xf92e0c35, 37826146), 627, 208}, - {GRISU_UINT64_C(0x9bbcc7a1, 42b17ccc), 631, 209}, - {GRISU_UINT64_C(0xc2abf989, 935ddbfe), 634, 210}, - {GRISU_UINT64_C(0xf356f7eb, f83552fe), 637, 211}, - {GRISU_UINT64_C(0x98165af3, 7b2153df), 641, 212}, - {GRISU_UINT64_C(0xbe1bf1b0, 59e9a8d6), 644, 213}, - {GRISU_UINT64_C(0xeda2ee1c, 7064130c), 647, 214}, - {GRISU_UINT64_C(0x9485d4d1, c63e8be8), 651, 215}, - {GRISU_UINT64_C(0xb9a74a06, 37ce2ee1), 654, 216}, - {GRISU_UINT64_C(0xe8111c87, c5c1ba9a), 657, 217}, - {GRISU_UINT64_C(0x910ab1d4, db9914a0), 661, 218}, - {GRISU_UINT64_C(0xb54d5e4a, 127f59c8), 664, 219}, - {GRISU_UINT64_C(0xe2a0b5dc, 971f303a), 667, 220}, - {GRISU_UINT64_C(0x8da471a9, de737e24), 671, 221}, - {GRISU_UINT64_C(0xb10d8e14, 56105dad), 674, 222}, - {GRISU_UINT64_C(0xdd50f199, 6b947519), 677, 223}, - {GRISU_UINT64_C(0x8a5296ff, e33cc930), 681, 224}, - {GRISU_UINT64_C(0xace73cbf, dc0bfb7b), 684, 225}, - {GRISU_UINT64_C(0xd8210bef, d30efa5a), 687, 226}, - {GRISU_UINT64_C(0x8714a775, e3e95c78), 691, 227}, - {GRISU_UINT64_C(0xa8d9d153, 5ce3b396), 694, 228}, - {GRISU_UINT64_C(0xd31045a8, 341ca07c), 697, 229}, - {GRISU_UINT64_C(0x83ea2b89, 2091e44e), 701, 230}, - {GRISU_UINT64_C(0xa4e4b66b, 68b65d61), 704, 231}, - {GRISU_UINT64_C(0xce1de406, 42e3f4b9), 707, 232}, - {GRISU_UINT64_C(0x80d2ae83, e9ce78f4), 711, 233}, - {GRISU_UINT64_C(0xa1075a24, e4421731), 714, 234}, - {GRISU_UINT64_C(0xc94930ae, 1d529cfd), 717, 235}, - {GRISU_UINT64_C(0xfb9b7cd9, a4a7443c), 720, 236}, - {GRISU_UINT64_C(0x9d412e08, 06e88aa6), 724, 237}, - {GRISU_UINT64_C(0xc491798a, 08a2ad4f), 727, 238}, - {GRISU_UINT64_C(0xf5b5d7ec, 8acb58a3), 730, 239}, - {GRISU_UINT64_C(0x9991a6f3, d6bf1766), 734, 240}, - {GRISU_UINT64_C(0xbff610b0, cc6edd3f), 737, 241}, - {GRISU_UINT64_C(0xeff394dc, ff8a948f), 740, 242}, - {GRISU_UINT64_C(0x95f83d0a, 1fb69cd9), 744, 243}, - {GRISU_UINT64_C(0xbb764c4c, a7a44410), 747, 244}, - {GRISU_UINT64_C(0xea53df5f, d18d5514), 750, 245}, - {GRISU_UINT64_C(0x92746b9b, e2f8552c), 754, 246}, - {GRISU_UINT64_C(0xb7118682, dbb66a77), 757, 247}, - {GRISU_UINT64_C(0xe4d5e823, 92a40515), 760, 248}, - {GRISU_UINT64_C(0x8f05b116, 3ba6832d), 764, 249}, - {GRISU_UINT64_C(0xb2c71d5b, ca9023f8), 767, 250}, - {GRISU_UINT64_C(0xdf78e4b2, bd342cf7), 770, 251}, - {GRISU_UINT64_C(0x8bab8eef, b6409c1a), 774, 252}, - {GRISU_UINT64_C(0xae9672ab, a3d0c321), 777, 253}, - {GRISU_UINT64_C(0xda3c0f56, 8cc4f3e9), 780, 254}, - {GRISU_UINT64_C(0x88658996, 17fb1871), 784, 255}, - {GRISU_UINT64_C(0xaa7eebfb, 9df9de8e), 787, 256}, - {GRISU_UINT64_C(0xd51ea6fa, 85785631), 790, 257}, - {GRISU_UINT64_C(0x8533285c, 936b35df), 794, 258}, - {GRISU_UINT64_C(0xa67ff273, b8460357), 797, 259}, - {GRISU_UINT64_C(0xd01fef10, a657842c), 800, 260}, - {GRISU_UINT64_C(0x8213f56a, 67f6b29c), 804, 261}, - {GRISU_UINT64_C(0xa298f2c5, 01f45f43), 807, 262}, - {GRISU_UINT64_C(0xcb3f2f76, 42717713), 810, 263}, - {GRISU_UINT64_C(0xfe0efb53, d30dd4d8), 813, 264}, - {GRISU_UINT64_C(0x9ec95d14, 63e8a507), 817, 265}, - {GRISU_UINT64_C(0xc67bb459, 7ce2ce49), 820, 266}, - {GRISU_UINT64_C(0xf81aa16f, dc1b81db), 823, 267}, - {GRISU_UINT64_C(0x9b10a4e5, e9913129), 827, 268}, - {GRISU_UINT64_C(0xc1d4ce1f, 63f57d73), 830, 269}, - {GRISU_UINT64_C(0xf24a01a7, 3cf2dcd0), 833, 270}, - {GRISU_UINT64_C(0x976e4108, 8617ca02), 837, 271}, - {GRISU_UINT64_C(0xbd49d14a, a79dbc82), 840, 272}, - {GRISU_UINT64_C(0xec9c459d, 51852ba3), 843, 273}, - {GRISU_UINT64_C(0x93e1ab82, 52f33b46), 847, 274}, - {GRISU_UINT64_C(0xb8da1662, e7b00a17), 850, 275}, - {GRISU_UINT64_C(0xe7109bfb, a19c0c9d), 853, 276}, - {GRISU_UINT64_C(0x906a617d, 450187e2), 857, 277}, - {GRISU_UINT64_C(0xb484f9dc, 9641e9db), 860, 278}, - {GRISU_UINT64_C(0xe1a63853, bbd26451), 863, 279}, - {GRISU_UINT64_C(0x8d07e334, 55637eb3), 867, 280}, - {GRISU_UINT64_C(0xb049dc01, 6abc5e60), 870, 281}, - {GRISU_UINT64_C(0xdc5c5301, c56b75f7), 873, 282}, - {GRISU_UINT64_C(0x89b9b3e1, 1b6329bb), 877, 283}, - {GRISU_UINT64_C(0xac2820d9, 623bf429), 880, 284}, - {GRISU_UINT64_C(0xd732290f, bacaf134), 883, 285}, - {GRISU_UINT64_C(0x867f59a9, d4bed6c0), 887, 286}, - {GRISU_UINT64_C(0xa81f3014, 49ee8c70), 890, 287}, - {GRISU_UINT64_C(0xd226fc19, 5c6a2f8c), 893, 288}, - {GRISU_UINT64_C(0x83585d8f, d9c25db8), 897, 289}, - {GRISU_UINT64_C(0xa42e74f3, d032f526), 900, 290}, - {GRISU_UINT64_C(0xcd3a1230, c43fb26f), 903, 291}, - {GRISU_UINT64_C(0x80444b5e, 7aa7cf85), 907, 292}, - {GRISU_UINT64_C(0xa0555e36, 1951c367), 910, 293}, - {GRISU_UINT64_C(0xc86ab5c3, 9fa63441), 913, 294}, - {GRISU_UINT64_C(0xfa856334, 878fc151), 916, 295}, - {GRISU_UINT64_C(0x9c935e00, d4b9d8d2), 920, 296}, - {GRISU_UINT64_C(0xc3b83581, 09e84f07), 923, 297}, - {GRISU_UINT64_C(0xf4a642e1, 4c6262c9), 926, 298}, - {GRISU_UINT64_C(0x98e7e9cc, cfbd7dbe), 930, 299}, - {GRISU_UINT64_C(0xbf21e440, 03acdd2d), 933, 300}, - {GRISU_UINT64_C(0xeeea5d50, 04981478), 936, 301}, - {GRISU_UINT64_C(0x95527a52, 02df0ccb), 940, 302}, - {GRISU_UINT64_C(0xbaa718e6, 8396cffe), 943, 303}, - {GRISU_UINT64_C(0xe950df20, 247c83fd), 946, 304}, - {GRISU_UINT64_C(0x91d28b74, 16cdd27e), 950, 305}, - {GRISU_UINT64_C(0xb6472e51, 1c81471e), 953, 306}, - {GRISU_UINT64_C(0xe3d8f9e5, 63a198e5), 956, 307}, - {GRISU_UINT64_C(0x8e679c2f, 5e44ff8f), 960, 308}, - {GRISU_UINT64_C(0xb201833b, 35d63f73), 963, 309}, - {GRISU_UINT64_C(0xde81e40a, 034bcf50), 966, 310}, - {GRISU_UINT64_C(0x8b112e86, 420f6192), 970, 311}, - {GRISU_UINT64_C(0xadd57a27, d29339f6), 973, 312}, - {GRISU_UINT64_C(0xd94ad8b1, c7380874), 976, 313}, - {GRISU_UINT64_C(0x87cec76f, 1c830549), 980, 314}, - {GRISU_UINT64_C(0xa9c2794a, e3a3c69b), 983, 315}, - {GRISU_UINT64_C(0xd433179d, 9c8cb841), 986, 316}, - {GRISU_UINT64_C(0x849feec2, 81d7f329), 990, 317}, - {GRISU_UINT64_C(0xa5c7ea73, 224deff3), 993, 318}, - {GRISU_UINT64_C(0xcf39e50f, eae16bf0), 996, 319}, - {GRISU_UINT64_C(0x81842f29, f2cce376), 1000, 320}, - {GRISU_UINT64_C(0xa1e53af4, 6f801c53), 1003, 321}, - {GRISU_UINT64_C(0xca5e89b1, 8b602368), 1006, 322}, - {GRISU_UINT64_C(0xfcf62c1d, ee382c42), 1009, 323}, - {GRISU_UINT64_C(0x9e19db92, b4e31ba9), 1013, 324}, - {GRISU_UINT64_C(0xc5a05277, 621be294), 1016, 325}, - {GRISU_UINT64_C(0xf7086715, 3aa2db39), 1019, 326}, - {GRISU_UINT64_C(0x9a65406d, 44a5c903), 1023, 327}, - {GRISU_UINT64_C(0xc0fe9088, 95cf3b44), 1026, 328}, - {GRISU_UINT64_C(0xf13e34aa, bb430a15), 1029, 329}, - {GRISU_UINT64_C(0x96c6e0ea, b509e64d), 1033, 330}, - {GRISU_UINT64_C(0xbc789925, 624c5fe1), 1036, 331}, - {GRISU_UINT64_C(0xeb96bf6e, badf77d9), 1039, 332}, - {GRISU_UINT64_C(0x933e37a5, 34cbaae8), 1043, 333}, - {GRISU_UINT64_C(0xb80dc58e, 81fe95a1), 1046, 334}, - {GRISU_UINT64_C(0xe61136f2, 227e3b0a), 1049, 335}, - {GRISU_UINT64_C(0x8fcac257, 558ee4e6), 1053, 336}, - {GRISU_UINT64_C(0xb3bd72ed, 2af29e20), 1056, 337}, - {GRISU_UINT64_C(0xe0accfa8, 75af45a8), 1059, 338}, - {GRISU_UINT64_C(0x8c6c01c9, 498d8b89), 1063, 339}, - {GRISU_UINT64_C(0xaf87023b, 9bf0ee6b), 1066, 340}, - {GRISU_UINT64_C(0xdb68c2ca, 82ed2a06), 1069, 341}, - {GRISU_UINT64_C(0x892179be, 91d43a44), 1073, 342}, - }; -static const int GRISU_CACHE_MAX_DISTANCE(1) = 4; -// nb elements (1): 651 -static const GRISU_CACHE_STRUCT GRISU_CACHE_NAME(2)[] = { - {GRISU_UINT64_C(0xe61acf03, 3d1a45df), -1087, -308}, - {GRISU_UINT64_C(0xb3c4f1ba, 87bc8697), -1080, -306}, - {GRISU_UINT64_C(0x8c71dcd9, ba0b4926), -1073, -304}, - {GRISU_UINT64_C(0xdb71e914, 32b1a24b), -1067, -302}, - {GRISU_UINT64_C(0xab70fe17, c79ac6ca), -1060, -300}, - {GRISU_UINT64_C(0x85f04682, 93f0eb4e), -1053, -298}, - {GRISU_UINT64_C(0xd1476e2c, 07286faa), -1047, -296}, - {GRISU_UINT64_C(0xa37fce12, 6597973d), -1040, -294}, - {GRISU_UINT64_C(0xff77b1fc, bebcdc4f), -1034, -292}, - {GRISU_UINT64_C(0xc795830d, 75038c1e), -1027, -290}, - {GRISU_UINT64_C(0x9becce62, 836ac577), -1020, -288}, - {GRISU_UINT64_C(0xf3a20279, ed56d48a), -1014, -286}, - {GRISU_UINT64_C(0xbe5691ef, 416bd60c), -1007, -284}, - {GRISU_UINT64_C(0x94b3a202, eb1c3f39), -1000, -282}, - {GRISU_UINT64_C(0xe858ad24, 8f5c22ca), -994, -280}, - {GRISU_UINT64_C(0xb5854744, 8ffffb2e), -987, -278}, - {GRISU_UINT64_C(0x8dd01fad, 907ffc3c), -980, -276}, - {GRISU_UINT64_C(0xdd95317f, 31c7fa1d), -974, -274}, - {GRISU_UINT64_C(0xad1c8eab, 5ee43b67), -967, -272}, - {GRISU_UINT64_C(0x873e4f75, e2224e68), -960, -270}, - {GRISU_UINT64_C(0xd3515c28, 31559a83), -954, -268}, - {GRISU_UINT64_C(0xa5178fff, 668ae0b6), -947, -266}, - {GRISU_UINT64_C(0x80fa687f, 881c7f8e), -940, -264}, - {GRISU_UINT64_C(0xc9874347, 44ac874f), -934, -262}, - {GRISU_UINT64_C(0x9d71ac8f, ada6c9b5), -927, -260}, - {GRISU_UINT64_C(0xf6019da0, 7f549b2b), -921, -258}, - {GRISU_UINT64_C(0xc0314325, 637a193a), -914, -256}, - {GRISU_UINT64_C(0x96267c75, 35b763b5), -907, -254}, - {GRISU_UINT64_C(0xea9c2277, 23ee8bcb), -901, -252}, - {GRISU_UINT64_C(0xb749faed, 14125d37), -894, -250}, - {GRISU_UINT64_C(0x8f31cc09, 37ae58d3), -887, -248}, - {GRISU_UINT64_C(0xdfbdcece, 67006ac9), -881, -246}, - {GRISU_UINT64_C(0xaecc4991, 4078536d), -874, -244}, - {GRISU_UINT64_C(0x888f9979, 7a5e012d), -867, -242}, - {GRISU_UINT64_C(0xd5605fcd, cf32e1d7), -861, -240}, - {GRISU_UINT64_C(0xa6b34ad8, c9dfc070), -854, -238}, - {GRISU_UINT64_C(0x823c1279, 5db6ce57), -847, -236}, - {GRISU_UINT64_C(0xcb7ddcdd, a26da269), -841, -234}, - {GRISU_UINT64_C(0x9efa548d, 26e5a6e2), -834, -232}, - {GRISU_UINT64_C(0xf867241c, 8cc6d4c1), -828, -230}, - {GRISU_UINT64_C(0xc2109436, 4dfb5637), -821, -228}, - {GRISU_UINT64_C(0x979cf3ca, 6cec5b5b), -814, -226}, - {GRISU_UINT64_C(0xece53cec, 4a314ebe), -808, -224}, - {GRISU_UINT64_C(0xb9131798, 99f68584), -801, -222}, - {GRISU_UINT64_C(0x9096ea6f, 3848984f), -794, -220}, - {GRISU_UINT64_C(0xe1ebce4d, c7f16dfc), -788, -218}, - {GRISU_UINT64_C(0xb080392c, c4349ded), -781, -216}, - {GRISU_UINT64_C(0x89e42caa, f9491b61), -774, -214}, - {GRISU_UINT64_C(0xd77485cb, 25823ac7), -768, -212}, - {GRISU_UINT64_C(0xa8530886, b54dbdec), -761, -210}, - {GRISU_UINT64_C(0x8380dea9, 3da4bc60), -754, -208}, - {GRISU_UINT64_C(0xcd795be8, 70516656), -748, -206}, - {GRISU_UINT64_C(0xa086cfcd, 97bf97f4), -741, -204}, - {GRISU_UINT64_C(0xfad2a4b1, 3d1b5d6c), -735, -202}, - {GRISU_UINT64_C(0xc3f490aa, 77bd60fd), -728, -200}, - {GRISU_UINT64_C(0x99171105, 2d8bf3c5), -721, -198}, - {GRISU_UINT64_C(0xef340a98, 172aace5), -715, -196}, - {GRISU_UINT64_C(0xbae0a846, d2195713), -708, -194}, - {GRISU_UINT64_C(0x91ff8377, 5423cc06), -701, -192}, - {GRISU_UINT64_C(0xe41f3d6a, 7377eeca), -695, -190}, - {GRISU_UINT64_C(0xb23867fb, 2a35b28e), -688, -188}, - {GRISU_UINT64_C(0x8b3c113c, 38f9f37f), -681, -186}, - {GRISU_UINT64_C(0xd98ddaee, 19068c76), -675, -184}, - {GRISU_UINT64_C(0xa9f6d30a, 038d1dbc), -668, -182}, - {GRISU_UINT64_C(0x84c8d4df, d2c63f3b), -661, -180}, - {GRISU_UINT64_C(0xcf79cc9d, b955c2cc), -655, -178}, - {GRISU_UINT64_C(0xa21727db, 38cb0030), -648, -176}, - {GRISU_UINT64_C(0xfd442e46, 88bd304b), -642, -174}, - {GRISU_UINT64_C(0xc5dd4427, 1ad3cdba), -635, -172}, - {GRISU_UINT64_C(0x9a94dd3e, 8cf578ba), -628, -170}, - {GRISU_UINT64_C(0xf18899b1, bc3f8ca2), -622, -168}, - {GRISU_UINT64_C(0xbcb2b812, db11a5de), -615, -166}, - {GRISU_UINT64_C(0x936b9fce, bb25c996), -608, -164}, - {GRISU_UINT64_C(0xe65829b3, 046b0afa), -602, -162}, - {GRISU_UINT64_C(0xb3f4e093, db73a093), -595, -160}, - {GRISU_UINT64_C(0x8c974f73, 83725573), -588, -158}, - {GRISU_UINT64_C(0xdbac6c24, 7d62a584), -582, -156}, - {GRISU_UINT64_C(0xab9eb47c, 81f5114f), -575, -154}, - {GRISU_UINT64_C(0x8613fd01, 45877586), -568, -152}, - {GRISU_UINT64_C(0xd17f3b51, fca3a7a1), -562, -150}, - {GRISU_UINT64_C(0xa3ab6658, 0d5fdaf6), -555, -148}, - {GRISU_UINT64_C(0xffbbcfe9, 94e5c620), -549, -146}, - {GRISU_UINT64_C(0xc7caba6e, 7c5382c9), -542, -144}, - {GRISU_UINT64_C(0x9c1661a6, 51213e2d), -535, -142}, - {GRISU_UINT64_C(0xf3e2f893, dec3f126), -529, -140}, - {GRISU_UINT64_C(0xbe895233, 86091466), -522, -138}, - {GRISU_UINT64_C(0x94db4838, 40b717f0), -515, -136}, - {GRISU_UINT64_C(0xe896a0d7, e51e1566), -509, -134}, - {GRISU_UINT64_C(0xb5b5ada8, aaff80b8), -502, -132}, - {GRISU_UINT64_C(0x8df5efab, c5979c90), -495, -130}, - {GRISU_UINT64_C(0xddd0467c, 64bce4a1), -489, -128}, - {GRISU_UINT64_C(0xad4ab711, 2eb3929e), -482, -126}, - {GRISU_UINT64_C(0x87625f05, 6c7c4a8b), -475, -124}, - {GRISU_UINT64_C(0xd389b478, 79823479), -469, -122}, - {GRISU_UINT64_C(0xa54394fe, 1eedb8ff), -462, -120}, - {GRISU_UINT64_C(0x811ccc66, 8829b887), -455, -118}, - {GRISU_UINT64_C(0xc9bcff60, 34c13053), -449, -116}, - {GRISU_UINT64_C(0x9d9ba783, 2936edc1), -442, -114}, - {GRISU_UINT64_C(0xf64335bc, f065d37d), -436, -112}, - {GRISU_UINT64_C(0xc06481fb, 9bcf8d3a), -429, -110}, - {GRISU_UINT64_C(0x964e858c, 91ba2655), -422, -108}, - {GRISU_UINT64_C(0xeadab0ab, a3b2dbe5), -416, -106}, - {GRISU_UINT64_C(0xb77ada06, 17e3bbcb), -409, -104}, - {GRISU_UINT64_C(0x8f57fa54, c2a9eab7), -402, -102}, - {GRISU_UINT64_C(0xdff97724, 70297ebd), -396, -100}, - {GRISU_UINT64_C(0xaefae514, 77a06b04), -389, -98}, - {GRISU_UINT64_C(0x88b402f7, fd75539b), -382, -96}, - {GRISU_UINT64_C(0xd59944a3, 7c0752a2), -376, -94}, - {GRISU_UINT64_C(0xa6dfbd9f, b8e5b88f), -369, -92}, - {GRISU_UINT64_C(0x825ecc24, c8737830), -362, -90}, - {GRISU_UINT64_C(0xcbb41ef9, 79346bca), -356, -88}, - {GRISU_UINT64_C(0x9f24b832, e6b0f436), -349, -86}, - {GRISU_UINT64_C(0xf8a95fcf, 88747d94), -343, -84}, - {GRISU_UINT64_C(0xc24452da, 229b021c), -336, -82}, - {GRISU_UINT64_C(0x97c560ba, 6b0919a6), -329, -80}, - {GRISU_UINT64_C(0xed246723, 473e3813), -323, -78}, - {GRISU_UINT64_C(0xb9447093, 8fa89bcf), -316, -76}, - {GRISU_UINT64_C(0x90bd77f3, 483bb9ba), -309, -74}, - {GRISU_UINT64_C(0xe2280b6c, 20dd5232), -303, -72}, - {GRISU_UINT64_C(0xb0af48ec, 79ace837), -296, -70}, - {GRISU_UINT64_C(0x8a08f0f8, bf0f156b), -289, -68}, - {GRISU_UINT64_C(0xd7adf884, aa879177), -283, -66}, - {GRISU_UINT64_C(0xa87fea27, a539e9a5), -276, -64}, - {GRISU_UINT64_C(0x83a3eeee, f9153e89), -269, -62}, - {GRISU_UINT64_C(0xcdb02555, 653131b6), -263, -60}, - {GRISU_UINT64_C(0xa0b19d2a, b70e6ed6), -256, -58}, - {GRISU_UINT64_C(0xfb158592, be068d2f), -250, -56}, - {GRISU_UINT64_C(0xc428d05a, a4751e4d), -243, -54}, - {GRISU_UINT64_C(0x993fe2c6, d07b7fac), -236, -52}, - {GRISU_UINT64_C(0xef73d256, a5c0f77d), -230, -50}, - {GRISU_UINT64_C(0xbb127c53, b17ec159), -223, -48}, - {GRISU_UINT64_C(0x92267121, 62ab070e), -216, -46}, - {GRISU_UINT64_C(0xe45c10c4, 2a2b3b06), -210, -44}, - {GRISU_UINT64_C(0xb267ed19, 40f1c61c), -203, -42}, - {GRISU_UINT64_C(0x8b61313b, babce2c6), -196, -40}, - {GRISU_UINT64_C(0xd9c7dced, 53c72256), -190, -38}, - {GRISU_UINT64_C(0xaa242499, 697392d3), -183, -36}, - {GRISU_UINT64_C(0x84ec3c97, da624ab5), -176, -34}, - {GRISU_UINT64_C(0xcfb11ead, 453994ba), -170, -32}, - {GRISU_UINT64_C(0xa2425ff7, 5e14fc32), -163, -30}, - {GRISU_UINT64_C(0xfd87b5f2, 8300ca0e), -157, -28}, - {GRISU_UINT64_C(0xc6120625, 76589ddb), -150, -26}, - {GRISU_UINT64_C(0x9abe14cd, 44753b53), -143, -24}, - {GRISU_UINT64_C(0xf1c90080, baf72cb1), -137, -22}, - {GRISU_UINT64_C(0xbce50864, 92111aeb), -130, -20}, - {GRISU_UINT64_C(0x9392ee8e, 921d5d07), -123, -18}, - {GRISU_UINT64_C(0xe69594be, c44de15b), -117, -16}, - {GRISU_UINT64_C(0xb424dc35, 095cd80f), -110, -14}, - {GRISU_UINT64_C(0x8cbccc09, 6f5088cc), -103, -12}, - {GRISU_UINT64_C(0xdbe6fece, bdedd5bf), -97, -10}, - {GRISU_UINT64_C(0xabcc7711, 8461cefd), -90, -8}, - {GRISU_UINT64_C(0x8637bd05, af6c69b6), -83, -6}, - {GRISU_UINT64_C(0xd1b71758, e219652c), -77, -4}, - {GRISU_UINT64_C(0xa3d70a3d, 70a3d70a), -70, -2}, - {GRISU_UINT64_C(0x80000000, 00000000), -63, 0}, - {GRISU_UINT64_C(0xc8000000, 00000000), -57, 2}, - {GRISU_UINT64_C(0x9c400000, 00000000), -50, 4}, - {GRISU_UINT64_C(0xf4240000, 00000000), -44, 6}, - {GRISU_UINT64_C(0xbebc2000, 00000000), -37, 8}, - {GRISU_UINT64_C(0x9502f900, 00000000), -30, 10}, - {GRISU_UINT64_C(0xe8d4a510, 00000000), -24, 12}, - {GRISU_UINT64_C(0xb5e620f4, 80000000), -17, 14}, - {GRISU_UINT64_C(0x8e1bc9bf, 04000000), -10, 16}, - {GRISU_UINT64_C(0xde0b6b3a, 76400000), -4, 18}, - {GRISU_UINT64_C(0xad78ebc5, ac620000), 3, 20}, - {GRISU_UINT64_C(0x87867832, 6eac9000), 10, 22}, - {GRISU_UINT64_C(0xd3c21bce, cceda100), 16, 24}, - {GRISU_UINT64_C(0xa56fa5b9, 9019a5c8), 23, 26}, - {GRISU_UINT64_C(0x813f3978, f8940984), 30, 28}, - {GRISU_UINT64_C(0xc9f2c9cd, 04674edf), 36, 30}, - {GRISU_UINT64_C(0x9dc5ada8, 2b70b59e), 43, 32}, - {GRISU_UINT64_C(0xf684df56, c3e01bc7), 49, 34}, - {GRISU_UINT64_C(0xc097ce7b, c90715b3), 56, 36}, - {GRISU_UINT64_C(0x96769950, b50d88f4), 63, 38}, - {GRISU_UINT64_C(0xeb194f8e, 1ae525fd), 69, 40}, - {GRISU_UINT64_C(0xb7abc627, 050305ae), 76, 42}, - {GRISU_UINT64_C(0x8f7e32ce, 7bea5c70), 83, 44}, - {GRISU_UINT64_C(0xe0352f62, a19e306f), 89, 46}, - {GRISU_UINT64_C(0xaf298d05, 0e4395d7), 96, 48}, - {GRISU_UINT64_C(0x88d8762b, f324cd10), 103, 50}, - {GRISU_UINT64_C(0xd5d238a4, abe98068), 109, 52}, - {GRISU_UINT64_C(0xa70c3c40, a64e6c52), 116, 54}, - {GRISU_UINT64_C(0x82818f12, 81ed44a0), 123, 56}, - {GRISU_UINT64_C(0xcbea6f8c, eb02bb3a), 129, 58}, - {GRISU_UINT64_C(0x9f4f2726, 179a2245), 136, 60}, - {GRISU_UINT64_C(0xf8ebad2b, 84e0d58c), 142, 62}, - {GRISU_UINT64_C(0xc2781f49, ffcfa6d5), 149, 64}, - {GRISU_UINT64_C(0x97edd871, cfda3a57), 156, 66}, - {GRISU_UINT64_C(0xed63a231, d4c4fb27), 162, 68}, - {GRISU_UINT64_C(0xb975d6b6, ee39e437), 169, 70}, - {GRISU_UINT64_C(0x90e40fbe, ea1d3a4b), 176, 72}, - {GRISU_UINT64_C(0xe264589a, 4dcdab15), 182, 74}, - {GRISU_UINT64_C(0xb0de6538, 8cc8ada8), 189, 76}, - {GRISU_UINT64_C(0x8a2dbf14, 2dfcc7ab), 196, 78}, - {GRISU_UINT64_C(0xd7e77a8f, 87daf7fc), 202, 80}, - {GRISU_UINT64_C(0xa8acd7c0, 222311bd), 209, 82}, - {GRISU_UINT64_C(0x83c7088e, 1aab65db), 216, 84}, - {GRISU_UINT64_C(0xcde6fd5e, 09abcf27), 222, 86}, - {GRISU_UINT64_C(0xa0dc75f1, 778e39d6), 229, 88}, - {GRISU_UINT64_C(0xfb587849, 4ace3a5f), 235, 90}, - {GRISU_UINT64_C(0xc45d1df9, 42711d9a), 242, 92}, - {GRISU_UINT64_C(0x9968bf6a, bbe85f20), 249, 94}, - {GRISU_UINT64_C(0xefb3ab16, c59b14a3), 255, 96}, - {GRISU_UINT64_C(0xbb445da9, ca61281f), 262, 98}, - {GRISU_UINT64_C(0x924d692c, a61be758), 269, 100}, - {GRISU_UINT64_C(0xe498f455, c38b997a), 275, 102}, - {GRISU_UINT64_C(0xb2977ee3, 00c50fe7), 282, 104}, - {GRISU_UINT64_C(0x8b865b21, 5899f46d), 289, 106}, - {GRISU_UINT64_C(0xda01ee64, 1a708dea), 295, 108}, - {GRISU_UINT64_C(0xaa51823e, 34a7eedf), 302, 110}, - {GRISU_UINT64_C(0x850fadc0, 9923329e), 309, 112}, - {GRISU_UINT64_C(0xcfe87f7c, ef46ff17), 315, 114}, - {GRISU_UINT64_C(0xa26da399, 9aef774a), 322, 116}, - {GRISU_UINT64_C(0xfdcb4fa0, 02162a63), 328, 118}, - {GRISU_UINT64_C(0xc646d635, 01a1511e), 335, 120}, - {GRISU_UINT64_C(0x9ae75759, 6946075f), 342, 122}, - {GRISU_UINT64_C(0xf209787b, b47d6b85), 348, 124}, - {GRISU_UINT64_C(0xbd176620, a501fc00), 355, 126}, - {GRISU_UINT64_C(0x93ba47c9, 80e98ce0), 362, 128}, - {GRISU_UINT64_C(0xe6d3102a, d96cec1e), 368, 130}, - {GRISU_UINT64_C(0xb454e4a1, 79dd1877), 375, 132}, - {GRISU_UINT64_C(0x8ce2529e, 2734bb1d), 382, 134}, - {GRISU_UINT64_C(0xdc21a117, 1d42645d), 388, 136}, - {GRISU_UINT64_C(0xabfa45da, 0edbde69), 395, 138}, - {GRISU_UINT64_C(0x865b8692, 5b9bc5c2), 402, 140}, - {GRISU_UINT64_C(0xd1ef0244, af2364ff), 408, 142}, - {GRISU_UINT64_C(0xa402b9c5, a8d3a6e7), 415, 144}, - {GRISU_UINT64_C(0x80222122, 6be55a65), 422, 146}, - {GRISU_UINT64_C(0xc83553c5, c8965d3d), 428, 148}, - {GRISU_UINT64_C(0x9c69a972, 84b578d8), 435, 150}, - {GRISU_UINT64_C(0xf46518c2, ef5b8cd1), 441, 152}, - {GRISU_UINT64_C(0xbeeefb58, 4aff8604), 448, 154}, - {GRISU_UINT64_C(0x952ab45c, fa97a0b3), 455, 156}, - {GRISU_UINT64_C(0xe912b9d1, 478ceb17), 461, 158}, - {GRISU_UINT64_C(0xb616a12b, 7fe617aa), 468, 160}, - {GRISU_UINT64_C(0x8e41ade9, fbebc27d), 475, 162}, - {GRISU_UINT64_C(0xde469fbd, 99a05fe3), 481, 164}, - {GRISU_UINT64_C(0xada72ccc, 20054aea), 488, 166}, - {GRISU_UINT64_C(0x87aa9aff, 79042287), 495, 168}, - {GRISU_UINT64_C(0xd3fa922f, 2d1675f2), 501, 170}, - {GRISU_UINT64_C(0xa59bc234, db398c25), 508, 172}, - {GRISU_UINT64_C(0x8161afb9, 4b44f57d), 515, 174}, - {GRISU_UINT64_C(0xca28a291, 859bbf93), 521, 176}, - {GRISU_UINT64_C(0x9defbf01, b061adab), 528, 178}, - {GRISU_UINT64_C(0xf6c69a72, a3989f5c), 534, 180}, - {GRISU_UINT64_C(0xc0cb28a9, 8fcf3c80), 541, 182}, - {GRISU_UINT64_C(0x969eb7c4, 7859e744), 548, 184}, - {GRISU_UINT64_C(0xeb57ff22, fc0c795a), 554, 186}, - {GRISU_UINT64_C(0xb7dcbf53, 54e9bece), 561, 188}, - {GRISU_UINT64_C(0x8fa47579, 1a569d11), 568, 190}, - {GRISU_UINT64_C(0xe070f78d, 3927556b), 574, 192}, - {GRISU_UINT64_C(0xaf584166, 54a6babb), 581, 194}, - {GRISU_UINT64_C(0x88fcf317, f22241e2), 588, 196}, - {GRISU_UINT64_C(0xd60b3bd5, 6a5586f2), 594, 198}, - {GRISU_UINT64_C(0xa738c6be, bb12d16d), 601, 200}, - {GRISU_UINT64_C(0x82a45b45, 0226b39d), 608, 202}, - {GRISU_UINT64_C(0xcc20ce9b, d35c78a5), 614, 204}, - {GRISU_UINT64_C(0x9f79a169, bd203e41), 621, 206}, - {GRISU_UINT64_C(0xf92e0c35, 37826146), 627, 208}, - {GRISU_UINT64_C(0xc2abf989, 935ddbfe), 634, 210}, - {GRISU_UINT64_C(0x98165af3, 7b2153df), 641, 212}, - {GRISU_UINT64_C(0xeda2ee1c, 7064130c), 647, 214}, - {GRISU_UINT64_C(0xb9a74a06, 37ce2ee1), 654, 216}, - {GRISU_UINT64_C(0x910ab1d4, db9914a0), 661, 218}, - {GRISU_UINT64_C(0xe2a0b5dc, 971f303a), 667, 220}, - {GRISU_UINT64_C(0xb10d8e14, 56105dad), 674, 222}, - {GRISU_UINT64_C(0x8a5296ff, e33cc930), 681, 224}, - {GRISU_UINT64_C(0xd8210bef, d30efa5a), 687, 226}, - {GRISU_UINT64_C(0xa8d9d153, 5ce3b396), 694, 228}, - {GRISU_UINT64_C(0x83ea2b89, 2091e44e), 701, 230}, - {GRISU_UINT64_C(0xce1de406, 42e3f4b9), 707, 232}, - {GRISU_UINT64_C(0xa1075a24, e4421731), 714, 234}, - {GRISU_UINT64_C(0xfb9b7cd9, a4a7443c), 720, 236}, - {GRISU_UINT64_C(0xc491798a, 08a2ad4f), 727, 238}, - {GRISU_UINT64_C(0x9991a6f3, d6bf1766), 734, 240}, - {GRISU_UINT64_C(0xeff394dc, ff8a948f), 740, 242}, - {GRISU_UINT64_C(0xbb764c4c, a7a44410), 747, 244}, - {GRISU_UINT64_C(0x92746b9b, e2f8552c), 754, 246}, - {GRISU_UINT64_C(0xe4d5e823, 92a40515), 760, 248}, - {GRISU_UINT64_C(0xb2c71d5b, ca9023f8), 767, 250}, - {GRISU_UINT64_C(0x8bab8eef, b6409c1a), 774, 252}, - {GRISU_UINT64_C(0xda3c0f56, 8cc4f3e9), 780, 254}, - {GRISU_UINT64_C(0xaa7eebfb, 9df9de8e), 787, 256}, - {GRISU_UINT64_C(0x8533285c, 936b35df), 794, 258}, - {GRISU_UINT64_C(0xd01fef10, a657842c), 800, 260}, - {GRISU_UINT64_C(0xa298f2c5, 01f45f43), 807, 262}, - {GRISU_UINT64_C(0xfe0efb53, d30dd4d8), 813, 264}, - {GRISU_UINT64_C(0xc67bb459, 7ce2ce49), 820, 266}, - {GRISU_UINT64_C(0x9b10a4e5, e9913129), 827, 268}, - {GRISU_UINT64_C(0xf24a01a7, 3cf2dcd0), 833, 270}, - {GRISU_UINT64_C(0xbd49d14a, a79dbc82), 840, 272}, - {GRISU_UINT64_C(0x93e1ab82, 52f33b46), 847, 274}, - {GRISU_UINT64_C(0xe7109bfb, a19c0c9d), 853, 276}, - {GRISU_UINT64_C(0xb484f9dc, 9641e9db), 860, 278}, - {GRISU_UINT64_C(0x8d07e334, 55637eb3), 867, 280}, - {GRISU_UINT64_C(0xdc5c5301, c56b75f7), 873, 282}, - {GRISU_UINT64_C(0xac2820d9, 623bf429), 880, 284}, - {GRISU_UINT64_C(0x867f59a9, d4bed6c0), 887, 286}, - {GRISU_UINT64_C(0xd226fc19, 5c6a2f8c), 893, 288}, - {GRISU_UINT64_C(0xa42e74f3, d032f526), 900, 290}, - {GRISU_UINT64_C(0x80444b5e, 7aa7cf85), 907, 292}, - {GRISU_UINT64_C(0xc86ab5c3, 9fa63441), 913, 294}, - {GRISU_UINT64_C(0x9c935e00, d4b9d8d2), 920, 296}, - {GRISU_UINT64_C(0xf4a642e1, 4c6262c9), 926, 298}, - {GRISU_UINT64_C(0xbf21e440, 03acdd2d), 933, 300}, - {GRISU_UINT64_C(0x95527a52, 02df0ccb), 940, 302}, - {GRISU_UINT64_C(0xe950df20, 247c83fd), 946, 304}, - {GRISU_UINT64_C(0xb6472e51, 1c81471e), 953, 306}, - {GRISU_UINT64_C(0x8e679c2f, 5e44ff8f), 960, 308}, - {GRISU_UINT64_C(0xde81e40a, 034bcf50), 966, 310}, - {GRISU_UINT64_C(0xadd57a27, d29339f6), 973, 312}, - {GRISU_UINT64_C(0x87cec76f, 1c830549), 980, 314}, - {GRISU_UINT64_C(0xd433179d, 9c8cb841), 986, 316}, - {GRISU_UINT64_C(0xa5c7ea73, 224deff3), 993, 318}, - {GRISU_UINT64_C(0x81842f29, f2cce376), 1000, 320}, - {GRISU_UINT64_C(0xca5e89b1, 8b602368), 1006, 322}, - {GRISU_UINT64_C(0x9e19db92, b4e31ba9), 1013, 324}, - {GRISU_UINT64_C(0xf7086715, 3aa2db39), 1019, 326}, - {GRISU_UINT64_C(0xc0fe9088, 95cf3b44), 1026, 328}, - {GRISU_UINT64_C(0x96c6e0ea, b509e64d), 1033, 330}, - {GRISU_UINT64_C(0xeb96bf6e, badf77d9), 1039, 332}, - {GRISU_UINT64_C(0xb80dc58e, 81fe95a1), 1046, 334}, - {GRISU_UINT64_C(0x8fcac257, 558ee4e6), 1053, 336}, - {GRISU_UINT64_C(0xe0accfa8, 75af45a8), 1059, 338}, - {GRISU_UINT64_C(0xaf87023b, 9bf0ee6b), 1066, 340}, - {GRISU_UINT64_C(0x892179be, 91d43a44), 1073, 342}, - }; -static const int GRISU_CACHE_MAX_DISTANCE(2) = 7; -// nb elements (2): 326 -static const GRISU_CACHE_STRUCT GRISU_CACHE_NAME(3)[] = { - {GRISU_UINT64_C(0xe61acf03, 3d1a45df), -1087, -308}, - {GRISU_UINT64_C(0xe0b62e29, 29aba83c), -1077, -305}, - {GRISU_UINT64_C(0xdb71e914, 32b1a24b), -1067, -302}, - {GRISU_UINT64_C(0xd64d3d9d, b981787d), -1057, -299}, - {GRISU_UINT64_C(0xd1476e2c, 07286faa), -1047, -296}, - {GRISU_UINT64_C(0xcc5fc196, fefd7d0c), -1037, -293}, - {GRISU_UINT64_C(0xc795830d, 75038c1e), -1027, -290}, - {GRISU_UINT64_C(0xc2e801fb, 244576d5), -1017, -287}, - {GRISU_UINT64_C(0xbe5691ef, 416bd60c), -1007, -284}, - {GRISU_UINT64_C(0xb9e08a83, a5e34f08), -997, -281}, - {GRISU_UINT64_C(0xb5854744, 8ffffb2e), -987, -278}, - {GRISU_UINT64_C(0xb1442798, f49ffb4b), -977, -275}, - {GRISU_UINT64_C(0xad1c8eab, 5ee43b67), -967, -272}, - {GRISU_UINT64_C(0xa90de353, 5aaae202), -957, -269}, - {GRISU_UINT64_C(0xa5178fff, 668ae0b6), -947, -266}, - {GRISU_UINT64_C(0xa139029f, 6a239f72), -937, -263}, - {GRISU_UINT64_C(0x9d71ac8f, ada6c9b5), -927, -260}, - {GRISU_UINT64_C(0x99c10284, 4f94e0fb), -917, -257}, - {GRISU_UINT64_C(0x96267c75, 35b763b5), -907, -254}, - {GRISU_UINT64_C(0x92a1958a, 7675175f), -897, -251}, - {GRISU_UINT64_C(0x8f31cc09, 37ae58d3), -887, -248}, - {GRISU_UINT64_C(0x8bd6a141, 006042be), -877, -245}, - {GRISU_UINT64_C(0x888f9979, 7a5e012d), -867, -242}, - {GRISU_UINT64_C(0x855c3be0, a17fcd26), -857, -239}, - {GRISU_UINT64_C(0x823c1279, 5db6ce57), -847, -236}, - {GRISU_UINT64_C(0xfe5d5415, 0b090b03), -838, -233}, - {GRISU_UINT64_C(0xf867241c, 8cc6d4c1), -828, -230}, - {GRISU_UINT64_C(0xf294b943, e17a2bc4), -818, -227}, - {GRISU_UINT64_C(0xece53cec, 4a314ebe), -808, -224}, - {GRISU_UINT64_C(0xe757dd7e, c07426e5), -798, -221}, - {GRISU_UINT64_C(0xe1ebce4d, c7f16dfc), -788, -218}, - {GRISU_UINT64_C(0xdca04777, f541c568), -778, -215}, - {GRISU_UINT64_C(0xd77485cb, 25823ac7), -768, -212}, - {GRISU_UINT64_C(0xd267caa8, 62a12d67), -758, -209}, - {GRISU_UINT64_C(0xcd795be8, 70516656), -748, -206}, - {GRISU_UINT64_C(0xc8a883c0, fdaf7df0), -738, -203}, - {GRISU_UINT64_C(0xc3f490aa, 77bd60fd), -728, -200}, - {GRISU_UINT64_C(0xbf5cd546, 78eef0b7), -718, -197}, - {GRISU_UINT64_C(0xbae0a846, d2195713), -708, -194}, - {GRISU_UINT64_C(0xb67f6455, 292cbf08), -698, -191}, - {GRISU_UINT64_C(0xb23867fb, 2a35b28e), -688, -188}, - {GRISU_UINT64_C(0xae0b158b, 4738705f), -678, -185}, - {GRISU_UINT64_C(0xa9f6d30a, 038d1dbc), -668, -182}, - {GRISU_UINT64_C(0xa5fb0a17, c777cf0a), -658, -179}, - {GRISU_UINT64_C(0xa21727db, 38cb0030), -648, -176}, - {GRISU_UINT64_C(0x9e4a9cec, 15763e2f), -638, -173}, - {GRISU_UINT64_C(0x9a94dd3e, 8cf578ba), -628, -170}, - {GRISU_UINT64_C(0x96f5600f, 15a7b7e5), -618, -167}, - {GRISU_UINT64_C(0x936b9fce, bb25c996), -608, -164}, - {GRISU_UINT64_C(0x8ff71a0f, e2c2e6dc), -598, -161}, - {GRISU_UINT64_C(0x8c974f73, 83725573), -588, -158}, - {GRISU_UINT64_C(0x894bc396, ce5da772), -578, -155}, - {GRISU_UINT64_C(0x8613fd01, 45877586), -568, -152}, - {GRISU_UINT64_C(0x82ef8513, 3de648c5), -558, -149}, - {GRISU_UINT64_C(0xffbbcfe9, 94e5c620), -549, -146}, - {GRISU_UINT64_C(0xf9bd690a, 1b68637b), -539, -143}, - {GRISU_UINT64_C(0xf3e2f893, dec3f126), -529, -140}, - {GRISU_UINT64_C(0xee2ba6c0, 678b597f), -519, -137}, - {GRISU_UINT64_C(0xe896a0d7, e51e1566), -509, -134}, - {GRISU_UINT64_C(0xe3231912, d5bf60e6), -499, -131}, - {GRISU_UINT64_C(0xddd0467c, 64bce4a1), -489, -128}, - {GRISU_UINT64_C(0xd89d64d5, 7a607745), -479, -125}, - {GRISU_UINT64_C(0xd389b478, 79823479), -469, -122}, - {GRISU_UINT64_C(0xce947a3d, a6a9273e), -459, -119}, - {GRISU_UINT64_C(0xc9bcff60, 34c13053), -449, -116}, - {GRISU_UINT64_C(0xc5029163, f384a931), -439, -113}, - {GRISU_UINT64_C(0xc06481fb, 9bcf8d3a), -429, -110}, - {GRISU_UINT64_C(0xbbe226ef, b628afeb), -419, -107}, - {GRISU_UINT64_C(0xb77ada06, 17e3bbcb), -409, -104}, - {GRISU_UINT64_C(0xb32df8e9, f3546564), -399, -101}, - {GRISU_UINT64_C(0xaefae514, 77a06b04), -389, -98}, - {GRISU_UINT64_C(0xaae103b5, fcd2a882), -379, -95}, - {GRISU_UINT64_C(0xa6dfbd9f, b8e5b88f), -369, -92}, - {GRISU_UINT64_C(0xa2f67f2d, fa90563b), -359, -89}, - {GRISU_UINT64_C(0x9f24b832, e6b0f436), -349, -86}, - {GRISU_UINT64_C(0x9b69dbe1, b548ce7d), -339, -83}, - {GRISU_UINT64_C(0x97c560ba, 6b0919a6), -329, -80}, - {GRISU_UINT64_C(0x9436c076, 0c86e30c), -319, -77}, - {GRISU_UINT64_C(0x90bd77f3, 483bb9ba), -309, -74}, - {GRISU_UINT64_C(0x8d590723, 948a535f), -299, -71}, - {GRISU_UINT64_C(0x8a08f0f8, bf0f156b), -289, -68}, - {GRISU_UINT64_C(0x86ccbb52, ea94baeb), -279, -65}, - {GRISU_UINT64_C(0x83a3eeee, f9153e89), -269, -62}, - {GRISU_UINT64_C(0x808e1755, 5f3ebf12), -259, -59}, - {GRISU_UINT64_C(0xfb158592, be068d2f), -250, -56}, - {GRISU_UINT64_C(0xf5330471, 4d9265e0), -240, -53}, - {GRISU_UINT64_C(0xef73d256, a5c0f77d), -230, -50}, - {GRISU_UINT64_C(0xe9d71b68, 9dde71b0), -220, -47}, - {GRISU_UINT64_C(0xe45c10c4, 2a2b3b06), -210, -44}, - {GRISU_UINT64_C(0xdf01e85f, 912e37a3), -200, -41}, - {GRISU_UINT64_C(0xd9c7dced, 53c72256), -190, -38}, - {GRISU_UINT64_C(0xd4ad2dbf, c3d07788), -180, -35}, - {GRISU_UINT64_C(0xcfb11ead, 453994ba), -170, -32}, - {GRISU_UINT64_C(0xcad2f7f5, 359a3b3e), -160, -29}, - {GRISU_UINT64_C(0xc6120625, 76589ddb), -150, -26}, - {GRISU_UINT64_C(0xc16d9a00, 95928a27), -140, -23}, - {GRISU_UINT64_C(0xbce50864, 92111aeb), -130, -20}, - {GRISU_UINT64_C(0xb877aa32, 36a4b449), -120, -17}, - {GRISU_UINT64_C(0xb424dc35, 095cd80f), -110, -14}, - {GRISU_UINT64_C(0xafebff0b, cb24aaff), -100, -11}, - {GRISU_UINT64_C(0xabcc7711, 8461cefd), -90, -8}, - {GRISU_UINT64_C(0xa7c5ac47, 1b478423), -80, -5}, - {GRISU_UINT64_C(0xa3d70a3d, 70a3d70a), -70, -2}, - {GRISU_UINT64_C(0xa0000000, 00000000), -60, 1}, - {GRISU_UINT64_C(0x9c400000, 00000000), -50, 4}, - {GRISU_UINT64_C(0x98968000, 00000000), -40, 7}, - {GRISU_UINT64_C(0x9502f900, 00000000), -30, 10}, - {GRISU_UINT64_C(0x9184e72a, 00000000), -20, 13}, - {GRISU_UINT64_C(0x8e1bc9bf, 04000000), -10, 16}, - {GRISU_UINT64_C(0x8ac72304, 89e80000), 0, 19}, - {GRISU_UINT64_C(0x87867832, 6eac9000), 10, 22}, - {GRISU_UINT64_C(0x84595161, 401484a0), 20, 25}, - {GRISU_UINT64_C(0x813f3978, f8940984), 30, 28}, - {GRISU_UINT64_C(0xfc6f7c40, 45812296), 39, 31}, - {GRISU_UINT64_C(0xf684df56, c3e01bc7), 49, 34}, - {GRISU_UINT64_C(0xf0bdc21a, bb48db20), 59, 37}, - {GRISU_UINT64_C(0xeb194f8e, 1ae525fd), 69, 40}, - {GRISU_UINT64_C(0xe596b7b0, c643c719), 79, 43}, - {GRISU_UINT64_C(0xe0352f62, a19e306f), 89, 46}, - {GRISU_UINT64_C(0xdaf3f046, 51d47b4c), 99, 49}, - {GRISU_UINT64_C(0xd5d238a4, abe98068), 109, 52}, - {GRISU_UINT64_C(0xd0cf4b50, cfe20766), 119, 55}, - {GRISU_UINT64_C(0xcbea6f8c, eb02bb3a), 129, 58}, - {GRISU_UINT64_C(0xc722f0ef, 9d80aad6), 139, 61}, - {GRISU_UINT64_C(0xc2781f49, ffcfa6d5), 149, 64}, - {GRISU_UINT64_C(0xbde94e8e, 43d0c8ec), 159, 67}, - {GRISU_UINT64_C(0xb975d6b6, ee39e437), 169, 70}, - {GRISU_UINT64_C(0xb51d13ae, a4a488dd), 179, 73}, - {GRISU_UINT64_C(0xb0de6538, 8cc8ada8), 189, 76}, - {GRISU_UINT64_C(0xacb92ed9, 397bf996), 199, 79}, - {GRISU_UINT64_C(0xa8acd7c0, 222311bd), 209, 82}, - {GRISU_UINT64_C(0xa4b8cab1, a1563f52), 219, 85}, - {GRISU_UINT64_C(0xa0dc75f1, 778e39d6), 229, 88}, - {GRISU_UINT64_C(0x9d174b2d, cec0e47b), 239, 91}, - {GRISU_UINT64_C(0x9968bf6a, bbe85f20), 249, 94}, - {GRISU_UINT64_C(0x95d04aee, 3b80ece6), 259, 97}, - {GRISU_UINT64_C(0x924d692c, a61be758), 269, 100}, - {GRISU_UINT64_C(0x8edf98b5, 9a373fec), 279, 103}, - {GRISU_UINT64_C(0x8b865b21, 5899f46d), 289, 106}, - {GRISU_UINT64_C(0x884134fe, 908658b2), 299, 109}, - {GRISU_UINT64_C(0x850fadc0, 9923329e), 309, 112}, - {GRISU_UINT64_C(0x81f14fae, 158c5f6e), 319, 115}, - {GRISU_UINT64_C(0xfdcb4fa0, 02162a63), 328, 118}, - {GRISU_UINT64_C(0xf7d88bc2, 4209a565), 338, 121}, - {GRISU_UINT64_C(0xf209787b, b47d6b85), 348, 124}, - {GRISU_UINT64_C(0xec5d3fa8, ce427b00), 358, 127}, - {GRISU_UINT64_C(0xe6d3102a, d96cec1e), 368, 130}, - {GRISU_UINT64_C(0xe16a1dc9, d8545e95), 378, 133}, - {GRISU_UINT64_C(0xdc21a117, 1d42645d), 388, 136}, - {GRISU_UINT64_C(0xd6f8d750, 9292d603), 398, 139}, - {GRISU_UINT64_C(0xd1ef0244, af2364ff), 408, 142}, - {GRISU_UINT64_C(0xcd036837, 130890a1), 418, 145}, - {GRISU_UINT64_C(0xc83553c5, c8965d3d), 428, 148}, - {GRISU_UINT64_C(0xc38413cf, 25e2d70e), 438, 151}, - {GRISU_UINT64_C(0xbeeefb58, 4aff8604), 448, 154}, - {GRISU_UINT64_C(0xba756174, 393d88e0), 458, 157}, - {GRISU_UINT64_C(0xb616a12b, 7fe617aa), 468, 160}, - {GRISU_UINT64_C(0xb1d21964, 7ae6b31c), 478, 163}, - {GRISU_UINT64_C(0xada72ccc, 20054aea), 488, 166}, - {GRISU_UINT64_C(0xa99541bf, 57452b28), 498, 169}, - {GRISU_UINT64_C(0xa59bc234, db398c25), 508, 172}, - {GRISU_UINT64_C(0xa1ba1ba7, 9e1632dc), 518, 175}, - {GRISU_UINT64_C(0x9defbf01, b061adab), 528, 178}, - {GRISU_UINT64_C(0x9a3c2087, a63f6399), 538, 181}, - {GRISU_UINT64_C(0x969eb7c4, 7859e744), 548, 184}, - {GRISU_UINT64_C(0x9316ff75, dd87cbd8), 558, 187}, - {GRISU_UINT64_C(0x8fa47579, 1a569d11), 568, 190}, - {GRISU_UINT64_C(0x8c469ab8, 43b89563), 578, 193}, - {GRISU_UINT64_C(0x88fcf317, f22241e2), 588, 196}, - {GRISU_UINT64_C(0x85c70565, 62757457), 598, 199}, - {GRISU_UINT64_C(0x82a45b45, 0226b39d), 608, 202}, - {GRISU_UINT64_C(0xff290242, c83396ce), 617, 205}, - {GRISU_UINT64_C(0xf92e0c35, 37826146), 627, 208}, - {GRISU_UINT64_C(0xf356f7eb, f83552fe), 637, 211}, - {GRISU_UINT64_C(0xeda2ee1c, 7064130c), 647, 214}, - {GRISU_UINT64_C(0xe8111c87, c5c1ba9a), 657, 217}, - {GRISU_UINT64_C(0xe2a0b5dc, 971f303a), 667, 220}, - {GRISU_UINT64_C(0xdd50f199, 6b947519), 677, 223}, - {GRISU_UINT64_C(0xd8210bef, d30efa5a), 687, 226}, - {GRISU_UINT64_C(0xd31045a8, 341ca07c), 697, 229}, - {GRISU_UINT64_C(0xce1de406, 42e3f4b9), 707, 232}, - {GRISU_UINT64_C(0xc94930ae, 1d529cfd), 717, 235}, - {GRISU_UINT64_C(0xc491798a, 08a2ad4f), 727, 238}, - {GRISU_UINT64_C(0xbff610b0, cc6edd3f), 737, 241}, - {GRISU_UINT64_C(0xbb764c4c, a7a44410), 747, 244}, - {GRISU_UINT64_C(0xb7118682, dbb66a77), 757, 247}, - {GRISU_UINT64_C(0xb2c71d5b, ca9023f8), 767, 250}, - {GRISU_UINT64_C(0xae9672ab, a3d0c321), 777, 253}, - {GRISU_UINT64_C(0xaa7eebfb, 9df9de8e), 787, 256}, - {GRISU_UINT64_C(0xa67ff273, b8460357), 797, 259}, - {GRISU_UINT64_C(0xa298f2c5, 01f45f43), 807, 262}, - {GRISU_UINT64_C(0x9ec95d14, 63e8a507), 817, 265}, - {GRISU_UINT64_C(0x9b10a4e5, e9913129), 827, 268}, - {GRISU_UINT64_C(0x976e4108, 8617ca02), 837, 271}, - {GRISU_UINT64_C(0x93e1ab82, 52f33b46), 847, 274}, - {GRISU_UINT64_C(0x906a617d, 450187e2), 857, 277}, - {GRISU_UINT64_C(0x8d07e334, 55637eb3), 867, 280}, - {GRISU_UINT64_C(0x89b9b3e1, 1b6329bb), 877, 283}, - {GRISU_UINT64_C(0x867f59a9, d4bed6c0), 887, 286}, - {GRISU_UINT64_C(0x83585d8f, d9c25db8), 897, 289}, - {GRISU_UINT64_C(0x80444b5e, 7aa7cf85), 907, 292}, - {GRISU_UINT64_C(0xfa856334, 878fc151), 916, 295}, - {GRISU_UINT64_C(0xf4a642e1, 4c6262c9), 926, 298}, - {GRISU_UINT64_C(0xeeea5d50, 04981478), 936, 301}, - {GRISU_UINT64_C(0xe950df20, 247c83fd), 946, 304}, - {GRISU_UINT64_C(0xe3d8f9e5, 63a198e5), 956, 307}, - {GRISU_UINT64_C(0xde81e40a, 034bcf50), 966, 310}, - {GRISU_UINT64_C(0xd94ad8b1, c7380874), 976, 313}, - {GRISU_UINT64_C(0xd433179d, 9c8cb841), 986, 316}, - {GRISU_UINT64_C(0xcf39e50f, eae16bf0), 996, 319}, - {GRISU_UINT64_C(0xca5e89b1, 8b602368), 1006, 322}, - {GRISU_UINT64_C(0xc5a05277, 621be294), 1016, 325}, - {GRISU_UINT64_C(0xc0fe9088, 95cf3b44), 1026, 328}, - {GRISU_UINT64_C(0xbc789925, 624c5fe1), 1036, 331}, - {GRISU_UINT64_C(0xb80dc58e, 81fe95a1), 1046, 334}, - {GRISU_UINT64_C(0xb3bd72ed, 2af29e20), 1056, 337}, - {GRISU_UINT64_C(0xaf87023b, 9bf0ee6b), 1066, 340}, - }; -static const int GRISU_CACHE_MAX_DISTANCE(3) = 10; -// nb elements (3): 217 -static const GRISU_CACHE_STRUCT GRISU_CACHE_NAME(4)[] = { - {GRISU_UINT64_C(0xe61acf03, 3d1a45df), -1087, -308}, - {GRISU_UINT64_C(0x8c71dcd9, ba0b4926), -1073, -304}, - {GRISU_UINT64_C(0xab70fe17, c79ac6ca), -1060, -300}, - {GRISU_UINT64_C(0xd1476e2c, 07286faa), -1047, -296}, - {GRISU_UINT64_C(0xff77b1fc, bebcdc4f), -1034, -292}, - {GRISU_UINT64_C(0x9becce62, 836ac577), -1020, -288}, - {GRISU_UINT64_C(0xbe5691ef, 416bd60c), -1007, -284}, - {GRISU_UINT64_C(0xe858ad24, 8f5c22ca), -994, -280}, - {GRISU_UINT64_C(0x8dd01fad, 907ffc3c), -980, -276}, - {GRISU_UINT64_C(0xad1c8eab, 5ee43b67), -967, -272}, - {GRISU_UINT64_C(0xd3515c28, 31559a83), -954, -268}, - {GRISU_UINT64_C(0x80fa687f, 881c7f8e), -940, -264}, - {GRISU_UINT64_C(0x9d71ac8f, ada6c9b5), -927, -260}, - {GRISU_UINT64_C(0xc0314325, 637a193a), -914, -256}, - {GRISU_UINT64_C(0xea9c2277, 23ee8bcb), -901, -252}, - {GRISU_UINT64_C(0x8f31cc09, 37ae58d3), -887, -248}, - {GRISU_UINT64_C(0xaecc4991, 4078536d), -874, -244}, - {GRISU_UINT64_C(0xd5605fcd, cf32e1d7), -861, -240}, - {GRISU_UINT64_C(0x823c1279, 5db6ce57), -847, -236}, - {GRISU_UINT64_C(0x9efa548d, 26e5a6e2), -834, -232}, - {GRISU_UINT64_C(0xc2109436, 4dfb5637), -821, -228}, - {GRISU_UINT64_C(0xece53cec, 4a314ebe), -808, -224}, - {GRISU_UINT64_C(0x9096ea6f, 3848984f), -794, -220}, - {GRISU_UINT64_C(0xb080392c, c4349ded), -781, -216}, - {GRISU_UINT64_C(0xd77485cb, 25823ac7), -768, -212}, - {GRISU_UINT64_C(0x8380dea9, 3da4bc60), -754, -208}, - {GRISU_UINT64_C(0xa086cfcd, 97bf97f4), -741, -204}, - {GRISU_UINT64_C(0xc3f490aa, 77bd60fd), -728, -200}, - {GRISU_UINT64_C(0xef340a98, 172aace5), -715, -196}, - {GRISU_UINT64_C(0x91ff8377, 5423cc06), -701, -192}, - {GRISU_UINT64_C(0xb23867fb, 2a35b28e), -688, -188}, - {GRISU_UINT64_C(0xd98ddaee, 19068c76), -675, -184}, - {GRISU_UINT64_C(0x84c8d4df, d2c63f3b), -661, -180}, - {GRISU_UINT64_C(0xa21727db, 38cb0030), -648, -176}, - {GRISU_UINT64_C(0xc5dd4427, 1ad3cdba), -635, -172}, - {GRISU_UINT64_C(0xf18899b1, bc3f8ca2), -622, -168}, - {GRISU_UINT64_C(0x936b9fce, bb25c996), -608, -164}, - {GRISU_UINT64_C(0xb3f4e093, db73a093), -595, -160}, - {GRISU_UINT64_C(0xdbac6c24, 7d62a584), -582, -156}, - {GRISU_UINT64_C(0x8613fd01, 45877586), -568, -152}, - {GRISU_UINT64_C(0xa3ab6658, 0d5fdaf6), -555, -148}, - {GRISU_UINT64_C(0xc7caba6e, 7c5382c9), -542, -144}, - {GRISU_UINT64_C(0xf3e2f893, dec3f126), -529, -140}, - {GRISU_UINT64_C(0x94db4838, 40b717f0), -515, -136}, - {GRISU_UINT64_C(0xb5b5ada8, aaff80b8), -502, -132}, - {GRISU_UINT64_C(0xddd0467c, 64bce4a1), -489, -128}, - {GRISU_UINT64_C(0x87625f05, 6c7c4a8b), -475, -124}, - {GRISU_UINT64_C(0xa54394fe, 1eedb8ff), -462, -120}, - {GRISU_UINT64_C(0xc9bcff60, 34c13053), -449, -116}, - {GRISU_UINT64_C(0xf64335bc, f065d37d), -436, -112}, - {GRISU_UINT64_C(0x964e858c, 91ba2655), -422, -108}, - {GRISU_UINT64_C(0xb77ada06, 17e3bbcb), -409, -104}, - {GRISU_UINT64_C(0xdff97724, 70297ebd), -396, -100}, - {GRISU_UINT64_C(0x88b402f7, fd75539b), -382, -96}, - {GRISU_UINT64_C(0xa6dfbd9f, b8e5b88f), -369, -92}, - {GRISU_UINT64_C(0xcbb41ef9, 79346bca), -356, -88}, - {GRISU_UINT64_C(0xf8a95fcf, 88747d94), -343, -84}, - {GRISU_UINT64_C(0x97c560ba, 6b0919a6), -329, -80}, - {GRISU_UINT64_C(0xb9447093, 8fa89bcf), -316, -76}, - {GRISU_UINT64_C(0xe2280b6c, 20dd5232), -303, -72}, - {GRISU_UINT64_C(0x8a08f0f8, bf0f156b), -289, -68}, - {GRISU_UINT64_C(0xa87fea27, a539e9a5), -276, -64}, - {GRISU_UINT64_C(0xcdb02555, 653131b6), -263, -60}, - {GRISU_UINT64_C(0xfb158592, be068d2f), -250, -56}, - {GRISU_UINT64_C(0x993fe2c6, d07b7fac), -236, -52}, - {GRISU_UINT64_C(0xbb127c53, b17ec159), -223, -48}, - {GRISU_UINT64_C(0xe45c10c4, 2a2b3b06), -210, -44}, - {GRISU_UINT64_C(0x8b61313b, babce2c6), -196, -40}, - {GRISU_UINT64_C(0xaa242499, 697392d3), -183, -36}, - {GRISU_UINT64_C(0xcfb11ead, 453994ba), -170, -32}, - {GRISU_UINT64_C(0xfd87b5f2, 8300ca0e), -157, -28}, - {GRISU_UINT64_C(0x9abe14cd, 44753b53), -143, -24}, - {GRISU_UINT64_C(0xbce50864, 92111aeb), -130, -20}, - {GRISU_UINT64_C(0xe69594be, c44de15b), -117, -16}, - {GRISU_UINT64_C(0x8cbccc09, 6f5088cc), -103, -12}, - {GRISU_UINT64_C(0xabcc7711, 8461cefd), -90, -8}, - {GRISU_UINT64_C(0xd1b71758, e219652c), -77, -4}, - {GRISU_UINT64_C(0x80000000, 00000000), -63, 0}, - {GRISU_UINT64_C(0x9c400000, 00000000), -50, 4}, - {GRISU_UINT64_C(0xbebc2000, 00000000), -37, 8}, - {GRISU_UINT64_C(0xe8d4a510, 00000000), -24, 12}, - {GRISU_UINT64_C(0x8e1bc9bf, 04000000), -10, 16}, - {GRISU_UINT64_C(0xad78ebc5, ac620000), 3, 20}, - {GRISU_UINT64_C(0xd3c21bce, cceda100), 16, 24}, - {GRISU_UINT64_C(0x813f3978, f8940984), 30, 28}, - {GRISU_UINT64_C(0x9dc5ada8, 2b70b59e), 43, 32}, - {GRISU_UINT64_C(0xc097ce7b, c90715b3), 56, 36}, - {GRISU_UINT64_C(0xeb194f8e, 1ae525fd), 69, 40}, - {GRISU_UINT64_C(0x8f7e32ce, 7bea5c70), 83, 44}, - {GRISU_UINT64_C(0xaf298d05, 0e4395d7), 96, 48}, - {GRISU_UINT64_C(0xd5d238a4, abe98068), 109, 52}, - {GRISU_UINT64_C(0x82818f12, 81ed44a0), 123, 56}, - {GRISU_UINT64_C(0x9f4f2726, 179a2245), 136, 60}, - {GRISU_UINT64_C(0xc2781f49, ffcfa6d5), 149, 64}, - {GRISU_UINT64_C(0xed63a231, d4c4fb27), 162, 68}, - {GRISU_UINT64_C(0x90e40fbe, ea1d3a4b), 176, 72}, - {GRISU_UINT64_C(0xb0de6538, 8cc8ada8), 189, 76}, - {GRISU_UINT64_C(0xd7e77a8f, 87daf7fc), 202, 80}, - {GRISU_UINT64_C(0x83c7088e, 1aab65db), 216, 84}, - {GRISU_UINT64_C(0xa0dc75f1, 778e39d6), 229, 88}, - {GRISU_UINT64_C(0xc45d1df9, 42711d9a), 242, 92}, - {GRISU_UINT64_C(0xefb3ab16, c59b14a3), 255, 96}, - {GRISU_UINT64_C(0x924d692c, a61be758), 269, 100}, - {GRISU_UINT64_C(0xb2977ee3, 00c50fe7), 282, 104}, - {GRISU_UINT64_C(0xda01ee64, 1a708dea), 295, 108}, - {GRISU_UINT64_C(0x850fadc0, 9923329e), 309, 112}, - {GRISU_UINT64_C(0xa26da399, 9aef774a), 322, 116}, - {GRISU_UINT64_C(0xc646d635, 01a1511e), 335, 120}, - {GRISU_UINT64_C(0xf209787b, b47d6b85), 348, 124}, - {GRISU_UINT64_C(0x93ba47c9, 80e98ce0), 362, 128}, - {GRISU_UINT64_C(0xb454e4a1, 79dd1877), 375, 132}, - {GRISU_UINT64_C(0xdc21a117, 1d42645d), 388, 136}, - {GRISU_UINT64_C(0x865b8692, 5b9bc5c2), 402, 140}, - {GRISU_UINT64_C(0xa402b9c5, a8d3a6e7), 415, 144}, - {GRISU_UINT64_C(0xc83553c5, c8965d3d), 428, 148}, - {GRISU_UINT64_C(0xf46518c2, ef5b8cd1), 441, 152}, - {GRISU_UINT64_C(0x952ab45c, fa97a0b3), 455, 156}, - {GRISU_UINT64_C(0xb616a12b, 7fe617aa), 468, 160}, - {GRISU_UINT64_C(0xde469fbd, 99a05fe3), 481, 164}, - {GRISU_UINT64_C(0x87aa9aff, 79042287), 495, 168}, - {GRISU_UINT64_C(0xa59bc234, db398c25), 508, 172}, - {GRISU_UINT64_C(0xca28a291, 859bbf93), 521, 176}, - {GRISU_UINT64_C(0xf6c69a72, a3989f5c), 534, 180}, - {GRISU_UINT64_C(0x969eb7c4, 7859e744), 548, 184}, - {GRISU_UINT64_C(0xb7dcbf53, 54e9bece), 561, 188}, - {GRISU_UINT64_C(0xe070f78d, 3927556b), 574, 192}, - {GRISU_UINT64_C(0x88fcf317, f22241e2), 588, 196}, - {GRISU_UINT64_C(0xa738c6be, bb12d16d), 601, 200}, - {GRISU_UINT64_C(0xcc20ce9b, d35c78a5), 614, 204}, - {GRISU_UINT64_C(0xf92e0c35, 37826146), 627, 208}, - {GRISU_UINT64_C(0x98165af3, 7b2153df), 641, 212}, - {GRISU_UINT64_C(0xb9a74a06, 37ce2ee1), 654, 216}, - {GRISU_UINT64_C(0xe2a0b5dc, 971f303a), 667, 220}, - {GRISU_UINT64_C(0x8a5296ff, e33cc930), 681, 224}, - {GRISU_UINT64_C(0xa8d9d153, 5ce3b396), 694, 228}, - {GRISU_UINT64_C(0xce1de406, 42e3f4b9), 707, 232}, - {GRISU_UINT64_C(0xfb9b7cd9, a4a7443c), 720, 236}, - {GRISU_UINT64_C(0x9991a6f3, d6bf1766), 734, 240}, - {GRISU_UINT64_C(0xbb764c4c, a7a44410), 747, 244}, - {GRISU_UINT64_C(0xe4d5e823, 92a40515), 760, 248}, - {GRISU_UINT64_C(0x8bab8eef, b6409c1a), 774, 252}, - {GRISU_UINT64_C(0xaa7eebfb, 9df9de8e), 787, 256}, - {GRISU_UINT64_C(0xd01fef10, a657842c), 800, 260}, - {GRISU_UINT64_C(0xfe0efb53, d30dd4d8), 813, 264}, - {GRISU_UINT64_C(0x9b10a4e5, e9913129), 827, 268}, - {GRISU_UINT64_C(0xbd49d14a, a79dbc82), 840, 272}, - {GRISU_UINT64_C(0xe7109bfb, a19c0c9d), 853, 276}, - {GRISU_UINT64_C(0x8d07e334, 55637eb3), 867, 280}, - {GRISU_UINT64_C(0xac2820d9, 623bf429), 880, 284}, - {GRISU_UINT64_C(0xd226fc19, 5c6a2f8c), 893, 288}, - {GRISU_UINT64_C(0x80444b5e, 7aa7cf85), 907, 292}, - {GRISU_UINT64_C(0x9c935e00, d4b9d8d2), 920, 296}, - {GRISU_UINT64_C(0xbf21e440, 03acdd2d), 933, 300}, - {GRISU_UINT64_C(0xe950df20, 247c83fd), 946, 304}, - {GRISU_UINT64_C(0x8e679c2f, 5e44ff8f), 960, 308}, - {GRISU_UINT64_C(0xadd57a27, d29339f6), 973, 312}, - {GRISU_UINT64_C(0xd433179d, 9c8cb841), 986, 316}, - {GRISU_UINT64_C(0x81842f29, f2cce376), 1000, 320}, - {GRISU_UINT64_C(0x9e19db92, b4e31ba9), 1013, 324}, - {GRISU_UINT64_C(0xc0fe9088, 95cf3b44), 1026, 328}, - {GRISU_UINT64_C(0xeb96bf6e, badf77d9), 1039, 332}, - {GRISU_UINT64_C(0x8fcac257, 558ee4e6), 1053, 336}, - {GRISU_UINT64_C(0xaf87023b, 9bf0ee6b), 1066, 340}, - }; -static const int GRISU_CACHE_MAX_DISTANCE(4) = 14; -// nb elements (4): 163 -static const GRISU_CACHE_STRUCT GRISU_CACHE_NAME(5)[] = { - {GRISU_UINT64_C(0xe61acf03, 3d1a45df), -1087, -308}, - {GRISU_UINT64_C(0xaf8e5410, 288e1b6f), -1070, -303}, - {GRISU_UINT64_C(0x85f04682, 93f0eb4e), -1053, -298}, - {GRISU_UINT64_C(0xcc5fc196, fefd7d0c), -1037, -293}, - {GRISU_UINT64_C(0x9becce62, 836ac577), -1020, -288}, - {GRISU_UINT64_C(0xedec366b, 11c6cb8f), -1004, -283}, - {GRISU_UINT64_C(0xb5854744, 8ffffb2e), -987, -278}, - {GRISU_UINT64_C(0x8a7d3eef, 7f1cfc52), -970, -273}, - {GRISU_UINT64_C(0xd3515c28, 31559a83), -954, -268}, - {GRISU_UINT64_C(0xa139029f, 6a239f72), -937, -263}, - {GRISU_UINT64_C(0xf6019da0, 7f549b2b), -921, -258}, - {GRISU_UINT64_C(0xbbb01b92, 83253ca3), -904, -253}, - {GRISU_UINT64_C(0x8f31cc09, 37ae58d3), -887, -248}, - {GRISU_UINT64_C(0xda7f5bf5, 90966849), -871, -243}, - {GRISU_UINT64_C(0xa6b34ad8, c9dfc070), -854, -238}, - {GRISU_UINT64_C(0xfe5d5415, 0b090b03), -838, -233}, - {GRISU_UINT64_C(0xc2109436, 4dfb5637), -821, -228}, - {GRISU_UINT64_C(0x940f4613, ae5ed137), -804, -223}, - {GRISU_UINT64_C(0xe1ebce4d, c7f16dfc), -788, -218}, - {GRISU_UINT64_C(0xac5d37d5, b79b6239), -771, -213}, - {GRISU_UINT64_C(0x8380dea9, 3da4bc60), -754, -208}, - {GRISU_UINT64_C(0xc8a883c0, fdaf7df0), -738, -203}, - {GRISU_UINT64_C(0x99171105, 2d8bf3c5), -721, -198}, - {GRISU_UINT64_C(0xe998d258, 869facd7), -705, -193}, - {GRISU_UINT64_C(0xb23867fb, 2a35b28e), -688, -188}, - {GRISU_UINT64_C(0x87f8a8d4, cfa417ca), -671, -183}, - {GRISU_UINT64_C(0xcf79cc9d, b955c2cc), -655, -178}, - {GRISU_UINT64_C(0x9e4a9cec, 15763e2f), -638, -173}, - {GRISU_UINT64_C(0xf18899b1, bc3f8ca2), -622, -168}, - {GRISU_UINT64_C(0xb84687c2, 69ef3bfb), -605, -163}, - {GRISU_UINT64_C(0x8c974f73, 83725573), -588, -158}, - {GRISU_UINT64_C(0xd686619b, a27255a3), -572, -153}, - {GRISU_UINT64_C(0xa3ab6658, 0d5fdaf6), -555, -148}, - {GRISU_UINT64_C(0xf9bd690a, 1b68637b), -539, -143}, - {GRISU_UINT64_C(0xbe895233, 86091466), -522, -138}, - {GRISU_UINT64_C(0x915e2486, ef32cd60), -505, -133}, - {GRISU_UINT64_C(0xddd0467c, 64bce4a1), -489, -128}, - {GRISU_UINT64_C(0xa93af6c6, c79b5d2e), -472, -123}, - {GRISU_UINT64_C(0x811ccc66, 8829b887), -455, -118}, - {GRISU_UINT64_C(0xc5029163, f384a931), -439, -113}, - {GRISU_UINT64_C(0x964e858c, 91ba2655), -422, -108}, - {GRISU_UINT64_C(0xe5599087, 9ddcaabe), -406, -103}, - {GRISU_UINT64_C(0xaefae514, 77a06b04), -389, -98}, - {GRISU_UINT64_C(0x857fcae6, 2d8493a5), -372, -93}, - {GRISU_UINT64_C(0xcbb41ef9, 79346bca), -356, -88}, - {GRISU_UINT64_C(0x9b69dbe1, b548ce7d), -339, -83}, - {GRISU_UINT64_C(0xed246723, 473e3813), -323, -78}, - {GRISU_UINT64_C(0xb4ecd5f0, 1a4aa828), -306, -73}, - {GRISU_UINT64_C(0x8a08f0f8, bf0f156b), -289, -68}, - {GRISU_UINT64_C(0xd29fe4b1, 8e88640f), -273, -63}, - {GRISU_UINT64_C(0xa0b19d2a, b70e6ed6), -256, -58}, - {GRISU_UINT64_C(0xf5330471, 4d9265e0), -240, -53}, - {GRISU_UINT64_C(0xbb127c53, b17ec159), -223, -48}, - {GRISU_UINT64_C(0x8eb98a7a, 9a5b04e3), -206, -43}, - {GRISU_UINT64_C(0xd9c7dced, 53c72256), -190, -38}, - {GRISU_UINT64_C(0xa6274bbd, d0fadd62), -173, -33}, - {GRISU_UINT64_C(0xfd87b5f2, 8300ca0e), -157, -28}, - {GRISU_UINT64_C(0xc16d9a00, 95928a27), -140, -23}, - {GRISU_UINT64_C(0x9392ee8e, 921d5d07), -123, -18}, - {GRISU_UINT64_C(0xe12e1342, 4bb40e13), -107, -13}, - {GRISU_UINT64_C(0xabcc7711, 8461cefd), -90, -8}, - {GRISU_UINT64_C(0x83126e97, 8d4fdf3b), -73, -3}, - {GRISU_UINT64_C(0xc8000000, 00000000), -57, 2}, - {GRISU_UINT64_C(0x98968000, 00000000), -40, 7}, - {GRISU_UINT64_C(0xe8d4a510, 00000000), -24, 12}, - {GRISU_UINT64_C(0xb1a2bc2e, c5000000), -7, 17}, - {GRISU_UINT64_C(0x87867832, 6eac9000), 10, 22}, - {GRISU_UINT64_C(0xcecb8f27, f4200f3a), 26, 27}, - {GRISU_UINT64_C(0x9dc5ada8, 2b70b59e), 43, 32}, - {GRISU_UINT64_C(0xf0bdc21a, bb48db20), 59, 37}, - {GRISU_UINT64_C(0xb7abc627, 050305ae), 76, 42}, - {GRISU_UINT64_C(0x8c213d9d, a502de45), 93, 47}, - {GRISU_UINT64_C(0xd5d238a4, abe98068), 109, 52}, - {GRISU_UINT64_C(0xa321f2d7, 226895c8), 126, 57}, - {GRISU_UINT64_C(0xf8ebad2b, 84e0d58c), 142, 62}, - {GRISU_UINT64_C(0xbde94e8e, 43d0c8ec), 159, 67}, - {GRISU_UINT64_C(0x90e40fbe, ea1d3a4b), 176, 72}, - {GRISU_UINT64_C(0xdd15fe86, affad912), 192, 77}, - {GRISU_UINT64_C(0xa8acd7c0, 222311bd), 209, 82}, - {GRISU_UINT64_C(0x80b05e5a, c60b6178), 226, 87}, - {GRISU_UINT64_C(0xc45d1df9, 42711d9a), 242, 92}, - {GRISU_UINT64_C(0x95d04aee, 3b80ece6), 259, 97}, - {GRISU_UINT64_C(0xe498f455, c38b997a), 275, 102}, - {GRISU_UINT64_C(0xae67f1e9, aec07188), 292, 107}, - {GRISU_UINT64_C(0x850fadc0, 9923329e), 309, 112}, - {GRISU_UINT64_C(0xcb090c80, 01ab551c), 325, 117}, - {GRISU_UINT64_C(0x9ae75759, 6946075f), 342, 122}, - {GRISU_UINT64_C(0xec5d3fa8, ce427b00), 358, 127}, - {GRISU_UINT64_C(0xb454e4a1, 79dd1877), 375, 132}, - {GRISU_UINT64_C(0x899504ae, 72497eba), 392, 137}, - {GRISU_UINT64_C(0xd1ef0244, af2364ff), 408, 142}, - {GRISU_UINT64_C(0xa02aa96b, 06deb0fe), 425, 147}, - {GRISU_UINT64_C(0xf46518c2, ef5b8cd1), 441, 152}, - {GRISU_UINT64_C(0xba756174, 393d88e0), 458, 157}, - {GRISU_UINT64_C(0x8e41ade9, fbebc27d), 475, 162}, - {GRISU_UINT64_C(0xd910f7ff, 28069da4), 491, 167}, - {GRISU_UINT64_C(0xa59bc234, db398c25), 508, 172}, - {GRISU_UINT64_C(0xfcb2cb35, e702af78), 524, 177}, - {GRISU_UINT64_C(0xc0cb28a9, 8fcf3c80), 541, 182}, - {GRISU_UINT64_C(0x9316ff75, dd87cbd8), 558, 187}, - {GRISU_UINT64_C(0xe070f78d, 3927556b), 574, 192}, - {GRISU_UINT64_C(0xab3c2fdd, eeaad25b), 591, 197}, - {GRISU_UINT64_C(0x82a45b45, 0226b39d), 608, 202}, - {GRISU_UINT64_C(0xc75809c4, 2c684dd1), 624, 207}, - {GRISU_UINT64_C(0x98165af3, 7b2153df), 641, 212}, - {GRISU_UINT64_C(0xe8111c87, c5c1ba9a), 657, 217}, - {GRISU_UINT64_C(0xb10d8e14, 56105dad), 674, 222}, - {GRISU_UINT64_C(0x8714a775, e3e95c78), 691, 227}, - {GRISU_UINT64_C(0xce1de406, 42e3f4b9), 707, 232}, - {GRISU_UINT64_C(0x9d412e08, 06e88aa6), 724, 237}, - {GRISU_UINT64_C(0xeff394dc, ff8a948f), 740, 242}, - {GRISU_UINT64_C(0xb7118682, dbb66a77), 757, 247}, - {GRISU_UINT64_C(0x8bab8eef, b6409c1a), 774, 252}, - {GRISU_UINT64_C(0xd51ea6fa, 85785631), 790, 257}, - {GRISU_UINT64_C(0xa298f2c5, 01f45f43), 807, 262}, - {GRISU_UINT64_C(0xf81aa16f, dc1b81db), 823, 267}, - {GRISU_UINT64_C(0xbd49d14a, a79dbc82), 840, 272}, - {GRISU_UINT64_C(0x906a617d, 450187e2), 857, 277}, - {GRISU_UINT64_C(0xdc5c5301, c56b75f7), 873, 282}, - {GRISU_UINT64_C(0xa81f3014, 49ee8c70), 890, 287}, - {GRISU_UINT64_C(0x80444b5e, 7aa7cf85), 907, 292}, - {GRISU_UINT64_C(0xc3b83581, 09e84f07), 923, 297}, - {GRISU_UINT64_C(0x95527a52, 02df0ccb), 940, 302}, - {GRISU_UINT64_C(0xe3d8f9e5, 63a198e5), 956, 307}, - {GRISU_UINT64_C(0xadd57a27, d29339f6), 973, 312}, - {GRISU_UINT64_C(0x849feec2, 81d7f329), 990, 317}, - {GRISU_UINT64_C(0xca5e89b1, 8b602368), 1006, 322}, - {GRISU_UINT64_C(0x9a65406d, 44a5c903), 1023, 327}, - {GRISU_UINT64_C(0xeb96bf6e, badf77d9), 1039, 332}, - {GRISU_UINT64_C(0xb3bd72ed, 2af29e20), 1056, 337}, - {GRISU_UINT64_C(0x892179be, 91d43a44), 1073, 342}, - }; -static const int GRISU_CACHE_MAX_DISTANCE(5) = 17; -// nb elements (5): 131 -static const GRISU_CACHE_STRUCT GRISU_CACHE_NAME(6)[] = { - {GRISU_UINT64_C(0xe61acf03, 3d1a45df), -1087, -308}, - {GRISU_UINT64_C(0xdb71e914, 32b1a24b), -1067, -302}, - {GRISU_UINT64_C(0xd1476e2c, 07286faa), -1047, -296}, - {GRISU_UINT64_C(0xc795830d, 75038c1e), -1027, -290}, - {GRISU_UINT64_C(0xbe5691ef, 416bd60c), -1007, -284}, - {GRISU_UINT64_C(0xb5854744, 8ffffb2e), -987, -278}, - {GRISU_UINT64_C(0xad1c8eab, 5ee43b67), -967, -272}, - {GRISU_UINT64_C(0xa5178fff, 668ae0b6), -947, -266}, - {GRISU_UINT64_C(0x9d71ac8f, ada6c9b5), -927, -260}, - {GRISU_UINT64_C(0x96267c75, 35b763b5), -907, -254}, - {GRISU_UINT64_C(0x8f31cc09, 37ae58d3), -887, -248}, - {GRISU_UINT64_C(0x888f9979, 7a5e012d), -867, -242}, - {GRISU_UINT64_C(0x823c1279, 5db6ce57), -847, -236}, - {GRISU_UINT64_C(0xf867241c, 8cc6d4c1), -828, -230}, - {GRISU_UINT64_C(0xece53cec, 4a314ebe), -808, -224}, - {GRISU_UINT64_C(0xe1ebce4d, c7f16dfc), -788, -218}, - {GRISU_UINT64_C(0xd77485cb, 25823ac7), -768, -212}, - {GRISU_UINT64_C(0xcd795be8, 70516656), -748, -206}, - {GRISU_UINT64_C(0xc3f490aa, 77bd60fd), -728, -200}, - {GRISU_UINT64_C(0xbae0a846, d2195713), -708, -194}, - {GRISU_UINT64_C(0xb23867fb, 2a35b28e), -688, -188}, - {GRISU_UINT64_C(0xa9f6d30a, 038d1dbc), -668, -182}, - {GRISU_UINT64_C(0xa21727db, 38cb0030), -648, -176}, - {GRISU_UINT64_C(0x9a94dd3e, 8cf578ba), -628, -170}, - {GRISU_UINT64_C(0x936b9fce, bb25c996), -608, -164}, - {GRISU_UINT64_C(0x8c974f73, 83725573), -588, -158}, - {GRISU_UINT64_C(0x8613fd01, 45877586), -568, -152}, - {GRISU_UINT64_C(0xffbbcfe9, 94e5c620), -549, -146}, - {GRISU_UINT64_C(0xf3e2f893, dec3f126), -529, -140}, - {GRISU_UINT64_C(0xe896a0d7, e51e1566), -509, -134}, - {GRISU_UINT64_C(0xddd0467c, 64bce4a1), -489, -128}, - {GRISU_UINT64_C(0xd389b478, 79823479), -469, -122}, - {GRISU_UINT64_C(0xc9bcff60, 34c13053), -449, -116}, - {GRISU_UINT64_C(0xc06481fb, 9bcf8d3a), -429, -110}, - {GRISU_UINT64_C(0xb77ada06, 17e3bbcb), -409, -104}, - {GRISU_UINT64_C(0xaefae514, 77a06b04), -389, -98}, - {GRISU_UINT64_C(0xa6dfbd9f, b8e5b88f), -369, -92}, - {GRISU_UINT64_C(0x9f24b832, e6b0f436), -349, -86}, - {GRISU_UINT64_C(0x97c560ba, 6b0919a6), -329, -80}, - {GRISU_UINT64_C(0x90bd77f3, 483bb9ba), -309, -74}, - {GRISU_UINT64_C(0x8a08f0f8, bf0f156b), -289, -68}, - {GRISU_UINT64_C(0x83a3eeee, f9153e89), -269, -62}, - {GRISU_UINT64_C(0xfb158592, be068d2f), -250, -56}, - {GRISU_UINT64_C(0xef73d256, a5c0f77d), -230, -50}, - {GRISU_UINT64_C(0xe45c10c4, 2a2b3b06), -210, -44}, - {GRISU_UINT64_C(0xd9c7dced, 53c72256), -190, -38}, - {GRISU_UINT64_C(0xcfb11ead, 453994ba), -170, -32}, - {GRISU_UINT64_C(0xc6120625, 76589ddb), -150, -26}, - {GRISU_UINT64_C(0xbce50864, 92111aeb), -130, -20}, - {GRISU_UINT64_C(0xb424dc35, 095cd80f), -110, -14}, - {GRISU_UINT64_C(0xabcc7711, 8461cefd), -90, -8}, - {GRISU_UINT64_C(0xa3d70a3d, 70a3d70a), -70, -2}, - {GRISU_UINT64_C(0x9c400000, 00000000), -50, 4}, - {GRISU_UINT64_C(0x9502f900, 00000000), -30, 10}, - {GRISU_UINT64_C(0x8e1bc9bf, 04000000), -10, 16}, - {GRISU_UINT64_C(0x87867832, 6eac9000), 10, 22}, - {GRISU_UINT64_C(0x813f3978, f8940984), 30, 28}, - {GRISU_UINT64_C(0xf684df56, c3e01bc7), 49, 34}, - {GRISU_UINT64_C(0xeb194f8e, 1ae525fd), 69, 40}, - {GRISU_UINT64_C(0xe0352f62, a19e306f), 89, 46}, - {GRISU_UINT64_C(0xd5d238a4, abe98068), 109, 52}, - {GRISU_UINT64_C(0xcbea6f8c, eb02bb3a), 129, 58}, - {GRISU_UINT64_C(0xc2781f49, ffcfa6d5), 149, 64}, - {GRISU_UINT64_C(0xb975d6b6, ee39e437), 169, 70}, - {GRISU_UINT64_C(0xb0de6538, 8cc8ada8), 189, 76}, - {GRISU_UINT64_C(0xa8acd7c0, 222311bd), 209, 82}, - {GRISU_UINT64_C(0xa0dc75f1, 778e39d6), 229, 88}, - {GRISU_UINT64_C(0x9968bf6a, bbe85f20), 249, 94}, - {GRISU_UINT64_C(0x924d692c, a61be758), 269, 100}, - {GRISU_UINT64_C(0x8b865b21, 5899f46d), 289, 106}, - {GRISU_UINT64_C(0x850fadc0, 9923329e), 309, 112}, - {GRISU_UINT64_C(0xfdcb4fa0, 02162a63), 328, 118}, - {GRISU_UINT64_C(0xf209787b, b47d6b85), 348, 124}, - {GRISU_UINT64_C(0xe6d3102a, d96cec1e), 368, 130}, - {GRISU_UINT64_C(0xdc21a117, 1d42645d), 388, 136}, - {GRISU_UINT64_C(0xd1ef0244, af2364ff), 408, 142}, - {GRISU_UINT64_C(0xc83553c5, c8965d3d), 428, 148}, - {GRISU_UINT64_C(0xbeeefb58, 4aff8604), 448, 154}, - {GRISU_UINT64_C(0xb616a12b, 7fe617aa), 468, 160}, - {GRISU_UINT64_C(0xada72ccc, 20054aea), 488, 166}, - {GRISU_UINT64_C(0xa59bc234, db398c25), 508, 172}, - {GRISU_UINT64_C(0x9defbf01, b061adab), 528, 178}, - {GRISU_UINT64_C(0x969eb7c4, 7859e744), 548, 184}, - {GRISU_UINT64_C(0x8fa47579, 1a569d11), 568, 190}, - {GRISU_UINT64_C(0x88fcf317, f22241e2), 588, 196}, - {GRISU_UINT64_C(0x82a45b45, 0226b39d), 608, 202}, - {GRISU_UINT64_C(0xf92e0c35, 37826146), 627, 208}, - {GRISU_UINT64_C(0xeda2ee1c, 7064130c), 647, 214}, - {GRISU_UINT64_C(0xe2a0b5dc, 971f303a), 667, 220}, - {GRISU_UINT64_C(0xd8210bef, d30efa5a), 687, 226}, - {GRISU_UINT64_C(0xce1de406, 42e3f4b9), 707, 232}, - {GRISU_UINT64_C(0xc491798a, 08a2ad4f), 727, 238}, - {GRISU_UINT64_C(0xbb764c4c, a7a44410), 747, 244}, - {GRISU_UINT64_C(0xb2c71d5b, ca9023f8), 767, 250}, - {GRISU_UINT64_C(0xaa7eebfb, 9df9de8e), 787, 256}, - {GRISU_UINT64_C(0xa298f2c5, 01f45f43), 807, 262}, - {GRISU_UINT64_C(0x9b10a4e5, e9913129), 827, 268}, - {GRISU_UINT64_C(0x93e1ab82, 52f33b46), 847, 274}, - {GRISU_UINT64_C(0x8d07e334, 55637eb3), 867, 280}, - {GRISU_UINT64_C(0x867f59a9, d4bed6c0), 887, 286}, - {GRISU_UINT64_C(0x80444b5e, 7aa7cf85), 907, 292}, - {GRISU_UINT64_C(0xf4a642e1, 4c6262c9), 926, 298}, - {GRISU_UINT64_C(0xe950df20, 247c83fd), 946, 304}, - {GRISU_UINT64_C(0xde81e40a, 034bcf50), 966, 310}, - {GRISU_UINT64_C(0xd433179d, 9c8cb841), 986, 316}, - {GRISU_UINT64_C(0xca5e89b1, 8b602368), 1006, 322}, - {GRISU_UINT64_C(0xc0fe9088, 95cf3b44), 1026, 328}, - {GRISU_UINT64_C(0xb80dc58e, 81fe95a1), 1046, 334}, - {GRISU_UINT64_C(0xaf87023b, 9bf0ee6b), 1066, 340}, - }; -static const int GRISU_CACHE_MAX_DISTANCE(6) = 20; -// nb elements (6): 109 -static const GRISU_CACHE_STRUCT GRISU_CACHE_NAME(7)[] = { - {GRISU_UINT64_C(0xe61acf03, 3d1a45df), -1087, -308}, - {GRISU_UINT64_C(0x892731ac, 9faf056f), -1063, -301}, - {GRISU_UINT64_C(0xa37fce12, 6597973d), -1040, -294}, - {GRISU_UINT64_C(0xc2e801fb, 244576d5), -1017, -287}, - {GRISU_UINT64_C(0xe858ad24, 8f5c22ca), -994, -280}, - {GRISU_UINT64_C(0x8a7d3eef, 7f1cfc52), -970, -273}, - {GRISU_UINT64_C(0xa5178fff, 668ae0b6), -947, -266}, - {GRISU_UINT64_C(0xc4ce17b3, 99107c23), -924, -259}, - {GRISU_UINT64_C(0xea9c2277, 23ee8bcb), -901, -252}, - {GRISU_UINT64_C(0x8bd6a141, 006042be), -877, -245}, - {GRISU_UINT64_C(0xa6b34ad8, c9dfc070), -854, -238}, - {GRISU_UINT64_C(0xc6b8e9b0, 709f109a), -831, -231}, - {GRISU_UINT64_C(0xece53cec, 4a314ebe), -808, -224}, - {GRISU_UINT64_C(0x8d3360f0, 9cf6e4bd), -784, -217}, - {GRISU_UINT64_C(0xa8530886, b54dbdec), -761, -210}, - {GRISU_UINT64_C(0xc8a883c0, fdaf7df0), -738, -203}, - {GRISU_UINT64_C(0xef340a98, 172aace5), -715, -196}, - {GRISU_UINT64_C(0x8e938662, 882af53e), -691, -189}, - {GRISU_UINT64_C(0xa9f6d30a, 038d1dbc), -668, -182}, - {GRISU_UINT64_C(0xca9cf1d2, 06fdc03c), -645, -175}, - {GRISU_UINT64_C(0xf18899b1, bc3f8ca2), -622, -168}, - {GRISU_UINT64_C(0x8ff71a0f, e2c2e6dc), -598, -161}, - {GRISU_UINT64_C(0xab9eb47c, 81f5114f), -575, -154}, - {GRISU_UINT64_C(0xcc963fee, 10b7d1b3), -552, -147}, - {GRISU_UINT64_C(0xf3e2f893, dec3f126), -529, -140}, - {GRISU_UINT64_C(0x915e2486, ef32cd60), -505, -133}, - {GRISU_UINT64_C(0xad4ab711, 2eb3929e), -482, -126}, - {GRISU_UINT64_C(0xce947a3d, a6a9273e), -459, -119}, - {GRISU_UINT64_C(0xf64335bc, f065d37d), -436, -112}, - {GRISU_UINT64_C(0x92c8ae6b, 464fc96f), -412, -105}, - {GRISU_UINT64_C(0xaefae514, 77a06b04), -389, -98}, - {GRISU_UINT64_C(0xd097ad07, a71f26b2), -366, -91}, - {GRISU_UINT64_C(0xf8a95fcf, 88747d94), -343, -84}, - {GRISU_UINT64_C(0x9436c076, 0c86e30c), -319, -77}, - {GRISU_UINT64_C(0xb0af48ec, 79ace837), -296, -70}, - {GRISU_UINT64_C(0xd29fe4b1, 8e88640f), -273, -63}, - {GRISU_UINT64_C(0xfb158592, be068d2f), -250, -56}, - {GRISU_UINT64_C(0x95a86376, 27989aae), -226, -49}, - {GRISU_UINT64_C(0xb267ed19, 40f1c61c), -203, -42}, - {GRISU_UINT64_C(0xd4ad2dbf, c3d07788), -180, -35}, - {GRISU_UINT64_C(0xfd87b5f2, 8300ca0e), -157, -28}, - {GRISU_UINT64_C(0x971da050, 74da7bef), -133, -21}, - {GRISU_UINT64_C(0xb424dc35, 095cd80f), -110, -14}, - {GRISU_UINT64_C(0xd6bf94d5, e57a42bc), -87, -7}, - {GRISU_UINT64_C(0x80000000, 00000000), -63, 0}, - {GRISU_UINT64_C(0x98968000, 00000000), -40, 7}, - {GRISU_UINT64_C(0xb5e620f4, 80000000), -17, 14}, - {GRISU_UINT64_C(0xd8d726b7, 177a8000), 6, 21}, - {GRISU_UINT64_C(0x813f3978, f8940984), 30, 28}, - {GRISU_UINT64_C(0x9a130b96, 3a6c115c), 53, 35}, - {GRISU_UINT64_C(0xb7abc627, 050305ae), 76, 42}, - {GRISU_UINT64_C(0xdaf3f046, 51d47b4c), 99, 49}, - {GRISU_UINT64_C(0x82818f12, 81ed44a0), 123, 56}, - {GRISU_UINT64_C(0x9b934c3b, 330c8577), 146, 63}, - {GRISU_UINT64_C(0xb975d6b6, ee39e437), 169, 70}, - {GRISU_UINT64_C(0xdd15fe86, affad912), 192, 77}, - {GRISU_UINT64_C(0x83c7088e, 1aab65db), 216, 84}, - {GRISU_UINT64_C(0x9d174b2d, cec0e47b), 239, 91}, - {GRISU_UINT64_C(0xbb445da9, ca61281f), 262, 98}, - {GRISU_UINT64_C(0xdf3d5e9b, c0f653e1), 285, 105}, - {GRISU_UINT64_C(0x850fadc0, 9923329e), 309, 112}, - {GRISU_UINT64_C(0x9e9f11c4, 014dda7e), 332, 119}, - {GRISU_UINT64_C(0xbd176620, a501fc00), 355, 126}, - {GRISU_UINT64_C(0xe16a1dc9, d8545e95), 378, 133}, - {GRISU_UINT64_C(0x865b8692, 5b9bc5c2), 402, 140}, - {GRISU_UINT64_C(0xa02aa96b, 06deb0fe), 425, 147}, - {GRISU_UINT64_C(0xbeeefb58, 4aff8604), 448, 154}, - {GRISU_UINT64_C(0xe39c4976, 5fdf9d95), 471, 161}, - {GRISU_UINT64_C(0x87aa9aff, 79042287), 495, 168}, - {GRISU_UINT64_C(0xa1ba1ba7, 9e1632dc), 518, 175}, - {GRISU_UINT64_C(0xc0cb28a9, 8fcf3c80), 541, 182}, - {GRISU_UINT64_C(0xe5d3ef28, 2a242e82), 564, 189}, - {GRISU_UINT64_C(0x88fcf317, f22241e2), 588, 196}, - {GRISU_UINT64_C(0xa34d7216, 42b06084), 611, 203}, - {GRISU_UINT64_C(0xc2abf989, 935ddbfe), 634, 210}, - {GRISU_UINT64_C(0xe8111c87, c5c1ba9a), 657, 217}, - {GRISU_UINT64_C(0x8a5296ff, e33cc930), 681, 224}, - {GRISU_UINT64_C(0xa4e4b66b, 68b65d61), 704, 231}, - {GRISU_UINT64_C(0xc491798a, 08a2ad4f), 727, 238}, - {GRISU_UINT64_C(0xea53df5f, d18d5514), 750, 245}, - {GRISU_UINT64_C(0x8bab8eef, b6409c1a), 774, 252}, - {GRISU_UINT64_C(0xa67ff273, b8460357), 797, 259}, - {GRISU_UINT64_C(0xc67bb459, 7ce2ce49), 820, 266}, - {GRISU_UINT64_C(0xec9c459d, 51852ba3), 843, 273}, - {GRISU_UINT64_C(0x8d07e334, 55637eb3), 867, 280}, - {GRISU_UINT64_C(0xa81f3014, 49ee8c70), 890, 287}, - {GRISU_UINT64_C(0xc86ab5c3, 9fa63441), 913, 294}, - {GRISU_UINT64_C(0xeeea5d50, 04981478), 936, 301}, - {GRISU_UINT64_C(0x8e679c2f, 5e44ff8f), 960, 308}, - {GRISU_UINT64_C(0xa9c2794a, e3a3c69b), 983, 315}, - {GRISU_UINT64_C(0xca5e89b1, 8b602368), 1006, 322}, - {GRISU_UINT64_C(0xf13e34aa, bb430a15), 1029, 329}, - {GRISU_UINT64_C(0x8fcac257, 558ee4e6), 1053, 336}, - }; -static const int GRISU_CACHE_MAX_DISTANCE(7) = 24; -// nb elements (7): 93 -static const GRISU_CACHE_STRUCT GRISU_CACHE_NAME(8)[] = { - {GRISU_UINT64_C(0xe61acf03, 3d1a45df), -1087, -308}, - {GRISU_UINT64_C(0xab70fe17, c79ac6ca), -1060, -300}, - {GRISU_UINT64_C(0xff77b1fc, bebcdc4f), -1034, -292}, - {GRISU_UINT64_C(0xbe5691ef, 416bd60c), -1007, -284}, - {GRISU_UINT64_C(0x8dd01fad, 907ffc3c), -980, -276}, - {GRISU_UINT64_C(0xd3515c28, 31559a83), -954, -268}, - {GRISU_UINT64_C(0x9d71ac8f, ada6c9b5), -927, -260}, - {GRISU_UINT64_C(0xea9c2277, 23ee8bcb), -901, -252}, - {GRISU_UINT64_C(0xaecc4991, 4078536d), -874, -244}, - {GRISU_UINT64_C(0x823c1279, 5db6ce57), -847, -236}, - {GRISU_UINT64_C(0xc2109436, 4dfb5637), -821, -228}, - {GRISU_UINT64_C(0x9096ea6f, 3848984f), -794, -220}, - {GRISU_UINT64_C(0xd77485cb, 25823ac7), -768, -212}, - {GRISU_UINT64_C(0xa086cfcd, 97bf97f4), -741, -204}, - {GRISU_UINT64_C(0xef340a98, 172aace5), -715, -196}, - {GRISU_UINT64_C(0xb23867fb, 2a35b28e), -688, -188}, - {GRISU_UINT64_C(0x84c8d4df, d2c63f3b), -661, -180}, - {GRISU_UINT64_C(0xc5dd4427, 1ad3cdba), -635, -172}, - {GRISU_UINT64_C(0x936b9fce, bb25c996), -608, -164}, - {GRISU_UINT64_C(0xdbac6c24, 7d62a584), -582, -156}, - {GRISU_UINT64_C(0xa3ab6658, 0d5fdaf6), -555, -148}, - {GRISU_UINT64_C(0xf3e2f893, dec3f126), -529, -140}, - {GRISU_UINT64_C(0xb5b5ada8, aaff80b8), -502, -132}, - {GRISU_UINT64_C(0x87625f05, 6c7c4a8b), -475, -124}, - {GRISU_UINT64_C(0xc9bcff60, 34c13053), -449, -116}, - {GRISU_UINT64_C(0x964e858c, 91ba2655), -422, -108}, - {GRISU_UINT64_C(0xdff97724, 70297ebd), -396, -100}, - {GRISU_UINT64_C(0xa6dfbd9f, b8e5b88f), -369, -92}, - {GRISU_UINT64_C(0xf8a95fcf, 88747d94), -343, -84}, - {GRISU_UINT64_C(0xb9447093, 8fa89bcf), -316, -76}, - {GRISU_UINT64_C(0x8a08f0f8, bf0f156b), -289, -68}, - {GRISU_UINT64_C(0xcdb02555, 653131b6), -263, -60}, - {GRISU_UINT64_C(0x993fe2c6, d07b7fac), -236, -52}, - {GRISU_UINT64_C(0xe45c10c4, 2a2b3b06), -210, -44}, - {GRISU_UINT64_C(0xaa242499, 697392d3), -183, -36}, - {GRISU_UINT64_C(0xfd87b5f2, 8300ca0e), -157, -28}, - {GRISU_UINT64_C(0xbce50864, 92111aeb), -130, -20}, - {GRISU_UINT64_C(0x8cbccc09, 6f5088cc), -103, -12}, - {GRISU_UINT64_C(0xd1b71758, e219652c), -77, -4}, - {GRISU_UINT64_C(0x9c400000, 00000000), -50, 4}, - {GRISU_UINT64_C(0xe8d4a510, 00000000), -24, 12}, - {GRISU_UINT64_C(0xad78ebc5, ac620000), 3, 20}, - {GRISU_UINT64_C(0x813f3978, f8940984), 30, 28}, - {GRISU_UINT64_C(0xc097ce7b, c90715b3), 56, 36}, - {GRISU_UINT64_C(0x8f7e32ce, 7bea5c70), 83, 44}, - {GRISU_UINT64_C(0xd5d238a4, abe98068), 109, 52}, - {GRISU_UINT64_C(0x9f4f2726, 179a2245), 136, 60}, - {GRISU_UINT64_C(0xed63a231, d4c4fb27), 162, 68}, - {GRISU_UINT64_C(0xb0de6538, 8cc8ada8), 189, 76}, - {GRISU_UINT64_C(0x83c7088e, 1aab65db), 216, 84}, - {GRISU_UINT64_C(0xc45d1df9, 42711d9a), 242, 92}, - {GRISU_UINT64_C(0x924d692c, a61be758), 269, 100}, - {GRISU_UINT64_C(0xda01ee64, 1a708dea), 295, 108}, - {GRISU_UINT64_C(0xa26da399, 9aef774a), 322, 116}, - {GRISU_UINT64_C(0xf209787b, b47d6b85), 348, 124}, - {GRISU_UINT64_C(0xb454e4a1, 79dd1877), 375, 132}, - {GRISU_UINT64_C(0x865b8692, 5b9bc5c2), 402, 140}, - {GRISU_UINT64_C(0xc83553c5, c8965d3d), 428, 148}, - {GRISU_UINT64_C(0x952ab45c, fa97a0b3), 455, 156}, - {GRISU_UINT64_C(0xde469fbd, 99a05fe3), 481, 164}, - {GRISU_UINT64_C(0xa59bc234, db398c25), 508, 172}, - {GRISU_UINT64_C(0xf6c69a72, a3989f5c), 534, 180}, - {GRISU_UINT64_C(0xb7dcbf53, 54e9bece), 561, 188}, - {GRISU_UINT64_C(0x88fcf317, f22241e2), 588, 196}, - {GRISU_UINT64_C(0xcc20ce9b, d35c78a5), 614, 204}, - {GRISU_UINT64_C(0x98165af3, 7b2153df), 641, 212}, - {GRISU_UINT64_C(0xe2a0b5dc, 971f303a), 667, 220}, - {GRISU_UINT64_C(0xa8d9d153, 5ce3b396), 694, 228}, - {GRISU_UINT64_C(0xfb9b7cd9, a4a7443c), 720, 236}, - {GRISU_UINT64_C(0xbb764c4c, a7a44410), 747, 244}, - {GRISU_UINT64_C(0x8bab8eef, b6409c1a), 774, 252}, - {GRISU_UINT64_C(0xd01fef10, a657842c), 800, 260}, - {GRISU_UINT64_C(0x9b10a4e5, e9913129), 827, 268}, - {GRISU_UINT64_C(0xe7109bfb, a19c0c9d), 853, 276}, - {GRISU_UINT64_C(0xac2820d9, 623bf429), 880, 284}, - {GRISU_UINT64_C(0x80444b5e, 7aa7cf85), 907, 292}, - {GRISU_UINT64_C(0xbf21e440, 03acdd2d), 933, 300}, - {GRISU_UINT64_C(0x8e679c2f, 5e44ff8f), 960, 308}, - {GRISU_UINT64_C(0xd433179d, 9c8cb841), 986, 316}, - {GRISU_UINT64_C(0x9e19db92, b4e31ba9), 1013, 324}, - {GRISU_UINT64_C(0xeb96bf6e, badf77d9), 1039, 332}, - {GRISU_UINT64_C(0xaf87023b, 9bf0ee6b), 1066, 340}, - }; -static const int GRISU_CACHE_MAX_DISTANCE(8) = 27; -// nb elements (8): 82 -static const GRISU_CACHE_STRUCT GRISU_CACHE_NAME(9)[] = { - {GRISU_UINT64_C(0xe61acf03, 3d1a45df), -1087, -308}, - {GRISU_UINT64_C(0xd64d3d9d, b981787d), -1057, -299}, - {GRISU_UINT64_C(0xc795830d, 75038c1e), -1027, -290}, - {GRISU_UINT64_C(0xb9e08a83, a5e34f08), -997, -281}, - {GRISU_UINT64_C(0xad1c8eab, 5ee43b67), -967, -272}, - {GRISU_UINT64_C(0xa139029f, 6a239f72), -937, -263}, - {GRISU_UINT64_C(0x96267c75, 35b763b5), -907, -254}, - {GRISU_UINT64_C(0x8bd6a141, 006042be), -877, -245}, - {GRISU_UINT64_C(0x823c1279, 5db6ce57), -847, -236}, - {GRISU_UINT64_C(0xf294b943, e17a2bc4), -818, -227}, - {GRISU_UINT64_C(0xe1ebce4d, c7f16dfc), -788, -218}, - {GRISU_UINT64_C(0xd267caa8, 62a12d67), -758, -209}, - {GRISU_UINT64_C(0xc3f490aa, 77bd60fd), -728, -200}, - {GRISU_UINT64_C(0xb67f6455, 292cbf08), -698, -191}, - {GRISU_UINT64_C(0xa9f6d30a, 038d1dbc), -668, -182}, - {GRISU_UINT64_C(0x9e4a9cec, 15763e2f), -638, -173}, - {GRISU_UINT64_C(0x936b9fce, bb25c996), -608, -164}, - {GRISU_UINT64_C(0x894bc396, ce5da772), -578, -155}, - {GRISU_UINT64_C(0xffbbcfe9, 94e5c620), -549, -146}, - {GRISU_UINT64_C(0xee2ba6c0, 678b597f), -519, -137}, - {GRISU_UINT64_C(0xddd0467c, 64bce4a1), -489, -128}, - {GRISU_UINT64_C(0xce947a3d, a6a9273e), -459, -119}, - {GRISU_UINT64_C(0xc06481fb, 9bcf8d3a), -429, -110}, - {GRISU_UINT64_C(0xb32df8e9, f3546564), -399, -101}, - {GRISU_UINT64_C(0xa6dfbd9f, b8e5b88f), -369, -92}, - {GRISU_UINT64_C(0x9b69dbe1, b548ce7d), -339, -83}, - {GRISU_UINT64_C(0x90bd77f3, 483bb9ba), -309, -74}, - {GRISU_UINT64_C(0x86ccbb52, ea94baeb), -279, -65}, - {GRISU_UINT64_C(0xfb158592, be068d2f), -250, -56}, - {GRISU_UINT64_C(0xe9d71b68, 9dde71b0), -220, -47}, - {GRISU_UINT64_C(0xd9c7dced, 53c72256), -190, -38}, - {GRISU_UINT64_C(0xcad2f7f5, 359a3b3e), -160, -29}, - {GRISU_UINT64_C(0xbce50864, 92111aeb), -130, -20}, - {GRISU_UINT64_C(0xafebff0b, cb24aaff), -100, -11}, - {GRISU_UINT64_C(0xa3d70a3d, 70a3d70a), -70, -2}, - {GRISU_UINT64_C(0x98968000, 00000000), -40, 7}, - {GRISU_UINT64_C(0x8e1bc9bf, 04000000), -10, 16}, - {GRISU_UINT64_C(0x84595161, 401484a0), 20, 25}, - {GRISU_UINT64_C(0xf684df56, c3e01bc7), 49, 34}, - {GRISU_UINT64_C(0xe596b7b0, c643c719), 79, 43}, - {GRISU_UINT64_C(0xd5d238a4, abe98068), 109, 52}, - {GRISU_UINT64_C(0xc722f0ef, 9d80aad6), 139, 61}, - {GRISU_UINT64_C(0xb975d6b6, ee39e437), 169, 70}, - {GRISU_UINT64_C(0xacb92ed9, 397bf996), 199, 79}, - {GRISU_UINT64_C(0xa0dc75f1, 778e39d6), 229, 88}, - {GRISU_UINT64_C(0x95d04aee, 3b80ece6), 259, 97}, - {GRISU_UINT64_C(0x8b865b21, 5899f46d), 289, 106}, - {GRISU_UINT64_C(0x81f14fae, 158c5f6e), 319, 115}, - {GRISU_UINT64_C(0xf209787b, b47d6b85), 348, 124}, - {GRISU_UINT64_C(0xe16a1dc9, d8545e95), 378, 133}, - {GRISU_UINT64_C(0xd1ef0244, af2364ff), 408, 142}, - {GRISU_UINT64_C(0xc38413cf, 25e2d70e), 438, 151}, - {GRISU_UINT64_C(0xb616a12b, 7fe617aa), 468, 160}, - {GRISU_UINT64_C(0xa99541bf, 57452b28), 498, 169}, - {GRISU_UINT64_C(0x9defbf01, b061adab), 528, 178}, - {GRISU_UINT64_C(0x9316ff75, dd87cbd8), 558, 187}, - {GRISU_UINT64_C(0x88fcf317, f22241e2), 588, 196}, - {GRISU_UINT64_C(0xff290242, c83396ce), 617, 205}, - {GRISU_UINT64_C(0xeda2ee1c, 7064130c), 647, 214}, - {GRISU_UINT64_C(0xdd50f199, 6b947519), 677, 223}, - {GRISU_UINT64_C(0xce1de406, 42e3f4b9), 707, 232}, - {GRISU_UINT64_C(0xbff610b0, cc6edd3f), 737, 241}, - {GRISU_UINT64_C(0xb2c71d5b, ca9023f8), 767, 250}, - {GRISU_UINT64_C(0xa67ff273, b8460357), 797, 259}, - {GRISU_UINT64_C(0x9b10a4e5, e9913129), 827, 268}, - {GRISU_UINT64_C(0x906a617d, 450187e2), 857, 277}, - {GRISU_UINT64_C(0x867f59a9, d4bed6c0), 887, 286}, - {GRISU_UINT64_C(0xfa856334, 878fc151), 916, 295}, - {GRISU_UINT64_C(0xe950df20, 247c83fd), 946, 304}, - {GRISU_UINT64_C(0xd94ad8b1, c7380874), 976, 313}, - {GRISU_UINT64_C(0xca5e89b1, 8b602368), 1006, 322}, - {GRISU_UINT64_C(0xbc789925, 624c5fe1), 1036, 331}, - {GRISU_UINT64_C(0xaf87023b, 9bf0ee6b), 1066, 340}, - }; -static const int GRISU_CACHE_MAX_DISTANCE(9) = 30; -// nb elements (9): 73 -static const GRISU_CACHE_STRUCT GRISU_CACHE_NAME(10)[] = { - {GRISU_UINT64_C(0xe61acf03, 3d1a45df), -1087, -308}, - {GRISU_UINT64_C(0x85f04682, 93f0eb4e), -1053, -298}, - {GRISU_UINT64_C(0x9becce62, 836ac577), -1020, -288}, - {GRISU_UINT64_C(0xb5854744, 8ffffb2e), -987, -278}, - {GRISU_UINT64_C(0xd3515c28, 31559a83), -954, -268}, - {GRISU_UINT64_C(0xf6019da0, 7f549b2b), -921, -258}, - {GRISU_UINT64_C(0x8f31cc09, 37ae58d3), -887, -248}, - {GRISU_UINT64_C(0xa6b34ad8, c9dfc070), -854, -238}, - {GRISU_UINT64_C(0xc2109436, 4dfb5637), -821, -228}, - {GRISU_UINT64_C(0xe1ebce4d, c7f16dfc), -788, -218}, - {GRISU_UINT64_C(0x8380dea9, 3da4bc60), -754, -208}, - {GRISU_UINT64_C(0x99171105, 2d8bf3c5), -721, -198}, - {GRISU_UINT64_C(0xb23867fb, 2a35b28e), -688, -188}, - {GRISU_UINT64_C(0xcf79cc9d, b955c2cc), -655, -178}, - {GRISU_UINT64_C(0xf18899b1, bc3f8ca2), -622, -168}, - {GRISU_UINT64_C(0x8c974f73, 83725573), -588, -158}, - {GRISU_UINT64_C(0xa3ab6658, 0d5fdaf6), -555, -148}, - {GRISU_UINT64_C(0xbe895233, 86091466), -522, -138}, - {GRISU_UINT64_C(0xddd0467c, 64bce4a1), -489, -128}, - {GRISU_UINT64_C(0x811ccc66, 8829b887), -455, -118}, - {GRISU_UINT64_C(0x964e858c, 91ba2655), -422, -108}, - {GRISU_UINT64_C(0xaefae514, 77a06b04), -389, -98}, - {GRISU_UINT64_C(0xcbb41ef9, 79346bca), -356, -88}, - {GRISU_UINT64_C(0xed246723, 473e3813), -323, -78}, - {GRISU_UINT64_C(0x8a08f0f8, bf0f156b), -289, -68}, - {GRISU_UINT64_C(0xa0b19d2a, b70e6ed6), -256, -58}, - {GRISU_UINT64_C(0xbb127c53, b17ec159), -223, -48}, - {GRISU_UINT64_C(0xd9c7dced, 53c72256), -190, -38}, - {GRISU_UINT64_C(0xfd87b5f2, 8300ca0e), -157, -28}, - {GRISU_UINT64_C(0x9392ee8e, 921d5d07), -123, -18}, - {GRISU_UINT64_C(0xabcc7711, 8461cefd), -90, -8}, - {GRISU_UINT64_C(0xc8000000, 00000000), -57, 2}, - {GRISU_UINT64_C(0xe8d4a510, 00000000), -24, 12}, - {GRISU_UINT64_C(0x87867832, 6eac9000), 10, 22}, - {GRISU_UINT64_C(0x9dc5ada8, 2b70b59e), 43, 32}, - {GRISU_UINT64_C(0xb7abc627, 050305ae), 76, 42}, - {GRISU_UINT64_C(0xd5d238a4, abe98068), 109, 52}, - {GRISU_UINT64_C(0xf8ebad2b, 84e0d58c), 142, 62}, - {GRISU_UINT64_C(0x90e40fbe, ea1d3a4b), 176, 72}, - {GRISU_UINT64_C(0xa8acd7c0, 222311bd), 209, 82}, - {GRISU_UINT64_C(0xc45d1df9, 42711d9a), 242, 92}, - {GRISU_UINT64_C(0xe498f455, c38b997a), 275, 102}, - {GRISU_UINT64_C(0x850fadc0, 9923329e), 309, 112}, - {GRISU_UINT64_C(0x9ae75759, 6946075f), 342, 122}, - {GRISU_UINT64_C(0xb454e4a1, 79dd1877), 375, 132}, - {GRISU_UINT64_C(0xd1ef0244, af2364ff), 408, 142}, - {GRISU_UINT64_C(0xf46518c2, ef5b8cd1), 441, 152}, - {GRISU_UINT64_C(0x8e41ade9, fbebc27d), 475, 162}, - {GRISU_UINT64_C(0xa59bc234, db398c25), 508, 172}, - {GRISU_UINT64_C(0xc0cb28a9, 8fcf3c80), 541, 182}, - {GRISU_UINT64_C(0xe070f78d, 3927556b), 574, 192}, - {GRISU_UINT64_C(0x82a45b45, 0226b39d), 608, 202}, - {GRISU_UINT64_C(0x98165af3, 7b2153df), 641, 212}, - {GRISU_UINT64_C(0xb10d8e14, 56105dad), 674, 222}, - {GRISU_UINT64_C(0xce1de406, 42e3f4b9), 707, 232}, - {GRISU_UINT64_C(0xeff394dc, ff8a948f), 740, 242}, - {GRISU_UINT64_C(0x8bab8eef, b6409c1a), 774, 252}, - {GRISU_UINT64_C(0xa298f2c5, 01f45f43), 807, 262}, - {GRISU_UINT64_C(0xbd49d14a, a79dbc82), 840, 272}, - {GRISU_UINT64_C(0xdc5c5301, c56b75f7), 873, 282}, - {GRISU_UINT64_C(0x80444b5e, 7aa7cf85), 907, 292}, - {GRISU_UINT64_C(0x95527a52, 02df0ccb), 940, 302}, - {GRISU_UINT64_C(0xadd57a27, d29339f6), 973, 312}, - {GRISU_UINT64_C(0xca5e89b1, 8b602368), 1006, 322}, - {GRISU_UINT64_C(0xeb96bf6e, badf77d9), 1039, 332}, - {GRISU_UINT64_C(0x892179be, 91d43a44), 1073, 342}, - }; -static const int GRISU_CACHE_MAX_DISTANCE(10) = 34; -// nb elements (10): 66 -static const GRISU_CACHE_STRUCT GRISU_CACHE_NAME(11)[] = { - {GRISU_UINT64_C(0xe61acf03, 3d1a45df), -1087, -308}, - {GRISU_UINT64_C(0xa76c5823, 38ed2622), -1050, -297}, - {GRISU_UINT64_C(0xf3a20279, ed56d48a), -1014, -286}, - {GRISU_UINT64_C(0xb1442798, f49ffb4b), -977, -275}, - {GRISU_UINT64_C(0x80fa687f, 881c7f8e), -940, -264}, - {GRISU_UINT64_C(0xbbb01b92, 83253ca3), -904, -253}, - {GRISU_UINT64_C(0x888f9979, 7a5e012d), -867, -242}, - {GRISU_UINT64_C(0xc6b8e9b0, 709f109a), -831, -231}, - {GRISU_UINT64_C(0x9096ea6f, 3848984f), -794, -220}, - {GRISU_UINT64_C(0xd267caa8, 62a12d67), -758, -209}, - {GRISU_UINT64_C(0x99171105, 2d8bf3c5), -721, -198}, - {GRISU_UINT64_C(0xdec681f9, f4c31f31), -685, -187}, - {GRISU_UINT64_C(0xa21727db, 38cb0030), -648, -176}, - {GRISU_UINT64_C(0xebdf6617, 91d60f56), -612, -165}, - {GRISU_UINT64_C(0xab9eb47c, 81f5114f), -575, -154}, - {GRISU_UINT64_C(0xf9bd690a, 1b68637b), -539, -143}, - {GRISU_UINT64_C(0xb5b5ada8, aaff80b8), -502, -132}, - {GRISU_UINT64_C(0x843610cb, 4bf160cc), -465, -121}, - {GRISU_UINT64_C(0xc06481fb, 9bcf8d3a), -429, -110}, - {GRISU_UINT64_C(0x8bfbea76, c619ef36), -392, -99}, - {GRISU_UINT64_C(0xcbb41ef9, 79346bca), -356, -88}, - {GRISU_UINT64_C(0x9436c076, 0c86e30c), -319, -77}, - {GRISU_UINT64_C(0xd7adf884, aa879177), -283, -66}, - {GRISU_UINT64_C(0x9ced737b, b6c4183d), -246, -55}, - {GRISU_UINT64_C(0xe45c10c4, 2a2b3b06), -210, -44}, - {GRISU_UINT64_C(0xa6274bbd, d0fadd62), -173, -33}, - {GRISU_UINT64_C(0xf1c90080, baf72cb1), -137, -22}, - {GRISU_UINT64_C(0xafebff0b, cb24aaff), -100, -11}, - {GRISU_UINT64_C(0x80000000, 00000000), -63, 0}, - {GRISU_UINT64_C(0xba43b740, 00000000), -27, 11}, - {GRISU_UINT64_C(0x87867832, 6eac9000), 10, 22}, - {GRISU_UINT64_C(0xc5371912, 364ce305), 46, 33}, - {GRISU_UINT64_C(0x8f7e32ce, 7bea5c70), 83, 44}, - {GRISU_UINT64_C(0xd0cf4b50, cfe20766), 119, 55}, - {GRISU_UINT64_C(0x97edd871, cfda3a57), 156, 66}, - {GRISU_UINT64_C(0xdd15fe86, affad912), 192, 77}, - {GRISU_UINT64_C(0xa0dc75f1, 778e39d6), 229, 88}, - {GRISU_UINT64_C(0xea157514, 3cf97227), 265, 99}, - {GRISU_UINT64_C(0xaa51823e, 34a7eedf), 302, 110}, - {GRISU_UINT64_C(0xf7d88bc2, 4209a565), 338, 121}, - {GRISU_UINT64_C(0xb454e4a1, 79dd1877), 375, 132}, - {GRISU_UINT64_C(0x8335616a, ed761f1f), 412, 143}, - {GRISU_UINT64_C(0xbeeefb58, 4aff8604), 448, 154}, - {GRISU_UINT64_C(0x8aec23d6, 80043bee), 485, 165}, - {GRISU_UINT64_C(0xca28a291, 859bbf93), 521, 176}, - {GRISU_UINT64_C(0x9316ff75, dd87cbd8), 558, 187}, - {GRISU_UINT64_C(0xd60b3bd5, 6a5586f2), 594, 198}, - {GRISU_UINT64_C(0x9bbcc7a1, 42b17ccc), 631, 209}, - {GRISU_UINT64_C(0xe2a0b5dc, 971f303a), 667, 220}, - {GRISU_UINT64_C(0xa4e4b66b, 68b65d61), 704, 231}, - {GRISU_UINT64_C(0xeff394dc, ff8a948f), 740, 242}, - {GRISU_UINT64_C(0xae9672ab, a3d0c321), 777, 253}, - {GRISU_UINT64_C(0xfe0efb53, d30dd4d8), 813, 264}, - {GRISU_UINT64_C(0xb8da1662, e7b00a17), 850, 275}, - {GRISU_UINT64_C(0x867f59a9, d4bed6c0), 887, 286}, - {GRISU_UINT64_C(0xc3b83581, 09e84f07), 923, 297}, - {GRISU_UINT64_C(0x8e679c2f, 5e44ff8f), 960, 308}, - {GRISU_UINT64_C(0xcf39e50f, eae16bf0), 996, 319}, - {GRISU_UINT64_C(0x96c6e0ea, b509e64d), 1033, 330}, - {GRISU_UINT64_C(0xdb68c2ca, 82ed2a06), 1069, 341}, - }; -static const int GRISU_CACHE_MAX_DISTANCE(11) = 37; -// nb elements (11): 60 -static const GRISU_CACHE_STRUCT GRISU_CACHE_NAME(12)[] = { - {GRISU_UINT64_C(0xe61acf03, 3d1a45df), -1087, -308}, - {GRISU_UINT64_C(0xd1476e2c, 07286faa), -1047, -296}, - {GRISU_UINT64_C(0xbe5691ef, 416bd60c), -1007, -284}, - {GRISU_UINT64_C(0xad1c8eab, 5ee43b67), -967, -272}, - {GRISU_UINT64_C(0x9d71ac8f, ada6c9b5), -927, -260}, - {GRISU_UINT64_C(0x8f31cc09, 37ae58d3), -887, -248}, - {GRISU_UINT64_C(0x823c1279, 5db6ce57), -847, -236}, - {GRISU_UINT64_C(0xece53cec, 4a314ebe), -808, -224}, - {GRISU_UINT64_C(0xd77485cb, 25823ac7), -768, -212}, - {GRISU_UINT64_C(0xc3f490aa, 77bd60fd), -728, -200}, - {GRISU_UINT64_C(0xb23867fb, 2a35b28e), -688, -188}, - {GRISU_UINT64_C(0xa21727db, 38cb0030), -648, -176}, - {GRISU_UINT64_C(0x936b9fce, bb25c996), -608, -164}, - {GRISU_UINT64_C(0x8613fd01, 45877586), -568, -152}, - {GRISU_UINT64_C(0xf3e2f893, dec3f126), -529, -140}, - {GRISU_UINT64_C(0xddd0467c, 64bce4a1), -489, -128}, - {GRISU_UINT64_C(0xc9bcff60, 34c13053), -449, -116}, - {GRISU_UINT64_C(0xb77ada06, 17e3bbcb), -409, -104}, - {GRISU_UINT64_C(0xa6dfbd9f, b8e5b88f), -369, -92}, - {GRISU_UINT64_C(0x97c560ba, 6b0919a6), -329, -80}, - {GRISU_UINT64_C(0x8a08f0f8, bf0f156b), -289, -68}, - {GRISU_UINT64_C(0xfb158592, be068d2f), -250, -56}, - {GRISU_UINT64_C(0xe45c10c4, 2a2b3b06), -210, -44}, - {GRISU_UINT64_C(0xcfb11ead, 453994ba), -170, -32}, - {GRISU_UINT64_C(0xbce50864, 92111aeb), -130, -20}, - {GRISU_UINT64_C(0xabcc7711, 8461cefd), -90, -8}, - {GRISU_UINT64_C(0x9c400000, 00000000), -50, 4}, - {GRISU_UINT64_C(0x8e1bc9bf, 04000000), -10, 16}, - {GRISU_UINT64_C(0x813f3978, f8940984), 30, 28}, - {GRISU_UINT64_C(0xeb194f8e, 1ae525fd), 69, 40}, - {GRISU_UINT64_C(0xd5d238a4, abe98068), 109, 52}, - {GRISU_UINT64_C(0xc2781f49, ffcfa6d5), 149, 64}, - {GRISU_UINT64_C(0xb0de6538, 8cc8ada8), 189, 76}, - {GRISU_UINT64_C(0xa0dc75f1, 778e39d6), 229, 88}, - {GRISU_UINT64_C(0x924d692c, a61be758), 269, 100}, - {GRISU_UINT64_C(0x850fadc0, 9923329e), 309, 112}, - {GRISU_UINT64_C(0xf209787b, b47d6b85), 348, 124}, - {GRISU_UINT64_C(0xdc21a117, 1d42645d), 388, 136}, - {GRISU_UINT64_C(0xc83553c5, c8965d3d), 428, 148}, - {GRISU_UINT64_C(0xb616a12b, 7fe617aa), 468, 160}, - {GRISU_UINT64_C(0xa59bc234, db398c25), 508, 172}, - {GRISU_UINT64_C(0x969eb7c4, 7859e744), 548, 184}, - {GRISU_UINT64_C(0x88fcf317, f22241e2), 588, 196}, - {GRISU_UINT64_C(0xf92e0c35, 37826146), 627, 208}, - {GRISU_UINT64_C(0xe2a0b5dc, 971f303a), 667, 220}, - {GRISU_UINT64_C(0xce1de406, 42e3f4b9), 707, 232}, - {GRISU_UINT64_C(0xbb764c4c, a7a44410), 747, 244}, - {GRISU_UINT64_C(0xaa7eebfb, 9df9de8e), 787, 256}, - {GRISU_UINT64_C(0x9b10a4e5, e9913129), 827, 268}, - {GRISU_UINT64_C(0x8d07e334, 55637eb3), 867, 280}, - {GRISU_UINT64_C(0x80444b5e, 7aa7cf85), 907, 292}, - {GRISU_UINT64_C(0xe950df20, 247c83fd), 946, 304}, - {GRISU_UINT64_C(0xd433179d, 9c8cb841), 986, 316}, - {GRISU_UINT64_C(0xc0fe9088, 95cf3b44), 1026, 328}, - {GRISU_UINT64_C(0xaf87023b, 9bf0ee6b), 1066, 340}, - }; -static const int GRISU_CACHE_MAX_DISTANCE(12) = 40; -// nb elements (12): 55 -static const GRISU_CACHE_STRUCT GRISU_CACHE_NAME(13)[] = { - {GRISU_UINT64_C(0xe61acf03, 3d1a45df), -1087, -308}, - {GRISU_UINT64_C(0x82cca4db, 847945ca), -1043, -295}, - {GRISU_UINT64_C(0x94b3a202, eb1c3f39), -1000, -282}, - {GRISU_UINT64_C(0xa90de353, 5aaae202), -957, -269}, - {GRISU_UINT64_C(0xc0314325, 637a193a), -914, -256}, - {GRISU_UINT64_C(0xda7f5bf5, 90966849), -871, -243}, - {GRISU_UINT64_C(0xf867241c, 8cc6d4c1), -828, -230}, - {GRISU_UINT64_C(0x8d3360f0, 9cf6e4bd), -784, -217}, - {GRISU_UINT64_C(0xa086cfcd, 97bf97f4), -741, -204}, - {GRISU_UINT64_C(0xb67f6455, 292cbf08), -698, -191}, - {GRISU_UINT64_C(0xcf79cc9d, b955c2cc), -655, -178}, - {GRISU_UINT64_C(0xebdf6617, 91d60f56), -612, -165}, - {GRISU_UINT64_C(0x8613fd01, 45877586), -568, -152}, - {GRISU_UINT64_C(0x986ddb5c, 6b3a76b8), -525, -139}, - {GRISU_UINT64_C(0xad4ab711, 2eb3929e), -482, -126}, - {GRISU_UINT64_C(0xc5029163, f384a931), -439, -113}, - {GRISU_UINT64_C(0xdff97724, 70297ebd), -396, -100}, - {GRISU_UINT64_C(0xfea126b7, d78186bd), -353, -87}, - {GRISU_UINT64_C(0x90bd77f3, 483bb9ba), -309, -74}, - {GRISU_UINT64_C(0xa48ceaaa, b75a8e2b), -266, -61}, - {GRISU_UINT64_C(0xbb127c53, b17ec159), -223, -48}, - {GRISU_UINT64_C(0xd4ad2dbf, c3d07788), -180, -35}, - {GRISU_UINT64_C(0xf1c90080, baf72cb1), -137, -22}, - {GRISU_UINT64_C(0x89705f41, 36b4a597), -93, -9}, - {GRISU_UINT64_C(0x9c400000, 00000000), -50, 4}, - {GRISU_UINT64_C(0xb1a2bc2e, c5000000), -7, 17}, - {GRISU_UINT64_C(0xc9f2c9cd, 04674edf), 36, 30}, - {GRISU_UINT64_C(0xe596b7b0, c643c719), 79, 43}, - {GRISU_UINT64_C(0x82818f12, 81ed44a0), 123, 56}, - {GRISU_UINT64_C(0x945e455f, 24fb1cf9), 166, 69}, - {GRISU_UINT64_C(0xa8acd7c0, 222311bd), 209, 82}, - {GRISU_UINT64_C(0xbfc2ef45, 6ae276e9), 252, 95}, - {GRISU_UINT64_C(0xda01ee64, 1a708dea), 295, 108}, - {GRISU_UINT64_C(0xf7d88bc2, 4209a565), 338, 121}, - {GRISU_UINT64_C(0x8ce2529e, 2734bb1d), 382, 134}, - {GRISU_UINT64_C(0xa02aa96b, 06deb0fe), 425, 147}, - {GRISU_UINT64_C(0xb616a12b, 7fe617aa), 468, 160}, - {GRISU_UINT64_C(0xcf02b2c2, 1207ef2f), 511, 173}, - {GRISU_UINT64_C(0xeb57ff22, fc0c795a), 554, 186}, - {GRISU_UINT64_C(0x85c70565, 62757457), 598, 199}, - {GRISU_UINT64_C(0x98165af3, 7b2153df), 641, 212}, - {GRISU_UINT64_C(0xace73cbf, dc0bfb7b), 684, 225}, - {GRISU_UINT64_C(0xc491798a, 08a2ad4f), 727, 238}, - {GRISU_UINT64_C(0xdf78e4b2, bd342cf7), 770, 251}, - {GRISU_UINT64_C(0xfe0efb53, d30dd4d8), 813, 264}, - {GRISU_UINT64_C(0x906a617d, 450187e2), 857, 277}, - {GRISU_UINT64_C(0xa42e74f3, d032f526), 900, 290}, - {GRISU_UINT64_C(0xbaa718e6, 8396cffe), 943, 303}, - {GRISU_UINT64_C(0xd433179d, 9c8cb841), 986, 316}, - {GRISU_UINT64_C(0xf13e34aa, bb430a15), 1029, 329}, - {GRISU_UINT64_C(0x892179be, 91d43a44), 1073, 342}, - }; -static const int GRISU_CACHE_MAX_DISTANCE(13) = 44; -// nb elements (13): 51 -static const GRISU_CACHE_STRUCT GRISU_CACHE_NAME(14)[] = { - {GRISU_UINT64_C(0xe61acf03, 3d1a45df), -1087, -308}, - {GRISU_UINT64_C(0xa37fce12, 6597973d), -1040, -294}, - {GRISU_UINT64_C(0xe858ad24, 8f5c22ca), -994, -280}, - {GRISU_UINT64_C(0xa5178fff, 668ae0b6), -947, -266}, - {GRISU_UINT64_C(0xea9c2277, 23ee8bcb), -901, -252}, - {GRISU_UINT64_C(0xa6b34ad8, c9dfc070), -854, -238}, - {GRISU_UINT64_C(0xece53cec, 4a314ebe), -808, -224}, - {GRISU_UINT64_C(0xa8530886, b54dbdec), -761, -210}, - {GRISU_UINT64_C(0xef340a98, 172aace5), -715, -196}, - {GRISU_UINT64_C(0xa9f6d30a, 038d1dbc), -668, -182}, - {GRISU_UINT64_C(0xf18899b1, bc3f8ca2), -622, -168}, - {GRISU_UINT64_C(0xab9eb47c, 81f5114f), -575, -154}, - {GRISU_UINT64_C(0xf3e2f893, dec3f126), -529, -140}, - {GRISU_UINT64_C(0xad4ab711, 2eb3929e), -482, -126}, - {GRISU_UINT64_C(0xf64335bc, f065d37d), -436, -112}, - {GRISU_UINT64_C(0xaefae514, 77a06b04), -389, -98}, - {GRISU_UINT64_C(0xf8a95fcf, 88747d94), -343, -84}, - {GRISU_UINT64_C(0xb0af48ec, 79ace837), -296, -70}, - {GRISU_UINT64_C(0xfb158592, be068d2f), -250, -56}, - {GRISU_UINT64_C(0xb267ed19, 40f1c61c), -203, -42}, - {GRISU_UINT64_C(0xfd87b5f2, 8300ca0e), -157, -28}, - {GRISU_UINT64_C(0xb424dc35, 095cd80f), -110, -14}, - {GRISU_UINT64_C(0x80000000, 00000000), -63, 0}, - {GRISU_UINT64_C(0xb5e620f4, 80000000), -17, 14}, - {GRISU_UINT64_C(0x813f3978, f8940984), 30, 28}, - {GRISU_UINT64_C(0xb7abc627, 050305ae), 76, 42}, - {GRISU_UINT64_C(0x82818f12, 81ed44a0), 123, 56}, - {GRISU_UINT64_C(0xb975d6b6, ee39e437), 169, 70}, - {GRISU_UINT64_C(0x83c7088e, 1aab65db), 216, 84}, - {GRISU_UINT64_C(0xbb445da9, ca61281f), 262, 98}, - {GRISU_UINT64_C(0x850fadc0, 9923329e), 309, 112}, - {GRISU_UINT64_C(0xbd176620, a501fc00), 355, 126}, - {GRISU_UINT64_C(0x865b8692, 5b9bc5c2), 402, 140}, - {GRISU_UINT64_C(0xbeeefb58, 4aff8604), 448, 154}, - {GRISU_UINT64_C(0x87aa9aff, 79042287), 495, 168}, - {GRISU_UINT64_C(0xc0cb28a9, 8fcf3c80), 541, 182}, - {GRISU_UINT64_C(0x88fcf317, f22241e2), 588, 196}, - {GRISU_UINT64_C(0xc2abf989, 935ddbfe), 634, 210}, - {GRISU_UINT64_C(0x8a5296ff, e33cc930), 681, 224}, - {GRISU_UINT64_C(0xc491798a, 08a2ad4f), 727, 238}, - {GRISU_UINT64_C(0x8bab8eef, b6409c1a), 774, 252}, - {GRISU_UINT64_C(0xc67bb459, 7ce2ce49), 820, 266}, - {GRISU_UINT64_C(0x8d07e334, 55637eb3), 867, 280}, - {GRISU_UINT64_C(0xc86ab5c3, 9fa63441), 913, 294}, - {GRISU_UINT64_C(0x8e679c2f, 5e44ff8f), 960, 308}, - {GRISU_UINT64_C(0xca5e89b1, 8b602368), 1006, 322}, - {GRISU_UINT64_C(0x8fcac257, 558ee4e6), 1053, 336}, - }; -static const int GRISU_CACHE_MAX_DISTANCE(14) = 47; -// nb elements (14): 47 -static const GRISU_CACHE_STRUCT GRISU_CACHE_NAME(15)[] = { - {GRISU_UINT64_C(0xe61acf03, 3d1a45df), -1087, -308}, - {GRISU_UINT64_C(0xcc5fc196, fefd7d0c), -1037, -293}, - {GRISU_UINT64_C(0xb5854744, 8ffffb2e), -987, -278}, - {GRISU_UINT64_C(0xa139029f, 6a239f72), -937, -263}, - {GRISU_UINT64_C(0x8f31cc09, 37ae58d3), -887, -248}, - {GRISU_UINT64_C(0xfe5d5415, 0b090b03), -838, -233}, - {GRISU_UINT64_C(0xe1ebce4d, c7f16dfc), -788, -218}, - {GRISU_UINT64_C(0xc8a883c0, fdaf7df0), -738, -203}, - {GRISU_UINT64_C(0xb23867fb, 2a35b28e), -688, -188}, - {GRISU_UINT64_C(0x9e4a9cec, 15763e2f), -638, -173}, - {GRISU_UINT64_C(0x8c974f73, 83725573), -588, -158}, - {GRISU_UINT64_C(0xf9bd690a, 1b68637b), -539, -143}, - {GRISU_UINT64_C(0xddd0467c, 64bce4a1), -489, -128}, - {GRISU_UINT64_C(0xc5029163, f384a931), -439, -113}, - {GRISU_UINT64_C(0xaefae514, 77a06b04), -389, -98}, - {GRISU_UINT64_C(0x9b69dbe1, b548ce7d), -339, -83}, - {GRISU_UINT64_C(0x8a08f0f8, bf0f156b), -289, -68}, - {GRISU_UINT64_C(0xf5330471, 4d9265e0), -240, -53}, - {GRISU_UINT64_C(0xd9c7dced, 53c72256), -190, -38}, - {GRISU_UINT64_C(0xc16d9a00, 95928a27), -140, -23}, - {GRISU_UINT64_C(0xabcc7711, 8461cefd), -90, -8}, - {GRISU_UINT64_C(0x98968000, 00000000), -40, 7}, - {GRISU_UINT64_C(0x87867832, 6eac9000), 10, 22}, - {GRISU_UINT64_C(0xf0bdc21a, bb48db20), 59, 37}, - {GRISU_UINT64_C(0xd5d238a4, abe98068), 109, 52}, - {GRISU_UINT64_C(0xbde94e8e, 43d0c8ec), 159, 67}, - {GRISU_UINT64_C(0xa8acd7c0, 222311bd), 209, 82}, - {GRISU_UINT64_C(0x95d04aee, 3b80ece6), 259, 97}, - {GRISU_UINT64_C(0x850fadc0, 9923329e), 309, 112}, - {GRISU_UINT64_C(0xec5d3fa8, ce427b00), 358, 127}, - {GRISU_UINT64_C(0xd1ef0244, af2364ff), 408, 142}, - {GRISU_UINT64_C(0xba756174, 393d88e0), 458, 157}, - {GRISU_UINT64_C(0xa59bc234, db398c25), 508, 172}, - {GRISU_UINT64_C(0x9316ff75, dd87cbd8), 558, 187}, - {GRISU_UINT64_C(0x82a45b45, 0226b39d), 608, 202}, - {GRISU_UINT64_C(0xe8111c87, c5c1ba9a), 657, 217}, - {GRISU_UINT64_C(0xce1de406, 42e3f4b9), 707, 232}, - {GRISU_UINT64_C(0xb7118682, dbb66a77), 757, 247}, - {GRISU_UINT64_C(0xa298f2c5, 01f45f43), 807, 262}, - {GRISU_UINT64_C(0x906a617d, 450187e2), 857, 277}, - {GRISU_UINT64_C(0x80444b5e, 7aa7cf85), 907, 292}, - {GRISU_UINT64_C(0xe3d8f9e5, 63a198e5), 956, 307}, - {GRISU_UINT64_C(0xca5e89b1, 8b602368), 1006, 322}, - {GRISU_UINT64_C(0xb3bd72ed, 2af29e20), 1056, 337}, - }; -static const int GRISU_CACHE_MAX_DISTANCE(15) = 50; -// nb elements (15): 44 -static const GRISU_CACHE_STRUCT GRISU_CACHE_NAME(16)[] = { - {GRISU_UINT64_C(0xe61acf03, 3d1a45df), -1087, -308}, - {GRISU_UINT64_C(0xff77b1fc, bebcdc4f), -1034, -292}, - {GRISU_UINT64_C(0x8dd01fad, 907ffc3c), -980, -276}, - {GRISU_UINT64_C(0x9d71ac8f, ada6c9b5), -927, -260}, - {GRISU_UINT64_C(0xaecc4991, 4078536d), -874, -244}, - {GRISU_UINT64_C(0xc2109436, 4dfb5637), -821, -228}, - {GRISU_UINT64_C(0xd77485cb, 25823ac7), -768, -212}, - {GRISU_UINT64_C(0xef340a98, 172aace5), -715, -196}, - {GRISU_UINT64_C(0x84c8d4df, d2c63f3b), -661, -180}, - {GRISU_UINT64_C(0x936b9fce, bb25c996), -608, -164}, - {GRISU_UINT64_C(0xa3ab6658, 0d5fdaf6), -555, -148}, - {GRISU_UINT64_C(0xb5b5ada8, aaff80b8), -502, -132}, - {GRISU_UINT64_C(0xc9bcff60, 34c13053), -449, -116}, - {GRISU_UINT64_C(0xdff97724, 70297ebd), -396, -100}, - {GRISU_UINT64_C(0xf8a95fcf, 88747d94), -343, -84}, - {GRISU_UINT64_C(0x8a08f0f8, bf0f156b), -289, -68}, - {GRISU_UINT64_C(0x993fe2c6, d07b7fac), -236, -52}, - {GRISU_UINT64_C(0xaa242499, 697392d3), -183, -36}, - {GRISU_UINT64_C(0xbce50864, 92111aeb), -130, -20}, - {GRISU_UINT64_C(0xd1b71758, e219652c), -77, -4}, - {GRISU_UINT64_C(0xe8d4a510, 00000000), -24, 12}, - {GRISU_UINT64_C(0x813f3978, f8940984), 30, 28}, - {GRISU_UINT64_C(0x8f7e32ce, 7bea5c70), 83, 44}, - {GRISU_UINT64_C(0x9f4f2726, 179a2245), 136, 60}, - {GRISU_UINT64_C(0xb0de6538, 8cc8ada8), 189, 76}, - {GRISU_UINT64_C(0xc45d1df9, 42711d9a), 242, 92}, - {GRISU_UINT64_C(0xda01ee64, 1a708dea), 295, 108}, - {GRISU_UINT64_C(0xf209787b, b47d6b85), 348, 124}, - {GRISU_UINT64_C(0x865b8692, 5b9bc5c2), 402, 140}, - {GRISU_UINT64_C(0x952ab45c, fa97a0b3), 455, 156}, - {GRISU_UINT64_C(0xa59bc234, db398c25), 508, 172}, - {GRISU_UINT64_C(0xb7dcbf53, 54e9bece), 561, 188}, - {GRISU_UINT64_C(0xcc20ce9b, d35c78a5), 614, 204}, - {GRISU_UINT64_C(0xe2a0b5dc, 971f303a), 667, 220}, - {GRISU_UINT64_C(0xfb9b7cd9, a4a7443c), 720, 236}, - {GRISU_UINT64_C(0x8bab8eef, b6409c1a), 774, 252}, - {GRISU_UINT64_C(0x9b10a4e5, e9913129), 827, 268}, - {GRISU_UINT64_C(0xac2820d9, 623bf429), 880, 284}, - {GRISU_UINT64_C(0xbf21e440, 03acdd2d), 933, 300}, - {GRISU_UINT64_C(0xd433179d, 9c8cb841), 986, 316}, - {GRISU_UINT64_C(0xeb96bf6e, badf77d9), 1039, 332}, - }; -static const int GRISU_CACHE_MAX_DISTANCE(16) = 54; -// nb elements (16): 41 -static const GRISU_CACHE_STRUCT GRISU_CACHE_NAME(17)[] = { - {GRISU_UINT64_C(0xe61acf03, 3d1a45df), -1087, -308}, - {GRISU_UINT64_C(0x9faacf3d, f73609b1), -1030, -291}, - {GRISU_UINT64_C(0xdd95317f, 31c7fa1d), -974, -274}, - {GRISU_UINT64_C(0x99c10284, 4f94e0fb), -917, -257}, - {GRISU_UINT64_C(0xd5605fcd, cf32e1d7), -861, -240}, - {GRISU_UINT64_C(0x940f4613, ae5ed137), -804, -223}, - {GRISU_UINT64_C(0xcd795be8, 70516656), -748, -206}, - {GRISU_UINT64_C(0x8e938662, 882af53e), -691, -189}, - {GRISU_UINT64_C(0xc5dd4427, 1ad3cdba), -635, -172}, - {GRISU_UINT64_C(0x894bc396, ce5da772), -578, -155}, - {GRISU_UINT64_C(0xbe895233, 86091466), -522, -138}, - {GRISU_UINT64_C(0x843610cb, 4bf160cc), -465, -121}, - {GRISU_UINT64_C(0xb77ada06, 17e3bbcb), -409, -104}, - {GRISU_UINT64_C(0xfea126b7, d78186bd), -353, -87}, - {GRISU_UINT64_C(0xb0af48ec, 79ace837), -296, -70}, - {GRISU_UINT64_C(0xf5330471, 4d9265e0), -240, -53}, - {GRISU_UINT64_C(0xaa242499, 697392d3), -183, -36}, - {GRISU_UINT64_C(0xec1e4a7d, b69561a5), -127, -19}, - {GRISU_UINT64_C(0xa3d70a3d, 70a3d70a), -70, -2}, - {GRISU_UINT64_C(0xe35fa931, a0000000), -14, 15}, - {GRISU_UINT64_C(0x9dc5ada8, 2b70b59e), 43, 32}, - {GRISU_UINT64_C(0xdaf3f046, 51d47b4c), 99, 49}, - {GRISU_UINT64_C(0x97edd871, cfda3a57), 156, 66}, - {GRISU_UINT64_C(0xd2d80db0, 2aabd62c), 212, 83}, - {GRISU_UINT64_C(0x924d692c, a61be758), 269, 100}, - {GRISU_UINT64_C(0xcb090c80, 01ab551c), 325, 117}, - {GRISU_UINT64_C(0x8ce2529e, 2734bb1d), 382, 134}, - {GRISU_UINT64_C(0xc38413cf, 25e2d70e), 438, 151}, - {GRISU_UINT64_C(0x87aa9aff, 79042287), 495, 168}, - {GRISU_UINT64_C(0xbc4665b5, 96706115), 551, 185}, - {GRISU_UINT64_C(0x82a45b45, 0226b39d), 608, 202}, - {GRISU_UINT64_C(0xb54d5e4a, 127f59c8), 664, 219}, - {GRISU_UINT64_C(0xfb9b7cd9, a4a7443c), 720, 236}, - {GRISU_UINT64_C(0xae9672ab, a3d0c321), 777, 253}, - {GRISU_UINT64_C(0xf24a01a7, 3cf2dcd0), 833, 270}, - {GRISU_UINT64_C(0xa81f3014, 49ee8c70), 890, 287}, - {GRISU_UINT64_C(0xe950df20, 247c83fd), 946, 304}, - {GRISU_UINT64_C(0xa1e53af4, 6f801c53), 1003, 321}, - {GRISU_UINT64_C(0xe0accfa8, 75af45a8), 1059, 338}, - }; -static const int GRISU_CACHE_MAX_DISTANCE(17) = 57; -// nb elements (17): 39 -static const GRISU_CACHE_STRUCT GRISU_CACHE_NAME(18)[] = { - {GRISU_UINT64_C(0xe61acf03, 3d1a45df), -1087, -308}, - {GRISU_UINT64_C(0xc795830d, 75038c1e), -1027, -290}, - {GRISU_UINT64_C(0xad1c8eab, 5ee43b67), -967, -272}, - {GRISU_UINT64_C(0x96267c75, 35b763b5), -907, -254}, - {GRISU_UINT64_C(0x823c1279, 5db6ce57), -847, -236}, - {GRISU_UINT64_C(0xe1ebce4d, c7f16dfc), -788, -218}, - {GRISU_UINT64_C(0xc3f490aa, 77bd60fd), -728, -200}, - {GRISU_UINT64_C(0xa9f6d30a, 038d1dbc), -668, -182}, - {GRISU_UINT64_C(0x936b9fce, bb25c996), -608, -164}, - {GRISU_UINT64_C(0xffbbcfe9, 94e5c620), -549, -146}, - {GRISU_UINT64_C(0xddd0467c, 64bce4a1), -489, -128}, - {GRISU_UINT64_C(0xc06481fb, 9bcf8d3a), -429, -110}, - {GRISU_UINT64_C(0xa6dfbd9f, b8e5b88f), -369, -92}, - {GRISU_UINT64_C(0x90bd77f3, 483bb9ba), -309, -74}, - {GRISU_UINT64_C(0xfb158592, be068d2f), -250, -56}, - {GRISU_UINT64_C(0xd9c7dced, 53c72256), -190, -38}, - {GRISU_UINT64_C(0xbce50864, 92111aeb), -130, -20}, - {GRISU_UINT64_C(0xa3d70a3d, 70a3d70a), -70, -2}, - {GRISU_UINT64_C(0x8e1bc9bf, 04000000), -10, 16}, - {GRISU_UINT64_C(0xf684df56, c3e01bc7), 49, 34}, - {GRISU_UINT64_C(0xd5d238a4, abe98068), 109, 52}, - {GRISU_UINT64_C(0xb975d6b6, ee39e437), 169, 70}, - {GRISU_UINT64_C(0xa0dc75f1, 778e39d6), 229, 88}, - {GRISU_UINT64_C(0x8b865b21, 5899f46d), 289, 106}, - {GRISU_UINT64_C(0xf209787b, b47d6b85), 348, 124}, - {GRISU_UINT64_C(0xd1ef0244, af2364ff), 408, 142}, - {GRISU_UINT64_C(0xb616a12b, 7fe617aa), 468, 160}, - {GRISU_UINT64_C(0x9defbf01, b061adab), 528, 178}, - {GRISU_UINT64_C(0x88fcf317, f22241e2), 588, 196}, - {GRISU_UINT64_C(0xeda2ee1c, 7064130c), 647, 214}, - {GRISU_UINT64_C(0xce1de406, 42e3f4b9), 707, 232}, - {GRISU_UINT64_C(0xb2c71d5b, ca9023f8), 767, 250}, - {GRISU_UINT64_C(0x9b10a4e5, e9913129), 827, 268}, - {GRISU_UINT64_C(0x867f59a9, d4bed6c0), 887, 286}, - {GRISU_UINT64_C(0xe950df20, 247c83fd), 946, 304}, - {GRISU_UINT64_C(0xca5e89b1, 8b602368), 1006, 322}, - {GRISU_UINT64_C(0xaf87023b, 9bf0ee6b), 1066, 340}, - }; -static const int GRISU_CACHE_MAX_DISTANCE(18) = 60; -// nb elements (18): 37 -static const GRISU_CACHE_STRUCT GRISU_CACHE_NAME(19)[] = { - {GRISU_UINT64_C(0xe61acf03, 3d1a45df), -1087, -308}, - {GRISU_UINT64_C(0xf97ae3d0, d2446f25), -1024, -289}, - {GRISU_UINT64_C(0x873e4f75, e2224e68), -960, -270}, - {GRISU_UINT64_C(0x92a1958a, 7675175f), -897, -251}, - {GRISU_UINT64_C(0x9efa548d, 26e5a6e2), -834, -232}, - {GRISU_UINT64_C(0xac5d37d5, b79b6239), -771, -213}, - {GRISU_UINT64_C(0xbae0a846, d2195713), -708, -194}, - {GRISU_UINT64_C(0xca9cf1d2, 06fdc03c), -645, -175}, - {GRISU_UINT64_C(0xdbac6c24, 7d62a584), -582, -156}, - {GRISU_UINT64_C(0xee2ba6c0, 678b597f), -519, -137}, - {GRISU_UINT64_C(0x811ccc66, 8829b887), -455, -118}, - {GRISU_UINT64_C(0x8bfbea76, c619ef36), -392, -99}, - {GRISU_UINT64_C(0x97c560ba, 6b0919a6), -329, -80}, - {GRISU_UINT64_C(0xa48ceaaa, b75a8e2b), -266, -61}, - {GRISU_UINT64_C(0xb267ed19, 40f1c61c), -203, -42}, - {GRISU_UINT64_C(0xc16d9a00, 95928a27), -140, -23}, - {GRISU_UINT64_C(0xd1b71758, e219652c), -77, -4}, - {GRISU_UINT64_C(0xe35fa931, a0000000), -14, 15}, - {GRISU_UINT64_C(0xf684df56, c3e01bc7), 49, 34}, - {GRISU_UINT64_C(0x85a36366, eb71f041), 113, 53}, - {GRISU_UINT64_C(0x90e40fbe, ea1d3a4b), 176, 72}, - {GRISU_UINT64_C(0x9d174b2d, cec0e47b), 239, 91}, - {GRISU_UINT64_C(0xaa51823e, 34a7eedf), 302, 110}, - {GRISU_UINT64_C(0xb8a8d9bb, e123f018), 365, 129}, - {GRISU_UINT64_C(0xc83553c5, c8965d3d), 428, 148}, - {GRISU_UINT64_C(0xd910f7ff, 28069da4), 491, 167}, - {GRISU_UINT64_C(0xeb57ff22, fc0c795a), 554, 186}, - {GRISU_UINT64_C(0xff290242, c83396ce), 617, 205}, - {GRISU_UINT64_C(0x8a5296ff, e33cc930), 681, 224}, - {GRISU_UINT64_C(0x95f83d0a, 1fb69cd9), 744, 243}, - {GRISU_UINT64_C(0xa298f2c5, 01f45f43), 807, 262}, - {GRISU_UINT64_C(0xb049dc01, 6abc5e60), 870, 281}, - {GRISU_UINT64_C(0xbf21e440, 03acdd2d), 933, 300}, - {GRISU_UINT64_C(0xcf39e50f, eae16bf0), 996, 319}, - {GRISU_UINT64_C(0xe0accfa8, 75af45a8), 1059, 338}, - }; -static const int GRISU_CACHE_MAX_DISTANCE(19) = 64; -// nb elements (19): 35 -static const GRISU_CACHE_STRUCT GRISU_CACHE_NAME(20)[] = { - {GRISU_UINT64_C(0xe61acf03, 3d1a45df), -1087, -308}, - {GRISU_UINT64_C(0x9becce62, 836ac577), -1020, -288}, - {GRISU_UINT64_C(0xd3515c28, 31559a83), -954, -268}, - {GRISU_UINT64_C(0x8f31cc09, 37ae58d3), -887, -248}, - {GRISU_UINT64_C(0xc2109436, 4dfb5637), -821, -228}, - {GRISU_UINT64_C(0x8380dea9, 3da4bc60), -754, -208}, - {GRISU_UINT64_C(0xb23867fb, 2a35b28e), -688, -188}, - {GRISU_UINT64_C(0xf18899b1, bc3f8ca2), -622, -168}, - {GRISU_UINT64_C(0xa3ab6658, 0d5fdaf6), -555, -148}, - {GRISU_UINT64_C(0xddd0467c, 64bce4a1), -489, -128}, - {GRISU_UINT64_C(0x964e858c, 91ba2655), -422, -108}, - {GRISU_UINT64_C(0xcbb41ef9, 79346bca), -356, -88}, - {GRISU_UINT64_C(0x8a08f0f8, bf0f156b), -289, -68}, - {GRISU_UINT64_C(0xbb127c53, b17ec159), -223, -48}, - {GRISU_UINT64_C(0xfd87b5f2, 8300ca0e), -157, -28}, - {GRISU_UINT64_C(0xabcc7711, 8461cefd), -90, -8}, - {GRISU_UINT64_C(0xe8d4a510, 00000000), -24, 12}, - {GRISU_UINT64_C(0x9dc5ada8, 2b70b59e), 43, 32}, - {GRISU_UINT64_C(0xd5d238a4, abe98068), 109, 52}, - {GRISU_UINT64_C(0x90e40fbe, ea1d3a4b), 176, 72}, - {GRISU_UINT64_C(0xc45d1df9, 42711d9a), 242, 92}, - {GRISU_UINT64_C(0x850fadc0, 9923329e), 309, 112}, - {GRISU_UINT64_C(0xb454e4a1, 79dd1877), 375, 132}, - {GRISU_UINT64_C(0xf46518c2, ef5b8cd1), 441, 152}, - {GRISU_UINT64_C(0xa59bc234, db398c25), 508, 172}, - {GRISU_UINT64_C(0xe070f78d, 3927556b), 574, 192}, - {GRISU_UINT64_C(0x98165af3, 7b2153df), 641, 212}, - {GRISU_UINT64_C(0xce1de406, 42e3f4b9), 707, 232}, - {GRISU_UINT64_C(0x8bab8eef, b6409c1a), 774, 252}, - {GRISU_UINT64_C(0xbd49d14a, a79dbc82), 840, 272}, - {GRISU_UINT64_C(0x80444b5e, 7aa7cf85), 907, 292}, - {GRISU_UINT64_C(0xadd57a27, d29339f6), 973, 312}, - {GRISU_UINT64_C(0xeb96bf6e, badf77d9), 1039, 332}, - }; -static const int GRISU_CACHE_MAX_DISTANCE(20) = 67; -// nb elements (20): 33 -static const int GRISU_CACHE_OFFSET = 308; diff --git a/src/profile-generator.cc b/src/profile-generator.cc index 525dea2f..977c67c8 100644 --- a/src/profile-generator.cc +++ b/src/profile-generator.cc @@ -94,12 +94,18 @@ StringsStorage::StringsStorage() } +static void DeleteIndexName(char** name_ptr) { + DeleteArray(*name_ptr); +} + + StringsStorage::~StringsStorage() { for (HashMap::Entry* p = names_.Start(); p != NULL; p = names_.Next(p)) { DeleteArray(reinterpret_cast<const char*>(p->value)); } + index_names_.Iterate(DeleteIndexName); } @@ -120,6 +126,22 @@ const char* StringsStorage::GetName(String* name) { } +const char* StringsStorage::GetName(int index) { + ASSERT(index >= 0); + if (index_names_.length() <= index) { + index_names_.AddBlock( + NULL, index - index_names_.length() + 1); + } + if (index_names_[index] == NULL) { + const int kMaximumNameLength = 32; + char* name = NewArray<char>(kMaximumNameLength); + OS::SNPrintF(Vector<char>(name, kMaximumNameLength), "%d", index); + index_names_[index] = name; + } + return index_names_[index]; +} + + const char* CodeEntry::kEmptyNamePrefix = ""; @@ -485,11 +507,6 @@ CpuProfilesCollection::CpuProfilesCollection() } -static void DeleteArgsCountName(char** name_ptr) { - DeleteArray(*name_ptr); -} - - static void DeleteCodeEntry(CodeEntry** entry_ptr) { delete *entry_ptr; } @@ -508,7 +525,6 @@ CpuProfilesCollection::~CpuProfilesCollection() { current_profiles_.Iterate(DeleteCpuProfile); profiles_by_token_.Iterate(DeleteProfilesList); code_entries_.Iterate(DeleteCodeEntry); - args_count_names_.Iterate(DeleteArgsCountName); } @@ -706,22 +722,6 @@ CodeEntry* CpuProfilesCollection::NewCodeEntry(int security_token_id) { } -const char* CpuProfilesCollection::GetName(int args_count) { - ASSERT(args_count >= 0); - if (args_count_names_.length() <= args_count) { - args_count_names_.AddBlock( - NULL, args_count - args_count_names_.length() + 1); - } - if (args_count_names_[args_count] == NULL) { - const int kMaximumNameLength = 32; - char* name = NewArray<char>(kMaximumNameLength); - OS::SNPrintF(Vector<char>(name, kMaximumNameLength), "%d", args_count); - args_count_names_[args_count] = name; - } - return args_count_names_[args_count]; -} - - void CpuProfilesCollection::AddPathToCurrentProfiles( const Vector<CodeEntry*>& path) { // As starting / stopping profiles is rare relatively to this @@ -952,7 +952,7 @@ void HeapEntry::PaintAllReachable() { void HeapEntry::Print(int max_depth, int indent) { - OS::Print("%6d %6d %6d [%ld] ", + OS::Print("%6d %6d %6d [%llu] ", self_size(), ReachableSize(), RetainedSize(), id_); if (type() != kString) { OS::Print("%s %.40s\n", TypeAsString(), name_); @@ -1001,6 +1001,8 @@ const char* HeapEntry::TypeAsString() { case kString: return "/string/"; case kCode: return "/code/"; case kArray: return "/array/"; + case kRegExp: return "/regexp/"; + case kHeapNumber: return "/number/"; default: return "???"; } } @@ -1237,7 +1239,7 @@ HeapSnapshot::HeapSnapshot(HeapSnapshotsCollection* collection, type_(type), title_(title), uid_(uid), - root_entry_index_(-1), + root_entry_(NULL), raw_entries_(NULL), entries_sorted_(false) { STATIC_ASSERT( @@ -1276,19 +1278,24 @@ HeapEntry* HeapSnapshot::AddEntry(HeapObject* object, int children_count, int retainers_count) { if (object == kInternalRootObject) { - ASSERT(root_entry_index_ == -1); - root_entry_index_ = entries_.length(); + ASSERT(root_entry_ == NULL); ASSERT(retainers_count == 0); - return AddEntry( + root_entry_ = AddEntry( HeapEntry::kInternal, "", 0, 0, children_count, retainers_count); + return root_entry_; } else if (object->IsJSFunction()) { JSFunction* func = JSFunction::cast(object); SharedFunctionInfo* shared = func->shared(); - String* name = String::cast(shared->name())->length() > 0 ? - String::cast(shared->name()) : shared->inferred_name(); return AddEntry(object, HeapEntry::kClosure, - collection_->GetFunctionName(name), + collection_->GetName(String::cast(shared->name())), + children_count, + retainers_count); + } else if (object->IsJSRegExp()) { + JSRegExp* re = JSRegExp::cast(object); + return AddEntry(object, + HeapEntry::kRegExp, + collection_->GetName(re->Pattern()), children_count, retainers_count); } else if (object->IsJSObject()) { @@ -1333,6 +1340,12 @@ HeapEntry* HeapSnapshot::AddEntry(HeapObject* object, "", children_count, retainers_count); + } else if (object->IsHeapNumber()) { + return AddEntry(object, + HeapEntry::kHeapNumber, + "number", + children_count, + retainers_count); } // No interest in this object. return NULL; @@ -1342,12 +1355,14 @@ HeapEntry* HeapSnapshot::AddEntry(HeapObject* object, bool HeapSnapshot::WillAddEntry(HeapObject* object) { return object == kInternalRootObject || object->IsJSFunction() + || object->IsJSRegExp() || object->IsJSObject() || object->IsString() || object->IsCode() || object->IsSharedFunctionInfo() || object->IsScript() - || object->IsFixedArray(); + || object->IsFixedArray() + || object->IsHeapNumber(); } @@ -1904,13 +1919,21 @@ void HeapSnapshotGenerator::ExtractReferences(HeapObject* obj) { ExtractClosureReferences(js_obj, entry); ExtractPropertyReferences(js_obj, entry); ExtractElementReferences(js_obj, entry); + ExtractInternalReferences(js_obj, entry); SetPropertyReference( - obj, entry, Heap::prototype_symbol(), js_obj->map()->prototype()); + obj, entry, Heap::Proto_symbol(), js_obj->GetPrototype()); + if (obj->IsJSFunction()) { + JSFunction* js_fun = JSFunction::cast(obj); + if (js_fun->has_prototype()) { + SetPropertyReference( + obj, entry, Heap::prototype_symbol(), js_fun->prototype()); + } + } } else if (obj->IsString()) { if (obj->IsConsString()) { ConsString* cs = ConsString::cast(obj); - SetElementReference(obj, entry, 0, cs->first()); - SetElementReference(obj, entry, 1, cs->second()); + SetInternalReference(obj, entry, "1", cs->first()); + SetInternalReference(obj, entry, "2", cs->second()); } } else if (obj->IsCode() || obj->IsSharedFunctionInfo() || obj->IsScript()) { IndexedReferencesExtractor refs_extractor(this, obj, entry); @@ -2005,6 +2028,16 @@ void HeapSnapshotGenerator::ExtractElementReferences(JSObject* js_obj, } +void HeapSnapshotGenerator::ExtractInternalReferences(JSObject* js_obj, + HeapEntry* entry) { + int length = js_obj->GetInternalFieldCount(); + for (int i = 0; i < length; ++i) { + Object* o = js_obj->GetInternalField(i); + SetInternalReference(js_obj, entry, i, o); + } +} + + void HeapSnapshotGenerator::SetClosureReference(HeapObject* parent_obj, HeapEntry* parent_entry, String* reference_name, @@ -2049,13 +2082,31 @@ void HeapSnapshotGenerator::SetInternalReference(HeapObject* parent_obj, } +void HeapSnapshotGenerator::SetInternalReference(HeapObject* parent_obj, + HeapEntry* parent_entry, + int index, + Object* child_obj) { + HeapEntry* child_entry = GetEntry(child_obj); + if (child_entry != NULL) { + filler_->SetNamedReference(HeapGraphEdge::kInternal, + parent_obj, + parent_entry, + collection_->GetName(index), + child_obj, + child_entry); + } +} + + void HeapSnapshotGenerator::SetPropertyReference(HeapObject* parent_obj, HeapEntry* parent_entry, String* reference_name, Object* child_obj) { HeapEntry* child_entry = GetEntry(child_obj); if (child_entry != NULL) { - filler_->SetNamedReference(HeapGraphEdge::kProperty, + HeapGraphEdge::Type type = reference_name->length() > 0 ? + HeapGraphEdge::kProperty : HeapGraphEdge::kInternal; + filler_->SetNamedReference(type, parent_obj, parent_entry, collection_->GetName(reference_name), @@ -2095,6 +2146,11 @@ HeapSnapshotsComparator::~HeapSnapshotsComparator() { HeapSnapshotsDiff* HeapSnapshotsComparator::Compare(HeapSnapshot* snapshot1, HeapSnapshot* snapshot2) { + snapshot1->ClearPaint(); + snapshot1->root()->PaintAllReachable(); + snapshot2->ClearPaint(); + snapshot2->root()->PaintAllReachable(); + List<HeapEntry*>* entries1 = snapshot1->GetSortedEntriesList(); List<HeapEntry*>* entries2 = snapshot2->GetSortedEntriesList(); int i = 0, j = 0; @@ -2103,8 +2159,14 @@ HeapSnapshotsDiff* HeapSnapshotsComparator::Compare(HeapSnapshot* snapshot1, uint64_t id1 = entries1->at(i)->id(); uint64_t id2 = entries2->at(j)->id(); if (id1 == id2) { - i++; - j++; + HeapEntry* entry1 = entries1->at(i++); + HeapEntry* entry2 = entries2->at(j++); + if (entry1->painted_reachable() != entry2->painted_reachable()) { + if (entry1->painted_reachable()) + deleted_entries.Add(entry1); + else + added_entries.Add(entry2); + } } else if (id1 < id2) { HeapEntry* entry = entries1->at(i++); deleted_entries.Add(entry); @@ -2122,35 +2184,17 @@ HeapSnapshotsDiff* HeapSnapshotsComparator::Compare(HeapSnapshot* snapshot1, added_entries.Add(entry); } - snapshot1->ClearPaint(); - snapshot1->root()->PaintAllReachable(); - snapshot2->ClearPaint(); - snapshot2->root()->PaintAllReachable(); - int reachable_deleted_entries = 0, reachable_added_entries = 0; - for (int i = 0; i < deleted_entries.length(); ++i) { - HeapEntry* entry = deleted_entries[i]; - if (entry->painted_reachable()) ++reachable_deleted_entries; - } - for (int i = 0; i < added_entries.length(); ++i) { - HeapEntry* entry = added_entries[i]; - if (entry->painted_reachable()) ++reachable_added_entries; - } - HeapSnapshotsDiff* diff = new HeapSnapshotsDiff(snapshot1, snapshot2); diffs_.Add(diff); - diff->CreateRoots(reachable_added_entries, reachable_deleted_entries); + diff->CreateRoots(added_entries.length(), deleted_entries.length()); - int del_child_index = 0, deleted_entry_index = 1; for (int i = 0; i < deleted_entries.length(); ++i) { HeapEntry* entry = deleted_entries[i]; - if (entry->painted_reachable()) - diff->AddDeletedEntry(del_child_index++, deleted_entry_index++, entry); + diff->AddDeletedEntry(i, i + 1, entry); } - int add_child_index = 0, added_entry_index = 1; for (int i = 0; i < added_entries.length(); ++i) { HeapEntry* entry = added_entries[i]; - if (entry->painted_reachable()) - diff->AddAddedEntry(add_child_index++, added_entry_index++, entry); + diff->AddAddedEntry(i, i + 1, entry); } return diff; } @@ -2358,7 +2402,9 @@ void HeapSnapshotJSONSerializer::SerializeNodes() { "," JSON_S("string") "," JSON_S("object") "," JSON_S("code") - "," JSON_S("closure")) + "," JSON_S("closure") + "," JSON_S("regexp") + "," JSON_S("number")) "," JSON_S("string") "," JSON_S("number") "," JSON_S("number") diff --git a/src/profile-generator.h b/src/profile-generator.h index 1e949a2c..6f63f6a1 100644 --- a/src/profile-generator.h +++ b/src/profile-generator.h @@ -67,6 +67,7 @@ class StringsStorage { ~StringsStorage(); const char* GetName(String* name); + const char* GetName(int index); inline const char* GetFunctionName(String* name); inline const char* GetFunctionName(const char* name); @@ -78,6 +79,8 @@ class StringsStorage { // Mapping of strings by String::Hash to const char* strings. HashMap names_; + // Mapping from ints to char* strings. + List<char*> index_names_; DISALLOW_COPY_AND_ASSIGN(StringsStorage); }; @@ -284,6 +287,9 @@ class CpuProfilesCollection { const char* GetName(String* name) { return function_and_resource_names_.GetName(name); } + const char* GetName(int args_count) { + return function_and_resource_names_.GetName(args_count); + } CpuProfile* GetProfile(int security_token_id, unsigned uid); bool IsLastProfile(const char* title); @@ -302,7 +308,6 @@ class CpuProfilesCollection { static const int kMaxSimultaneousProfiles = 100; private: - const char* GetName(int args_count); const char* GetFunctionName(String* name) { return function_and_resource_names_.GetFunctionName(name); } @@ -317,8 +322,6 @@ class CpuProfilesCollection { } StringsStorage function_and_resource_names_; - // Mapping from args_count (int) to char* strings. - List<char*> args_count_names_; List<CodeEntry*> code_entries_; List<List<CpuProfile*>* > profiles_by_token_; // Mapping from profiles' uids to indexes in the second nested list @@ -502,7 +505,9 @@ class HeapEntry BASE_EMBEDDED { kString = v8::HeapGraphNode::kString, kObject = v8::HeapGraphNode::kObject, kCode = v8::HeapGraphNode::kCode, - kClosure = v8::HeapGraphNode::kClosure + kClosure = v8::HeapGraphNode::kClosure, + kRegExp = v8::HeapGraphNode::kRegExp, + kHeapNumber = v8::HeapGraphNode::kHeapNumber }; HeapEntry() { } @@ -662,7 +667,7 @@ class HeapSnapshot { Type type() { return type_; } const char* title() { return title_; } unsigned uid() { return uid_; } - HeapEntry* root() { return entries_[root_entry_index_]; } + HeapEntry* root() { return root_entry_; } void AllocateEntries( int entries_count, int children_count, int retainers_count); @@ -704,7 +709,7 @@ class HeapSnapshot { Type type_; const char* title_; unsigned uid_; - int root_entry_index_; + HeapEntry* root_entry_; char* raw_entries_; List<HeapEntry*> entries_; bool entries_sorted_; @@ -824,6 +829,7 @@ class HeapSnapshotsCollection { HeapSnapshot* GetSnapshot(unsigned uid); const char* GetName(String* name) { return names_.GetName(name); } + const char* GetName(int index) { return names_.GetName(index); } const char* GetFunctionName(String* name) { return names_.GetFunctionName(name); } @@ -948,6 +954,7 @@ class HeapSnapshotGenerator { void ExtractClosureReferences(JSObject* js_obj, HeapEntry* entry); void ExtractPropertyReferences(JSObject* js_obj, HeapEntry* entry); void ExtractElementReferences(JSObject* js_obj, HeapEntry* entry); + void ExtractInternalReferences(JSObject* js_obj, HeapEntry* entry); void SetClosureReference(HeapObject* parent_obj, HeapEntry* parent, String* reference_name, @@ -960,6 +967,10 @@ class HeapSnapshotGenerator { HeapEntry* parent, const char* reference_name, Object* child); + void SetInternalReference(HeapObject* parent_obj, + HeapEntry* parent, + int index, + Object* child); void SetPropertyReference(HeapObject* parent_obj, HeapEntry* parent, String* reference_name, diff --git a/src/regexp-macro-assembler-irregexp.cc b/src/regexp-macro-assembler-irregexp.cc index 90abe912..6fbb14ad 100644 --- a/src/regexp-macro-assembler-irregexp.cc +++ b/src/regexp-macro-assembler-irregexp.cc @@ -145,6 +145,12 @@ void RegExpMacroAssemblerIrregexp::ReadStackPointerFromRegister( } +void RegExpMacroAssemblerIrregexp::SetCurrentPositionFromEnd(int by) { + ASSERT(is_uint24(by)); + Emit(BC_SET_CURRENT_POSITION_FROM_END, by); +} + + void RegExpMacroAssemblerIrregexp::SetRegister(int register_index, int to) { ASSERT(register_index >= 0); ASSERT(register_index <= kMaxRegister); diff --git a/src/regexp-macro-assembler-irregexp.h b/src/regexp-macro-assembler-irregexp.h index 3ddbc2fe..6c9c2eb0 100644 --- a/src/regexp-macro-assembler-irregexp.h +++ b/src/regexp-macro-assembler-irregexp.h @@ -65,6 +65,7 @@ class RegExpMacroAssemblerIrregexp: public RegExpMacroAssembler { virtual void PushRegister(int register_index, StackCheckFlag check_stack_limit); virtual void AdvanceRegister(int reg, int by); // r[reg] += by. + virtual void SetCurrentPositionFromEnd(int by); virtual void SetRegister(int register_index, int to); virtual void WriteCurrentPositionToRegister(int reg, int cp_offset); virtual void ClearRegisters(int reg_from, int reg_to); diff --git a/src/regexp-macro-assembler-tracer.cc b/src/regexp-macro-assembler-tracer.cc index c08602eb..463c1a81 100644 --- a/src/regexp-macro-assembler-tracer.cc +++ b/src/regexp-macro-assembler-tracer.cc @@ -47,8 +47,15 @@ RegExpMacroAssemblerTracer::~RegExpMacroAssemblerTracer() { } +// This is used for printing out debugging information. It makes an integer +// that is closely related to the address of an object. +static int LabelToInt(Label* label) { + return static_cast<int>(reinterpret_cast<intptr_t>(label)); +} + + void RegExpMacroAssemblerTracer::Bind(Label* label) { - PrintF("label[%08x]: (Bind)\n", label, label); + PrintF("label[%08x]: (Bind)\n", LabelToInt(label)); assembler_->Bind(label); } @@ -60,7 +67,7 @@ void RegExpMacroAssemblerTracer::AdvanceCurrentPosition(int by) { void RegExpMacroAssemblerTracer::CheckGreedyLoop(Label* label) { - PrintF(" CheckGreedyLoop(label[%08x]);\n\n", label); + PrintF(" CheckGreedyLoop(label[%08x]);\n\n", LabelToInt(label)); assembler_->CheckGreedyLoop(label); } @@ -84,14 +91,13 @@ void RegExpMacroAssemblerTracer::Backtrack() { void RegExpMacroAssemblerTracer::GoTo(Label* label) { - PrintF(" GoTo(label[%08x]);\n\n", label); + PrintF(" GoTo(label[%08x]);\n\n", LabelToInt(label)); assembler_->GoTo(label); } void RegExpMacroAssemblerTracer::PushBacktrack(Label* label) { - PrintF(" PushBacktrack(label[%08x]);\n", - label); + PrintF(" PushBacktrack(label[%08x]);\n", LabelToInt(label)); assembler_->PushBacktrack(label); } @@ -130,6 +136,12 @@ void RegExpMacroAssemblerTracer::AdvanceRegister(int reg, int by) { } +void RegExpMacroAssemblerTracer::SetCurrentPositionFromEnd(int by) { + PrintF(" SetCurrentPositionFromEnd(by=%d);\n", by); + assembler_->SetCurrentPositionFromEnd(by); +} + + void RegExpMacroAssemblerTracer::SetRegister(int register_index, int to) { PrintF(" SetRegister(register=%d, to=%d);\n", register_index, to); assembler_->SetRegister(register_index, to); @@ -176,7 +188,7 @@ void RegExpMacroAssemblerTracer::LoadCurrentCharacter(int cp_offset, const char* check_msg = check_bounds ? "" : " (unchecked)"; PrintF(" LoadCurrentCharacter(cp_offset=%d, label[%08x]%s (%d chars));\n", cp_offset, - on_end_of_input, + LabelToInt(on_end_of_input), check_msg, characters); assembler_->LoadCurrentCharacter(cp_offset, @@ -187,39 +199,43 @@ void RegExpMacroAssemblerTracer::LoadCurrentCharacter(int cp_offset, void RegExpMacroAssemblerTracer::CheckCharacterLT(uc16 limit, Label* on_less) { - PrintF(" CheckCharacterLT(c='u%04x', label[%08x]);\n", limit, on_less); + PrintF(" CheckCharacterLT(c='u%04x', label[%08x]);\n", + limit, LabelToInt(on_less)); assembler_->CheckCharacterLT(limit, on_less); } void RegExpMacroAssemblerTracer::CheckCharacterGT(uc16 limit, Label* on_greater) { - PrintF(" CheckCharacterGT(c='u%04x', label[%08x]);\n", limit, on_greater); + PrintF(" CheckCharacterGT(c='u%04x', label[%08x]);\n", + limit, LabelToInt(on_greater)); assembler_->CheckCharacterGT(limit, on_greater); } void RegExpMacroAssemblerTracer::CheckCharacter(uint32_t c, Label* on_equal) { - PrintF(" CheckCharacter(c='u%04x', label[%08x]);\n", c, on_equal); + PrintF(" CheckCharacter(c='u%04x', label[%08x]);\n", + c, LabelToInt(on_equal)); assembler_->CheckCharacter(c, on_equal); } void RegExpMacroAssemblerTracer::CheckAtStart(Label* on_at_start) { - PrintF(" CheckAtStart(label[%08x]);\n", on_at_start); + PrintF(" CheckAtStart(label[%08x]);\n", LabelToInt(on_at_start)); assembler_->CheckAtStart(on_at_start); } void RegExpMacroAssemblerTracer::CheckNotAtStart(Label* on_not_at_start) { - PrintF(" CheckNotAtStart(label[%08x]);\n", on_not_at_start); + PrintF(" CheckNotAtStart(label[%08x]);\n", LabelToInt(on_not_at_start)); assembler_->CheckNotAtStart(on_not_at_start); } void RegExpMacroAssemblerTracer::CheckNotCharacter(uint32_t c, Label* on_not_equal) { - PrintF(" CheckNotCharacter(c='u%04x', label[%08x]);\n", c, on_not_equal); + PrintF(" CheckNotCharacter(c='u%04x', label[%08x]);\n", + c, LabelToInt(on_not_equal)); assembler_->CheckNotCharacter(c, on_not_equal); } @@ -231,7 +247,7 @@ void RegExpMacroAssemblerTracer::CheckCharacterAfterAnd( PrintF(" CheckCharacterAfterAnd(c='u%04x', mask=0x%04x, label[%08x]);\n", c, mask, - on_equal); + LabelToInt(on_equal)); assembler_->CheckCharacterAfterAnd(c, mask, on_equal); } @@ -243,7 +259,7 @@ void RegExpMacroAssemblerTracer::CheckNotCharacterAfterAnd( PrintF(" CheckNotCharacterAfterAnd(c='u%04x', mask=0x%04x, label[%08x]);\n", c, mask, - on_not_equal); + LabelToInt(on_not_equal)); assembler_->CheckNotCharacterAfterAnd(c, mask, on_not_equal); } @@ -258,7 +274,7 @@ void RegExpMacroAssemblerTracer::CheckNotCharacterAfterMinusAnd( c, minus, mask, - on_not_equal); + LabelToInt(on_not_equal)); assembler_->CheckNotCharacterAfterMinusAnd(c, minus, mask, on_not_equal); } @@ -266,7 +282,7 @@ void RegExpMacroAssemblerTracer::CheckNotCharacterAfterMinusAnd( void RegExpMacroAssemblerTracer::CheckNotBackReference(int start_reg, Label* on_no_match) { PrintF(" CheckNotBackReference(register=%d, label[%08x]);\n", start_reg, - on_no_match); + LabelToInt(on_no_match)); assembler_->CheckNotBackReference(start_reg, on_no_match); } @@ -275,7 +291,7 @@ void RegExpMacroAssemblerTracer::CheckNotBackReferenceIgnoreCase( int start_reg, Label* on_no_match) { PrintF(" CheckNotBackReferenceIgnoreCase(register=%d, label[%08x]);\n", - start_reg, on_no_match); + start_reg, LabelToInt(on_no_match)); assembler_->CheckNotBackReferenceIgnoreCase(start_reg, on_no_match); } @@ -286,7 +302,7 @@ void RegExpMacroAssemblerTracer::CheckNotRegistersEqual(int reg1, PrintF(" CheckNotRegistersEqual(reg1=%d, reg2=%d, label[%08x]);\n", reg1, reg2, - on_not_equal); + LabelToInt(on_not_equal)); assembler_->CheckNotRegistersEqual(reg1, reg2, on_not_equal); } @@ -300,7 +316,8 @@ void RegExpMacroAssemblerTracer::CheckCharacters(Vector<const uc16> str, for (int i = 0; i < str.length(); i++) { PrintF("u%04x", str[i]); } - PrintF("\", cp_offset=%d, label[%08x])\n", cp_offset, on_failure); + PrintF("\", cp_offset=%d, label[%08x])\n", + cp_offset, LabelToInt(on_failure)); assembler_->CheckCharacters(str, cp_offset, on_failure, check_end_of_string); } @@ -312,7 +329,7 @@ bool RegExpMacroAssemblerTracer::CheckSpecialCharacterClass( on_no_match); PrintF(" CheckSpecialCharacterClass(type='%c', label[%08x]): %s;\n", type, - on_no_match, + LabelToInt(on_no_match), supported ? "true" : "false"); return supported; } @@ -321,7 +338,7 @@ bool RegExpMacroAssemblerTracer::CheckSpecialCharacterClass( void RegExpMacroAssemblerTracer::IfRegisterLT(int register_index, int comparand, Label* if_lt) { PrintF(" IfRegisterLT(register=%d, number=%d, label[%08x]);\n", - register_index, comparand, if_lt); + register_index, comparand, LabelToInt(if_lt)); assembler_->IfRegisterLT(register_index, comparand, if_lt); } @@ -329,7 +346,7 @@ void RegExpMacroAssemblerTracer::IfRegisterLT(int register_index, void RegExpMacroAssemblerTracer::IfRegisterEqPos(int register_index, Label* if_eq) { PrintF(" IfRegisterEqPos(register=%d, label[%08x]);\n", - register_index, if_eq); + register_index, LabelToInt(if_eq)); assembler_->IfRegisterEqPos(register_index, if_eq); } @@ -337,7 +354,7 @@ void RegExpMacroAssemblerTracer::IfRegisterEqPos(int register_index, void RegExpMacroAssemblerTracer::IfRegisterGE(int register_index, int comparand, Label* if_ge) { PrintF(" IfRegisterGE(register=%d, number=%d, label[%08x]);\n", - register_index, comparand, if_ge); + register_index, comparand, LabelToInt(if_ge)); assembler_->IfRegisterGE(register_index, comparand, if_ge); } diff --git a/src/regexp-macro-assembler-tracer.h b/src/regexp-macro-assembler-tracer.h index 9608f9e1..6a8f4d47 100644 --- a/src/regexp-macro-assembler-tracer.h +++ b/src/regexp-macro-assembler-tracer.h @@ -89,6 +89,7 @@ class RegExpMacroAssemblerTracer: public RegExpMacroAssembler { StackCheckFlag check_stack_limit); virtual void ReadCurrentPositionFromRegister(int reg); virtual void ReadStackPointerFromRegister(int reg); + virtual void SetCurrentPositionFromEnd(int by); virtual void SetRegister(int register_index, int to); virtual void Succeed(); virtual void WriteCurrentPositionToRegister(int reg, int cp_offset); diff --git a/src/regexp-macro-assembler.h b/src/regexp-macro-assembler.h index 652b690d..dc3bd824 100644 --- a/src/regexp-macro-assembler.h +++ b/src/regexp-macro-assembler.h @@ -155,6 +155,7 @@ class RegExpMacroAssembler { StackCheckFlag check_stack_limit) = 0; virtual void ReadCurrentPositionFromRegister(int reg) = 0; virtual void ReadStackPointerFromRegister(int reg) = 0; + virtual void SetCurrentPositionFromEnd(int by) = 0; virtual void SetRegister(int register_index, int to) = 0; virtual void Succeed() = 0; virtual void WriteCurrentPositionToRegister(int reg, int cp_offset) = 0; diff --git a/src/regexp.js b/src/regexp.js index faa525d6..51f4b094 100644 --- a/src/regexp.js +++ b/src/regexp.js @@ -126,11 +126,11 @@ function RegExpCache() { this.regExp = 0; this.subject = 0; this.replaceString = 0; - this.lastIndex = 0; // Also used for splitLimit when type is "split" this.answer = 0; // answerSaved marks whether the contents of answer is valid for a cache // hit in RegExpExec, StringMatch and StringSplit. this.answerSaved = false; + this.splitLimit = 0; // Used only when type is "split". } @@ -181,22 +181,30 @@ function RegExpExec(string) { var cache = regExpCache; var saveAnswer = false; + var lastIndex = this.lastIndex; + + // Since cache.subject is always a string, a matching input can not + // cause visible side-effects when converted to a string, so we can omit + // the conversion required by the specification. + // Likewise, the regexp.lastIndex and regexp.global properties are value + // properties that are not configurable, so reading them can also not cause + // any side effects (converting lastIndex to a number can, though). if (%_ObjectEquals(cache.type, 'exec') && - %_ObjectEquals(cache.lastIndex, this.lastIndex) && + %_ObjectEquals(0, lastIndex) && %_IsRegExpEquivalent(cache.regExp, this) && %_ObjectEquals(cache.subject, string)) { if (cache.answerSaved) { - // If this regexp is not global, cache.lastIndex is zero, so we only get - // here if this.lastIndex is zero, and resulting this.lastIndex - // must be zero too, so no change is necessary. - if (this.global) this.lastIndex = lastMatchInfo[CAPTURE1]; + // The regexp.lastIndex value must be 0 for non-global RegExps, and for + // global RegExps we only cache negative results, which gives a lastIndex + // of zero as well. + this.lastIndex = 0; return %_RegExpCloneResult(cache.answer); } else { saveAnswer = true; } } - if (%_ArgumentsLength() == 0) { + if (%_ArgumentsLength() === 0) { var regExpInput = LAST_INPUT(lastMatchInfo); if (IS_UNDEFINED(regExpInput)) { throw MakeError('no_input_to_regexp', [this]); @@ -209,41 +217,48 @@ function RegExpExec(string) { } else { s = ToString(string); } - var lastIndex = this.lastIndex; - - var i = this.global ? TO_INTEGER(lastIndex) : 0; + var global = this.global; - if (i < 0 || i > s.length) { - this.lastIndex = 0; - return null; + // Conversion is required by the ES5 specification (RegExp.prototype.exec + // algorithm, step 5) even if the value is discarded for non-global RegExps. + var i = TO_INTEGER(lastIndex); + if (global) { + if (i < 0 || i > s.length) { + this.lastIndex = 0; + return null; + } + } else { + i = 0; } %_Log('regexp', 'regexp-exec,%0r,%1S,%2i', [this, s, lastIndex]); // matchIndices is either null or the lastMatchInfo array. var matchIndices = %_RegExpExec(this, s, i, lastMatchInfo); - if (matchIndices == null) { - if (this.global) { + if (matchIndices === null) { + if (global) { + // Cache negative result only if initial lastIndex was zero. this.lastIndex = 0; - if (lastIndex != 0) return matchIndices; + if (lastIndex !== 0) return matchIndices; } - cache.lastIndex = lastIndex; cache.regExp = this; - cache.subject = s; - cache.answer = matchIndices; // Null. + cache.subject = s; // Always a string. + cache.answer = null; cache.answerSaved = true; // Safe since no cloning is needed. cache.type = 'exec'; return matchIndices; // No match. } + + // Successful match. lastMatchInfoOverride = null; var result = BuildResultFromMatchInfo(matchIndices, s); - if (this.global) { + if (global) { + // Don't cache positive results for global regexps. this.lastIndex = lastMatchInfo[CAPTURE1]; } else { cache.regExp = this; cache.subject = s; - cache.lastIndex = lastIndex; if (saveAnswer) cache.answer = %_RegExpCloneResult(result); cache.answerSaved = saveAnswer; cache.type = 'exec'; @@ -273,32 +288,49 @@ function RegExpTest(string) { } string = regExpInput; } - var s; - if (IS_STRING(string)) { - s = string; - } else { - s = ToString(string); - } var lastIndex = this.lastIndex; + var cache = regExpCache; if (%_ObjectEquals(cache.type, 'test') && %_IsRegExpEquivalent(cache.regExp, this) && %_ObjectEquals(cache.subject, string) && - %_ObjectEquals(cache.lastIndex, lastIndex)) { - // If this regexp is not global, cache.lastIndex is zero, so we only get - // here if this.lastIndex is zero, and resulting this.lastIndex - // must be zero too, so no change is necessary. - if (this.global) this.lastIndex = lastMatchInfo[CAPTURE1]; + %_ObjectEquals(0, lastIndex)) { + // The regexp.lastIndex value must be 0 for non-global RegExps, and for + // global RegExps we only cache negative results, which gives a resulting + // lastIndex of zero as well. + if (global) this.lastIndex = 0; return cache.answer; } + var s; + if (IS_STRING(string)) { + s = string; + } else { + s = ToString(string); + } + var length = s.length; + + // Conversion is required by the ES5 specification (RegExp.prototype.exec + // algorithm, step 5) even if the value is discarded for non-global RegExps. + var i = TO_INTEGER(lastIndex); + if (global) { + if (i < 0 || i > length) { + this.lastIndex = 0; + return false; + } + } else { + i = 0; + } + + var global = this.global; + // Remove irrelevant preceeding '.*' in a test regexp. The expression // checks whether this.source starts with '.*' and that the third // char is not a '?' - if (%_StringCharCodeAt(this.source,0) == 46 && // '.' - %_StringCharCodeAt(this.source,1) == 42 && // '*' - %_StringCharCodeAt(this.source,2) != 63) { // '?' + if (%_StringCharCodeAt(this.source, 0) == 46 && // '.' + %_StringCharCodeAt(this.source, 1) == 42 && // '*' + %_StringCharCodeAt(this.source, 2) != 63) { // '?' if (!%_ObjectEquals(regexp_key, this)) { regexp_key = this; regexp_val = new $RegExp(this.source.substring(2, this.source.length), @@ -309,33 +341,28 @@ function RegExpTest(string) { if (!regexp_val.test(s)) return false; } - var length = s.length; - var i = this.global ? TO_INTEGER(lastIndex) : 0; - - cache.type = 'test'; - cache.regExp = this; - cache.subject = s; - cache.lastIndex = i; - - if (i < 0 || i > length) { - this.lastIndex = 0; - cache.answer = false; - return false; - } - %_Log('regexp', 'regexp-exec,%0r,%1S,%2i', [this, s, lastIndex]); // matchIndices is either null or the lastMatchInfo array. var matchIndices = %_RegExpExec(this, s, i, lastMatchInfo); - if (matchIndices == null) { - if (this.global) this.lastIndex = 0; - cache.answer = false; - return false; + var result = (matchIndices !== null); + if (result) { + lastMatchInfoOverride = null; } - lastMatchInfoOverride = null; - if (this.global) this.lastIndex = lastMatchInfo[CAPTURE1]; - cache.answer = true; - return true; + if (global) { + if (result) { + this.lastIndex = lastMatchInfo[CAPTURE1]; + return true; + } else { + this.lastIndex = 0; + if (lastIndex !== 0) return false; + } + } + cache.type = 'test'; + cache.regExp = this; + cache.subject = s; + cache.answer = result; + return result; } @@ -345,12 +372,9 @@ function RegExpToString() { // ecma_2/RegExp/properties-001.js. var src = this.source ? this.source : '(?:)'; var result = '/' + src + '/'; - if (this.global) - result += 'g'; - if (this.ignoreCase) - result += 'i'; - if (this.multiline) - result += 'm'; + if (this.global) result += 'g'; + if (this.ignoreCase) result += 'i'; + if (this.multiline) result += 'm'; return result; } diff --git a/src/rewriter.cc b/src/rewriter.cc index f253ec53..b6f82406 100644 --- a/src/rewriter.cc +++ b/src/rewriter.cc @@ -1,4 +1,4 @@ -// Copyright 2006-2008 the V8 project authors. All rights reserved. +// 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: @@ -27,9 +27,11 @@ #include "v8.h" +#include "rewriter.h" + #include "ast.h" +#include "compiler.h" #include "scopes.h" -#include "rewriter.h" namespace v8 { namespace internal { @@ -986,34 +988,40 @@ void Processor::VisitThisFunction(ThisFunction* node) { } -bool Rewriter::Process(FunctionLiteral* function) { - HistogramTimerScope timer(&Counters::rewriting); +// Assumes code has been parsed and scopes hve been analyzed. Mutates the +// AST, so the AST should not continue to be used in the case of failure. +bool Rewriter::Rewrite(CompilationInfo* info) { + FunctionLiteral* function = info->function(); + ASSERT(function != NULL); Scope* scope = function->scope(); + ASSERT(scope != NULL); if (scope->is_function_scope()) return true; ZoneList<Statement*>* body = function->body(); - if (body->is_empty()) return true; + if (!body->is_empty()) { + VariableProxy* result = scope->NewTemporary(Factory::result_symbol()); + Processor processor(result); + processor.Process(body); + if (processor.HasStackOverflow()) return false; - VariableProxy* result = scope->NewTemporary(Factory::result_symbol()); - Processor processor(result); - processor.Process(body); - if (processor.HasStackOverflow()) return false; + if (processor.result_assigned()) body->Add(new ReturnStatement(result)); + } - if (processor.result_assigned()) body->Add(new ReturnStatement(result)); return true; } -bool Rewriter::Optimize(FunctionLiteral* function) { - ZoneList<Statement*>* body = function->body(); +// Assumes code has been parsed and scopes have been analyzed. Mutates the +// AST, so the AST should not continue to be used in the case of failure. +bool Rewriter::Analyze(CompilationInfo* info) { + FunctionLiteral* function = info->function(); + ASSERT(function != NULL && function->scope() != NULL); + ZoneList<Statement*>* body = function->body(); if (FLAG_optimize_ast && !body->is_empty()) { - HistogramTimerScope timer(&Counters::ast_optimization); AstOptimizer optimizer; optimizer.Optimize(body); - if (optimizer.HasStackOverflow()) { - return false; - } + if (optimizer.HasStackOverflow()) return false; } return true; } diff --git a/src/rewriter.h b/src/rewriter.h index 8943e75a..62e1b7f7 100644 --- a/src/rewriter.h +++ b/src/rewriter.h @@ -1,4 +1,4 @@ -// Copyright 2006-2008 the V8 project authors. All rights reserved. +// 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: @@ -31,21 +31,26 @@ namespace v8 { namespace internal { - -// Currently, the rewriter takes function literals (only top-level) -// and rewrites them to return the value of the last expression in -// them. -// -// The rewriter adds a (hidden) variable, called .result, to the -// activation, and tries to figure out where it needs to store into -// this variable. If the variable is ever used, we conclude by adding -// a return statement that returns the variable to the body of the -// given function. +class CompilationInfo; class Rewriter { public: - static bool Process(FunctionLiteral* function); - static bool Optimize(FunctionLiteral* function); + // Rewrite top-level code (ECMA 262 "programs") so as to conservatively + // include an assignment of the value of the last statement in the code to + // a compiler-generated temporary variable wherever needed. + // + // Assumes code has been parsed and scopes have been analyzed. Mutates the + // AST, so the AST should not continue to be used in the case of failure. + static bool Rewrite(CompilationInfo* info); + + // Perform a suite of simple non-iterative analyses of the AST. Mark + // expressions that are likely smis, expressions without side effects, + // expressions whose value will be converted to Int32, and expressions in a + // context where +0 and -0 are treated the same. + // + // Assumes code has been parsed and scopes have been analyzed. Mutates the + // AST, so the AST should not continue to be used in the case of failure. + static bool Analyze(CompilationInfo* info); }; diff --git a/src/runtime.cc b/src/runtime.cc index 8d58db74..9a604a03 100644 --- a/src/runtime.cc +++ b/src/runtime.cc @@ -2624,15 +2624,15 @@ int Runtime::StringMatch(Handle<String> sub, if (seq_pat->IsAsciiRepresentation()) { Vector<const char> pat_vector = seq_pat->ToAsciiVector(); if (seq_sub->IsAsciiRepresentation()) { - return StringSearch(seq_sub->ToAsciiVector(), pat_vector, start_index); + return SearchString(seq_sub->ToAsciiVector(), pat_vector, start_index); } - return StringSearch(seq_sub->ToUC16Vector(), pat_vector, start_index); + return SearchString(seq_sub->ToUC16Vector(), pat_vector, start_index); } Vector<const uc16> pat_vector = seq_pat->ToUC16Vector(); if (seq_sub->IsAsciiRepresentation()) { - return StringSearch(seq_sub->ToAsciiVector(), pat_vector, start_index); + return SearchString(seq_sub->ToAsciiVector(), pat_vector, start_index); } - return StringSearch(seq_sub->ToUC16Vector(), pat_vector, start_index); + return SearchString(seq_sub->ToUC16Vector(), pat_vector, start_index); } @@ -2889,67 +2889,39 @@ static void SetLastMatchInfoNoCaptures(Handle<String> subject, } -template <typename schar, typename pchar> -static bool SearchStringMultiple(Vector<schar> subject, - String* pattern, - Vector<pchar> pattern_string, +template <typename SubjectChar, typename PatternChar> +static bool SearchStringMultiple(Vector<const SubjectChar> subject, + Vector<const PatternChar> pattern, + String* pattern_string, FixedArrayBuilder* builder, int* match_pos) { int pos = *match_pos; int subject_length = subject.length(); - int pattern_length = pattern_string.length(); + int pattern_length = pattern.length(); int max_search_start = subject_length - pattern_length; - bool is_ascii = (sizeof(schar) == 1); - StringSearchStrategy strategy = - InitializeStringSearch(pattern_string, is_ascii); - switch (strategy) { - case SEARCH_FAIL: break; - case SEARCH_SHORT: - while (pos <= max_search_start) { - if (!builder->HasCapacity(kMaxBuilderEntriesPerRegExpMatch)) { - *match_pos = pos; - return false; - } - // Position of end of previous match. - int match_end = pos + pattern_length; - int new_pos = SimpleIndexOf(subject, pattern_string, match_end); - if (new_pos >= 0) { - // A match. - if (new_pos > match_end) { - ReplacementStringBuilder::AddSubjectSlice(builder, - match_end, - new_pos); - } - pos = new_pos; - builder->Add(pattern); - } else { - break; - } - } - break; - case SEARCH_LONG: - while (pos <= max_search_start) { - if (!builder->HasCapacity(kMaxBuilderEntriesPerRegExpMatch)) { - *match_pos = pos; - return false; - } - int match_end = pos + pattern_length; - int new_pos = ComplexIndexOf(subject, pattern_string, match_end); - if (new_pos >= 0) { - // A match has been found. - if (new_pos > match_end) { - ReplacementStringBuilder::AddSubjectSlice(builder, - match_end, - new_pos); - } - pos = new_pos; - builder->Add(pattern); - } else { - break; - } + StringSearch<PatternChar, SubjectChar> search(pattern); + while (pos <= max_search_start) { + if (!builder->HasCapacity(kMaxBuilderEntriesPerRegExpMatch)) { + *match_pos = pos; + return false; + } + // Position of end of previous match. + int match_end = pos + pattern_length; + int new_pos = search.Search(subject, match_end); + if (new_pos >= 0) { + // A match. + if (new_pos > match_end) { + ReplacementStringBuilder::AddSubjectSlice(builder, + match_end, + new_pos); } + pos = new_pos; + builder->Add(pattern_string); + } else { break; + } } + if (pos < max_search_start) { ReplacementStringBuilder::AddSubjectSlice(builder, pos + pattern_length, @@ -2977,14 +2949,14 @@ static bool SearchStringMultiple(Handle<String> subject, Vector<const char> subject_vector = subject->ToAsciiVector(); if (pattern->IsAsciiRepresentation()) { if (SearchStringMultiple(subject_vector, - *pattern, pattern->ToAsciiVector(), + *pattern, builder, &match_pos)) break; } else { if (SearchStringMultiple(subject_vector, - *pattern, pattern->ToUC16Vector(), + *pattern, builder, &match_pos)) break; } @@ -2992,14 +2964,14 @@ static bool SearchStringMultiple(Handle<String> subject, Vector<const uc16> subject_vector = subject->ToUC16Vector(); if (pattern->IsAsciiRepresentation()) { if (SearchStringMultiple(subject_vector, - *pattern, pattern->ToAsciiVector(), + *pattern, builder, &match_pos)) break; } else { if (SearchStringMultiple(subject_vector, - *pattern, pattern->ToUC16Vector(), + *pattern, builder, &match_pos)) break; } @@ -4781,51 +4753,23 @@ static Object* Runtime_StringTrim(Arguments args) { } -// Define storage for buffers declared in header file. -// TODO(lrn): Remove these when rewriting search code. -int BMBuffers::bad_char_occurrence[kBMAlphabetSize]; -BMGoodSuffixBuffers BMBuffers::bmgs_buffers; - - -template <typename schar, typename pchar> -void FindStringIndices(Vector<const schar> subject, - Vector<const pchar> pattern, +template <typename SubjectChar, typename PatternChar> +void FindStringIndices(Vector<const SubjectChar> subject, + Vector<const PatternChar> pattern, ZoneList<int>* indices, unsigned int limit) { ASSERT(limit > 0); // Collect indices of pattern in subject, and the end-of-string index. // Stop after finding at most limit values. - StringSearchStrategy strategy = - InitializeStringSearch(pattern, sizeof(schar) == 1); - switch (strategy) { - case SEARCH_FAIL: return; - case SEARCH_SHORT: { - int pattern_length = pattern.length(); - int index = 0; - while (limit > 0) { - index = SimpleIndexOf(subject, pattern, index); - if (index < 0) return; - indices->Add(index); - index += pattern_length; - limit--; - } - return; - } - case SEARCH_LONG: { - int pattern_length = pattern.length(); - int index = 0; - while (limit > 0) { - index = ComplexIndexOf(subject, pattern, index); - if (index < 0) return; - indices->Add(index); - index += pattern_length; - limit--; - } - return; - } - default: - UNREACHABLE(); - return; + StringSearch<PatternChar, SubjectChar> search(pattern); + int pattern_length = pattern.length(); + int index = 0; + while (limit > 0) { + index = search.Search(subject, index); + if (index < 0) return; + indices->Add(index); + index += pattern_length; + limit--; } } @@ -6430,7 +6374,7 @@ static Object* Runtime_LazyCompile(Arguments args) { // this means that things called through constructors are never known to // be in loops. We compile them as if they are in loops here just in case. ASSERT(!function->is_compiled()); - if (!CompileLazyInLoop(function, Handle<Object>::null(), KEEP_EXCEPTION)) { + if (!CompileLazyInLoop(function, KEEP_EXCEPTION)) { return Failure::Exception(); } @@ -6759,7 +6703,7 @@ static Object* Runtime_StackOverflow(Arguments args) { static Object* Runtime_StackGuard(Arguments args) { - ASSERT(args.length() == 1); + ASSERT(args.length() == 0); // First check if this is a real stack overflow. if (StackGuard::IsStackOverflow()) { @@ -6801,7 +6745,7 @@ static void PrintObject(Object* obj) { } else if (obj->IsFalse()) { PrintF("<false>"); } else { - PrintF("%p", obj); + PrintF("%p", reinterpret_cast<void*>(obj)); } } @@ -7253,15 +7197,15 @@ static uint32_t IterateExternalArrayElements(Handle<JSObject> receiver, Handle<Smi> e(Smi::FromInt(static_cast<int>(val))); visitor->visit(j, e); } else { - Handle<Object> e( - Heap::AllocateHeapNumber(static_cast<ElementType>(val))); + Handle<Object> e = + Factory::NewNumber(static_cast<ElementType>(val)); visitor->visit(j, e); } } } } else { for (uint32_t j = 0; j < len; j++) { - Handle<Object> e(Heap::AllocateHeapNumber(array->get(j))); + Handle<Object> e = Factory::NewNumber(array->get(j)); visitor->visit(j, e); } } @@ -10209,7 +10153,7 @@ void Runtime::PerformGC(Object* result) { if (failure->IsRetryAfterGC()) { // Try to do a garbage collection; ignore it if it fails. The C // entry stub will throw an out-of-memory exception in that case. - Heap::CollectGarbage(failure->requested(), failure->allocation_space()); + Heap::CollectGarbage(failure->allocation_space()); } else { // Handle last resort GC and make sure to allow future allocations // to grow the heap without causing GCs (if possible). diff --git a/src/runtime.h b/src/runtime.h index 19f41441..2cd95c49 100644 --- a/src/runtime.h +++ b/src/runtime.h @@ -267,7 +267,7 @@ namespace internal { F(Throw, 1, 1) \ F(ReThrow, 1, 1) \ F(ThrowReferenceError, 1, 1) \ - F(StackGuard, 1, 1) \ + F(StackGuard, 0, 1) \ F(PromoteScheduledException, 0, 1) \ \ /* Contexts */ \ diff --git a/src/scopes.cc b/src/scopes.cc index c4436fe0..5ff250ff 100644 --- a/src/scopes.cc +++ b/src/scopes.cc @@ -1,4 +1,4 @@ -// Copyright 2006-2008 the V8 project authors. All rights reserved. +// 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: @@ -27,9 +27,12 @@ #include "v8.h" +#include "scopes.h" + +#include "bootstrapper.h" +#include "compiler.h" #include "prettyprinter.h" #include "scopeinfo.h" -#include "scopes.h" namespace v8 { namespace internal { @@ -168,6 +171,25 @@ Scope::Scope(Scope* outer_scope, Type type) } +bool Scope::Analyze(CompilationInfo* info) { + ASSERT(info->function() != NULL); + Scope* top = info->function()->scope(); + while (top->outer_scope() != NULL) top = top->outer_scope(); + top->AllocateVariables(info->calling_context()); + +#ifdef DEBUG + if (Bootstrapper::IsActive() + ? FLAG_print_builtin_scopes + : FLAG_print_scopes) { + info->function()->scope()->Print(); + } +#endif + + info->SetScope(info->function()->scope()); + return true; // Can not fail. +} + + void Scope::Initialize(bool inside_with) { // Add this scope as a new inner scope of the outer scope. if (outer_scope_ != NULL) { @@ -201,7 +223,6 @@ void Scope::Initialize(bool inside_with) { } - Variable* Scope::LocalLookup(Handle<String> name) { return variables_.Lookup(name); } diff --git a/src/scopes.h b/src/scopes.h index 68cf5e51..526c3d34 100644 --- a/src/scopes.h +++ b/src/scopes.h @@ -1,4 +1,4 @@ -// Copyright 2006-2008 the V8 project authors. All rights reserved. +// 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: @@ -34,6 +34,8 @@ namespace v8 { namespace internal { +class CompilationInfo; + // A hash map to support fast variable declaration and lookup. class VariableMap: public HashMap { @@ -97,11 +99,20 @@ class Scope: public ZoneObject { virtual ~Scope() { } + // Compute top scope and allocate variables. For lazy compilation the top + // scope only contains the single lazily compiled function, so this + // doesn't re-allocate variables repeatedly. + static bool Analyze(CompilationInfo* info); + // The scope name is only used for printing/debugging. void SetScopeName(Handle<String> scope_name) { scope_name_ = scope_name; } - void Initialize(bool inside_with); + virtual void Initialize(bool inside_with); + // Called just before leaving a scope. + virtual void Leave() { + // No cleanup or fixup necessary. + } // --------------------------------------------------------------------------- // Declarations @@ -272,7 +283,7 @@ class Scope: public ZoneObject { bool AllowsLazyCompilation() const; // True if the outer context of this scope is always the global context. - bool HasTrivialOuterContext() const; + virtual bool HasTrivialOuterContext() const; // The number of contexts between this and scope; zero if this == scope. int ContextChainLength(Scope* scope); @@ -378,20 +389,53 @@ class Scope: public ZoneObject { }; +// Scope used during pre-parsing. class DummyScope : public Scope { public: - DummyScope() : Scope(GLOBAL_SCOPE) { + DummyScope() + : Scope(GLOBAL_SCOPE), + nesting_level_(1), // Allows us to Leave the initial scope. + inside_with_level_(kNotInsideWith) { outer_scope_ = this; + scope_inside_with_ = false; } - virtual Variable* Lookup(Handle<String> name) { return NULL; } - virtual Variable* Declare(Handle<String> name, Variable::Mode mode) { - return NULL; + virtual void Initialize(bool inside_with) { + nesting_level_++; + if (inside_with && inside_with_level_ == kNotInsideWith) { + inside_with_level_ = nesting_level_; + } + ASSERT(inside_with_level_ <= nesting_level_); + } + + virtual void Leave() { + nesting_level_--; + ASSERT(nesting_level_ >= 0); + if (nesting_level_ < inside_with_level_) { + inside_with_level_ = kNotInsideWith; + } + ASSERT(inside_with_level_ <= nesting_level_); } + + virtual Variable* Lookup(Handle<String> name) { return NULL; } + virtual VariableProxy* NewUnresolved(Handle<String> name, bool inside_with) { return NULL; } + virtual VariableProxy* NewTemporary(Handle<String> name) { return NULL; } + + virtual bool HasTrivialOuterContext() const { + return (nesting_level_ == 0 || inside_with_level_ <= 0); + } + + private: + static const int kNotInsideWith = -1; + // Number of surrounding scopes of the current scope. + int nesting_level_; + // Nesting level of outermost scope that is contained in a with statement, + // or kNotInsideWith if there are no with's around the current scope. + int inside_with_level_; }; diff --git a/src/serialize.cc b/src/serialize.cc index cde7577c..ccba737d 100644 --- a/src/serialize.cc +++ b/src/serialize.cc @@ -500,7 +500,7 @@ void ExternalReferenceEncoder::Put(Address key, int index) { ExternalReferenceDecoder::ExternalReferenceDecoder() - : encodings_(NewArray<Address*>(kTypeCodeCount)) { + : encodings_(NewArray<Address*>(kTypeCodeCount)) { ExternalReferenceTable* external_references = ExternalReferenceTable::instance(); for (int type = kFirstTypeCode; type < kTypeCodeCount; ++type) { @@ -619,6 +619,8 @@ void Deserializer::Deserialize() { external_reference_decoder_ = new ExternalReferenceDecoder(); Heap::IterateStrongRoots(this, VISIT_ONLY_STRONG); Heap::IterateWeakRoots(this, VISIT_ALL); + + Heap::set_global_contexts_list(Heap::undefined_value()); } diff --git a/src/spaces-inl.h b/src/spaces-inl.h index fbb26732..8a0dd07c 100644 --- a/src/spaces-inl.h +++ b/src/spaces-inl.h @@ -407,8 +407,7 @@ void MemoryAllocator::UnprotectChunkFromPage(Page* page) { bool PagedSpace::Contains(Address addr) { Page* p = Page::FromAddress(addr); - ASSERT(p->is_valid()); - + if (!p->is_valid()) return false; return MemoryAllocator::IsPageInSpace(p, this); } @@ -440,7 +439,7 @@ Object* PagedSpace::AllocateRaw(int size_in_bytes) { object = SlowAllocateRaw(size_in_bytes); if (object != NULL) return object; - return Failure::RetryAfterGC(size_in_bytes, identity()); + return Failure::RetryAfterGC(identity()); } @@ -454,7 +453,7 @@ Object* PagedSpace::MCAllocateRaw(int size_in_bytes) { object = SlowMCAllocateRaw(size_in_bytes); if (object != NULL) return object; - return Failure::RetryAfterGC(size_in_bytes, identity()); + return Failure::RetryAfterGC(identity()); } @@ -475,7 +474,7 @@ HeapObject* LargeObjectChunk::GetObject() { Object* NewSpace::AllocateRawInternal(int size_in_bytes, AllocationInfo* alloc_info) { Address new_top = alloc_info->top + size_in_bytes; - if (new_top > alloc_info->limit) return Failure::RetryAfterGC(size_in_bytes); + if (new_top > alloc_info->limit) return Failure::RetryAfterGC(); Object* obj = HeapObject::FromAddress(alloc_info->top); alloc_info->top = new_top; diff --git a/src/spaces.cc b/src/spaces.cc index 3d2d42f0..5bdbcc78 100644 --- a/src/spaces.cc +++ b/src/spaces.cc @@ -270,9 +270,9 @@ void CodeRange::TearDown() { // ----------------------------------------------------------------------------- // MemoryAllocator // -int MemoryAllocator::capacity_ = 0; -int MemoryAllocator::size_ = 0; -int MemoryAllocator::size_executable_ = 0; +intptr_t MemoryAllocator::capacity_ = 0; +intptr_t MemoryAllocator::size_ = 0; +intptr_t MemoryAllocator::size_executable_ = 0; List<MemoryAllocator::MemoryAllocationCallbackRegistration> MemoryAllocator::memory_allocation_callbacks_; @@ -302,7 +302,7 @@ int MemoryAllocator::Pop() { } -bool MemoryAllocator::Setup(int capacity) { +bool MemoryAllocator::Setup(intptr_t capacity) { capacity_ = RoundUp(capacity, Page::kPageSize); // Over-estimate the size of chunks_ array. It assumes the expansion of old @@ -314,7 +314,8 @@ bool MemoryAllocator::Setup(int capacity) { // // Reserve two chunk ids for semispaces, one for map space, one for old // space, and one for code space. - max_nof_chunks_ = (capacity_ / (kChunkSize - Page::kPageSize)) + 5; + max_nof_chunks_ = + static_cast<int>((capacity_ / (kChunkSize - Page::kPageSize))) + 5; if (max_nof_chunks_ > kMaxNofChunks) return false; size_ = 0; @@ -691,7 +692,9 @@ Page* MemoryAllocator::FindLastPageInSameChunk(Page* p) { #ifdef DEBUG void MemoryAllocator::ReportStatistics() { float pct = static_cast<float>(capacity_ - size_) / capacity_; - PrintF(" capacity: %d, used: %d, available: %%%d\n\n", + PrintF(" capacity: %" V8_PTR_PREFIX "d" + ", used: %" V8_PTR_PREFIX "d" + ", available: %%%d\n\n", capacity_, size_, static_cast<int>(pct*100)); } #endif @@ -769,7 +772,7 @@ Page* MemoryAllocator::RelinkPagesInChunk(int chunk_id, // ----------------------------------------------------------------------------- // PagedSpace implementation -PagedSpace::PagedSpace(int max_capacity, +PagedSpace::PagedSpace(intptr_t max_capacity, AllocationSpace id, Executability executable) : Space(id, executable) { @@ -797,8 +800,9 @@ bool PagedSpace::Setup(Address start, size_t size) { Page::kPageSize * pages_in_chunk, this, &num_pages); } else { - int requested_pages = Min(MemoryAllocator::kPagesPerChunk, - max_capacity_ / Page::kObjectAreaSize); + int requested_pages = + Min(MemoryAllocator::kPagesPerChunk, + static_cast<int>(max_capacity_ / Page::kObjectAreaSize)); first_page_ = MemoryAllocator::AllocatePages(requested_pages, &num_pages, this); if (!first_page_->is_valid()) return false; @@ -984,7 +988,8 @@ bool PagedSpace::Expand(Page* last_page) { // Last page must be valid and its next page is invalid. ASSERT(last_page->is_valid() && !last_page->next_page()->is_valid()); - int available_pages = (max_capacity_ - Capacity()) / Page::kObjectAreaSize; + int available_pages = + static_cast<int>((max_capacity_ - Capacity()) / Page::kObjectAreaSize); if (available_pages <= 0) return false; int desired_pages = Min(available_pages, MemoryAllocator::kPagesPerChunk); @@ -1264,7 +1269,7 @@ void NewSpace::Grow() { void NewSpace::Shrink() { - int new_capacity = Max(InitialCapacity(), 2 * Size()); + int new_capacity = Max(InitialCapacity(), 2 * SizeAsInt()); int rounded_new_capacity = RoundUp(new_capacity, static_cast<int>(OS::AllocateAlignment())); if (rounded_new_capacity < Capacity() && @@ -1643,7 +1648,8 @@ void NewSpace::ReportStatistics() { #ifdef DEBUG if (FLAG_heap_stats) { float pct = static_cast<float>(Available()) / Capacity(); - PrintF(" capacity: %d, available: %d, %%%d\n", + PrintF(" capacity: %" V8_PTR_PREFIX "d" + ", available: %" V8_PTR_PREFIX "d, %%%d\n", Capacity(), Available(), static_cast<int>(pct*100)); PrintF("\n Object Histogram:\n"); for (int i = 0; i <= LAST_TYPE; i++) { @@ -1822,7 +1828,7 @@ Object* OldSpaceFreeList::Allocate(int size_in_bytes, int* wasted_bytes) { if (cur == kEnd) { // No large enough size in list. *wasted_bytes = 0; - return Failure::RetryAfterGC(size_in_bytes, owner_); + return Failure::RetryAfterGC(owner_); } ASSERT(!FLAG_always_compact); // We only use the freelists with mark-sweep. int rem = cur - index; @@ -1920,7 +1926,7 @@ void FixedSizeFreeList::Free(Address start) { Object* FixedSizeFreeList::Allocate() { if (head_ == NULL) { - return Failure::RetryAfterGC(object_size_, owner_); + return Failure::RetryAfterGC(owner_); } ASSERT(!FLAG_always_compact); // We only use the freelists with mark-sweep. @@ -2401,8 +2407,10 @@ void PagedSpace::CollectCodeStatistics() { void OldSpace::ReportStatistics() { - int pct = Available() * 100 / Capacity(); - PrintF(" capacity: %d, waste: %d, available: %d, %%%d\n", + int pct = static_cast<int>(Available() * 100 / Capacity()); + PrintF(" capacity: %" V8_PTR_PREFIX "d" + ", waste: %" V8_PTR_PREFIX "d" + ", available: %" V8_PTR_PREFIX "d, %%%d\n", Capacity(), Waste(), Available(), pct); ClearHistograms(); @@ -2558,8 +2566,10 @@ void FixedSpace::DeallocateBlock(Address start, #ifdef DEBUG void FixedSpace::ReportStatistics() { - int pct = Available() * 100 / Capacity(); - PrintF(" capacity: %d, waste: %d, available: %d, %%%d\n", + int pct = static_cast<int>(Available() * 100 / Capacity()); + PrintF(" capacity: %" V8_PTR_PREFIX "d" + ", waste: %" V8_PTR_PREFIX "d" + ", available: %" V8_PTR_PREFIX "d, %%%d\n", Capacity(), Waste(), Available(), pct); ClearHistograms(); @@ -2743,14 +2753,14 @@ Object* LargeObjectSpace::AllocateRawInternal(int requested_size, // Check if we want to force a GC before growing the old space further. // If so, fail the allocation. if (!Heap::always_allocate() && Heap::OldGenerationAllocationLimitReached()) { - return Failure::RetryAfterGC(requested_size, identity()); + return Failure::RetryAfterGC(identity()); } size_t chunk_size; LargeObjectChunk* chunk = LargeObjectChunk::New(requested_size, &chunk_size, executable); if (chunk == NULL) { - return Failure::RetryAfterGC(requested_size, identity()); + return Failure::RetryAfterGC(identity()); } size_ += static_cast<int>(chunk_size); @@ -3011,7 +3021,7 @@ void LargeObjectSpace::Print() { void LargeObjectSpace::ReportStatistics() { - PrintF(" size: %d\n", size_); + PrintF(" size: %" V8_PTR_PREFIX "d\n", size_); int num_objects = 0; ClearHistograms(); LargeObjectIterator it(this); diff --git a/src/spaces.h b/src/spaces.h index 94e0cd24..0e6a91e2 100644 --- a/src/spaces.h +++ b/src/spaces.h @@ -371,7 +371,7 @@ class Space : public Malloced { // Identity used in error reporting. AllocationSpace identity() { return id_; } - virtual int Size() = 0; + virtual intptr_t Size() = 0; #ifdef ENABLE_HEAP_PROTECTION // Protect/unprotect the space by marking it read-only/writable. @@ -491,7 +491,7 @@ class MemoryAllocator : public AllStatic { public: // Initializes its internal bookkeeping structures. // Max capacity of the total space. - static bool Setup(int max_capacity); + static bool Setup(intptr_t max_capacity); // Deletes valid chunks. static void TearDown(); @@ -582,16 +582,18 @@ class MemoryAllocator : public AllStatic { MemoryAllocationCallback callback); // Returns the maximum available bytes of heaps. - static int Available() { return capacity_ < size_ ? 0 : capacity_ - size_; } + static intptr_t Available() { + return capacity_ < size_ ? 0 : capacity_ - size_; + } // Returns allocated spaces in bytes. - static int Size() { return size_; } + static intptr_t Size() { return size_; } // Returns allocated executable spaces in bytes. - static int SizeExecutable() { return size_executable_; } + static intptr_t SizeExecutable() { return size_executable_; } // Returns maximum available bytes that the old space can have. - static int MaxAvailable() { + static intptr_t MaxAvailable() { return (Available() / Page::kPageSize) * Page::kObjectAreaSize; } @@ -649,12 +651,12 @@ class MemoryAllocator : public AllStatic { private: // Maximum space size in bytes. - static int capacity_; + static intptr_t capacity_; // Allocated space size in bytes. - static int size_; + static intptr_t size_; // Allocated executable space size in bytes. - static int size_executable_; + static intptr_t size_executable_; struct MemoryAllocationCallbackRegistration { MemoryAllocationCallbackRegistration(MemoryAllocationCallback callback, @@ -927,10 +929,10 @@ class AllocationStats BASE_EMBEDDED { } // Accessors for the allocation statistics. - int Capacity() { return capacity_; } - int Available() { return available_; } - int Size() { return size_; } - int Waste() { return waste_; } + intptr_t Capacity() { return capacity_; } + intptr_t Available() { return available_; } + intptr_t Size() { return size_; } + intptr_t Waste() { return waste_; } // Grow the space by adding available bytes. void ExpandSpace(int size_in_bytes) { @@ -945,13 +947,13 @@ class AllocationStats BASE_EMBEDDED { } // Allocate from available bytes (available -> size). - void AllocateBytes(int size_in_bytes) { + void AllocateBytes(intptr_t size_in_bytes) { available_ -= size_in_bytes; size_ += size_in_bytes; } // Free allocated bytes, making them available (size -> available). - void DeallocateBytes(int size_in_bytes) { + void DeallocateBytes(intptr_t size_in_bytes) { size_ -= size_in_bytes; available_ += size_in_bytes; } @@ -964,23 +966,25 @@ class AllocationStats BASE_EMBEDDED { // Consider the wasted bytes to be allocated, as they contain filler // objects (waste -> size). - void FillWastedBytes(int size_in_bytes) { + void FillWastedBytes(intptr_t size_in_bytes) { waste_ -= size_in_bytes; size_ += size_in_bytes; } private: - int capacity_; - int available_; - int size_; - int waste_; + intptr_t capacity_; + intptr_t available_; + intptr_t size_; + intptr_t waste_; }; class PagedSpace : public Space { public: // Creates a space with a maximum capacity, and an id. - PagedSpace(int max_capacity, AllocationSpace id, Executability executable); + PagedSpace(intptr_t max_capacity, + AllocationSpace id, + Executability executable); virtual ~PagedSpace() {} @@ -1031,21 +1035,21 @@ class PagedSpace : public Space { } // Current capacity without growing (Size() + Available() + Waste()). - int Capacity() { return accounting_stats_.Capacity(); } + intptr_t Capacity() { return accounting_stats_.Capacity(); } // Total amount of memory committed for this space. For paged // spaces this equals the capacity. - int CommittedMemory() { return Capacity(); } + intptr_t CommittedMemory() { return Capacity(); } // Available bytes without growing. - int Available() { return accounting_stats_.Available(); } + intptr_t Available() { return accounting_stats_.Available(); } // Allocated bytes in this space. - virtual int Size() { return accounting_stats_.Size(); } + virtual intptr_t Size() { return accounting_stats_.Size(); } // Wasted bytes due to fragmentation and not recoverable until the // next GC of this space. - int Waste() { return accounting_stats_.Waste(); } + intptr_t Waste() { return accounting_stats_.Waste(); } // Returns the address of the first object in this space. Address bottom() { return first_page_->ObjectAreaStart(); } @@ -1137,7 +1141,7 @@ class PagedSpace : public Space { protected: // Maximum capacity of this space. - int max_capacity_; + intptr_t max_capacity_; // Accounting information for this space. AllocationStats accounting_stats_; @@ -1328,7 +1332,7 @@ class SemiSpace : public Space { // If we don't have these here then SemiSpace will be abstract. However // they should never be called. - virtual int Size() { + virtual intptr_t Size() { UNREACHABLE(); return 0; } @@ -1471,22 +1475,26 @@ class NewSpace : public Space { } // Return the allocated bytes in the active semispace. - virtual int Size() { return static_cast<int>(top() - bottom()); } + virtual intptr_t Size() { return static_cast<int>(top() - bottom()); } + // The same, but returning an int. We have to have the one that returns + // intptr_t because it is inherited, but if we know we are dealing with the + // new space, which can't get as big as the other spaces then this is useful: + int SizeAsInt() { return static_cast<int>(Size()); } // Return the current capacity of a semispace. - int Capacity() { + intptr_t Capacity() { ASSERT(to_space_.Capacity() == from_space_.Capacity()); return to_space_.Capacity(); } // Return the total amount of memory committed for new space. - int CommittedMemory() { + intptr_t CommittedMemory() { if (from_space_.is_committed()) return 2 * Capacity(); return Capacity(); } // Return the available bytes without growing in the active semispace. - int Available() { return Capacity() - Size(); } + intptr_t Available() { return Capacity() - Size(); } // Return the maximum capacity of a semispace. int MaximumCapacity() { @@ -1681,7 +1689,7 @@ class OldSpaceFreeList BASE_EMBEDDED { void Reset(); // Return the number of bytes available on the free list. - int available() { return available_; } + intptr_t available() { return available_; } // Place a node on the free list. The block of size 'size_in_bytes' // starting at 'start' is placed on the free list. The return value is the @@ -1783,7 +1791,7 @@ class FixedSizeFreeList BASE_EMBEDDED { void Reset(); // Return the number of bytes available on the free list. - int available() { return available_; } + intptr_t available() { return available_; } // Place a node on the free list. The block starting at 'start' (assumed to // have size object_size_) is placed on the free list. Bookkeeping @@ -1797,7 +1805,7 @@ class FixedSizeFreeList BASE_EMBEDDED { private: // Available bytes on the free list. - int available_; + intptr_t available_; // The head of the free list. Address head_; @@ -1823,7 +1831,7 @@ class OldSpace : public PagedSpace { public: // Creates an old space object with a given maximum capacity. // The constructor does not allocate pages from OS. - explicit OldSpace(int max_capacity, + explicit OldSpace(intptr_t max_capacity, AllocationSpace id, Executability executable) : PagedSpace(max_capacity, id, executable), free_list_(id) { @@ -1832,7 +1840,7 @@ class OldSpace : public PagedSpace { // The bytes available on the free list (ie, not above the linear allocation // pointer). - int AvailableFree() { return free_list_.available(); } + intptr_t AvailableFree() { return free_list_.available(); } // The limit of allocation for a page in this space. virtual Address PageAllocationLimit(Page* page) { @@ -1893,7 +1901,7 @@ class OldSpace : public PagedSpace { class FixedSpace : public PagedSpace { public: - FixedSpace(int max_capacity, + FixedSpace(intptr_t max_capacity, AllocationSpace id, int object_size_in_bytes, const char* name) @@ -1968,7 +1976,7 @@ class FixedSpace : public PagedSpace { class MapSpace : public FixedSpace { public: // Creates a map space object with a maximum capacity. - MapSpace(int max_capacity, int max_map_space_pages, AllocationSpace id) + MapSpace(intptr_t max_capacity, int max_map_space_pages, AllocationSpace id) : FixedSpace(max_capacity, id, Map::kSize, "map"), max_map_space_pages_(max_map_space_pages) { ASSERT(max_map_space_pages < kMaxMapPageIndex); @@ -2073,7 +2081,7 @@ class MapSpace : public FixedSpace { class CellSpace : public FixedSpace { public: // Creates a property cell space object with a maximum capacity. - CellSpace(int max_capacity, AllocationSpace id) + CellSpace(intptr_t max_capacity, AllocationSpace id) : FixedSpace(max_capacity, id, JSGlobalPropertyCell::kSize, "cell") {} protected: @@ -2129,7 +2137,7 @@ class LargeObjectChunk { // Given a chunk size, returns the object size it can accommodate. Used by // LargeObjectSpace::Available. - static int ObjectSizeFor(int chunk_size) { + static intptr_t ObjectSizeFor(intptr_t chunk_size) { if (chunk_size <= (Page::kPageSize + Page::kObjectStartOffset)) return 0; return chunk_size - Page::kPageSize - Page::kObjectStartOffset; } @@ -2165,11 +2173,11 @@ class LargeObjectSpace : public Space { Object* AllocateRawFixedArray(int size_in_bytes); // Available bytes for objects in this space. - int Available() { + intptr_t Available() { return LargeObjectChunk::ObjectSizeFor(MemoryAllocator::Available()); } - virtual int Size() { + virtual intptr_t Size() { return size_; } @@ -2186,7 +2194,6 @@ class LargeObjectSpace : public Space { // if such a page doesn't exist. LargeObjectChunk* FindChunkContainingPc(Address pc); - // Iterates objects covered by dirty regions. void IterateDirtyRegions(ObjectSlotCallback func); @@ -2223,7 +2230,7 @@ class LargeObjectSpace : public Space { private: // The head of the linked list of large object chunks. LargeObjectChunk* first_chunk_; - int size_; // allocated bytes + intptr_t size_; // allocated bytes int page_count_; // number of chunks diff --git a/src/string-search.cc b/src/string-search.cc new file mode 100644 index 00000000..56874432 --- /dev/null +++ b/src/string-search.cc @@ -0,0 +1,40 @@ +// 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. + +#include "v8.h" +#include "string-search.h" + +namespace v8 { +namespace internal { + +// Storage for constants used by string-search. + +int StringSearchBase::kBadCharShiftTable[kUC16AlphabetSize]; +int StringSearchBase::kGoodSuffixShiftTable[kBMMaxShift + 1]; +int StringSearchBase::kSuffixTable[kBMMaxShift + 1]; + +}} // namespace v8::internal diff --git a/src/string-search.h b/src/string-search.h index d7959c0b..eac84757 100644 --- a/src/string-search.h +++ b/src/string-search.h @@ -32,278 +32,484 @@ namespace v8 { namespace internal { -// Cap on the maximal shift in the Boyer-Moore implementation. By setting a -// limit, we can fix the size of tables. For a needle longer than this limit, -// search will not be optimal, since we only build tables for a smaller suffix -// of the string, which is a safe approximation. -static const int kBMMaxShift = 250; -// Reduce alphabet to this size. -// One of the tables used by Boyer-Moore and Boyer-Moore-Horspool has size -// proportional to the input alphabet. We reduce the alphabet size by -// equating input characters modulo a smaller alphabet size. This gives -// a potentially less efficient searching, but is a safe approximation. -// For needles using only characters in the same Unicode 256-code point page, -// there is no search speed degradation. -static const int kBMAlphabetSize = 256; -// For patterns below this length, the skip length of Boyer-Moore is too short -// to compensate for the algorithmic overhead compared to simple brute force. -static const int kBMMinPatternLength = 7; - -// Holds the two buffers used by Boyer-Moore string search's Good Suffix -// shift. Only allows the last kBMMaxShift characters of the needle -// to be indexed. -class BMGoodSuffixBuffers { +//--------------------------------------------------------------------- +// String Search object. +//--------------------------------------------------------------------- + +// Class holding constants and methods that apply to all string search variants, +// independently of subject and pattern char size. +class StringSearchBase { + protected: + // Cap on the maximal shift in the Boyer-Moore implementation. By setting a + // limit, we can fix the size of tables. For a needle longer than this limit, + // search will not be optimal, since we only build tables for a suffix + // of the string, but it is a safe approximation. + static const int kBMMaxShift = 250; + + // Reduce alphabet to this size. + // One of the tables used by Boyer-Moore and Boyer-Moore-Horspool has size + // proportional to the input alphabet. We reduce the alphabet size by + // equating input characters modulo a smaller alphabet size. This gives + // a potentially less efficient searching, but is a safe approximation. + // For needles using only characters in the same Unicode 256-code point page, + // there is no search speed degradation. + static const int kAsciiAlphabetSize = 128; + static const int kUC16AlphabetSize = 256; + + // Bad-char shift table stored in the state. It's length is the alphabet size. + // For patterns below this length, the skip length of Boyer-Moore is too short + // to compensate for the algorithmic overhead compared to simple brute force. + static const int kBMMinPatternLength = 7; + + static inline bool IsAsciiString(Vector<const char>) { + return true; + } + + static inline bool IsAsciiString(Vector<const uc16> string) { + for (int i = 0, n = string.length(); i < n; i++) { + if (static_cast<unsigned>(string[i]) > String::kMaxAsciiCharCodeU) { + return false; + } + } + return true; + } + + // The following tables are shared by all searches. + // TODO(lrn): Introduce a way for a pattern to keep its tables + // between searches (e.g., for an Atom RegExp). + + // Store for the BoyerMoore(Horspool) bad char shift table. + static int kBadCharShiftTable[kUC16AlphabetSize]; + // Store for the BoyerMoore good suffix shift table. + static int kGoodSuffixShiftTable[kBMMaxShift + 1]; + // Table used temporarily while building the BoyerMoore good suffix + // shift table. + static int kSuffixTable[kBMMaxShift + 1]; +}; + + +template <typename PatternChar, typename SubjectChar> +class StringSearch : private StringSearchBase { public: - BMGoodSuffixBuffers() {} - inline void Initialize(int needle_length) { - ASSERT(needle_length > 1); - int start = needle_length < kBMMaxShift ? 0 : needle_length - kBMMaxShift; - int len = needle_length - start; - biased_suffixes_ = suffixes_ - start; - biased_good_suffix_shift_ = good_suffix_shift_ - start; - for (int i = 0; i <= len; i++) { - good_suffix_shift_[i] = len; + explicit StringSearch(Vector<const PatternChar> pattern) + : pattern_(pattern), + start_(Max(0, pattern.length() - kBMMaxShift)) { + if (sizeof(PatternChar) > sizeof(SubjectChar)) { + if (!IsAsciiString(pattern_)) { + strategy_ = &FailSearch; + return; + } + } + int pattern_length = pattern_.length(); + if (pattern_length < kBMMinPatternLength) { + if (pattern_length == 1) { + strategy_ = &SingleCharSearch; + return; + } + strategy_ = &LinearSearch; + return; } + strategy_ = &InitialSearch; } - inline int& suffix(int index) { - ASSERT(biased_suffixes_ + index >= suffixes_); - return biased_suffixes_[index]; + + int Search(Vector<const SubjectChar> subject, int index) { + return strategy_(this, subject, index); } - inline int& shift(int index) { - ASSERT(biased_good_suffix_shift_ + index >= good_suffix_shift_); - return biased_good_suffix_shift_[index]; + + static inline int AlphabetSize() { + if (sizeof(PatternChar) == 1) { + // ASCII needle. + return kAsciiAlphabetSize; + } else { + ASSERT(sizeof(PatternChar) == 2); + // UC16 needle. + return kUC16AlphabetSize; + } } + private: - int suffixes_[kBMMaxShift + 1]; - int good_suffix_shift_[kBMMaxShift + 1]; - int* biased_suffixes_; - int* biased_good_suffix_shift_; - DISALLOW_COPY_AND_ASSIGN(BMGoodSuffixBuffers); -}; + typedef int (*SearchFunction)( // NOLINT - it's not a cast! + StringSearch<PatternChar, SubjectChar>*, + Vector<const SubjectChar>, + int); + + static int FailSearch(StringSearch<PatternChar, SubjectChar>*, + Vector<const SubjectChar>, + int) { + return -1; + } -// buffers reused by BoyerMoore -struct BMBuffers { - public: - static int bad_char_occurrence[kBMAlphabetSize]; - static BMGoodSuffixBuffers bmgs_buffers; + static int SingleCharSearch(StringSearch<PatternChar, SubjectChar>* search, + Vector<const SubjectChar> subject, + int start_index); + + static int LinearSearch(StringSearch<PatternChar, SubjectChar>* search, + Vector<const SubjectChar> subject, + int start_index); + + static int InitialSearch(StringSearch<PatternChar, SubjectChar>* search, + Vector<const SubjectChar> subject, + int start_index); + + static int BoyerMooreHorspoolSearch( + StringSearch<PatternChar, SubjectChar>* search, + Vector<const SubjectChar> subject, + int start_index); + + static int BoyerMooreSearch(StringSearch<PatternChar, SubjectChar>* search, + Vector<const SubjectChar> subject, + int start_index); + + void PopulateBoyerMooreHorspoolTable(); + + void PopulateBoyerMooreTable(); + + static inline int CharOccurrence(int* bad_char_occurrence, + SubjectChar char_code) { + if (sizeof(SubjectChar) == 1) { + return bad_char_occurrence[static_cast<int>(char_code)]; + } + if (sizeof(PatternChar) == 1) { + if (static_cast<unsigned int>(char_code) > String::kMaxAsciiCharCodeU) { + return -1; + } + return bad_char_occurrence[static_cast<unsigned int>(char_code)]; + } + // Both pattern and subject are UC16. Reduce character to equivalence class. + int equiv_class = char_code % kUC16AlphabetSize; + return bad_char_occurrence[equiv_class]; + } + + // Return a table covering the last kBMMaxShift+1 positions of + // pattern. + int* bad_char_table() { + return kBadCharShiftTable; + } + + int* good_suffix_shift_table() { + // Return biased pointer that maps the range [start_..pattern_.length() + // to the kGoodSuffixShiftTable array. + return kGoodSuffixShiftTable - start_; + } + + int* suffix_table() { + // Return biased pointer that maps the range [start_..pattern_.length() + // to the kSuffixTable array. + return kSuffixTable - start_; + } + + // The pattern to search for. + Vector<const PatternChar> pattern_; + // Pointer to implementation of the search. + SearchFunction strategy_; + // Cache value of Max(0, pattern_length() - kBMMaxShift) + int start_; }; -// State of the string match tables. -// SIMPLE: No usable content in the buffers. -// BOYER_MOORE_HORSPOOL: The bad_char_occurence table has been populated. -// BOYER_MOORE: The bmgs_buffers tables have also been populated. -// Whenever starting with a new needle, one should call InitializeStringSearch -// to determine which search strategy to use, and in the case of a long-needle -// strategy, the call also initializes the algorithm to SIMPLE. -enum StringSearchAlgorithm { SIMPLE_SEARCH, BOYER_MOORE_HORSPOOL, BOYER_MOORE }; -static StringSearchAlgorithm algorithm; +//--------------------------------------------------------------------- +// Single Character Pattern Search Strategy +//--------------------------------------------------------------------- -// Compute the bad-char table for Boyer-Moore in the static buffer. -template <typename PatternChar> -static void BoyerMoorePopulateBadCharTable(Vector<const PatternChar> pattern) { - // Only preprocess at most kBMMaxShift last characters of pattern. - int start = Max(pattern.length() - kBMMaxShift, 0); - // Run forwards to populate bad_char_table, so that *last* instance - // of character equivalence class is the one registered. - // Notice: Doesn't include the last character. - int table_size = (sizeof(PatternChar) == 1) ? String::kMaxAsciiCharCode + 1 - : kBMAlphabetSize; - if (start == 0) { // All patterns less than kBMMaxShift in length. - memset(BMBuffers::bad_char_occurrence, - -1, - table_size * sizeof(*BMBuffers::bad_char_occurrence)); +template <typename PatternChar, typename SubjectChar> +int StringSearch<PatternChar, SubjectChar>::SingleCharSearch( + StringSearch<PatternChar, SubjectChar>* search, + Vector<const SubjectChar> subject, + int index) { + ASSERT_EQ(1, search->pattern_.length()); + PatternChar pattern_first_char = search->pattern_[0]; + int i = index; + if (sizeof(SubjectChar) == 1 && sizeof(PatternChar) == 1) { + const SubjectChar* pos = reinterpret_cast<const SubjectChar*>( + memchr(subject.start() + i, + pattern_first_char, + subject.length() - i)); + if (pos == NULL) return -1; + return static_cast<int>(pos - subject.start()); } else { - for (int i = 0; i < table_size; i++) { - BMBuffers::bad_char_occurrence[i] = start - 1; + if (sizeof(PatternChar) > sizeof(SubjectChar)) { + if (static_cast<uc16>(pattern_first_char) > String::kMaxAsciiCharCodeU) { + return -1; + } } + SubjectChar search_char = static_cast<SubjectChar>(pattern_first_char); + int n = subject.length(); + while (i < n) { + if (subject[i++] == search_char) return i - 1; + } + return -1; } - for (int i = start; i < pattern.length() - 1; i++) { - PatternChar c = pattern[i]; - int bucket = (sizeof(PatternChar) ==1) ? c : c % kBMAlphabetSize; - BMBuffers::bad_char_occurrence[bucket] = i; +} + +//--------------------------------------------------------------------- +// Linear Search Strategy +//--------------------------------------------------------------------- + + +template <typename PatternChar, typename SubjectChar> +static inline bool CharCompare(const PatternChar* pattern, + const SubjectChar* subject, + int length) { + ASSERT(length > 0); + int pos = 0; + do { + if (pattern[pos] != subject[pos]) { + return false; + } + pos++; + } while (pos < length); + return true; +} + + +// Simple linear search for short patterns. Never bails out. +template <typename PatternChar, typename SubjectChar> +int StringSearch<PatternChar, SubjectChar>::LinearSearch( + StringSearch<PatternChar, SubjectChar>* search, + Vector<const SubjectChar> subject, + int index) { + Vector<const PatternChar> pattern = search->pattern_; + ASSERT(pattern.length() > 1); + int pattern_length = pattern.length(); + PatternChar pattern_first_char = pattern[0]; + int i = index; + int n = subject.length() - pattern_length; + while (i <= n) { + if (sizeof(SubjectChar) == 1 && sizeof(PatternChar) == 1) { + const SubjectChar* pos = reinterpret_cast<const SubjectChar*>( + memchr(subject.start() + i, + pattern_first_char, + n - i + 1)); + if (pos == NULL) return -1; + i = static_cast<int>(pos - subject.start()) + 1; + } else { + if (subject[i++] != pattern_first_char) continue; + } + // Loop extracted to separate function to allow using return to do + // a deeper break. + if (CharCompare(pattern.start() + 1, + subject.start() + i, + pattern_length - 1)) { + return i - 1; + } + } + return -1; +} + +//--------------------------------------------------------------------- +// Boyer-Moore string search +//--------------------------------------------------------------------- + +template <typename PatternChar, typename SubjectChar> +int StringSearch<PatternChar, SubjectChar>::BoyerMooreSearch( + StringSearch<PatternChar, SubjectChar>* search, + Vector<const SubjectChar> subject, + int start_index) { + Vector<const PatternChar> pattern = search->pattern_; + int subject_length = subject.length(); + int pattern_length = pattern.length(); + // Only preprocess at most kBMMaxShift last characters of pattern. + int start = search->start_; + + int* bad_char_occurence = search->bad_char_table(); + int* good_suffix_shift = search->good_suffix_shift_table(); + + PatternChar last_char = pattern[pattern_length - 1]; + int index = start_index; + // Continue search from i. + while (index <= subject_length - pattern_length) { + int j = pattern_length - 1; + int c; + while (last_char != (c = subject[index + j])) { + int shift = + j - CharOccurrence(bad_char_occurence, c); + index += shift; + if (index > subject_length - pattern_length) { + return -1; + } + } + while (j >= 0 && pattern[j] == (c = subject[index + j])) j--; + if (j < 0) { + return index; + } else if (j < start) { + // we have matched more than our tables allow us to be smart about. + // Fall back on BMH shift. + index += pattern_length - 1 + - CharOccurrence(bad_char_occurence, + static_cast<SubjectChar>(last_char)); + } else { + int gs_shift = good_suffix_shift[j + 1]; + int bc_occ = + CharOccurrence(bad_char_occurence, c); + int shift = j - bc_occ; + if (gs_shift > shift) { + shift = gs_shift; + } + index += shift; + } } + + return -1; } -template <typename PatternChar> -static void BoyerMoorePopulateGoodSuffixTable( - Vector<const PatternChar> pattern) { - int m = pattern.length(); - int start = m < kBMMaxShift ? 0 : m - kBMMaxShift; - int len = m - start; - // Compute Good Suffix tables. - BMBuffers::bmgs_buffers.Initialize(m); +template <typename PatternChar, typename SubjectChar> +void StringSearch<PatternChar, SubjectChar>::PopulateBoyerMooreTable() { + int pattern_length = pattern_.length(); + const PatternChar* pattern = pattern_.start(); + // Only look at the last kBMMaxShift characters of pattern (from start_ + // to pattern_length). + int start = start_; + int length = pattern_length - start; + + // Biased tables so that we can use pattern indices as table indices, + // even if we only cover the part of the pattern from offset start. + int* shift_table = good_suffix_shift_table(); + int* suffix_table = this->suffix_table(); + + // Initialize table. + for (int i = start; i < pattern_length; i++) { + shift_table[i] = length; + } + shift_table[pattern_length] = 1; + suffix_table[pattern_length] = pattern_length + 1; - BMBuffers::bmgs_buffers.shift(m-1) = 1; - BMBuffers::bmgs_buffers.suffix(m) = m + 1; - PatternChar last_char = pattern[m - 1]; - int suffix = m + 1; + // Find suffixes. + PatternChar last_char = pattern[pattern_length - 1]; + int suffix = pattern_length + 1; { - int i = m; + int i = pattern_length; while (i > start) { PatternChar c = pattern[i - 1]; - while (suffix <= m && c != pattern[suffix - 1]) { - if (BMBuffers::bmgs_buffers.shift(suffix) == len) { - BMBuffers::bmgs_buffers.shift(suffix) = suffix - i; + while (suffix <= pattern_length && c != pattern[suffix - 1]) { + if (shift_table[suffix] == length) { + shift_table[suffix] = suffix - i; } - suffix = BMBuffers::bmgs_buffers.suffix(suffix); + suffix = suffix_table[suffix]; } - BMBuffers::bmgs_buffers.suffix(--i) = --suffix; - if (suffix == m) { + suffix_table[--i] = --suffix; + if (suffix == pattern_length) { // No suffix to extend, so we check against last_char only. while ((i > start) && (pattern[i - 1] != last_char)) { - if (BMBuffers::bmgs_buffers.shift(m) == len) { - BMBuffers::bmgs_buffers.shift(m) = m - i; + if (shift_table[pattern_length] == length) { + shift_table[pattern_length] = pattern_length - i; } - BMBuffers::bmgs_buffers.suffix(--i) = m; + suffix_table[--i] = pattern_length; } if (i > start) { - BMBuffers::bmgs_buffers.suffix(--i) = --suffix; + suffix_table[--i] = --suffix; } } } } - if (suffix < m) { - for (int i = start; i <= m; i++) { - if (BMBuffers::bmgs_buffers.shift(i) == len) { - BMBuffers::bmgs_buffers.shift(i) = suffix - start; + // Build shift table using suffixes. + if (suffix < pattern_length) { + for (int i = start; i <= pattern_length; i++) { + if (shift_table[i] == length) { + shift_table[i] = suffix - start; } if (i == suffix) { - suffix = BMBuffers::bmgs_buffers.suffix(suffix); + suffix = suffix_table[suffix]; } } } } +//--------------------------------------------------------------------- +// Boyer-Moore-Horspool string search. +//--------------------------------------------------------------------- -template <typename SubjectChar, typename PatternChar> -static inline int CharOccurrence(int char_code) { - if (sizeof(SubjectChar) == 1) { - return BMBuffers::bad_char_occurrence[char_code]; - } - if (sizeof(PatternChar) == 1) { - if (char_code > String::kMaxAsciiCharCode) { - return -1; - } - return BMBuffers::bad_char_occurrence[char_code]; - } - return BMBuffers::bad_char_occurrence[char_code % kBMAlphabetSize]; -} - - -// Restricted simplified Boyer-Moore string matching. -// Uses only the bad-shift table of Boyer-Moore and only uses it -// for the character compared to the last character of the needle. -template <typename SubjectChar, typename PatternChar> -static int BoyerMooreHorspool(Vector<const SubjectChar> subject, - Vector<const PatternChar> pattern, - int start_index, - bool* complete) { - ASSERT(algorithm <= BOYER_MOORE_HORSPOOL); - int n = subject.length(); - int m = pattern.length(); - - int badness = -m; +template <typename PatternChar, typename SubjectChar> +int StringSearch<PatternChar, SubjectChar>::BoyerMooreHorspoolSearch( + StringSearch<PatternChar, SubjectChar>* search, + Vector<const SubjectChar> subject, + int start_index) { + Vector<const PatternChar> pattern = search->pattern_; + int subject_length = subject.length(); + int pattern_length = pattern.length(); + int* char_occurrences = search->bad_char_table(); + int badness = -pattern_length; // How bad we are doing without a good-suffix table. - int idx; // No matches found prior to this index. - PatternChar last_char = pattern[m - 1]; - int last_char_shift = - m - 1 - CharOccurrence<SubjectChar, PatternChar>(last_char); + PatternChar last_char = pattern[pattern_length - 1]; + int last_char_shift = pattern_length - 1 - + CharOccurrence(char_occurrences, static_cast<SubjectChar>(last_char)); // Perform search - for (idx = start_index; idx <= n - m;) { - int j = m - 1; - int c; - while (last_char != (c = subject[idx + j])) { - int bc_occ = CharOccurrence<SubjectChar, PatternChar>(c); + int index = start_index; // No matches found prior to this index. + while (index <= subject_length - pattern_length) { + int j = pattern_length - 1; + int subject_char; + while (last_char != (subject_char = subject[index + j])) { + int bc_occ = CharOccurrence(char_occurrences, subject_char); int shift = j - bc_occ; - idx += shift; + index += shift; badness += 1 - shift; // at most zero, so badness cannot increase. - if (idx > n - m) { - *complete = true; + if (index > subject_length - pattern_length) { return -1; } } j--; - while (j >= 0 && pattern[j] == (subject[idx + j])) j--; + while (j >= 0 && pattern[j] == (subject[index + j])) j--; if (j < 0) { - *complete = true; - return idx; + return index; } else { - idx += last_char_shift; + index += last_char_shift; // Badness increases by the number of characters we have // checked, and decreases by the number of characters we // can skip by shifting. It's a measure of how we are doing // compared to reading each character exactly once. - badness += (m - j) - last_char_shift; + badness += (pattern_length - j) - last_char_shift; if (badness > 0) { - *complete = false; - return idx; + search->PopulateBoyerMooreTable(); + search->strategy_ = &BoyerMooreSearch; + return BoyerMooreSearch(search, subject, index); } } } - *complete = true; return -1; } -template <typename SubjectChar, typename PatternChar> -static int BoyerMooreIndexOf(Vector<const SubjectChar> subject, - Vector<const PatternChar> pattern, - int idx) { - ASSERT(algorithm <= BOYER_MOORE); - int n = subject.length(); - int m = pattern.length(); - // Only preprocess at most kBMMaxShift last characters of pattern. - int start = m < kBMMaxShift ? 0 : m - kBMMaxShift; +template <typename PatternChar, typename SubjectChar> +void StringSearch<PatternChar, SubjectChar>::PopulateBoyerMooreHorspoolTable() { + int pattern_length = pattern_.length(); - PatternChar last_char = pattern[m - 1]; - // Continue search from i. - while (idx <= n - m) { - int j = m - 1; - SubjectChar c; - while (last_char != (c = subject[idx + j])) { - int shift = j - CharOccurrence<SubjectChar, PatternChar>(c); - idx += shift; - if (idx > n - m) { - return -1; - } - } - while (j >= 0 && pattern[j] == (c = subject[idx + j])) j--; - if (j < 0) { - return idx; - } else if (j < start) { - // we have matched more than our tables allow us to be smart about. - // Fall back on BMH shift. - idx += m - 1 - CharOccurrence<SubjectChar, PatternChar>(last_char); - } else { - int gs_shift = BMBuffers::bmgs_buffers.shift(j + 1); - int bc_occ = CharOccurrence<SubjectChar, PatternChar>(c); - int shift = j - bc_occ; - if (gs_shift > shift) { - shift = gs_shift; - } - idx += shift; + int* bad_char_occurrence = bad_char_table(); + + // Only preprocess at most kBMMaxShift last characters of pattern. + int start = start_; + // Run forwards to populate bad_char_table, so that *last* instance + // of character equivalence class is the one registered. + // Notice: Doesn't include the last character. + int table_size = AlphabetSize(); + if (start == 0) { // All patterns less than kBMMaxShift in length. + memset(bad_char_occurrence, + -1, + table_size * sizeof(*bad_char_occurrence)); + } else { + for (int i = 0; i < table_size; i++) { + bad_char_occurrence[i] = start - 1; } } - - return -1; + for (int i = start; i < pattern_length - 1; i++) { + PatternChar c = pattern_[i]; + int bucket = (sizeof(PatternChar) == 1) ? c : c % AlphabetSize(); + bad_char_occurrence[bucket] = i; + } } +//--------------------------------------------------------------------- +// Linear string search with bailout to BMH. +//--------------------------------------------------------------------- -// Trivial string search for shorter strings. -// On return, if "complete" is set to true, the return value is the -// final result of searching for the patter in the subject. -// If "complete" is set to false, the return value is the index where -// further checking should start, i.e., it's guaranteed that the pattern -// does not occur at a position prior to the returned index. +// Simple linear search for short patterns, which bails out if the string +// isn't found very early in the subject. Upgrades to BoyerMooreHorspool. template <typename PatternChar, typename SubjectChar> -static int SimpleIndexOf(Vector<const SubjectChar> subject, - Vector<const PatternChar> pattern, - int idx, - bool* complete) { - ASSERT(pattern.length() > 1); +int StringSearch<PatternChar, SubjectChar>::InitialSearch( + StringSearch<PatternChar, SubjectChar>* search, + Vector<const SubjectChar> subject, + int index) { + Vector<const PatternChar> pattern = search->pattern_; int pattern_length = pattern.length(); // Badness is a count of how much work we have done. When we have // done enough work we decide it's probably worth switching to a better @@ -313,149 +519,52 @@ static int SimpleIndexOf(Vector<const SubjectChar> subject, // We know our pattern is at least 2 characters, we cache the first so // the common case of the first character not matching is faster. PatternChar pattern_first_char = pattern[0]; - for (int i = idx, n = subject.length() - pattern_length; i <= n; i++) { + for (int i = index, n = subject.length() - pattern_length; i <= n; i++) { badness++; - if (badness > 0) { - *complete = false; - return i; - } - if (sizeof(SubjectChar) == 1 && sizeof(PatternChar) == 1) { - const SubjectChar* pos = reinterpret_cast<const SubjectChar*>( - memchr(subject.start() + i, - pattern_first_char, - n - i + 1)); - if (pos == NULL) { - *complete = true; - return -1; + if (badness <= 0) { + if (sizeof(SubjectChar) == 1 && sizeof(PatternChar) == 1) { + const SubjectChar* pos = reinterpret_cast<const SubjectChar*>( + memchr(subject.start() + i, + pattern_first_char, + n - i + 1)); + if (pos == NULL) { + return -1; + } + i = static_cast<int>(pos - subject.start()); + } else { + if (subject[i] != pattern_first_char) continue; } - i = static_cast<int>(pos - subject.start()); - } else { - if (subject[i] != pattern_first_char) continue; - } - int j = 1; - do { - if (pattern[j] != subject[i+j]) { - break; + int j = 1; + do { + if (pattern[j] != subject[i + j]) { + break; + } + j++; + } while (j < pattern_length); + if (j == pattern_length) { + return i; } - j++; - } while (j < pattern_length); - if (j == pattern_length) { - *complete = true; - return i; - } - badness += j; - } - *complete = true; - return -1; -} - -// Simple indexOf that never bails out. For short patterns only. -template <typename PatternChar, typename SubjectChar> -static int SimpleIndexOf(Vector<const SubjectChar> subject, - Vector<const PatternChar> pattern, - int idx) { - int pattern_length = pattern.length(); - PatternChar pattern_first_char = pattern[0]; - for (int i = idx, n = subject.length() - pattern_length; i <= n; i++) { - if (sizeof(SubjectChar) == 1 && sizeof(PatternChar) == 1) { - const SubjectChar* pos = reinterpret_cast<const SubjectChar*>( - memchr(subject.start() + i, - pattern_first_char, - n - i + 1)); - if (pos == NULL) return -1; - i = static_cast<int>(pos - subject.start()); + badness += j; } else { - if (subject[i] != pattern_first_char) continue; - } - int j = 1; - while (j < pattern_length) { - if (pattern[j] != subject[i+j]) { - break; - } - j++; - } - if (j == pattern_length) { - return i; + search->PopulateBoyerMooreHorspoolTable(); + search->strategy_ = &BoyerMooreHorspoolSearch; + return BoyerMooreHorspoolSearch(search, subject, i); } } return -1; } -// Strategy for searching for a string in another string. -enum StringSearchStrategy { SEARCH_FAIL, SEARCH_SHORT, SEARCH_LONG }; - - -template <typename PatternChar> -static inline StringSearchStrategy InitializeStringSearch( - Vector<const PatternChar> pat, bool ascii_subject) { - // We have an ASCII haystack and a non-ASCII needle. Check if there - // really is a non-ASCII character in the needle and bail out if there - // is. - if (ascii_subject && sizeof(PatternChar) > 1) { - for (int i = 0; i < pat.length(); i++) { - uc16 c = pat[i]; - if (c > String::kMaxAsciiCharCode) { - return SEARCH_FAIL; - } - } - } - if (pat.length() < kBMMinPatternLength) { - return SEARCH_SHORT; - } - algorithm = SIMPLE_SEARCH; - return SEARCH_LONG; -} - - -// Dispatch long needle searches to different algorithms. +// Perform a a single stand-alone search. +// If searching multiple times for the same pattern, a search +// object should be constructed once and the Search function then called +// for each search. template <typename SubjectChar, typename PatternChar> -static int ComplexIndexOf(Vector<const SubjectChar> sub, - Vector<const PatternChar> pat, - int start_index) { - ASSERT(pat.length() >= kBMMinPatternLength); - // Try algorithms in order of increasing setup cost and expected performance. - bool complete; - int idx = start_index; - switch (algorithm) { - case SIMPLE_SEARCH: - idx = SimpleIndexOf(sub, pat, idx, &complete); - if (complete) return idx; - BoyerMoorePopulateBadCharTable(pat); - algorithm = BOYER_MOORE_HORSPOOL; - // FALLTHROUGH. - case BOYER_MOORE_HORSPOOL: - idx = BoyerMooreHorspool(sub, pat, idx, &complete); - if (complete) return idx; - // Build the Good Suffix table and continue searching. - BoyerMoorePopulateGoodSuffixTable(pat); - algorithm = BOYER_MOORE; - // FALLTHROUGH. - case BOYER_MOORE: - return BoyerMooreIndexOf(sub, pat, idx); - } - UNREACHABLE(); - return -1; -} - - -// Dispatch to different search strategies for a single search. -// If searching multiple times on the same needle, the search -// strategy should only be computed once and then dispatch to different -// loops. -template <typename SubjectChar, typename PatternChar> -static int StringSearch(Vector<const SubjectChar> sub, - Vector<const PatternChar> pat, +static int SearchString(Vector<const SubjectChar> subject, + Vector<const PatternChar> pattern, int start_index) { - bool ascii_subject = (sizeof(SubjectChar) == 1); - StringSearchStrategy strategy = InitializeStringSearch(pat, ascii_subject); - switch (strategy) { - case SEARCH_FAIL: return -1; - case SEARCH_SHORT: return SimpleIndexOf(sub, pat, start_index); - case SEARCH_LONG: return ComplexIndexOf(sub, pat, start_index); - } - UNREACHABLE(); - return -1; + StringSearch<PatternChar, SubjectChar> search(pattern); + return search.Search(subject, start_index); } }} // namespace v8::internal diff --git a/src/string.js b/src/string.js index 30eedb3c..d97f632b 100644 --- a/src/string.js +++ b/src/string.js @@ -611,7 +611,7 @@ function StringSplit(separator, limit) { if (%_ObjectEquals(cache.type, 'split') && %_IsRegExpEquivalent(cache.regExp, separator) && %_ObjectEquals(cache.subject, subject) && - %_ObjectEquals(cache.lastIndex, limit)) { + %_ObjectEquals(cache.splitLimit, limit)) { if (cache.answerSaved) { return CloneDenseArray(cache.answer); } else { @@ -622,8 +622,7 @@ function StringSplit(separator, limit) { cache.type = 'split'; cache.regExp = separator; cache.subject = subject; - // Reuse lastIndex field for split limit when type is "split". - cache.lastIndex = limit; + cache.splitLimit = limit; %_Log('regexp', 'regexp-split,%0S,%1r', [subject, separator]); diff --git a/src/strtod.cc b/src/strtod.cc new file mode 100644 index 00000000..ae278bd9 --- /dev/null +++ b/src/strtod.cc @@ -0,0 +1,214 @@ +// 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. + +#include <stdarg.h> +#include <limits.h> + +#include "v8.h" + +#include "strtod.h" +// #include "cached-powers.h" + +namespace v8 { +namespace internal { + +// 2^53 = 9007199254740992. +// Any integer with at most 15 decimal digits will hence fit into a double +// (which has a 53bit significand) without loss of precision. +static const int kMaxExactDoubleIntegerDecimalDigits = 15; +// 2^64 = 18446744073709551616 +// Any integer with at most 19 digits will hence fit into a 64bit datatype. +static const int kMaxUint64DecimalDigits = 19; +// Max double: 1.7976931348623157 x 10^308 +// Min non-zero double: 4.9406564584124654 x 10^-324 +// Any x >= 10^309 is interpreted as +infinity. +// Any x <= 10^-324 is interpreted as 0. +// Note that 2.5e-324 (despite being smaller than the min double) will be read +// as non-zero (equal to the min non-zero double). +static const int kMaxDecimalPower = 309; +static const int kMinDecimalPower = -324; + +static const double exact_powers_of_ten[] = { + 1.0, // 10^0 + 10.0, + 100.0, + 1000.0, + 10000.0, + 100000.0, + 1000000.0, + 10000000.0, + 100000000.0, + 1000000000.0, + 10000000000.0, // 10^10 + 100000000000.0, + 1000000000000.0, + 10000000000000.0, + 100000000000000.0, + 1000000000000000.0, + 10000000000000000.0, + 100000000000000000.0, + 1000000000000000000.0, + 10000000000000000000.0, + 100000000000000000000.0, // 10^20 + 1000000000000000000000.0, + // 10^22 = 0x21e19e0c9bab2400000 = 0x878678326eac9 * 2^22 + 10000000000000000000000.0 +}; + +static const int kExactPowersOfTenSize = ARRAY_SIZE(exact_powers_of_ten); + + +extern "C" double gay_strtod(const char* s00, const char** se); + +static double old_strtod(Vector<const char> buffer, int exponent) { + // gay_strtod is broken on Linux,x86. For numbers with few decimal digits + // the computation is done using floating-point operations which (on Linux) + // are prone to double-rounding errors. + // By adding several zeroes to the buffer gay_strtod falls back to a slower + // (but correct) algorithm. + const int kInsertedZeroesCount = 20; + char gay_buffer[1024]; + Vector<char> gay_buffer_vector(gay_buffer, sizeof(gay_buffer)); + int pos = 0; + for (int i = 0; i < buffer.length(); ++i) { + gay_buffer_vector[pos++] = buffer[i]; + } + for (int i = 0; i < kInsertedZeroesCount; ++i) { + gay_buffer_vector[pos++] = '0'; + } + exponent -= kInsertedZeroesCount; + gay_buffer_vector[pos++] = 'e'; + if (exponent < 0) { + gay_buffer_vector[pos++] = '-'; + exponent = -exponent; + } + const int kNumberOfExponentDigits = 5; + for (int i = kNumberOfExponentDigits - 1; i >= 0; i--) { + gay_buffer_vector[pos + i] = exponent % 10 + '0'; + exponent /= 10; + } + pos += kNumberOfExponentDigits; + gay_buffer_vector[pos] = '\0'; + return gay_strtod(gay_buffer, NULL); +} + + +static Vector<const char> TrimLeadingZeros(Vector<const char> buffer) { + for (int i = 0; i < buffer.length(); i++) { + if (buffer[i] != '0') { + return Vector<const char>(buffer.start() + i, buffer.length() - i); + } + } + return Vector<const char>(buffer.start(), 0); +} + + +static Vector<const char> TrimTrailingZeros(Vector<const char> buffer) { + for (int i = buffer.length() - 1; i >= 0; --i) { + if (buffer[i] != '0') { + return Vector<const char>(buffer.start(), i + 1); + } + } + return Vector<const char>(buffer.start(), 0); +} + + +uint64_t ReadUint64(Vector<const char> buffer) { + ASSERT(buffer.length() <= kMaxUint64DecimalDigits); + uint64_t result = 0; + for (int i = 0; i < buffer.length(); ++i) { + int digit = buffer[i] - '0'; + ASSERT(0 <= digit && digit <= 9); + result = 10 * result + digit; + } + return result; +} + + +static bool DoubleStrtod(Vector<const char> trimmed, + int exponent, + double* result) { +#if (defined(V8_TARGET_ARCH_IA32) || defined(USE_SIMULATOR)) && !defined(WIN32) + // On x86 the floating-point stack can be 64 or 80 bits wide. If it is + // 80 bits wide (as is the case on Linux) then double-rounding occurs and the + // result is not accurate. + // We know that Windows32 uses 64 bits and is therefore accurate. + // Note that the ARM simulator is compiled for 32bits. It therefore exhibits + // the same problem. + return false; +#endif + if (trimmed.length() <= kMaxExactDoubleIntegerDecimalDigits) { + // The trimmed input fits into a double. + // If the 10^exponent (resp. 10^-exponent) fits into a double too then we + // can compute the result-double simply by multiplying (resp. dividing) the + // two numbers. + // This is possible because IEEE guarantees that floating-point operations + // return the best possible approximation. + if (exponent < 0 && -exponent < kExactPowersOfTenSize) { + // 10^-exponent fits into a double. + *result = static_cast<double>(ReadUint64(trimmed)); + *result /= exact_powers_of_ten[-exponent]; + return true; + } + if (0 <= exponent && exponent < kExactPowersOfTenSize) { + // 10^exponent fits into a double. + *result = static_cast<double>(ReadUint64(trimmed)); + *result *= exact_powers_of_ten[exponent]; + return true; + } + int remaining_digits = + kMaxExactDoubleIntegerDecimalDigits - trimmed.length(); + if ((0 <= exponent) && + (exponent - remaining_digits < kExactPowersOfTenSize)) { + // The trimmed string was short and we can multiply it with + // 10^remaining_digits. As a result the remaining exponent now fits + // into a double too. + *result = static_cast<double>(ReadUint64(trimmed)); + *result *= exact_powers_of_ten[remaining_digits]; + *result *= exact_powers_of_ten[exponent - remaining_digits]; + return true; + } + } + return false; +} + + +double Strtod(Vector<const char> buffer, int exponent) { + Vector<const char> left_trimmed = TrimLeadingZeros(buffer); + Vector<const char> trimmed = TrimTrailingZeros(left_trimmed); + exponent += left_trimmed.length() - trimmed.length(); + if (trimmed.length() == 0) return 0.0; + if (exponent + trimmed.length() - 1 >= kMaxDecimalPower) return V8_INFINITY; + if (exponent + trimmed.length() <= kMinDecimalPower) return 0.0; + double result; + if (DoubleStrtod(trimmed, exponent, &result)) { + return result; + } + return old_strtod(trimmed, exponent); +} + +} } // namespace v8::internal diff --git a/src/vm-state.cc b/src/strtod.h index 6bd737df..1a5a96c8 100644 --- a/src/vm-state.cc +++ b/src/strtod.h @@ -25,15 +25,16 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -#include "v8.h" - -#include "vm-state.h" +#ifndef V8_STRTOD_H_ +#define V8_STRTOD_H_ namespace v8 { namespace internal { -#ifdef ENABLE_VMSTATE_TRACKING -AtomicWord VMState::current_state_ = 0; -#endif +// The buffer must only contain digits in the range [0-9]. It must not +// contain a dot or a sign. It must not start with '0', and must not be empty. +double Strtod(Vector<const char> buffer, int exponent); } } // namespace v8::internal + +#endif // V8_STRTOD_H_ diff --git a/src/stub-cache.cc b/src/stub-cache.cc index 6b41577e..e6df1b49 100644 --- a/src/stub-cache.cc +++ b/src/stub-cache.cc @@ -988,6 +988,7 @@ Object* StoreInterceptorProperty(Arguments args) { Object* KeyedLoadPropertyWithInterceptor(Arguments args) { JSObject* receiver = JSObject::cast(args[0]); + ASSERT(Smi::cast(args[1])->value() >= 0); uint32_t index = Smi::cast(args[1])->value(); return receiver->GetElementWithInterceptor(receiver, index); } diff --git a/src/stub-cache.h b/src/stub-cache.h index c47cab71..e4a9e955 100644 --- a/src/stub-cache.h +++ b/src/stub-cache.h @@ -626,7 +626,8 @@ class KeyedStoreStubCompiler: public StubCompiler { V(String.prototype, charCodeAt, StringCharCodeAt) \ V(String.prototype, charAt, StringCharAt) \ V(String, fromCharCode, StringFromCharCode) \ - V(Math, floor, MathFloor) + V(Math, floor, MathFloor) \ + V(Math, abs, MathAbs) class CallStubCompiler: public StubCompiler { @@ -69,6 +69,9 @@ void ThreadLocalTop::Initialize() { #ifdef ENABLE_LOGGING_AND_PROFILING js_entry_sp_ = 0; #endif +#ifdef ENABLE_VMSTATE_TRACKING + current_vm_state_ = NULL; +#endif try_catch_handler_address_ = NULL; context_ = NULL; int id = ThreadManager::CurrentId(); @@ -344,6 +347,10 @@ Handle<JSArray> Top::CaptureCurrentStackTrace( Handle<String> column_key = Factory::LookupAsciiSymbol("column"); Handle<String> line_key = Factory::LookupAsciiSymbol("lineNumber"); Handle<String> script_key = Factory::LookupAsciiSymbol("scriptName"); + Handle<String> name_or_source_url_key = + Factory::LookupAsciiSymbol("nameOrSourceURL"); + Handle<String> script_name_or_source_url_key = + Factory::LookupAsciiSymbol("scriptNameOrSourceURL"); Handle<String> function_key = Factory::LookupAsciiSymbol("functionName"); Handle<String> eval_key = Factory::LookupAsciiSymbol("isEval"); Handle<String> constructor_key = Factory::LookupAsciiSymbol("isConstructor"); @@ -355,13 +362,13 @@ Handle<JSArray> Top::CaptureCurrentStackTrace( Handle<JSObject> stackFrame = Factory::NewJSObject(object_function()); JavaScriptFrame* frame = it.frame(); - JSFunction* fun(JSFunction::cast(frame->function())); - Script* script = Script::cast(fun->shared()->script()); + Handle<JSFunction> fun(JSFunction::cast(frame->function())); + Handle<Script> script(Script::cast(fun->shared()->script())); if (options & StackTrace::kLineNumber) { int script_line_offset = script->line_offset()->value(); int position = frame->code()->SourcePosition(frame->pc()); - int line_number = GetScriptLineNumber(Handle<Script>(script), position); + int line_number = GetScriptLineNumber(script, position); // line_number is already shifted by the script_line_offset. int relative_line_number = line_number - script_line_offset; if (options & StackTrace::kColumnOffset && relative_line_number >= 0) { @@ -385,6 +392,22 @@ Handle<JSArray> Top::CaptureCurrentStackTrace( SetProperty(stackFrame, script_key, script_name, NONE); } + if (options & StackTrace::kScriptNameOrSourceURL) { + Handle<Object> script_name(script->name()); + Handle<JSValue> script_wrapper = GetScriptWrapper(script); + Handle<Object> property = GetProperty(script_wrapper, + name_or_source_url_key); + ASSERT(property->IsJSFunction()); + Handle<JSFunction> method = Handle<JSFunction>::cast(property); + bool caught_exception; + Handle<Object> result = Execution::TryCall(method, script_wrapper, 0, + NULL, &caught_exception); + if (caught_exception) { + result = Factory::undefined_value(); + } + SetProperty(stackFrame, script_name_or_source_url_key, result, NONE); + } + if (options & StackTrace::kFunctionName) { Handle<Object> fun_name(fun->shared()->name()); if (fun_name->ToBoolean()->IsFalse()) { @@ -41,6 +41,7 @@ namespace internal { class SaveContext; // Forward declaration. class ThreadVisitor; // Defined in v8threads.h +class VMState; // Defined in vm-state.h class ThreadLocalTop BASE_EMBEDDED { public: @@ -101,10 +102,15 @@ class ThreadLocalTop BASE_EMBEDDED { // Stack. Address c_entry_fp_; // the frame pointer of the top c entry frame Address handler_; // try-blocks are chained through the stack + #ifdef ENABLE_LOGGING_AND_PROFILING Address js_entry_sp_; // the stack pointer of the bottom js entry frame #endif +#ifdef ENABLE_VMSTATE_TRACKING + VMState* current_vm_state_; +#endif + // Generated code scratch locations. int32_t formal_count_; @@ -254,6 +260,16 @@ class Top { } #endif +#ifdef ENABLE_VMSTATE_TRACKING + static VMState* current_vm_state() { + return thread_local_.current_vm_state_; + } + + static void set_current_vm_state(VMState* state) { + thread_local_.current_vm_state_ = state; + } +#endif + // Generated code scratch locations. static void* formal_count_address() { return &thread_local_.formal_count_; } diff --git a/src/utils.h b/src/utils.h index fefbfe9a..ffdb639e 100644 --- a/src/utils.h +++ b/src/utils.h @@ -222,11 +222,21 @@ uint32_t ComputeIntegerHash(uint32_t key); // ---------------------------------------------------------------------------- // I/O support. -// Our version of printf(). Avoids compilation errors that we get -// with standard printf when attempting to print pointers, etc. -// (the errors are due to the extra compilation flags, which we -// want elsewhere). -void PrintF(const char* format, ...); +#if __GNUC__ >= 4 +// On gcc we can ask the compiler to check the types of %d-style format +// specifiers and their associated arguments. TODO(erikcorry) fix this +// so it works on MacOSX. +#if defined(__MACH__) && defined(__APPLE__) +#define PRINTF_CHECKING +#else // MacOsX. +#define PRINTF_CHECKING __attribute__ ((format (printf, 1, 2))) +#endif +#else +#define PRINTF_CHECKING +#endif + +// Our version of printf(). +void PRINTF_CHECKING PrintF(const char* format, ...); // Our version of fflush. void Flush(); diff --git a/src/v8-counters.h b/src/v8-counters.h index a8eb9d2a..60e8741d 100644 --- a/src/v8-counters.h +++ b/src/v8-counters.h @@ -1,4 +1,4 @@ -// Copyright 2007-2008 the V8 project authors. All rights reserved. +// 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: @@ -45,14 +45,7 @@ namespace internal { /* Total compilation times. */ \ HT(compile, V8.Compile) \ HT(compile_eval, V8.CompileEval) \ - HT(compile_lazy, V8.CompileLazy) \ - /* Individual compiler passes. */ \ - HT(rewriting, V8.Rewriting) \ - HT(usage_analysis, V8.UsageAnalysis) \ - HT(variable_allocation, V8.VariableAllocation) \ - HT(ast_optimization, V8.ASTOptimization) \ - HT(code_generation, V8.CodeGeneration) \ - HT(deferred_code_generation, V8.DeferredCodeGeneration) + HT(compile_lazy, V8.CompileLazy) // WARNING: STATS_COUNTER_LIST_* is a very large macro that is causing MSVC @@ -161,6 +154,8 @@ namespace internal { SC(named_load_inline_miss, V8.NamedLoadInlineMiss) \ SC(named_load_global_inline, V8.NamedLoadGlobalInline) \ SC(named_load_global_inline_miss, V8.NamedLoadGlobalInlineMiss) \ + SC(dont_delete_hint_hit, V8.DontDeleteHintHit) \ + SC(dont_delete_hint_miss, V8.DontDeleteHintMiss) \ SC(named_load_global_stub, V8.NamedLoadGlobalStub) \ SC(named_load_global_stub_miss, V8.NamedLoadGlobalStubMiss) \ SC(keyed_store_field, V8.KeyedStoreField) \ @@ -68,7 +68,7 @@ bool V8::Initialize(Deserializer* des) { OS::Setup(); // Initialize other runtime facilities -#if !V8_HOST_ARCH_ARM && V8_TARGET_ARCH_ARM +#if (defined(USE_SIMULATOR) || !V8_HOST_ARCH_ARM) && V8_TARGET_ARCH_ARM ::assembler::arm::Simulator::Initialize(); #endif diff --git a/src/v8natives.js b/src/v8natives.js index ca1c99d4..88aea9c1 100644 --- a/src/v8natives.js +++ b/src/v8natives.js @@ -547,11 +547,11 @@ function DefineOwnProperty(obj, p, desc, should_throw) { if (!IS_UNDEFINED(current) && !current.isConfigurable()) { // Step 5 and 6 - if ((!desc.hasEnumerable() || + if ((!desc.hasEnumerable() || SameValue(desc.isEnumerable() && current.isEnumerable())) && - (!desc.hasConfigurable() || + (!desc.hasConfigurable() || SameValue(desc.isConfigurable(), current.isConfigurable())) && - (!desc.hasWritable() || + (!desc.hasWritable() || SameValue(desc.isWritable(), current.isWritable())) && (!desc.hasValue() || SameValue(desc.getValue(), current.getValue())) && @@ -755,7 +755,7 @@ function ObjectSeal(obj) { var desc = GetOwnProperty(obj, name); if (desc.isConfigurable()) desc.setConfigurable(false); DefineOwnProperty(obj, name, desc, true); - } + } return ObjectPreventExtension(obj); } @@ -772,7 +772,7 @@ function ObjectFreeze(obj) { if (IsDataDescriptor(desc)) desc.setWritable(false); if (desc.isConfigurable()) desc.setConfigurable(false); DefineOwnProperty(obj, name, desc, true); - } + } return ObjectPreventExtension(obj); } @@ -1118,12 +1118,12 @@ function FunctionBind(this_arg) { // Length is 1. var bound_args = new $Array(argc_bound); for(var i = 0; i < argc_bound; i++) { bound_args[i] = %_Arguments(i+1); - } + } } var fn = this; var result = function() { // Combine the args we got from the bind call with the args - // given as argument to the invocation. + // given as argument to the invocation. var argc = %_ArgumentsLength(); var args = new $Array(argc + argc_bound); // Add bound arguments. @@ -1132,7 +1132,7 @@ function FunctionBind(this_arg) { // Length is 1. } // Add arguments from call. for (var i = 0; i < argc; i++) { - args[argc_bound + i] = %_Arguments(i); + args[argc_bound + i] = %_Arguments(i); } // If this is a construct call we use a special runtime method // to generate the actual object using the bound function. @@ -1147,7 +1147,7 @@ function FunctionBind(this_arg) { // Length is 1. // try to redefine these as defined by the spec. The spec says // that bind should make these throw a TypeError if get or set // is called and make them non-enumerable and non-configurable. - // To be consistent with our normal functions we leave this as it is. + // To be consistent with our normal functions we leave this as it is. // Set the correct length. var length = (this.length - argc_bound) > 0 ? this.length - argc_bound : 0; diff --git a/src/version.cc b/src/version.cc index 5be1e822..6d98b044 100644 --- a/src/version.cc +++ b/src/version.cc @@ -33,10 +33,10 @@ // NOTE these macros are used by the SCons build script so their names // cannot be changed without changing the SCons build script. #define MAJOR_VERSION 2 -#define MINOR_VERSION 4 -#define BUILD_NUMBER 7 +#define MINOR_VERSION 5 +#define BUILD_NUMBER 1 #define PATCH_LEVEL 0 -#define CANDIDATE_VERSION true +#define CANDIDATE_VERSION false // Define SONAME to have the SCons build the put a specific SONAME into the // shared library instead the generic SONAME generated from the V8 version diff --git a/src/vm-state-inl.h b/src/vm-state-inl.h index aa4cedbb..74f4a6a7 100644 --- a/src/vm-state-inl.h +++ b/src/vm-state-inl.h @@ -75,9 +75,9 @@ VMState::VMState(StateTag state) #endif state_ = state; // Save the previous state. - previous_ = reinterpret_cast<VMState*>(current_state_); + previous_ = Top::current_vm_state(); // Install the new state. - OS::ReleaseStore(¤t_state_, reinterpret_cast<AtomicWord>(this)); + Top::set_current_vm_state(this); #ifdef ENABLE_LOGGING_AND_PROFILING if (FLAG_log_state_changes) { @@ -106,7 +106,7 @@ VMState::VMState(StateTag state) VMState::~VMState() { if (disabled_) return; // Return to the previous state. - OS::ReleaseStore(¤t_state_, reinterpret_cast<AtomicWord>(previous_)); + Top::set_current_vm_state(previous_); #ifdef ENABLE_LOGGING_AND_PROFILING if (FLAG_log_state_changes) { diff --git a/src/vm-state.h b/src/vm-state.h index 080eb8de..cc91e837 100644 --- a/src/vm-state.h +++ b/src/vm-state.h @@ -28,6 +28,8 @@ #ifndef V8_VM_STATE_H_ #define V8_VM_STATE_H_ +#include "top.h" + namespace v8 { namespace internal { @@ -44,16 +46,16 @@ class VMState BASE_EMBEDDED { // Used for debug asserts. static bool is_outermost_external() { - return current_state_ == 0; + return Top::current_vm_state() == 0; } static StateTag current_state() { - VMState* state = reinterpret_cast<VMState*>(current_state_); + VMState* state = Top::current_vm_state(); return state ? state->state() : EXTERNAL; } static Address external_callback() { - VMState* state = reinterpret_cast<VMState*>(current_state_); + VMState* state = Top::current_vm_state(); return state ? state->external_callback_ : NULL; } @@ -63,8 +65,6 @@ class VMState BASE_EMBEDDED { VMState* previous_; Address external_callback_; - // A stack of VM states. - static AtomicWord current_state_; #else public: explicit VMState(StateTag state) {} diff --git a/src/x64/builtins-x64.cc b/src/x64/builtins-x64.cc index 08c19ba6..0dead6b7 100644 --- a/src/x64/builtins-x64.cc +++ b/src/x64/builtins-x64.cc @@ -715,7 +715,7 @@ static void ArrayNativeCode(MacroAssembler* masm, __ cmpq(rax, Immediate(1)); __ j(not_equal, &argc_two_or_more); __ movq(rdx, Operand(rsp, kPointerSize)); // Get the argument from the stack. - __ JumpIfNotPositiveSmi(rdx, call_generic_code); + __ JumpUnlessNonNegativeSmi(rdx, call_generic_code); // Handle construction of an empty array of a certain size. Bail out if size // is to large to actually allocate an elements array. diff --git a/src/x64/code-stubs-x64.cc b/src/x64/code-stubs-x64.cc index 9d82e0e3..2d87667b 100644 --- a/src/x64/code-stubs-x64.cc +++ b/src/x64/code-stubs-x64.cc @@ -1413,20 +1413,8 @@ void GenericUnaryOpStub::Generate(MacroAssembler* masm) { __ j(equal, &done); } __ SmiNeg(rax, rax, &done); + __ jmp(&slow); // zero, if not handled above, and Smi::kMinValue. - // Either zero or Smi::kMinValue, neither of which become a smi when - // negated. We handle negative zero here if required. We always enter - // the runtime system if we have Smi::kMinValue. - if (negative_zero_ == kStrictNegativeZero) { - __ SmiCompare(rax, Smi::FromInt(0)); - __ j(not_equal, &slow); - __ Move(rax, Factory::minus_zero_value()); - __ jmp(&done); - } else { - __ SmiCompare(rax, Smi::FromInt(Smi::kMinValue)); - __ j(equal, &slow); - __ jmp(&done); - } // Try floating point case. __ bind(&try_float); } else if (FLAG_debug_code) { @@ -2135,7 +2123,7 @@ void CompareStub::Generate(MacroAssembler* masm) { __ JumpIfNotBothSmi(rax, rdx, &non_smi); __ subq(rdx, rax); __ j(no_overflow, &smi_done); - __ neg(rdx); // Correct sign in case of overflow. + __ not_(rdx); // Correct sign in case of overflow. rdx cannot be 0 here. __ bind(&smi_done); __ movq(rax, rdx); __ ret(0); @@ -2406,16 +2394,7 @@ void CompareStub::BranchIfNonSymbol(MacroAssembler* masm, void StackCheckStub::Generate(MacroAssembler* masm) { - // Because builtins always remove the receiver from the stack, we - // have to fake one to avoid underflowing the stack. The receiver - // must be inserted below the return address on the stack so we - // temporarily store that in a register. - __ pop(rax); - __ Push(Smi::FromInt(0)); - __ push(rax); - - // Do tail-call to runtime routine. - __ TailCallRuntime(Runtime::kStackGuard, 1, 1); + __ TailCallRuntime(Runtime::kStackGuard, 0, 1); } @@ -3801,7 +3780,7 @@ void SubStringStub::Generate(MacroAssembler* masm) { Label result_longer_than_two; __ movq(rcx, Operand(rsp, kToOffset)); __ movq(rdx, Operand(rsp, kFromOffset)); - __ JumpIfNotBothPositiveSmi(rcx, rdx, &runtime); + __ JumpUnlessBothNonNegativeSmi(rcx, rdx, &runtime); __ SmiSub(rcx, rcx, rdx); // Overflow doesn't happen. __ cmpq(FieldOperand(rax, String::kLengthOffset), rcx); diff --git a/src/x64/codegen-x64.cc b/src/x64/codegen-x64.cc index 0d8b827d..9e6ef3b5 100644 --- a/src/x64/codegen-x64.cc +++ b/src/x64/codegen-x64.cc @@ -178,22 +178,12 @@ void CodeGenerator::Generate(CompilationInfo* info) { // Adjust for function-level loop nesting. ASSERT_EQ(0, loop_nesting_); - loop_nesting_ = info->loop_nesting(); + loop_nesting_ = info->is_in_loop() ? 1 : 0; JumpTarget::set_compiling_deferred_code(false); -#ifdef DEBUG - if (strlen(FLAG_stop_at) > 0 && - info->function()->name()->IsEqualTo(CStrVector(FLAG_stop_at))) { - frame_->SpillAll(); - __ int3(); - } -#endif - - // New scope to get automatic timing calculation. - { HistogramTimerScope codegen_timer(&Counters::code_generation); + { CodeGenState state(this); - // Entry: // Stack: receiver, arguments, return address. // rbp: caller's frame pointer @@ -202,6 +192,14 @@ void CodeGenerator::Generate(CompilationInfo* info) { // rsi: callee's context allocator_->Initialize(); +#ifdef DEBUG + if (strlen(FLAG_stop_at) > 0 && + info->function()->name()->IsEqualTo(CStrVector(FLAG_stop_at))) { + frame_->SpillAll(); + __ int3(); + } +#endif + frame_->Enter(); // Allocate space for locals and initialize them. @@ -356,7 +354,7 @@ void CodeGenerator::Generate(CompilationInfo* info) { } // Adjust for function-level loop nesting. - ASSERT_EQ(loop_nesting_, info->loop_nesting()); + ASSERT_EQ(loop_nesting_, info->is_in_loop() ? 1 : 0); loop_nesting_ = 0; // Code generation state must be reset. @@ -367,7 +365,6 @@ void CodeGenerator::Generate(CompilationInfo* info) { // Process any deferred code using the register allocator. if (!HasStackOverflow()) { - HistogramTimerScope deferred_timer(&Counters::deferred_code_generation); JumpTarget::set_compiling_deferred_code(true); ProcessDeferred(); JumpTarget::set_compiling_deferred_code(false); @@ -1884,8 +1881,7 @@ Result CodeGenerator::ConstantSmiBinaryOperation(BinaryOperation* expr, operand->reg(), smi_value, overwrite_mode); - // Check for negative or non-Smi left hand side. - __ JumpIfNotPositiveSmi(operand->reg(), deferred->entry_label()); + __ JumpUnlessNonNegativeSmi(operand->reg(), deferred->entry_label()); if (int_value < 0) int_value = -int_value; if (int_value == 1) { __ Move(operand->reg(), Smi::FromInt(0)); @@ -4277,9 +4273,12 @@ void CodeGenerator::VisitFunctionLiteral(FunctionLiteral* node) { // Build the function info and instantiate it. Handle<SharedFunctionInfo> function_info = - Compiler::BuildFunctionInfo(node, script(), this); + Compiler::BuildFunctionInfo(node, script()); // Check for stack-overflow exception. - if (HasStackOverflow()) return; + if (function_info.is_null()) { + SetStackOverflow(); + return; + } InstantiateFunction(function_info); } @@ -5684,9 +5683,9 @@ void CodeGenerator::GenerateIsNonNegativeSmi(ZoneList<Expression*>* args) { Result value = frame_->Pop(); value.ToRegister(); ASSERT(value.is_valid()); - Condition positive_smi = masm_->CheckPositiveSmi(value.reg()); + Condition non_negative_smi = masm_->CheckNonNegativeSmi(value.reg()); value.Unuse(); - destination()->Split(positive_smi); + destination()->Split(non_negative_smi); } @@ -6911,7 +6910,7 @@ void CodeGenerator::GenerateSwapElements(ZoneList<Expression*>* args) { deferred->Branch(not_equal); // Check that both indices are smis. - Condition both_smi = __ CheckBothSmi(index1.reg(), index2.reg()); + Condition both_smi = masm()->CheckBothSmi(index1.reg(), index2.reg()); deferred->Branch(NegateCondition(both_smi)); // Bring addresses into index1 and index2. @@ -8377,7 +8376,7 @@ Result CodeGenerator::EmitNamedStore(Handle<String> name, bool is_contextual) { } // Check that the receiver is a heap object. - Condition is_smi = __ CheckSmi(receiver.reg()); + Condition is_smi = masm()->CheckSmi(receiver.reg()); slow.Branch(is_smi, &value, &receiver); // This is the map check instruction that will be patched. @@ -8506,8 +8505,7 @@ Result CodeGenerator::EmitKeyedLoad() { kScratchRegister); deferred->Branch(not_equal); - // Check that the key is a non-negative smi. - __ JumpIfNotPositiveSmi(key.reg(), deferred->entry_label()); + __ JumpUnlessNonNegativeSmi(key.reg(), deferred->entry_label()); // Get the elements array from the receiver. __ movq(elements.reg(), diff --git a/src/x64/codegen-x64.h b/src/x64/codegen-x64.h index 6e1dd727..79573245 100644 --- a/src/x64/codegen-x64.h +++ b/src/x64/codegen-x64.h @@ -298,9 +298,7 @@ enum ArgumentsAllocationMode { class CodeGenerator: public AstVisitor { public: - // Takes a function literal, generates code for it. This function should only - // be called by compiler.cc. - static Handle<Code> MakeCode(CompilationInfo* info); + static bool MakeCode(CompilationInfo* info); // Printing of AST, etc. as requested by flags. static void MakeCodePrologue(CompilationInfo* info); @@ -586,9 +584,6 @@ class CodeGenerator: public AstVisitor { void CheckStack(); - static InlineFunctionGenerator FindInlineFunctionGenerator( - Runtime::FunctionId function_id); - bool CheckForInlineRuntimeCall(CallRuntime* node); void ProcessDeclarations(ZoneList<Declaration*>* declarations); diff --git a/src/x64/full-codegen-x64.cc b/src/x64/full-codegen-x64.cc index c15860c7..32d62426 100644 --- a/src/x64/full-codegen-x64.cc +++ b/src/x64/full-codegen-x64.cc @@ -61,6 +61,12 @@ void FullCodeGenerator::Generate(CompilationInfo* info) { SetFunctionPosition(function()); Comment cmnt(masm_, "[ function compiled by full code generator"); +#ifdef DEBUG + if (strlen(FLAG_stop_at) > 0 && + info->function()->name()->IsEqualTo(CStrVector(FLAG_stop_at))) { + __ int3(); + } +#endif __ push(rbp); // Caller's frame pointer. __ movq(rbp, rsp); __ push(rsi); // Callee's context. @@ -767,7 +773,7 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) { // Get the current entry of the array into register rbx. __ movq(rbx, Operand(rsp, 2 * kPointerSize)); - SmiIndex index = __ SmiToIndex(rax, rax, kPointerSizeLog2); + SmiIndex index = masm()->SmiToIndex(rax, rax, kPointerSizeLog2); __ movq(rbx, FieldOperand(rbx, index.reg, index.scale, @@ -1407,7 +1413,7 @@ void FullCodeGenerator::EmitInlineSmiBinaryOp(Expression* expr, Label done, stub_call, smi_case; __ pop(rdx); __ movq(rcx, rax); - Condition smi = __ CheckBothSmi(rdx, rax); + Condition smi = masm()->CheckBothSmi(rdx, rax); __ j(smi, &smi_case); __ bind(&stub_call); @@ -1965,8 +1971,8 @@ void FullCodeGenerator::EmitIsNonNegativeSmi(ZoneList<Expression*>* args) { context()->PrepareTest(&materialize_true, &materialize_false, &if_true, &if_false, &fall_through); - Condition positive_smi = __ CheckPositiveSmi(rax); - Split(positive_smi, if_true, if_false, fall_through); + Condition non_negative_smi = masm()->CheckNonNegativeSmi(rax); + Split(non_negative_smi, if_true, if_false, fall_through); context()->Plug(if_true, if_false); } diff --git a/src/x64/ic-x64.cc b/src/x64/ic-x64.cc index 62e76912..1d95b7f6 100644 --- a/src/x64/ic-x64.cc +++ b/src/x64/ic-x64.cc @@ -893,8 +893,9 @@ void KeyedLoadIC::GenerateIndexedInterceptor(MacroAssembler* masm) { // Check that the receiver isn't a smi. __ JumpIfSmi(rdx, &slow); - // Check that the key is a smi. - __ JumpIfNotSmi(rax, &slow); + // Check that the key is an array index, that is Uint32. + STATIC_ASSERT(kSmiValueSize <= 32); + __ JumpUnlessNonNegativeSmi(rax, &slow); // Get the map of the receiver. __ movq(rcx, FieldOperand(rdx, HeapObject::kMapOffset)); @@ -1728,7 +1729,8 @@ bool LoadIC::PatchInlinedLoad(Address address, Object* map, int offset) { bool LoadIC::PatchInlinedContextualLoad(Address address, Object* map, - Object* cell) { + Object* cell, + bool is_dont_delete) { // TODO(<bug#>): implement this. return false; } diff --git a/src/x64/macro-assembler-x64.cc b/src/x64/macro-assembler-x64.cc index 869986eb..2c946f56 100644 --- a/src/x64/macro-assembler-x64.cc +++ b/src/x64/macro-assembler-x64.cc @@ -825,7 +825,7 @@ Condition MacroAssembler::CheckSmi(Register src) { } -Condition MacroAssembler::CheckPositiveSmi(Register src) { +Condition MacroAssembler::CheckNonNegativeSmi(Register src) { ASSERT_EQ(0, kSmiTag); // Make mask 0x8000000000000001 and test that both bits are zero. movq(kScratchRegister, src); @@ -846,15 +846,15 @@ Condition MacroAssembler::CheckBothSmi(Register first, Register second) { } -Condition MacroAssembler::CheckBothPositiveSmi(Register first, - Register second) { +Condition MacroAssembler::CheckBothNonNegativeSmi(Register first, + Register second) { if (first.is(second)) { - return CheckPositiveSmi(first); + return CheckNonNegativeSmi(first); } movq(kScratchRegister, first); or_(kScratchRegister, second); rol(kScratchRegister, Immediate(1)); - testl(kScratchRegister, Immediate(0x03)); + testl(kScratchRegister, Immediate(3)); return zero; } diff --git a/src/x64/macro-assembler-x64.h b/src/x64/macro-assembler-x64.h index a8ffca91..cb910675 100644 --- a/src/x64/macro-assembler-x64.h +++ b/src/x64/macro-assembler-x64.h @@ -101,9 +101,9 @@ class MacroAssembler: public Assembler { // dirty. |object| is the object being stored into, |value| is the // object being stored. If |offset| is zero, then the |scratch| // register contains the array index into the elements array - // represented as a Smi. All registers are clobbered by the - // operation. RecordWrite filters out smis so it does not update the - // write barrier if the value is a smi. + // represented as an untagged 32-bit integer. All registers are + // clobbered by the operation. RecordWrite filters out smis so it + // does not update the write barrier if the value is a smi. void RecordWrite(Register object, int offset, Register value, @@ -122,7 +122,7 @@ class MacroAssembler: public Assembler { // The value is known to not be a smi. // object is the object being stored into, value is the object being stored. // If offset is zero, then the scratch register contains the array index into - // the elements array represented as a Smi. + // the elements array represented as an untagged 32-bit integer. // All registers are clobbered by the operation. void RecordWriteNonSmi(Register object, int offset, @@ -265,14 +265,14 @@ class MacroAssembler: public Assembler { // Is the value a tagged smi. Condition CheckSmi(Register src); - // Is the value a positive tagged smi. - Condition CheckPositiveSmi(Register src); + // Is the value a non-negative tagged smi. + Condition CheckNonNegativeSmi(Register src); // Are both values tagged smis. Condition CheckBothSmi(Register first, Register second); - // Are both values tagged smis. - Condition CheckBothPositiveSmi(Register first, Register second); + // Are both values non-negative tagged smis. + Condition CheckBothNonNegativeSmi(Register first, Register second); // Are either value a tagged smi. Condition CheckEitherSmi(Register first, @@ -311,9 +311,9 @@ class MacroAssembler: public Assembler { template <typename LabelType> void JumpIfNotSmi(Register src, LabelType* on_not_smi); - // Jump to label if the value is not a positive tagged smi. + // Jump to label if the value is not a non-negative tagged smi. template <typename LabelType> - void JumpIfNotPositiveSmi(Register src, LabelType* on_not_smi); + void JumpUnlessNonNegativeSmi(Register src, LabelType* on_not_smi); // Jump to label if the value, which must be a tagged smi, has value equal // to the constant. @@ -328,10 +328,10 @@ class MacroAssembler: public Assembler { Register src2, LabelType* on_not_both_smi); - // Jump if either or both register are not positive smi values. + // Jump if either or both register are not non-negative smi values. template <typename LabelType> - void JumpIfNotBothPositiveSmi(Register src1, Register src2, - LabelType* on_not_both_smi); + void JumpUnlessBothNonNegativeSmi(Register src1, Register src2, + LabelType* on_not_both_smi); // Operations on tagged smi values. @@ -1463,10 +1463,10 @@ void MacroAssembler::JumpIfNotSmi(Register src, LabelType* on_not_smi) { template <typename LabelType> -void MacroAssembler::JumpIfNotPositiveSmi(Register src, - LabelType* on_not_positive_smi) { - Condition positive_smi = CheckPositiveSmi(src); - j(NegateCondition(positive_smi), on_not_positive_smi); +void MacroAssembler::JumpUnlessNonNegativeSmi( + Register src, LabelType* on_not_smi_or_negative) { + Condition non_negative_smi = CheckNonNegativeSmi(src); + j(NegateCondition(non_negative_smi), on_not_smi_or_negative); } @@ -1505,10 +1505,10 @@ void MacroAssembler::JumpIfNotBothSmi(Register src1, template <typename LabelType> -void MacroAssembler::JumpIfNotBothPositiveSmi(Register src1, - Register src2, - LabelType* on_not_both_smi) { - Condition both_smi = CheckBothPositiveSmi(src1, src2); +void MacroAssembler::JumpUnlessBothNonNegativeSmi(Register src1, + Register src2, + LabelType* on_not_both_smi) { + Condition both_smi = CheckBothNonNegativeSmi(src1, src2); j(NegateCondition(both_smi), on_not_both_smi); } diff --git a/src/x64/regexp-macro-assembler-x64.cc b/src/x64/regexp-macro-assembler-x64.cc index 91e2b449..47c19c7e 100644 --- a/src/x64/regexp-macro-assembler-x64.cc +++ b/src/x64/regexp-macro-assembler-x64.cc @@ -145,7 +145,6 @@ int RegExpMacroAssemblerX64::stack_limit_slack() { void RegExpMacroAssemblerX64::AdvanceCurrentPosition(int by) { if (by != 0) { - Label inside_string; __ addq(rdi, Immediate(by * char_size())); } } @@ -1053,6 +1052,19 @@ void RegExpMacroAssemblerX64::ReadStackPointerFromRegister(int reg) { } +void RegExpMacroAssemblerX64::SetCurrentPositionFromEnd(int by) { + NearLabel after_position; + __ cmpq(rdi, Immediate(-by * char_size())); + __ j(greater_equal, &after_position); + __ movq(rdi, Immediate(-by * char_size())); + // On RegExp code entry (where this operation is used), the character before + // the current position is expected to be already loaded. + // We have advanced the position, so it's safe to read backwards. + LoadCurrentCharacterUnchecked(-1, 1); + __ bind(&after_position); +} + + void RegExpMacroAssemblerX64::SetRegister(int register_index, int to) { ASSERT(register_index >= num_saved_registers_); // Reserved for positions! __ movq(register_location(register_index), Immediate(to)); diff --git a/src/x64/regexp-macro-assembler-x64.h b/src/x64/regexp-macro-assembler-x64.h index 3bcc3ac1..182bc552 100644 --- a/src/x64/regexp-macro-assembler-x64.h +++ b/src/x64/regexp-macro-assembler-x64.h @@ -93,6 +93,7 @@ class RegExpMacroAssemblerX64: public NativeRegExpMacroAssembler { StackCheckFlag check_stack_limit); virtual void ReadCurrentPositionFromRegister(int reg); virtual void ReadStackPointerFromRegister(int reg); + virtual void SetCurrentPositionFromEnd(int by); virtual void SetRegister(int register_index, int to); virtual void Succeed(); virtual void WriteCurrentPositionToRegister(int reg, int cp_offset); diff --git a/src/x64/stub-cache-x64.cc b/src/x64/stub-cache-x64.cc index 68b18a24..eb48da9a 100644 --- a/src/x64/stub-cache-x64.cc +++ b/src/x64/stub-cache-x64.cc @@ -1558,6 +1558,109 @@ Object* CallStubCompiler::CompileMathFloorCall(Object* object, } +Object* CallStubCompiler::CompileMathAbsCall(Object* object, + JSObject* holder, + JSGlobalPropertyCell* cell, + JSFunction* function, + String* name) { + // ----------- S t a t e ------------- + // -- rcx : function name + // -- rsp[0] : return address + // -- rsp[(argc - n) * 8] : arg[n] (zero-based) + // -- ... + // -- rsp[(argc + 1) * 8] : receiver + // ----------------------------------- + + const int argc = arguments().immediate(); + + // If the object is not a JSObject or we got an unexpected number of + // arguments, bail out to the regular call. + if (!object->IsJSObject() || argc != 1) return Heap::undefined_value(); + + Label miss; + GenerateNameCheck(name, &miss); + + if (cell == NULL) { + __ movq(rdx, Operand(rsp, 2 * kPointerSize)); + + __ JumpIfSmi(rdx, &miss); + + CheckPrototypes(JSObject::cast(object), rdx, holder, rbx, rax, rdi, name, + &miss); + } else { + ASSERT(cell->value() == function); + GenerateGlobalReceiverCheck(JSObject::cast(object), holder, name, &miss); + GenerateLoadFunctionFromCell(cell, function, &miss); + } + + // Load the (only) argument into rax. + __ movq(rax, Operand(rsp, 1 * kPointerSize)); + + // Check if the argument is a smi. + Label not_smi; + STATIC_ASSERT(kSmiTag == 0); + __ JumpIfNotSmi(rax, ¬_smi); + __ SmiToInteger32(rax, rax); + + // Set ebx to 1...1 (== -1) if the argument is negative, or to 0...0 + // otherwise. + __ movl(rbx, rax); + __ sarl(rbx, Immediate(kBitsPerInt - 1)); + + // Do bitwise not or do nothing depending on ebx. + __ xorl(rax, rbx); + + // Add 1 or do nothing depending on ebx. + __ subl(rax, rbx); + + // If the result is still negative, go to the slow case. + // This only happens for the most negative smi. + Label slow; + __ j(negative, &slow); + + // Smi case done. + __ Integer32ToSmi(rax, rax); + __ ret(2 * kPointerSize); + + // Check if the argument is a heap number and load its value. + __ bind(¬_smi); + __ CheckMap(rax, Factory::heap_number_map(), &slow, true); + __ movq(rbx, FieldOperand(rax, HeapNumber::kValueOffset)); + + // Check the sign of the argument. If the argument is positive, + // just return it. + Label negative_sign; + const int sign_mask_shift = + (HeapNumber::kExponentOffset - HeapNumber::kValueOffset) * kBitsPerByte; + __ movq(rdi, static_cast<int64_t>(HeapNumber::kSignMask) << sign_mask_shift, + RelocInfo::NONE); + __ testq(rbx, rdi); + __ j(not_zero, &negative_sign); + __ ret(2 * kPointerSize); + + // If the argument is negative, clear the sign, and return a new + // number. We still have the sign mask in rdi. + __ bind(&negative_sign); + __ xor_(rbx, rdi); + __ AllocateHeapNumber(rax, rdx, &slow); + __ movq(FieldOperand(rax, HeapNumber::kValueOffset), rbx); + __ ret(2 * kPointerSize); + + // Tail call the full function. We do not have to patch the receiver + // because the function makes no use of it. + __ bind(&slow); + __ InvokeFunction(function, arguments(), JUMP_FUNCTION); + + __ bind(&miss); + // rcx: function name. + Object* obj = GenerateMissBranch(); + if (obj->IsFailure()) return obj; + + // Return the generated code. + return (cell == NULL) ? GetCode(function) : GetCode(NORMAL, name); +} + + Object* CallStubCompiler::CompileCallInterceptor(JSObject* object, JSObject* holder, String* name) { |