atomic_intrinsics_win32.h   atomic_intrinsics_win32.h 
skipping to change at line 90 skipping to change at line 90
AtomicIntrinsics(); AtomicIntrinsics();
~AtomicIntrinsics(); ~AtomicIntrinsics();
}; };
/** /**
* Instantiation of AtomicIntrinsics<> for 64-bit word sizes. * Instantiation of AtomicIntrinsics<> for 64-bit word sizes.
*/ */
template <typename T> template <typename T>
class AtomicIntrinsics<T, typename boost::enable_if_c<sizeof(T) == size of(LONGLONG)>::type> { class AtomicIntrinsics<T, typename boost::enable_if_c<sizeof(T) == size of(LONGLONG)>::type> {
public: public:
static const bool kHaveInterlocked64 = (_WIN32_WINNT >= _WIN32_WINN
T_VISTA); #if defined(_WIN32_WINNT_VISTA) && (_WIN32_WINNT >= _WIN32_WINNT_VISTA)
static const bool kHaveInterlocked64 = true;
#else
static const bool kHaveInterlocked64 = false;
#endif
static T compareAndSwap(volatile T* dest, T expected, T newValue) { static T compareAndSwap(volatile T* dest, T expected, T newValue) {
return InterlockedImpl<kHaveInterlocked64>::compareAndSwap(dest , expected, newValue); return InterlockedImpl<kHaveInterlocked64>::compareAndSwap(dest , expected, newValue);
} }
static T swap(volatile T* dest, T newValue) { static T swap(volatile T* dest, T newValue) {
return InterlockedImpl<kHaveInterlocked64>::swap(dest, newValue ); return InterlockedImpl<kHaveInterlocked64>::swap(dest, newValue );
} }
static T load(volatile const T* value) { static T load(volatile const T* value) {
 End of changes. 1 change blocks. 
2 lines changed or deleted 6 lines changed or added


 bsonelement.h   bsonelement.h 
skipping to change at line 26 skipping to change at line 26
*/ */
#pragma once #pragma once
#include <string.h> // strlen #include <string.h> // strlen
#include <string> #include <string>
#include <vector> #include <vector>
#include "mongo/bson/bsontypes.h" #include "mongo/bson/bsontypes.h"
#include "mongo/bson/oid.h" #include "mongo/bson/oid.h"
#include "mongo/platform/cstdint.h"
#include "mongo/platform/float_utils.h" #include "mongo/platform/float_utils.h"
namespace mongo { namespace mongo {
class OpTime; class OpTime;
class BSONObj; class BSONObj;
class BSONElement; class BSONElement;
class BSONObjBuilder; class BSONObjBuilder;
} }
namespace bson { namespace bson {
skipping to change at line 238 skipping to change at line 239
/** Size (length) of a string element. /** Size (length) of a string element.
You must assure of type String first. You must assure of type String first.
@return string size including terminating null @return string size including terminating null
*/ */
int valuestrsize() const { int valuestrsize() const {
return *reinterpret_cast< const int* >( value() ); return *reinterpret_cast< const int* >( value() );
} }
// for objects the size *includes* the size of the size field // for objects the size *includes* the size of the size field
int objsize() const { size_t objsize() const {
return *reinterpret_cast< const int* >( value() ); return static_cast< const size_t >( *reinterpret_cast< const ui
nt32_t* >( value() ) );
} }
/** Get a string's value. Also gives you start of the real data fo r an embedded object. /** Get a string's value. Also gives you start of the real data fo r an embedded object.
You must assure data is of an appropriate type first -- see als o valuestrsafe(). You must assure data is of an appropriate type first -- see als o valuestrsafe().
*/ */
const char * valuestr() const { const char * valuestr() const {
return value() + 4; return value() + 4;
} }
/** Get the string value of the element. If not a string returns " ". */ /** Get the string value of the element. If not a string returns " ". */
 End of changes. 2 change blocks. 
2 lines changed or deleted 4 lines changed or added


 compiler.h   compiler.h 
// @file mongo/platform/compiler.h // Copyright 2012 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.
/* #ifndef V8_COMPILER_H_
* Copyright 2012 10gen Inc. #define V8_COMPILER_H_
*
* Licensed under the Apache License, Version 2.0 (the "License"); #include "allocation.h"
* you may not use this file except in compliance with the License. #include "ast.h"
* You may obtain a copy of the License at #include "zone.h"
*
* http://www.apache.org/licenses/LICENSE-2.0 namespace v8 {
* namespace internal {
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, class ScriptDataImpl;
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and // CompilationInfo encapsulates some information known at compile time. It
* limitations under the License. // is constructed based on the resources available at compile-time.
*/ class CompilationInfo {
public:
#pragma once CompilationInfo(Handle<Script> script, Zone* zone);
CompilationInfo(Handle<SharedFunctionInfo> shared_info, Zone* zone);
/** CompilationInfo(Handle<JSFunction> closure, Zone* zone);
* Include "mongo/platform/compiler.h" to get compiler-specific macro defin
itions and utilities. virtual ~CompilationInfo();
*/
Isolate* isolate() {
#if defined(_MSC_VER) ASSERT(Isolate::Current() == isolate_);
#include "mongo/platform/compiler_msvc.h" return isolate_;
#elif defined(__GNUC__) }
#include "mongo/platform/compiler_gcc.h" Zone* zone() {
#else return zone_;
#error "Unsupported compiler family" }
bool is_lazy() const { return IsLazy::decode(flags_); }
bool is_eval() const { return IsEval::decode(flags_); }
bool is_global() const { return IsGlobal::decode(flags_); }
bool is_classic_mode() const { return language_mode() == CLASSIC_MODE; }
bool is_extended_mode() const { return language_mode() == EXTENDED_MODE;
}
LanguageMode language_mode() const {
return LanguageModeField::decode(flags_);
}
bool is_in_loop() const { return IsInLoop::decode(flags_); }
FunctionLiteral* function() const { return function_; }
Scope* scope() const { return scope_; }
Scope* global_scope() const { return global_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_; }
int osr_ast_id() const { return osr_ast_id_; }
void MarkAsEval() {
ASSERT(!is_lazy());
flags_ |= IsEval::encode(true);
}
void MarkAsGlobal() {
ASSERT(!is_lazy());
flags_ |= IsGlobal::encode(true);
}
void SetLanguageMode(LanguageMode language_mode) {
ASSERT(this->language_mode() == CLASSIC_MODE ||
this->language_mode() == language_mode ||
language_mode == EXTENDED_MODE);
flags_ = LanguageModeField::update(flags_, language_mode);
}
void MarkAsInLoop() {
ASSERT(is_lazy());
flags_ |= IsInLoop::encode(true);
}
void MarkAsNative() {
flags_ |= IsNative::encode(true);
}
bool is_native() const {
return IsNative::decode(flags_);
}
void SetFunction(FunctionLiteral* literal) {
ASSERT(function_ == NULL);
function_ = literal;
}
void SetScope(Scope* scope) {
ASSERT(scope_ == NULL);
scope_ = scope;
}
void SetGlobalScope(Scope* global_scope) {
ASSERT(global_scope_ == NULL);
global_scope_ = global_scope;
}
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;
}
void SetOsrAstId(int osr_ast_id) {
ASSERT(IsOptimizing());
osr_ast_id_ = osr_ast_id;
}
void MarkCompilingForDebugging(Handle<Code> current_code) {
ASSERT(mode_ != OPTIMIZE);
ASSERT(current_code->kind() == Code::FUNCTION);
flags_ |= IsCompilingForDebugging::encode(true);
if (current_code->is_compiled_optimizable()) {
EnableDeoptimizationSupport();
} else {
mode_ = CompilationInfo::NONOPT;
}
}
bool IsCompilingForDebugging() {
return IsCompilingForDebugging::decode(flags_);
}
bool has_global_object() const {
return !closure().is_null() && (closure()->context()->global() != NULL)
;
}
GlobalObject* global_object() const {
return has_global_object() ? closure()->context()->global() : NULL;
}
// Accessors for the different compilation modes.
bool IsOptimizing() const { return mode_ == OPTIMIZE; }
bool IsOptimizable() const { return mode_ == BASE; }
void SetOptimizing(int osr_ast_id) {
SetMode(OPTIMIZE);
osr_ast_id_ = osr_ast_id;
}
void DisableOptimization();
// Deoptimization support.
bool HasDeoptimizationSupport() const {
return SupportsDeoptimization::decode(flags_);
}
void EnableDeoptimizationSupport() {
ASSERT(IsOptimizable());
flags_ |= SupportsDeoptimization::encode(true);
}
// Determines whether or not to insert a self-optimization header.
bool ShouldSelfOptimize();
// Disable all optimization attempts of this info for the rest of the
// current compilation pipeline.
void AbortOptimization();
void set_deferred_handles(DeferredHandles* deferred_handles) {
ASSERT(deferred_handles_ == NULL);
deferred_handles_ = deferred_handles;
}
void SaveHandles() {
SaveHandle(&closure_);
SaveHandle(&shared_info_);
SaveHandle(&calling_context_);
SaveHandle(&script_);
}
private:
Isolate* isolate_;
// Compilation mode.
// BASE is generated by the full codegen, optionally prepared for bailout
s.
// OPTIMIZE is optimized code generated by the Hydrogen-based backend.
// NONOPT is generated by the full codegen and is not prepared for
// recompilation/bailouts. These functions are never recompiled.
enum Mode {
BASE,
OPTIMIZE,
NONOPT
};
void Initialize(Mode mode) {
mode_ = V8::UseCrankshaft() ? mode : NONOPT;
ASSERT(!script_.is_null());
if (script_->type()->value() == Script::TYPE_NATIVE) {
MarkAsNative();
}
if (!shared_info_.is_null()) {
ASSERT(language_mode() == CLASSIC_MODE);
SetLanguageMode(shared_info_->language_mode());
}
}
void SetMode(Mode mode) {
ASSERT(V8::UseCrankshaft());
mode_ = mode;
}
// 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> {};
// Flags that can be set for lazy compilation.
class IsInLoop: public BitField<bool, 3, 1> {};
// Strict mode - used in eager compilation.
class LanguageModeField: public BitField<LanguageMode, 4, 2> {};
// Is this a function from our natives.
class IsNative: public BitField<bool, 6, 1> {};
// Is this code being compiled with support for deoptimization..
class SupportsDeoptimization: public BitField<bool, 7, 1> {};
// If compiling for debugging produce just full code matching the
// initial mode setting.
class IsCompilingForDebugging: public BitField<bool, 8, 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 indicate
// that scopes have been analyzed.
Scope* scope_;
// The global scope provided as a convenience.
Scope* global_scope_;
// The compiled code.
Handle<Code> code_;
// Possible initial inputs to the compilation process.
Handle<JSFunction> closure_;
Handle<SharedFunctionInfo> shared_info_;
Handle<Script> script_;
// Fields possibly needed for eager compilation, NULL by default.
v8::Extension* extension_;
ScriptDataImpl* pre_parse_data_;
// The context of the caller is needed for eval code, and will be a null
// handle otherwise.
Handle<Context> calling_context_;
// Compilation mode flag and whether deoptimization is allowed.
Mode mode_;
int osr_ast_id_;
// The zone from which the compilation pipeline working on this
// CompilationInfo allocates.
Zone* zone_;
DeferredHandles* deferred_handles_;
template<typename T>
void SaveHandle(Handle<T> *object) {
if (!object->is_null()) {
Handle<T> handle(*(*object));
*object = handle;
}
}
DISALLOW_COPY_AND_ASSIGN(CompilationInfo);
};
// Exactly like a CompilationInfo, except also creates and enters a
// Zone on construction and deallocates it on exit.
class CompilationInfoWithZone: public CompilationInfo {
public:
explicit CompilationInfoWithZone(Handle<Script> script)
: CompilationInfo(script, &zone_),
zone_(script->GetIsolate()),
zone_scope_(&zone_, DELETE_ON_EXIT) {}
explicit CompilationInfoWithZone(Handle<SharedFunctionInfo> shared_info)
: CompilationInfo(shared_info, &zone_),
zone_(shared_info->GetIsolate()),
zone_scope_(&zone_, DELETE_ON_EXIT) {}
explicit CompilationInfoWithZone(Handle<JSFunction> closure)
: CompilationInfo(closure, &zone_),
zone_(closure->GetIsolate()),
zone_scope_(&zone_, DELETE_ON_EXIT) {}
private:
Zone zone_;
ZoneScope zone_scope_;
};
// A wrapper around a CompilationInfo that detaches the Handles from
// the underlying DeferredHandleScope and stores them in info_ on
// destruction.
class CompilationHandleScope BASE_EMBEDDED {
public:
explicit CompilationHandleScope(CompilationInfo* info)
: deferred_(info->isolate()), info_(info) {}
~CompilationHandleScope() {
info_->set_deferred_handles(deferred_.Detach());
}
private:
DeferredHandleScope deferred_;
CompilationInfo* info_;
};
class HGraph;
class HGraphBuilder;
class LChunk;
// A helper class that calls the three compilation phases in
// Crankshaft and keeps track of its state. The three phases
// CreateGraph, OptimizeGraph and GenerateAndInstallCode can either
// fail, bail-out to the full code generator or succeed. Apart from
// their return value, the status of the phase last run can be checked
// using last_status().
class OptimizingCompiler: public ZoneObject {
public:
explicit OptimizingCompiler(CompilationInfo* info)
: info_(info),
oracle_(NULL),
graph_builder_(NULL),
graph_(NULL),
chunk_(NULL),
time_taken_to_create_graph_(0),
time_taken_to_optimize_(0),
time_taken_to_codegen_(0),
last_status_(FAILED) { }
enum Status {
FAILED, BAILED_OUT, SUCCEEDED
};
MUST_USE_RESULT Status CreateGraph();
MUST_USE_RESULT Status OptimizeGraph();
MUST_USE_RESULT Status GenerateAndInstallCode();
Status last_status() const { return last_status_; }
CompilationInfo* info() const { return info_; }
MUST_USE_RESULT Status AbortOptimization() {
info_->AbortOptimization();
info_->shared_info()->DisableOptimization();
return SetLastStatus(BAILED_OUT);
}
private:
CompilationInfo* info_;
TypeFeedbackOracle* oracle_;
HGraphBuilder* graph_builder_;
HGraph* graph_;
LChunk* chunk_;
int64_t time_taken_to_create_graph_;
int64_t time_taken_to_optimize_;
int64_t time_taken_to_codegen_;
Status last_status_;
MUST_USE_RESULT Status SetLastStatus(Status status) {
last_status_ = status;
return last_status_;
}
void RecordOptimizationStats();
struct Timer {
Timer(OptimizingCompiler* compiler, int64_t* location)
: compiler_(compiler),
start_(OS::Ticks()),
location_(location) { }
~Timer() {
*location_ += (OS::Ticks() - start_);
}
OptimizingCompiler* compiler_;
int64_t start_;
int64_t* location_;
};
};
// The V8 compiler
//
// General strategy: Source code is translated into an anonymous function w
/o
// parameters which then can be executed. If the source code contains other
// functions, they will be compiled and allocated as part of the compilatio
n
// of the source code.
// Please note this interface returns shared function infos. This means yo
u
// need to call Factory::NewFunctionFromSharedFunctionInfo before you have
a
// real function with a context.
class Compiler : public AllStatic {
public:
// Default maximum number of function optimization attempts before we
// give up.
static const int kDefaultMaxOptCount = 10;
static const int kMaxInliningLevels = 3;
// Call count before primitive functions trigger their own optimization.
static const int kCallsUntilPrimitiveOpt = 200;
// All routines return a SharedFunctionInfo.
// If an error occurs an exception is raised and the return handle
// contains NULL.
// Compile a String source within a context.
static Handle<SharedFunctionInfo> Compile(Handle<String> source,
Handle<Object> script_name,
int line_offset,
int column_offset,
v8::Extension* extension,
ScriptDataImpl* pre_data,
Handle<Object> script_data,
NativesFlag is_natives_code);
// Compile a String source within a context for Eval.
static Handle<SharedFunctionInfo> CompileEval(Handle<String> source,
Handle<Context> context,
bool is_global,
LanguageMode language_mode,
int scope_position);
// Compile from function info (used for lazy compilation). Returns true o
n
// success and false if the compilation resulted in a stack overflow.
static bool CompileLazy(CompilationInfo* info);
static void RecompileParallel(Handle<JSFunction> function);
// Compile a shared function info object (the function is possibly lazily
// compiled).
static Handle<SharedFunctionInfo> BuildFunctionInfo(FunctionLiteral* node
,
Handle<Script> script
);
// Set the function info for a newly compiled function.
static void SetFunctionInfo(Handle<SharedFunctionInfo> function_info,
FunctionLiteral* lit,
bool is_toplevel,
Handle<Script> script);
static void InstallOptimizedCode(OptimizingCompiler* info);
#ifdef ENABLE_DEBUGGER_SUPPORT
static bool MakeCodeForLiveEdit(CompilationInfo* info);
#endif #endif
static void RecordFunctionCompilation(Logger::LogEventsAndTags tag,
CompilationInfo* info,
Handle<SharedFunctionInfo> shared);
};
} } // namespace v8::internal
#endif // V8_COMPILER_H_
 End of changes. 3 change blocks. 
30 lines changed or deleted 471 lines changed or added


 counters.h   counters.h 
// counters.h // Copyright 2012 the V8 project authors. All rights reserved.
/* // Redistribution and use in source and binary forms, with or without
* Copyright (C) 2010 10gen Inc. // modification, are permitted provided that the following conditions are
* // met:
* This program is free software: you can redistribute it and/or modify //
* it under the terms of the GNU Affero General Public License, version // * Redistributions of source code must retain the above copyright
3, // notice, this list of conditions and the following disclaimer.
* as published by the Free Software Foundation. // * Redistributions in binary form must reproduce the above
* // copyright notice, this list of conditions and the following
* This program is distributed in the hope that it will be useful, // disclaimer in the documentation and/or other materials provided
* but WITHOUT ANY WARRANTY; without even the implied warranty of // with the distribution.
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // * Neither the name of Google Inc. nor the names of its
* GNU Affero General Public License for more details. // contributors may be used to endorse or promote products derived
* // from this software without specific prior written permission.
* You should have received a copy of the GNU Affero General Public Lice //
nse // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* along with this program. If not, see <http://www.gnu.org/licenses/>. // "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
#pragma once // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
#include "mongo/pch.h" // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
#include "../jsobj.h" // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
#include "../../util/net/message.h" // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
#include "../../util/processinfo.h" // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
#include "../../util/concurrency/spin_lock.h" // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "mongo/db/pdfile.h"
#ifndef V8_COUNTERS_H_
namespace mongo { #define V8_COUNTERS_H_
/** #include "../include/v8.h"
* for storing operation counters #include "allocation.h"
* note: not thread safe. ok with that for speed
*/ namespace v8 {
class OpCounters { namespace internal {
public:
// StatsCounters is an interface for plugging into external
OpCounters(); // counters for monitoring. Counters can be looked up and
void incInsertInWriteLock(int n) { _insert.x += n; } // manipulated by name.
void gotInsert() { _insert++; }
void gotQuery() { _query++; } class StatsTable {
void gotUpdate() { _update++; } public:
void gotDelete() { _delete++; } // Register an application-defined function where
void gotGetMore() { _getmore++; } // counters can be looked up.
void gotCommand() { _command++; } void SetCounterFunction(CounterLookupCallback f) {
lookup_function_ = f;
void gotOp( int op , bool isCommand ); }
BSONObj getObj() const; // Register an application-defined function to create
// a histogram for passing to the AddHistogramSample function
// thse are used by snmp, and other things, do not remove void SetCreateHistogramFunction(CreateHistogramCallback f) {
const AtomicUInt * getInsert() const { return &_insert; } create_histogram_function_ = f;
const AtomicUInt * getQuery() const { return &_query; } }
const AtomicUInt * getUpdate() const { return &_update; }
const AtomicUInt * getDelete() const { return &_delete; } // Register an application-defined function to add a sample
const AtomicUInt * getGetMore() const { return &_getmore; } // to a histogram created with CreateHistogram function
const AtomicUInt * getCommand() const { return &_command; } void SetAddHistogramSampleFunction(AddHistogramSampleCallback f) {
add_histogram_sample_function_ = f;
private: }
void _checkWrap();
bool HasCounterFunction() const {
// todo: there will be a lot of cache line contention on these. ne return lookup_function_ != NULL;
ed to do something }
// else eventually.
AtomicUInt _insert; // Lookup the location of a counter by name. If the lookup
AtomicUInt _query; // is successful, returns a non-NULL pointer for writing the
AtomicUInt _update; // value of the counter. Each thread calling this function
AtomicUInt _delete; // may receive a different location to store it's counter.
AtomicUInt _getmore; // The return value must not be cached and re-used across
AtomicUInt _command; // threads, although a single thread is free to cache it.
}; int* FindLocation(const char* name) {
if (!lookup_function_) return NULL;
extern OpCounters globalOpCounters; return lookup_function_(name);
extern OpCounters replOpCounters; }
class NetworkCounter { // Create a histogram by name. If the create is successful,
public: // returns a non-NULL pointer for use with AddHistogramSample
NetworkCounter() : _bytesIn(0), _bytesOut(0), _requests(0), _overfl // function. min and max define the expected minimum and maximum
ows(0) {} // sample values. buckets is the maximum number of buckets
void hit( long long bytesIn , long long bytesOut ); // that the samples will be grouped into.
void append( BSONObjBuilder& b ); void* CreateHistogram(const char* name,
private: int min,
long long _bytesIn; int max,
long long _bytesOut; size_t buckets) {
long long _requests; if (!create_histogram_function_) return NULL;
return create_histogram_function_(name, min, max, buckets);
}
// Add a sample to a histogram created with the CreateHistogram
// function.
void AddHistogramSample(void* histogram, int sample) {
if (!add_histogram_sample_function_) return;
return add_histogram_sample_function_(histogram, sample);
}
private:
StatsTable();
CounterLookupCallback lookup_function_;
CreateHistogramCallback create_histogram_function_;
AddHistogramSampleCallback add_histogram_sample_function_;
friend class Isolate;
DISALLOW_COPY_AND_ASSIGN(StatsTable);
};
// StatsCounters are dynamically created values which can be tracked in
// the StatsTable. They are designed to be lightweight to create and
// easy to use.
//
// Internally, a counter represents a value in a row of a StatsTable.
// The row has a 32bit value for each process/thread in the table and also
// a name (stored in the table metadata). Since the storage location can b
e
// thread-specific, this class cannot be shared across threads.
//
// This class is designed to be POD initialized. It will be registered wit
h
// the counter system on first use. For example:
// StatsCounter c = { "c:myctr", NULL, false };
struct StatsCounter {
const char* name_;
int* ptr_;
bool lookup_done_;
// Sets the counter to a specific value.
void Set(int value) {
int* loc = GetPtr();
if (loc) *loc = value;
}
// Increments the counter.
void Increment() {
int* loc = GetPtr();
if (loc) (*loc)++;
}
void Increment(int value) {
int* loc = GetPtr();
if (loc)
(*loc) += value;
}
// Decrements the counter.
void Decrement() {
int* loc = GetPtr();
if (loc) (*loc)--;
}
void Decrement(int value) {
int* loc = GetPtr();
if (loc) (*loc) -= value;
}
// Is this counter enabled?
// Returns false if table is full.
bool Enabled() {
return GetPtr() != NULL;
}
// Get the internal pointer to the counter. This is used
// by the code generator to emit code that manipulates a
// given counter without calling the runtime system.
int* GetInternalPointer() {
int* loc = GetPtr();
ASSERT(loc != NULL);
return loc;
}
protected:
// Returns the cached address of this counter location.
int* GetPtr() {
if (lookup_done_) return ptr_;
lookup_done_ = true;
ptr_ = FindLocationInStatsTable();
return ptr_;
}
private:
int* FindLocationInStatsTable() const;
};
// StatsCounterTimer t = { { L"t:foo", NULL, false }, 0, 0 };
struct StatsCounterTimer {
StatsCounter counter_;
int64_t start_time_;
int64_t stop_time_;
// Start the timer.
void Start();
// Stop the timer and record the results.
void Stop();
// Returns true if the timer is running.
bool Running() {
return counter_.Enabled() && start_time_ != 0 && stop_time_ == 0;
}
};
// A Histogram represents a dynamically created histogram in the StatsTable
.
//
// This class is designed to be POD initialized. It will be registered wit
h
// the histogram system on first use. For example:
// Histogram h = { "myhist", 0, 10000, 50, NULL, false };
struct Histogram {
const char* name_;
int min_;
int max_;
int num_buckets_;
void* histogram_;
bool lookup_done_;
// Add a single sample to this histogram.
void AddSample(int sample);
// Returns true if this histogram is enabled.
bool Enabled() {
return GetHistogram() != NULL;
}
protected:
// Returns the handle to the histogram.
void* GetHistogram() {
if (!lookup_done_) {
lookup_done_ = true;
histogram_ = CreateHistogram();
}
return histogram_;
}
private:
void* CreateHistogram() const;
};
// A HistogramTimer allows distributions of results to be created
// HistogramTimer t = { {L"foo", 0, 10000, 50, NULL, false}, 0, 0 };
struct HistogramTimer {
Histogram histogram_;
int64_t start_time_;
int64_t stop_time_;
// Start the timer.
void Start();
// Stop the timer and record the results.
void Stop();
// Returns true if the timer is running.
bool Running() {
return histogram_.Enabled() && (start_time_ != 0) && (stop_time_ == 0);
}
};
// Helper class for scoping a HistogramTimer.
class HistogramTimerScope BASE_EMBEDDED {
public:
explicit HistogramTimerScope(HistogramTimer* timer) :
timer_(timer) {
timer_->Start();
}
~HistogramTimerScope() {
timer_->Stop();
}
private:
HistogramTimer* timer_;
};
long long _overflows; } } // namespace v8::internal
SpinLock _lock; #endif // V8_COUNTERS_H_
};
extern NetworkCounter networkCounter;
}
 End of changes. 3 change blocks. 
86 lines changed or deleted 273 lines changed or added


 curop.h   curop.h 
skipping to change at line 123 skipping to change at line 123
} }
void reset( int sz = 0 ) { void reset( int sz = 0 ) {
_lock.lock(); _lock.lock();
_reset( sz ); _reset( sz );
_lock.unlock(); _lock.unlock();
} }
void set( const BSONObj& o ) { void set( const BSONObj& o ) {
scoped_spinlock lk(_lock); scoped_spinlock lk(_lock);
int sz = o.objsize(); size_t sz = o.objsize();
if ( sz > (int) sizeof(_buf) ) { if ( sz > sizeof(_buf) ) {
_reset(TOO_BIG_SENTINEL); _reset(TOO_BIG_SENTINEL);
} }
else { else {
memcpy(_buf, o.objdata(), sz ); memcpy(_buf, o.objdata(), sz );
} }
} }
int size() const { return *_size; } int size() const { return *_size; }
bool have() const { return size() > 0; } bool have() const { return size() > 0; }
 End of changes. 1 change blocks. 
2 lines changed or deleted 2 lines changed or added


 engine_v8.h   engine_v8.h 
skipping to change at line 26 skipping to change at line 26
*/ */
#pragma once #pragma once
#include <v8.h> #include <v8.h>
#include <vector> #include <vector>
#include "mongo/base/disallow_copying.h" #include "mongo/base/disallow_copying.h"
#include "mongo/client/dbclientinterface.h" #include "mongo/client/dbclientinterface.h"
#include "mongo/client/dbclientcursor.h" #include "mongo/client/dbclientcursor.h"
#include "mongo/platform/unordered_map.h"
#include "mongo/scripting/engine.h" #include "mongo/scripting/engine.h"
#include "mongo/scripting/v8_deadline_monitor.h" #include "mongo/scripting/v8_deadline_monitor.h"
#include "mongo/scripting/v8_profiler.h" #include "mongo/scripting/v8_profiler.h"
/** /**
* V8_SIMPLE_HEADER must be placed in any function called from a public API * V8_SIMPLE_HEADER must be placed in any function called from a public API
* that work with v8 handles (and/or must be within the V8Scope's isolate * that work with v8 handles (and/or must be within the V8Scope's isolate
* and context). Be sure to close the handle_scope if returning a v8::Hand le! * and context). Be sure to close the handle_scope if returning a v8::Hand le!
*/ */
#define V8_SIMPLE_HEADER \ #define V8_SIMPLE_HEADER \
skipping to change at line 204 skipping to change at line 205
int timeoutMs = 0, bool ignoreReturn = false, int timeoutMs = 0, bool ignoreReturn = false,
bool readOnlyArgs = false, bool readOnlyRecv = f alse); bool readOnlyArgs = false, bool readOnlyRecv = f alse);
virtual bool exec(const StringData& code, const string& name, bool printResult, virtual bool exec(const StringData& code, const string& name, bool printResult,
bool reportError, bool assertOnError, int timeout Ms); bool reportError, bool assertOnError, int timeout Ms);
// functions to create v8 object and function templates // functions to create v8 object and function templates
virtual void injectNative(const char* field, NativeFunction func, v oid* data = 0); virtual void injectNative(const char* field, NativeFunction func, v oid* data = 0);
void injectNative(const char* field, NativeFunction func, v8::Handl e<v8::Object>& obj, void injectNative(const char* field, NativeFunction func, v8::Handl e<v8::Object>& obj,
void* data = 0); void* data = 0);
void injectV8Function(const char* field, v8Function func);
void injectV8Function(const char* field, v8Function func, v8::Handl // These functions inject a function (either an unwrapped function
e<v8::Object>& obj); pointer or a pre-wrapped
void injectV8Function(const char* field, v8Function func, v8::Handl // FunctionTemplate) into the provided object. If no object is prov
e<v8::Template>& t); ided, the function will
// be injected at global scope. These functions take care of settin
g the function and class
// name on the returned FunctionTemplate.
v8::Handle<v8::FunctionTemplate> injectV8Function(const char* name,
v8Function func);
v8::Handle<v8::FunctionTemplate> injectV8Function(const char* name,
v8Function func,
v8::Handle<v8::Ob
ject>& obj);
v8::Handle<v8::FunctionTemplate> injectV8Function(const char* name,
v8::Handle<v8::Fu
nctionTemplate> ft,
v8::Handle<v8::Ob
ject>& obj);
// Injects a method into the provided prototype
v8::Handle<v8::FunctionTemplate> injectV8Method(const char* name,
v8Function func,
v8::Handle<v8::Obje
ctTemplate>& proto);
v8::Handle<v8::FunctionTemplate> createV8Function(v8Function func); v8::Handle<v8::FunctionTemplate> createV8Function(v8Function func);
virtual ScriptingFunction _createFunction(const char* code, virtual ScriptingFunction _createFunction(const char* code,
ScriptingFunction functio nNumber = 0); ScriptingFunction functio nNumber = 0);
v8::Local<v8::Function> __createFunction(const char* code, v8::Local<v8::Function> __createFunction(const char* code,
ScriptingFunction function Number = 0); ScriptingFunction function Number = 0);
/** /**
* Convert BSON types to v8 Javascript types * Convert BSON types to v8 Javascript types
*/ */
v8::Persistent<v8::Object> mongoToLZV8(const mongo::BSONObj& m, boo l readOnly = false); v8::Handle<v8::Object> mongoToLZV8(const mongo::BSONObj& m, bool re adOnly = false);
v8::Handle<v8::Value> mongoToV8Element(const BSONElement& f, bool r eadOnly = false); v8::Handle<v8::Value> mongoToV8Element(const BSONElement& f, bool r eadOnly = false);
/** /**
* Convert v8 Javascript types to BSON types * Convert v8 Javascript types to BSON types
*/ */
mongo::BSONObj v8ToMongo(v8::Handle<v8::Object> obj, int depth = 0) ; mongo::BSONObj v8ToMongo(v8::Handle<v8::Object> obj, int depth = 0) ;
void v8ToMongoElement(BSONObjBuilder& b, void v8ToMongoElement(BSONObjBuilder& b,
const string& sname, const StringData& sname,
v8::Handle<v8::Value> value, v8::Handle<v8::Value> value,
int depth = 0, int depth = 0,
BSONObj* originalParent = 0); BSONObj* originalParent = 0);
void v8ToMongoObject(BSONObjBuilder& b, void v8ToMongoObject(BSONObjBuilder& b,
const string& sname, const StringData& sname,
v8::Handle<v8::Value> value, v8::Handle<v8::Value> value,
int depth, int depth,
BSONObj* originalParent); BSONObj* originalParent);
void v8ToMongoNumber(BSONObjBuilder& b, void v8ToMongoNumber(BSONObjBuilder& b,
const string& elementName, const StringData& elementName,
v8::Handle<v8::Value> value, v8::Handle<v8::Number> value,
BSONObj* originalParent); BSONObj* originalParent);
void v8ToMongoNumberLong(BSONObjBuilder& b,
const string& elementName,
v8::Handle<v8::Object> obj);
void v8ToMongoInternal(BSONObjBuilder& b,
const string& elementName,
v8::Handle<v8::Object> obj);
void v8ToMongoRegex(BSONObjBuilder& b, void v8ToMongoRegex(BSONObjBuilder& b,
const string& elementName, const StringData& elementName,
v8::Handle<v8::Object> v8Regex); v8::Handle<v8::RegExp> v8Regex);
void v8ToMongoDBRef(BSONObjBuilder& b, void v8ToMongoDBRef(BSONObjBuilder& b,
const string& elementName, const StringData& elementName,
v8::Handle<v8::Object> obj); v8::Handle<v8::Object> obj);
void v8ToMongoBinData(BSONObjBuilder& b, void v8ToMongoBinData(BSONObjBuilder& b,
const string& elementName, const StringData& elementName,
v8::Handle<v8::Object> obj); v8::Handle<v8::Object> obj);
void v8ToMongoObjectID(BSONObjBuilder& b, OID v8ToMongoObjectID(v8::Handle<v8::Object> obj);
const string& elementName,
v8::Handle<v8::Object> obj);
v8::Function* getNamedCons(const char* name);
v8::Function* getObjectIdCons();
v8::Local<v8::Value> newId(const OID& id); v8::Local<v8::Value> newId(const OID& id);
/** /**
* Convert a JavaScript exception to a stl string. Requires * Convert a JavaScript exception to a stl string. Requires
* access to the V8Scope instance to report source context informat ion. * access to the V8Scope instance to report source context informat ion.
*/ */
std::string v8ExceptionToSTLString(const v8::TryCatch* try_catch); std::string v8ExceptionToSTLString(const v8::TryCatch* try_catch);
/** /**
* GC callback for weak references to BSON objects (via BSONHolder)
*/
v8::Persistent<v8::Object> wrapBSONObject(v8::Local<v8::Object> obj
, BSONHolder* data);
/**
* Create a V8 string with a local handle * Create a V8 string with a local handle
*/ */
static inline v8::Handle<v8::String> v8StringData(StringData str) { static inline v8::Handle<v8::String> v8StringData(StringData str) {
return v8::String::New(str.rawData()); return v8::String::New(str.rawData());
} }
/** /**
* Get the isolate this scope belongs to (can be called from any th read, but v8 requires * Get the isolate this scope belongs to (can be called from any th read, but v8 requires
* the new thread enter the isolate and context. Only one thread can enter the isolate. * the new thread enter the isolate and context. Only one thread can enter the isolate.
*/ */
v8::Isolate* getIsolate() { return _isolate; } v8::Isolate* getIsolate() { return _isolate; }
/** /**
* Get the JS context this scope executes within. * Get the JS context this scope executes within.
*/ */
v8::Persistent<v8::Context> getContext() { return _context; } v8::Persistent<v8::Context> getContext() { return _context; }
/**
* Get the global JS object
*/
v8::Persistent<v8::Object> getGlobal() { return _global; }
ObjTracker<BSONHolder> bsonHolderTracker; ObjTracker<BSONHolder> bsonHolderTracker;
ObjTracker<DBClientWithCommands> dbClientWithCommandsTracker; ObjTracker<DBClientWithCommands> dbClientWithCommandsTracker;
ObjTracker<DBClientBase> dbClientBaseTracker; ObjTracker<DBClientBase> dbClientBaseTracker;
ObjTracker<DBClientCursor> dbClientCursorTracker; ObjTracker<DBClientCursor> dbClientCursorTracker;
// These are all named after the JS constructor name + FT
v8::Handle<v8::FunctionTemplate> ObjectIdFT() const { return
_ObjectIdFT; }
v8::Handle<v8::FunctionTemplate> DBRefFT() const { return
_DBRefFT; }
v8::Handle<v8::FunctionTemplate> DBPointerFT() const { return
_DBPointerFT; }
v8::Handle<v8::FunctionTemplate> BinDataFT() const { return
_BinDataFT; }
v8::Handle<v8::FunctionTemplate> NumberLongFT() const { return
_NumberLongFT; }
v8::Handle<v8::FunctionTemplate> NumberIntFT() const { return
_NumberIntFT; }
v8::Handle<v8::FunctionTemplate> TimestampFT() const { return
_TimestampFT; }
v8::Handle<v8::FunctionTemplate> MinKeyFT() const { return
_MinKeyFT; }
v8::Handle<v8::FunctionTemplate> MaxKeyFT() const { return
_MaxKeyFT; }
v8::Handle<v8::FunctionTemplate> MongoFT() const { return
_MongoFT; }
v8::Handle<v8::FunctionTemplate> DBFT() const { return
_DBFT; }
v8::Handle<v8::FunctionTemplate> DBCollectionFT() const { return
_DBCollectionFT; }
v8::Handle<v8::FunctionTemplate> DBQueryFT() const { return
_DBQueryFT; }
v8::Handle<v8::FunctionTemplate> InternalCursorFT() const { return
_InternalCursorFT; }
v8::Handle<v8::FunctionTemplate> LazyBsonFT() const { return
_LazyBsonFT; }
v8::Handle<v8::FunctionTemplate> ROBsonFT() const { return
_ROBsonFT; }
template <size_t N>
v8::Handle<v8::String> strLitToV8(const char (&str)[N]) {
// Note that _strLitMap is keyed on string pointer not string
// value. This is OK because each string literal has a constant
// pointer for the program's lifetime. This works best if (but
does
// not require) the linker interns all string literals giving
// identical strings used in different places the same pointer.
StrLitMap::iterator it = _strLitMap.find(str);
if (it != _strLitMap.end())
return it->second;
StringData sd (str, StringData::LiteralTag());
v8::Handle<v8::String> v8Str = v8StringData(sd);
// We never need to Dispose since this should last as long as V
8Scope exists
_strLitMap[str] = v8::Persistent<v8::String>::New(v8Str);
return v8Str;
}
private: private:
/** /**
* Attach data to obj such that the data has the same lifetime as t
he Object obj points to.
* obj must have been created by either LazyBsonFT or ROBsonFT.
*/
void wrapBSONObject(v8::Handle<v8::Object> obj, BSONObj data, bool
readOnly);
/**
* Trampoline to call a c++ function with a specific signature (V8S cope*, v8::Arguments&). * Trampoline to call a c++ function with a specific signature (V8S cope*, v8::Arguments&).
* Handles interruption, exceptions, etc. * Handles interruption, exceptions, etc.
*/ */
static v8::Handle<v8::Value> v8Callback(const v8::Arguments& args); static v8::Handle<v8::Value> v8Callback(const v8::Arguments& args);
/** /**
* Interpreter agnostic 'Native Callback' trampoline. Note this is only called * Interpreter agnostic 'Native Callback' trampoline. Note this is only called
* from v8Callback(). * from v8Callback().
*/ */
static v8::Handle<v8::Value> nativeCallback(V8Scope* scope, const v 8::Arguments& args); static v8::Handle<v8::Value> nativeCallback(V8Scope* scope, const v 8::Arguments& args);
skipping to change at line 345 skipping to change at line 393
* be supported. * be supported.
*/ */
void registerOpId(); void registerOpId();
/** /**
* Unregister this scope with the mongo op id. * Unregister this scope with the mongo op id.
*/ */
void unregisterOpId(); void unregisterOpId();
/** /**
* Creates a new instance of the MinKey object
*/
v8::Local<v8::Object> newMinKeyInstance();
/**
* Creates a new instance of the MaxKey object
*/
v8::Local<v8::Object> newMaxKeyInstance();
/**
* Create a new function; primarily used for BSON/V8 conversion. * Create a new function; primarily used for BSON/V8 conversion.
*/ */
v8::Local<v8::Value> newFunction(const char *code); v8::Local<v8::Value> newFunction(const char *code);
template <typename _HandleType> template <typename _HandleType>
bool checkV8ErrorState(const _HandleType& resultHandle, bool checkV8ErrorState(const _HandleType& resultHandle,
const v8::TryCatch& try_catch, const v8::TryCatch& try_catch,
bool reportError = true, bool reportError = true,
bool assertOnError = true); bool assertOnError = true);
V8ScriptEngine* _engine; V8ScriptEngine* _engine;
v8::Persistent<v8::Context> _context; v8::Persistent<v8::Context> _context;
v8::Persistent<v8::Object> _global; v8::Persistent<v8::Object> _global;
string _error; string _error;
vector<v8::Persistent<v8::Value> > _funcs; vector<v8::Persistent<v8::Value> > _funcs;
enum ConnectState { NOT, LOCAL, EXTERNAL }; enum ConnectState { NOT, LOCAL, EXTERNAL };
ConnectState _connectState; ConnectState _connectState;
v8::Persistent<v8::FunctionTemplate> lzFunctionTemplate; // These are all named after the JS constructor name + FT
v8::Persistent<v8::ObjectTemplate> lzObjectTemplate; v8::Persistent<v8::FunctionTemplate> _ObjectIdFT;
v8::Persistent<v8::ObjectTemplate> roObjectTemplate; v8::Persistent<v8::FunctionTemplate> _DBRefFT;
v8::Persistent<v8::ObjectTemplate> lzArrayTemplate; v8::Persistent<v8::FunctionTemplate> _DBPointerFT;
v8::Persistent<v8::ObjectTemplate> internalFieldObjects; v8::Persistent<v8::FunctionTemplate> _BinDataFT;
v8::Persistent<v8::FunctionTemplate> _NumberLongFT;
v8::Persistent<v8::FunctionTemplate> _NumberIntFT;
v8::Persistent<v8::FunctionTemplate> _TimestampFT;
v8::Persistent<v8::FunctionTemplate> _MinKeyFT;
v8::Persistent<v8::FunctionTemplate> _MaxKeyFT;
v8::Persistent<v8::FunctionTemplate> _MongoFT;
v8::Persistent<v8::FunctionTemplate> _DBFT;
v8::Persistent<v8::FunctionTemplate> _DBCollectionFT;
v8::Persistent<v8::FunctionTemplate> _DBQueryFT;
v8::Persistent<v8::FunctionTemplate> _InternalCursorFT;
v8::Persistent<v8::FunctionTemplate> _LazyBsonFT;
v8::Persistent<v8::FunctionTemplate> _ROBsonFT;
v8::Persistent<v8::Function> _jsRegExpConstructor;
v8::Isolate* _isolate; v8::Isolate* _isolate;
V8CpuProfiler _cpuProfiler; V8CpuProfiler _cpuProfiler;
// See comments in strLitToV8
typedef unordered_map<const char*, v8::Handle<v8::String> > StrLitM
ap;
StrLitMap _strLitMap;
mongo::mutex _interruptLock; // protects interruption-related flags mongo::mutex _interruptLock; // protects interruption-related flags
bool _inNativeExecution; // protected by _interruptLock bool _inNativeExecution; // protected by _interruptLock
bool _pendingKill; // protected by _interruptLock bool _pendingKill; // protected by _interruptLock
int _opId; // op id for this scope int _opId; // op id for this scope
}; };
/// Helper to extract V8Scope for an Isolate
inline V8Scope* getScope(v8::Isolate* isolate) {
return static_cast<V8Scope*>(isolate->GetData());
}
class V8ScriptEngine : public ScriptEngine { class V8ScriptEngine : public ScriptEngine {
public: public:
V8ScriptEngine(); V8ScriptEngine();
virtual ~V8ScriptEngine(); virtual ~V8ScriptEngine();
virtual Scope* createScope() { return new V8Scope(this); } virtual Scope* createScope() { return new V8Scope(this); }
virtual void runTest() {} virtual void runTest() {}
bool utf8Ok() const { return true; } bool utf8Ok() const { return true; }
/** /**
* Interrupt a single active v8 execution context * Interrupt a single active v8 execution context
 End of changes. 19 change blocks. 
48 lines changed or deleted 135 lines changed or added


 hash.h   hash.h 
/** @file hash.h */ /**
* Copyright (C) 2008-2012 10gen Inc.
/* Copyright 2009 10gen Inc. *
* * This program is free software: you can redistribute it and/or modify
* Licensed under the Apache License, Version 2.0 (the "License"); * it under the terms of the GNU Affero General Public License, version 3
* you may not use this file except in compliance with the License. ,
* You may obtain a copy of the License at * as published by the Free Software Foundation.
* *
* http://www.apache.org/licenses/LICENSE-2.0 * This program is distributed in the hope that it will be useful,
* * but WITHOUT ANY WARRANTY; without even the implied warranty of
* Unless required by applicable law or agreed to in writing, software * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* distributed under the License is distributed on an "AS IS" BASIS, * GNU Affero General Public License for more details.
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or impli *
ed. * You should have received a copy of the GNU Affero General Public Licen
* See the License for the specific language governing permissions and se
* limitations under the License. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#pragma once #pragma once
namespace mongoutils { #include "mongo/pch.h"
#include "mongo/db/jsobj.h"
/** @return hash of a pointer to an unsigned. so you get a 32 bit hash #include <iostream>
out, regardless of whether
pointers are 32 or 64 bit on the particular platform. namespace mongo {
is there a faster way to impl this that hashes just as well? class GeoHash;
*/ struct Point;
inline unsigned hashPointer(void *v) { std::ostream& operator<<(std::ostream &s, const GeoHash &h);
unsigned x = 0;
unsigned char *p = (unsigned char *) &v; /* This class maps an unsigned x,y coordinate pair to a hash value.
for( unsigned i = 0; i < sizeof(void*); i++ ) { * To hash values more interesting than unsigned, use the GeoHashConver
x = x * 131 + p[i]; ter,
} * which maps doubles to unsigned values.
return x; */
} class GeoHash {
public:
inline unsigned hash(unsigned u) { GeoHash();
unsigned char *p = (unsigned char *) &u; // The strings are binary values of length <= 64,
return (((((p[3] * 131) + p[2]) * 131) + p[1]) * 131) + p[0]; // examples: 1001010100101, 1
} explicit GeoHash(const string& hash);
explicit GeoHash(const char *s);
} // bits is how many bits are used to hash each of x and y.
GeoHash(unsigned x, unsigned y, unsigned bits = 32);
GeoHash(const GeoHash& old);
// hash is a raw hash value. we just copy these into our private f
ields.
GeoHash(long long hash, unsigned bits);
// This only works if e is BinData. To get a GeoHash from other BS
ONElements,
// use the converter class.
explicit GeoHash(const BSONElement& e, unsigned bits = 32);
// Convert from the hashed value to unsigned.
void unhash(unsigned *x, unsigned *y) const;
/** Is the 'bit'-th most significant bit set? (NOT the least signi
ficant) */
static bool isBitSet(unsigned val, unsigned bit);
/** Return a GeoHash with one bit of precision lost. */
GeoHash up() const;
bool hasPrefix(const GeoHash& other) const;
string toString() const;
string toStringHex1() const;
void setBit(unsigned pos, bool value);
bool getBit(unsigned pos) const;
bool getBitX(unsigned pos) const;
bool getBitY(unsigned pos) const;
// XXX: what does this really do?
BSONObj wrap(const char* name = "") const;
// XXX what does this do
bool constrains() const;
bool canRefine() const;
// XXX comment better
bool atMinX() const;
bool atMinY() const;
// XXX comment better
bool atMaxX() const;
bool atMaxY() const;
// XXX: what does this do
void move(int x, int y);
GeoHash& operator=(const GeoHash& h);
bool operator==(const GeoHash& h) const;
bool operator!=(const GeoHash& h) const;
bool operator<(const GeoHash& h) const;
// Append the hash in s to our current hash. We expect s to be '0'
or '1' or '\0',
// though we also treat non-'1' values as '0'.
GeoHash& operator+=(const char* s);
GeoHash operator+(const char *s) const;
GeoHash operator+(const std::string& s) const;
// Append the hash to the builder provided.
void appendToBuilder(BSONObjBuilder* b, const char * name) const;
long long getHash() const;
unsigned getBits() const;
GeoHash commonPrefix(const GeoHash& other) const;
private:
// XXX not sure why this is done exactly. Why does binary
// data need to be reversed? byte ordering of some sort?
static void _copyAndReverse(char *dst, const char *src);
// Create a hash from the provided string. Used by the string and
char* cons.
void initFromString(const char *s);
/* Keep the upper _bits*2 bits of _hash, clear the lower bits.
* Maybe there's junk in there? XXX Not sure why this is done.
*/
void clearUnusedBits();
// XXX: what does this do
void _move(unsigned offset, int d);
// XXX: this is nasty and has no example
void unhash_fast(unsigned *x, unsigned *y) const;
void unhash_slow(unsigned *x, unsigned *y) const;
long long _hash;
// Bits per field. Our hash is 64 bits, and we have an X and a Y f
ield,
// so this is 1 to 32.
unsigned _bits;
};
/* Convert between various types and the GeoHash. We need additional in
formation (scaling etc.)
* to convert to/from GeoHash. The additional information doesn't chan
ge often and is the same
* for all conversions, so we stick all the conversion methods here wit
h their associated
* data.
*/
class GeoHashConverter {
public:
struct Parameters {
// How many bits to use for the hash?
int bits;
// X/Y values must be [min, max]
double min;
double max;
// Values are scaled by this when converted to/from hash scale.
double scaling;
};
GeoHashConverter(const Parameters &params);
int getBits() const { return _params.bits; }
double getError() const { return _error; }
double getErrorSphere() const { return _errorSphere ;}
double getMin() const { return _params.min; }
double getMax() const { return _params.max; }
double distanceBetweenHashes(const GeoHash& a, const GeoHash& b) co
nst;
/**
* Hashing functions. Convert the following types to a GeoHash:
* BSONElement
* BSONObj
* Point
* double, double
*/
GeoHash hash(const Point &p) const;
GeoHash hash(const BSONElement& e) const;
GeoHash hash(const BSONObj& o) const;
// src is printed out as debugging information. I'm not sure if it
's actually
// somehow the 'source' of o? Anyway, this is nasty, very nasty.
XXX
GeoHash hash(const BSONObj& o, const BSONObj* src) const;
GeoHash hash(double x, double y) const;
/** Unhashing functions.
* Convert from a hash to the following types:
* double, double
* Point
* BSONObj
*/
// XXX: these should have consistent naming
Point unhashToPoint(const GeoHash &h) const;
Point unhashToPoint(const BSONElement &e) const;
BSONObj unhashToBSONObj(const GeoHash& h) const;
void unhash(const GeoHash &h, double *x, double *y) const;
double sizeOfDiag(const GeoHash& a) const;
// XXX: understand/clean this.
double sizeEdge(const GeoHash& a) const;
private:
// Convert from an unsigned in [0, (max-min)*scaling] to [min, max]
double convertFromHashScale(unsigned in) const;
// Convert from a double that is [min, max] to an unsigned in [0, (
max-min)*scaling]
unsigned convertToHashScale(double in) const;
Parameters _params;
// We compute these based on the _params:
double _error;
double _errorSphere;
};
} // namespace mongo
 End of changes. 2 change blocks. 
17 lines changed or deleted 17 lines changed or added


 jsregexp.h   jsregexp.h 
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- // Copyright 2012 the V8 project authors. All rights reserved.
* // Redistribution and use in source and binary forms, with or without
* ***** BEGIN LICENSE BLOCK ***** // modification, are permitted provided that the following conditions are
* Version: MPL 1.1/GPL 2.0/LGPL 2.1 // met:
* //
* The contents of this file are subject to the Mozilla Public License Vers // * Redistributions of source code must retain the above copyright
ion // notice, this list of conditions and the following disclaimer.
* 1.1 (the "License"); you may not use this file except in compliance with // * Redistributions in binary form must reproduce the above
* the License. You may obtain a copy of the License at // copyright notice, this list of conditions and the following
* http://www.mozilla.org/MPL/ // disclaimer in the documentation and/or other materials provided
* // with the distribution.
* Software distributed under the License is distributed on an "AS IS" basi // * Neither the name of Google Inc. nor the names of its
s, // contributors may be used to endorse or promote products derived
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License // from this software without specific prior written permission.
* for the specific language governing rights and limitations under the //
* License. // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* The Original Code is Mozilla Communicator client code, released // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* March 31, 1998. // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* The Initial Developer of the Original Code is // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* Netscape Communications Corporation. // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* Portions created by the Initial Developer are Copyright (C) 1998 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* the Initial Developer. All Rights Reserved. // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* Contributor(s): // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Alternatively, the contents of this file may be used under the terms of #ifndef V8_JSREGEXP_H_
* either of the GNU General Public License Version 2 or later (the "GPL"), #define V8_JSREGEXP_H_
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL
"), #include "allocation.h"
* in which case the provisions of the GPL or the LGPL are applicable inste #include "assembler.h"
ad #include "zone-inl.h"
* of those above. If you wish to allow use of your version of this file on
ly namespace v8 {
* under the terms of either the GPL or the LGPL, and not to allow others t namespace internal {
o
* use your version of this file under the terms of the MPL, indicate your class NodeVisitor;
* decision by deleting the provisions above and replace them with the noti class RegExpCompiler;
ce class RegExpMacroAssembler;
* and other provisions required by the GPL or the LGPL. If you do not dele class RegExpNode;
te class RegExpTree;
* the provisions above, a recipient may use your version of this file unde class BoyerMooreLookahead;
r
* the terms of any one of the MPL, the GPL or the LGPL. class RegExpImpl {
* public:
* ***** END LICENSE BLOCK ***** */ // Whether V8 is compiled with native regexp support or not.
static bool UsesNativeRegExp() {
#ifndef jsregexp_h___ #ifdef V8_INTERPRETED_REGEXP
#define jsregexp_h___ return false;
/* #else
* JS regular expression interface. return true;
*/
#include <stddef.h>
#include "jspubtd.h"
#include "jsstr.h"
#ifdef JS_THREADSAFE
#include "jsdhash.h"
#endif #endif
}
// Creates a regular expression literal in the old space.
// This function calls the garbage collector if necessary.
static Handle<Object> CreateRegExpLiteral(Handle<JSFunction> constructor,
Handle<String> pattern,
Handle<String> flags,
bool* has_pending_exception);
// Returns a string representation of a regular expression.
// Implements RegExp.prototype.toString, see ECMA-262 section 15.10.6.4.
// This function calls the garbage collector if necessary.
static Handle<String> ToString(Handle<Object> value);
// Parses the RegExp pattern and prepares the JSRegExp object with
// generic data and choice of implementation - as well as what
// the implementation wants to store in the data field.
// Returns false if compilation fails.
static Handle<Object> Compile(Handle<JSRegExp> re,
Handle<String> pattern,
Handle<String> flags,
Zone* zone);
// See ECMA-262 section 15.10.6.2.
// This function calls the garbage collector if necessary.
static Handle<Object> Exec(Handle<JSRegExp> regexp,
Handle<String> subject,
int index,
Handle<JSArray> lastMatchInfo);
// Prepares a JSRegExp object with Irregexp-specific data.
static void IrregexpInitialize(Handle<JSRegExp> re,
Handle<String> pattern,
JSRegExp::Flags flags,
int capture_register_count);
static void AtomCompile(Handle<JSRegExp> re,
Handle<String> pattern,
JSRegExp::Flags flags,
Handle<String> match_pattern);
static Handle<Object> AtomExec(Handle<JSRegExp> regexp,
Handle<String> subject,
int index,
Handle<JSArray> lastMatchInfo);
enum IrregexpResult { RE_FAILURE = 0, RE_SUCCESS = 1, RE_EXCEPTION = -1 }
;
// Prepare a RegExp for being executed one or more times (using
// IrregexpExecOnce) on the subject.
// This ensures that the regexp is compiled for the subject, and that
// the subject is flat.
// Returns the number of integer spaces required by IrregexpExecOnce
// as its "registers" argument. If the regexp cannot be compiled,
// an exception is set as pending, and this function returns negative.
static int IrregexpPrepare(Handle<JSRegExp> regexp,
Handle<String> subject);
// Calculate the size of offsets vector for the case of global regexp
// and the number of matches this vector is able to store.
static int GlobalOffsetsVectorSize(Handle<JSRegExp> regexp,
int registers_per_match,
int* max_matches);
// Execute a regular expression on the subject, starting from index.
// If matching succeeds, return the number of matches. This can be large
r
// than one in the case of global regular expressions.
// The captures and subcaptures are stored into the registers vector.
// If matching fails, returns RE_FAILURE.
// If execution fails, sets a pending exception and returns RE_EXCEPTION.
static int IrregexpExecRaw(Handle<JSRegExp> regexp,
Handle<String> subject,
int index,
Vector<int> registers);
// Execute an Irregexp bytecode pattern.
// On a successful match, the result is a JSArray containing
// captured positions. On a failure, the result is the null value.
// Returns an empty handle in case of an exception.
static Handle<Object> IrregexpExec(Handle<JSRegExp> regexp,
Handle<String> subject,
int index,
Handle<JSArray> lastMatchInfo);
// Array index in the lastMatchInfo array.
static const int kLastCaptureCount = 0;
static const int kLastSubject = 1;
static const int kLastInput = 2;
static const int kFirstCapture = 3;
static const int kLastMatchOverhead = 3;
// Direct offset into the lastMatchInfo array.
static const int kLastCaptureCountOffset =
FixedArray::kHeaderSize + kLastCaptureCount * kPointerSize;
static const int kLastSubjectOffset =
FixedArray::kHeaderSize + kLastSubject * kPointerSize;
static const int kLastInputOffset =
FixedArray::kHeaderSize + kLastInput * kPointerSize;
static const int kFirstCaptureOffset =
FixedArray::kHeaderSize + kFirstCapture * kPointerSize;
// Used to access the lastMatchInfo array.
static int GetCapture(FixedArray* array, int index) {
return Smi::cast(array->get(index + kFirstCapture))->value();
}
static void SetLastCaptureCount(FixedArray* array, int to) {
array->set(kLastCaptureCount, Smi::FromInt(to));
}
static void SetLastSubject(FixedArray* array, String* to) {
array->set(kLastSubject, to);
}
static void SetLastInput(FixedArray* array, String* to) {
array->set(kLastInput, to);
}
static void SetCapture(FixedArray* array, int index, int to) {
array->set(index + kFirstCapture, Smi::FromInt(to));
}
static int GetLastCaptureCount(FixedArray* array) {
return Smi::cast(array->get(kLastCaptureCount))->value();
}
// For acting on the JSRegExp data FixedArray.
static int IrregexpMaxRegisterCount(FixedArray* re);
static void SetIrregexpMaxRegisterCount(FixedArray* re, int value);
static int IrregexpNumberOfCaptures(FixedArray* re);
static int IrregexpNumberOfRegisters(FixedArray* re);
static ByteArray* IrregexpByteCode(FixedArray* re, bool is_ascii);
static Code* IrregexpNativeCode(FixedArray* re, bool is_ascii);
// Limit the space regexps take up on the heap. In order to limit this w
e
// would like to keep track of the amount of regexp code on the heap. Th
is
// is not tracked, however. As a conservative approximation we track the
// total regexp code compiled including code that has subsequently been f
reed
// and the total executable memory at any point.
static const int kRegExpExecutableMemoryLimit = 16 * MB;
static const int kRegWxpCompiledLimit = 1 * MB;
private:
static String* last_ascii_string_;
static String* two_byte_cached_string_;
static bool CompileIrregexp(
Handle<JSRegExp> re, Handle<String> sample_subject, bool is_ascii);
static inline bool EnsureCompiledIrregexp(
Handle<JSRegExp> re, Handle<String> sample_subject, bool is_ascii);
// Set the subject cache. The previous string buffer is not deleted, so
the
// caller should ensure that it doesn't leak.
static void SetSubjectCache(String* subject,
char* utf8_subject,
int uft8_length,
int character_position,
int utf8_position);
// A one element cache of the last utf8_subject string and its length. T
he
// subject JS String object is cached in the heap. We also cache a
// translation between position and utf8 position.
static char* utf8_subject_cache_;
static int utf8_length_cache_;
static int utf8_position_;
static int character_position_;
};
// Represents the location of one element relative to the intersection of
// two sets. Corresponds to the four areas of a Venn diagram.
enum ElementInSetsRelation {
kInsideNone = 0,
kInsideFirst = 1,
kInsideSecond = 2,
kInsideBoth = 3
};
// Represents code units in the range from from_ to to_, both ends are
// inclusive.
class CharacterRange {
public:
CharacterRange() : from_(0), to_(0) { }
// For compatibility with the CHECK_OK macro
CharacterRange(void* null) { ASSERT_EQ(NULL, null); } //NOLINT
CharacterRange(uc16 from, uc16 to) : from_(from), to_(to) { }
static void AddClassEscape(uc16 type, ZoneList<CharacterRange>* ranges,
Zone* zone);
static Vector<const int> GetWordBounds();
static inline CharacterRange Singleton(uc16 value) {
return CharacterRange(value, value);
}
static inline CharacterRange Range(uc16 from, uc16 to) {
ASSERT(from <= to);
return CharacterRange(from, to);
}
static inline CharacterRange Everything() {
return CharacterRange(0, 0xFFFF);
}
bool Contains(uc16 i) { return from_ <= i && i <= to_; }
uc16 from() const { return from_; }
void set_from(uc16 value) { from_ = value; }
uc16 to() const { return to_; }
void set_to(uc16 value) { to_ = value; }
bool is_valid() { return from_ <= to_; }
bool IsEverything(uc16 max) { return from_ == 0 && to_ >= max; }
bool IsSingleton() { return (from_ == to_); }
void AddCaseEquivalents(ZoneList<CharacterRange>* ranges, bool is_ascii,
Zone* zone);
static void Split(ZoneList<CharacterRange>* base,
Vector<const int> overlay,
ZoneList<CharacterRange>** included,
ZoneList<CharacterRange>** excluded,
Zone* zone);
// Whether a range list is in canonical form: Ranges ordered by from valu
e,
// and ranges non-overlapping and non-adjacent.
static bool IsCanonical(ZoneList<CharacterRange>* ranges);
// Convert range list to canonical form. The characters covered by the ra
nges
// will still be the same, but no character is in more than one range, an
d
// adjacent ranges are merged. The resulting list may be shorter than the
// original, but cannot be longer.
static void Canonicalize(ZoneList<CharacterRange>* ranges);
// Negate the contents of a character range in canonical form.
static void Negate(ZoneList<CharacterRange>* src,
ZoneList<CharacterRange>* dst,
Zone* zone);
static const int kStartMarker = (1 << 24);
static const int kPayloadMask = (1 << 24) - 1;
private:
uc16 from_;
uc16 to_;
};
// A set of unsigned integers that behaves especially well on small
// integers (< 32). May do zone-allocation.
class OutSet: public ZoneObject {
public:
OutSet() : first_(0), remaining_(NULL), successors_(NULL) { }
OutSet* Extend(unsigned value, Zone* zone);
bool Get(unsigned value);
static const unsigned kFirstLimit = 32;
private:
// Destructively set a value in this set. In most cases you want
// to use Extend instead to ensure that only one instance exists
// that contains the same values.
void Set(unsigned value, Zone* zone);
// The successors are a list of sets that contain the same values
// as this set and the one more value that is not present in this
// set.
ZoneList<OutSet*>* successors(Zone* zone) { return successors_; }
OutSet(uint32_t first, ZoneList<unsigned>* remaining)
: first_(first), remaining_(remaining), successors_(NULL) { }
uint32_t first_;
ZoneList<unsigned>* remaining_;
ZoneList<OutSet*>* successors_;
friend class Trace;
};
// A mapping from integers, specified as ranges, to a set of integers.
// Used for mapping character ranges to choices.
class DispatchTable : public ZoneObject {
public:
explicit DispatchTable(Zone* zone) : tree_(zone) { }
class Entry {
public:
Entry() : from_(0), to_(0), out_set_(NULL) { }
Entry(uc16 from, uc16 to, OutSet* out_set)
: from_(from), to_(to), out_set_(out_set) { }
uc16 from() { return from_; }
uc16 to() { return to_; }
void set_to(uc16 value) { to_ = value; }
void AddValue(int value, Zone* zone) {
out_set_ = out_set_->Extend(value, zone);
}
OutSet* out_set() { return out_set_; }
private:
uc16 from_;
uc16 to_;
OutSet* out_set_;
};
class Config {
public:
typedef uc16 Key;
typedef Entry Value;
static const uc16 kNoKey;
static const Entry NoValue() { return Value(); }
static inline int Compare(uc16 a, uc16 b) {
if (a == b)
return 0;
else if (a < b)
return -1;
else
return 1;
}
};
void AddRange(CharacterRange range, int value, Zone* zone);
OutSet* Get(uc16 value);
void Dump();
template <typename Callback>
void ForEach(Callback* callback) {
return tree()->ForEach(callback);
}
private:
// There can't be a static empty set since it allocates its
// successors in a zone and caches them.
OutSet* empty() { return &empty_; }
OutSet empty_;
ZoneSplayTree<Config>* tree() { return &tree_; }
ZoneSplayTree<Config> tree_;
};
#define FOR_EACH_NODE_TYPE(VISIT) \
VISIT(End) \
VISIT(Action) \
VISIT(Choice) \
VISIT(BackReference) \
VISIT(Assertion) \
VISIT(Text)
#define FOR_EACH_REG_EXP_TREE_TYPE(VISIT) \
VISIT(Disjunction) \
VISIT(Alternative) \
VISIT(Assertion) \
VISIT(CharacterClass) \
VISIT(Atom) \
VISIT(Quantifier) \
VISIT(Capture) \
VISIT(Lookahead) \
VISIT(BackReference) \
VISIT(Empty) \
VISIT(Text)
#define FORWARD_DECLARE(Name) class RegExp##Name;
FOR_EACH_REG_EXP_TREE_TYPE(FORWARD_DECLARE)
#undef FORWARD_DECLARE
class TextElement {
public:
enum Type {UNINITIALIZED, ATOM, CHAR_CLASS};
TextElement() : type(UNINITIALIZED) { }
explicit TextElement(Type t) : type(t), cp_offset(-1) { }
static TextElement Atom(RegExpAtom* atom);
static TextElement CharClass(RegExpCharacterClass* char_class);
int length();
Type type;
union {
RegExpAtom* u_atom;
RegExpCharacterClass* u_char_class;
} data;
int cp_offset;
};
class Trace;
struct NodeInfo {
NodeInfo()
: being_analyzed(false),
been_analyzed(false),
follows_word_interest(false),
follows_newline_interest(false),
follows_start_interest(false),
at_end(false),
visited(false),
replacement_calculated(false) { }
// Returns true if the interests and assumptions of this node
// matches the given one.
bool Matches(NodeInfo* that) {
return (at_end == that->at_end) &&
(follows_word_interest == that->follows_word_interest) &&
(follows_newline_interest == that->follows_newline_interest) &&
(follows_start_interest == that->follows_start_interest);
}
// Updates the interests of this node given the interests of the
// node preceding it.
void AddFromPreceding(NodeInfo* that) {
at_end |= that->at_end;
follows_word_interest |= that->follows_word_interest;
follows_newline_interest |= that->follows_newline_interest;
follows_start_interest |= that->follows_start_interest;
}
bool HasLookbehind() {
return follows_word_interest ||
follows_newline_interest ||
follows_start_interest;
}
// Sets the interests of this node to include the interests of the
// following node.
void AddFromFollowing(NodeInfo* that) {
follows_word_interest |= that->follows_word_interest;
follows_newline_interest |= that->follows_newline_interest;
follows_start_interest |= that->follows_start_interest;
}
void ResetCompilationState() {
being_analyzed = false;
been_analyzed = false;
}
bool being_analyzed: 1;
bool been_analyzed: 1;
// These bits are set of this node has to know what the preceding
// character was.
bool follows_word_interest: 1;
bool follows_newline_interest: 1;
bool follows_start_interest: 1;
bool at_end: 1;
bool visited: 1;
bool replacement_calculated: 1;
};
// Details of a quick mask-compare check that can look ahead in the
// input stream.
class QuickCheckDetails {
public:
QuickCheckDetails()
: characters_(0),
mask_(0),
value_(0),
cannot_match_(false) { }
explicit QuickCheckDetails(int characters)
: characters_(characters),
mask_(0),
value_(0),
cannot_match_(false) { }
bool Rationalize(bool ascii);
// Merge in the information from another branch of an alternation.
void Merge(QuickCheckDetails* other, int from_index);
// Advance the current position by some amount.
void Advance(int by, bool ascii);
void Clear();
bool cannot_match() { return cannot_match_; }
void set_cannot_match() { cannot_match_ = true; }
struct Position {
Position() : mask(0), value(0), determines_perfectly(false) { }
uc16 mask;
uc16 value;
bool determines_perfectly;
};
int characters() { return characters_; }
void set_characters(int characters) { characters_ = characters; }
Position* positions(int index) {
ASSERT(index >= 0);
ASSERT(index < characters_);
return positions_ + index;
}
uint32_t mask() { return mask_; }
uint32_t value() { return value_; }
private:
// How many characters do we have quick check information from. This is
// the same for all branches of a choice node.
int characters_;
Position positions_[4];
// These values are the condensate of the above array after Rationalize()
.
uint32_t mask_;
uint32_t value_;
// If set to true, there is no way this quick check can match at all.
// E.g., if it requires to be at the start of the input, and isn't.
bool cannot_match_;
};
extern int kUninitializedRegExpNodePlaceHolder;
struct JSRegExpStatics { class RegExpNode: public ZoneObject {
JSString *input; /* input string to match (perl $_, GC root) public:
*/ explicit RegExpNode(Zone* zone)
JSBool multiline; /* whether input contains newlines (perl $* : replacement_(NULL), trace_count_(0), zone_(zone) {
) */ bm_info_[0] = bm_info_[1] = NULL;
uint16 parenCount; /* number of valid elements in parens[] */ }
uint16 moreLength; /* number of allocated elements in morePare virtual ~RegExpNode();
ns */ virtual void Accept(NodeVisitor* visitor) = 0;
JSSubString parens[9]; /* last set of parens matched (perl $1, $2) // Generates a goto to this node or actually generates the code at this p
*/ oint.
JSSubString *moreParens; /* null or realloc'd vector for $10, etc. * virtual void Emit(RegExpCompiler* compiler, Trace* trace) = 0;
/ // How many characters must this node consume at a minimum in order to
JSSubString lastMatch; /* last string matched (perl $&) */ // succeed. If we have found at least 'still_to_find' characters that
JSSubString lastParen; /* last paren matched (perl $+) */ // must be consumed there is no need to ask any following nodes whether
JSSubString leftContext; /* input to left of last match (perl $`) */ // they are sure to eat any more characters. The not_at_start argument i
JSSubString rightContext; /* input to right of last match (perl $') * s
/ // used to indicate that we know we are not at the start of the input. I
}; n
// this case anchored branches will always fail and can be ignored when
/* // determining how many characters are consumed on success.
* This struct holds a bitmap representation of a class from a regexp. virtual int EatsAtLeast(int still_to_find,
* There's a list of these referenced by the classList field in the JSRegEx int recursion_depth,
p bool not_at_start) = 0;
* struct below. The initial state has startIndex set to the offset in the // Emits some quick code that checks whether the preloaded characters mat
* original regexp source of the beginning of the class contents. The first ch.
* use of the class converts the source representation into a bitmap. // Falls through on certain failure, jumps to the label on possible succe
* ss.
*/ // If the node cannot make a quick check it does nothing and returns fals
typedef struct RECharSet { e.
JSPackedBool converted; bool EmitQuickCheck(RegExpCompiler* compiler,
JSPackedBool sense; Trace* trace,
uint16 length; bool preload_has_checked_bounds,
union { Label* on_possible_success,
uint8 *bits; QuickCheckDetails* details_return,
struct { bool fall_through_on_failure);
size_t startIndex; // For a given number of characters this returns a mask and a value. The
size_t length; // next n characters are anded with the mask and compared with the value.
} src; // A comparison failure indicates the node cannot match the next n charac
} u; ters.
} RECharSet; // A comparison success indicates the node may match.
virtual void GetQuickCheckDetails(QuickCheckDetails* details,
/* RegExpCompiler* compiler,
* This macro is safe because moreParens is guaranteed to be allocated and int characters_filled_in,
big bool not_at_start) = 0;
* enough to hold parenCount, or else be null when parenCount is 0. static const int kNodeIsTooComplexForGreedyLoops = -1;
*/ virtual int GreedyLoopTextLength() { return kNodeIsTooComplexForGreedyLoo
#define REGEXP_PAREN_SUBSTRING(res, num) ps; }
\ // Only returns the successor for a text node of length 1 that matches an
(((jsuint)(num) < (jsuint)(res)->parenCount) y
\ // character and that has no guards on it.
? ((jsuint)(num) < 9) virtual RegExpNode* GetSuccessorOfOmnivorousTextNode(
\ RegExpCompiler* compiler) {
? &(res)->parens[num] return NULL;
\ }
: &(res)->moreParens[(num) - 9]
\ // Collects information on the possible code units (mod 128) that can mat
: &js_EmptySubString) ch if
// we look forward. This is used for a Boyer-Moore-like string searching
typedef struct RENode RENode; // implementation. TODO(erikcorry): This should share more code with
// EatsAtLeast, GetQuickCheckDetails. The budget argument is used to lim
struct JSRegExp { it
jsrefcount nrefs; /* reference count */ // the number of nodes we are willing to look at in order to create this
uint16 flags; /* flags, see jsapi.h's JSREG_* defines */ data.
uint16 cloneIndex; /* index in fp->vars or funobj->slots of static const int kFillInBMBudget = 200;
cloned regexp object */ virtual void FillInBMInfo(int offset,
size_t parenCount; /* number of parenthesized submatches */ int recursion_depth,
size_t classCount; /* count [...] bitmaps */ int budget,
RECharSet *classList; /* list of [...] bitmaps */ BoyerMooreLookahead* bm,
JSString *source; /* locked source string, sans // */ bool not_at_start) {
jsbytecode program[1]; /* regular expression bytecode */ UNREACHABLE();
}; }
extern JSRegExp * // If we know that the input is ASCII then there are some nodes that can
js_NewRegExp(JSContext *cx, JSTokenStream *ts, // never match. This method returns a node that can be substituted for
JSString *str, uintN flags, JSBool flat); // itself, or NULL if the node can never match.
virtual RegExpNode* FilterASCII(int depth) { return this; }
extern JSRegExp * // Helper for FilterASCII.
js_NewRegExpOpt(JSContext *cx, JSTokenStream *ts, RegExpNode* replacement() {
JSString *str, JSString *opt, JSBool flat); ASSERT(info()->replacement_calculated);
return replacement_;
#define HOLD_REGEXP(cx, re) JS_ATOMIC_INCREMENT(&(re)->nrefs) }
#define DROP_REGEXP(cx, re) js_DestroyRegExp(cx, re) RegExpNode* set_replacement(RegExpNode* replacement) {
info()->replacement_calculated = true;
extern void replacement_ = replacement;
js_DestroyRegExp(JSContext *cx, JSRegExp *re); return replacement; // For convenience.
}
/*
* Execute re on input str at *indexp, returning null in *rval on mismatch. // We want to avoid recalculating the lookahead info, so we store it on t
* On match, return true if test is true, otherwise return an array object. he
* Update *indexp and cx->regExpStatics always on match. // node. Only info that is for this node is stored. We can tell that th
*/ e
extern JSBool // info is for this node when offset == 0, so the information is calculat
js_ExecuteRegExp(JSContext *cx, JSRegExp *re, JSString *str, size_t *indexp ed
, // relative to this node.
JSBool test, jsval *rval); void SaveBMInfo(BoyerMooreLookahead* bm, bool not_at_start, int offset) {
if (offset == 0) set_bm_info(not_at_start, bm);
/* }
* These two add and remove GC roots, respectively, so their calls must be
* well-ordered. Label* label() { return &label_; }
*/ // If non-generic code is generated for a node (i.e. the node is not at t
extern JSBool he
js_InitRegExpStatics(JSContext *cx, JSRegExpStatics *res); // start of the trace) then it cannot be reused. This variable sets a li
mit
extern void // on how often we allow that to happen before we insist on starting a ne
js_FreeRegExpStatics(JSContext *cx, JSRegExpStatics *res); w
// trace and generating generic code for a node that can be reused by flu
#define JSVAL_IS_REGEXP(cx, v) shing
\ // the deferred actions in the current trace and generating a goto.
(JSVAL_IS_OBJECT(v) && JSVAL_TO_OBJECT(v) && static const int kMaxCopiesCodeGenerated = 10;
\
OBJ_GET_CLASS(cx, JSVAL_TO_OBJECT(v)) == &js_RegExpClass) NodeInfo* info() { return &info_; }
extern JSClass js_RegExpClass; BoyerMooreLookahead* bm_info(bool not_at_start) {
return bm_info_[not_at_start ? 1 : 0];
extern JSObject * }
js_InitRegExpClass(JSContext *cx, JSObject *obj);
Zone* zone() const { return zone_; }
/*
* Export js_regexp_toString to the decompiler. protected:
*/ enum LimitResult { DONE, CONTINUE };
extern JSBool RegExpNode* replacement_;
js_regexp_toString(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
jsval *rval); LimitResult LimitVersions(RegExpCompiler* compiler, Trace* trace);
/* void set_bm_info(bool not_at_start, BoyerMooreLookahead* bm) {
* Create, serialize/deserialize, or clone a RegExp object. bm_info_[not_at_start ? 1 : 0] = bm;
*/ }
extern JSObject *
js_NewRegExpObject(JSContext *cx, JSTokenStream *ts, private:
jschar *chars, size_t length, uintN flags); static const int kFirstCharBudget = 10;
Label label_;
extern JSBool NodeInfo info_;
js_XDRRegExp(JSXDRState *xdr, JSObject **objp); // This variable keeps track of how many times code has been generated fo
r
extern JSObject * // this node (in different traces). We don't keep track of where the
js_CloneRegExpObject(JSContext *cx, JSObject *obj, JSObject *parent); // generated code is located unless the code is generated at the start of
// a trace, in which case it is generic and can be reused by flushing the
/* // deferred operations in the current trace and generating a goto.
* Get and set the per-object (clone or clone-parent) lastIndex slot. int trace_count_;
*/ BoyerMooreLookahead* bm_info_[2];
extern JSBool
js_GetLastIndex(JSContext *cx, JSObject *obj, jsdouble *lastIndex); Zone* zone_;
};
// A simple closed interval.
class Interval {
public:
Interval() : from_(kNone), to_(kNone) { }
Interval(int from, int to) : from_(from), to_(to) { }
Interval Union(Interval that) {
if (that.from_ == kNone)
return *this;
else if (from_ == kNone)
return that;
else
return Interval(Min(from_, that.from_), Max(to_, that.to_));
}
bool Contains(int value) {
return (from_ <= value) && (value <= to_);
}
bool is_empty() { return from_ == kNone; }
int from() const { return from_; }
int to() const { return to_; }
static Interval Empty() { return Interval(); }
static const int kNone = -1;
private:
int from_;
int to_;
};
class SeqRegExpNode: public RegExpNode {
public:
explicit SeqRegExpNode(RegExpNode* on_success)
: RegExpNode(on_success->zone()), on_success_(on_success) { }
RegExpNode* on_success() { return on_success_; }
void set_on_success(RegExpNode* node) { on_success_ = node; }
virtual RegExpNode* FilterASCII(int depth);
virtual void FillInBMInfo(int offset,
int recursion_depth,
int budget,
BoyerMooreLookahead* bm,
bool not_at_start) {
on_success_->FillInBMInfo(
offset, recursion_depth + 1, budget - 1, bm, not_at_start);
if (offset == 0) set_bm_info(not_at_start, bm);
}
protected:
RegExpNode* FilterSuccessor(int depth);
private:
RegExpNode* on_success_;
};
class ActionNode: public SeqRegExpNode {
public:
enum Type {
SET_REGISTER,
INCREMENT_REGISTER,
STORE_POSITION,
BEGIN_SUBMATCH,
POSITIVE_SUBMATCH_SUCCESS,
EMPTY_MATCH_CHECK,
CLEAR_CAPTURES
};
static ActionNode* SetRegister(int reg, int val, RegExpNode* on_success);
static ActionNode* IncrementRegister(int reg, RegExpNode* on_success);
static ActionNode* StorePosition(int reg,
bool is_capture,
RegExpNode* on_success);
static ActionNode* ClearCaptures(Interval range, RegExpNode* on_success);
static ActionNode* BeginSubmatch(int stack_pointer_reg,
int position_reg,
RegExpNode* on_success);
static ActionNode* PositiveSubmatchSuccess(int stack_pointer_reg,
int restore_reg,
int clear_capture_count,
int clear_capture_from,
RegExpNode* on_success);
static ActionNode* EmptyMatchCheck(int start_register,
int repetition_register,
int repetition_limit,
RegExpNode* on_success);
virtual void Accept(NodeVisitor* visitor);
virtual void Emit(RegExpCompiler* compiler, Trace* trace);
virtual int EatsAtLeast(int still_to_find,
int recursion_depth,
bool not_at_start);
virtual void GetQuickCheckDetails(QuickCheckDetails* details,
RegExpCompiler* compiler,
int filled_in,
bool not_at_start) {
return on_success()->GetQuickCheckDetails(
details, compiler, filled_in, not_at_start);
}
virtual void FillInBMInfo(int offset,
int recursion_depth,
int budget,
BoyerMooreLookahead* bm,
bool not_at_start);
Type type() { return type_; }
// TODO(erikcorry): We should allow some action nodes in greedy loops.
virtual int GreedyLoopTextLength() { return kNodeIsTooComplexForGreedyLoo
ps; }
private:
union {
struct {
int reg;
int value;
} u_store_register;
struct {
int reg;
} u_increment_register;
struct {
int reg;
bool is_capture;
} u_position_register;
struct {
int stack_pointer_register;
int current_position_register;
int clear_register_count;
int clear_register_from;
} u_submatch;
struct {
int start_register;
int repetition_register;
int repetition_limit;
} u_empty_match_check;
struct {
int range_from;
int range_to;
} u_clear_captures;
} data_;
ActionNode(Type type, RegExpNode* on_success)
: SeqRegExpNode(on_success),
type_(type) { }
Type type_;
friend class DotPrinter;
};
class TextNode: public SeqRegExpNode {
public:
TextNode(ZoneList<TextElement>* elms,
RegExpNode* on_success)
: SeqRegExpNode(on_success),
elms_(elms) { }
TextNode(RegExpCharacterClass* that,
RegExpNode* on_success)
: SeqRegExpNode(on_success),
elms_(new(zone()) ZoneList<TextElement>(1, zone())) {
elms_->Add(TextElement::CharClass(that), zone());
}
virtual void Accept(NodeVisitor* visitor);
virtual void Emit(RegExpCompiler* compiler, Trace* trace);
virtual int EatsAtLeast(int still_to_find,
int recursion_depth,
bool not_at_start);
virtual void GetQuickCheckDetails(QuickCheckDetails* details,
RegExpCompiler* compiler,
int characters_filled_in,
bool not_at_start);
ZoneList<TextElement>* elements() { return elms_; }
void MakeCaseIndependent(bool is_ascii);
virtual int GreedyLoopTextLength();
virtual RegExpNode* GetSuccessorOfOmnivorousTextNode(
RegExpCompiler* compiler);
virtual void FillInBMInfo(int offset,
int recursion_depth,
int budget,
BoyerMooreLookahead* bm,
bool not_at_start);
void CalculateOffsets();
virtual RegExpNode* FilterASCII(int depth);
private:
enum TextEmitPassType {
NON_ASCII_MATCH, // Check for characters that can't match.
SIMPLE_CHARACTER_MATCH, // Case-dependent single character check.
NON_LETTER_CHARACTER_MATCH, // Check characters that have no case equi
vs.
CASE_CHARACTER_MATCH, // Case-independent single character check
.
CHARACTER_CLASS_MATCH // Character class.
};
static bool SkipPass(int pass, bool ignore_case);
static const int kFirstRealPass = SIMPLE_CHARACTER_MATCH;
static const int kLastPass = CHARACTER_CLASS_MATCH;
void TextEmitPass(RegExpCompiler* compiler,
TextEmitPassType pass,
bool preloaded,
Trace* trace,
bool first_element_checked,
int* checked_up_to);
int Length();
ZoneList<TextElement>* elms_;
};
class AssertionNode: public SeqRegExpNode {
public:
enum AssertionNodeType {
AT_END,
AT_START,
AT_BOUNDARY,
AT_NON_BOUNDARY,
AFTER_NEWLINE
};
static AssertionNode* AtEnd(RegExpNode* on_success) {
return new(on_success->zone()) AssertionNode(AT_END, on_success);
}
static AssertionNode* AtStart(RegExpNode* on_success) {
return new(on_success->zone()) AssertionNode(AT_START, on_success);
}
static AssertionNode* AtBoundary(RegExpNode* on_success) {
return new(on_success->zone()) AssertionNode(AT_BOUNDARY, on_success);
}
static AssertionNode* AtNonBoundary(RegExpNode* on_success) {
return new(on_success->zone()) AssertionNode(AT_NON_BOUNDARY, on_succes
s);
}
static AssertionNode* AfterNewline(RegExpNode* on_success) {
return new(on_success->zone()) AssertionNode(AFTER_NEWLINE, on_success)
;
}
virtual void Accept(NodeVisitor* visitor);
virtual void Emit(RegExpCompiler* compiler, Trace* trace);
virtual int EatsAtLeast(int still_to_find,
int recursion_depth,
bool not_at_start);
virtual void GetQuickCheckDetails(QuickCheckDetails* details,
RegExpCompiler* compiler,
int filled_in,
bool not_at_start);
virtual void FillInBMInfo(int offset,
int recursion_depth,
int budget,
BoyerMooreLookahead* bm,
bool not_at_start);
AssertionNodeType type() { return type_; }
void set_type(AssertionNodeType type) { type_ = type; }
private:
void EmitBoundaryCheck(RegExpCompiler* compiler, Trace* trace);
enum IfPrevious { kIsNonWord, kIsWord };
void BacktrackIfPrevious(RegExpCompiler* compiler,
Trace* trace,
IfPrevious backtrack_if_previous);
AssertionNode(AssertionNodeType t, RegExpNode* on_success)
: SeqRegExpNode(on_success), type_(t) { }
AssertionNodeType type_;
};
class BackReferenceNode: public SeqRegExpNode {
public:
BackReferenceNode(int start_reg,
int end_reg,
RegExpNode* on_success)
: SeqRegExpNode(on_success),
start_reg_(start_reg),
end_reg_(end_reg) { }
virtual void Accept(NodeVisitor* visitor);
int start_register() { return start_reg_; }
int end_register() { return end_reg_; }
virtual void Emit(RegExpCompiler* compiler, Trace* trace);
virtual int EatsAtLeast(int still_to_find,
int recursion_depth,
bool not_at_start);
virtual void GetQuickCheckDetails(QuickCheckDetails* details,
RegExpCompiler* compiler,
int characters_filled_in,
bool not_at_start) {
return;
}
virtual void FillInBMInfo(int offset,
int recursion_depth,
int budget,
BoyerMooreLookahead* bm,
bool not_at_start);
private:
int start_reg_;
int end_reg_;
};
class EndNode: public RegExpNode {
public:
enum Action { ACCEPT, BACKTRACK, NEGATIVE_SUBMATCH_SUCCESS };
explicit EndNode(Action action, Zone* zone)
: RegExpNode(zone), action_(action) { }
virtual void Accept(NodeVisitor* visitor);
virtual void Emit(RegExpCompiler* compiler, Trace* trace);
virtual int EatsAtLeast(int still_to_find,
int recursion_depth,
bool not_at_start) { return 0; }
virtual void GetQuickCheckDetails(QuickCheckDetails* details,
RegExpCompiler* compiler,
int characters_filled_in,
bool not_at_start) {
// Returning 0 from EatsAtLeast should ensure we never get here.
UNREACHABLE();
}
virtual void FillInBMInfo(int offset,
int recursion_depth,
int budget,
BoyerMooreLookahead* bm,
bool not_at_start) {
// Returning 0 from EatsAtLeast should ensure we never get here.
UNREACHABLE();
}
private:
Action action_;
};
class NegativeSubmatchSuccess: public EndNode {
public:
NegativeSubmatchSuccess(int stack_pointer_reg,
int position_reg,
int clear_capture_count,
int clear_capture_start,
Zone* zone)
: EndNode(NEGATIVE_SUBMATCH_SUCCESS, zone),
stack_pointer_register_(stack_pointer_reg),
current_position_register_(position_reg),
clear_capture_count_(clear_capture_count),
clear_capture_start_(clear_capture_start) { }
virtual void Emit(RegExpCompiler* compiler, Trace* trace);
private:
int stack_pointer_register_;
int current_position_register_;
int clear_capture_count_;
int clear_capture_start_;
};
class Guard: public ZoneObject {
public:
enum Relation { LT, GEQ };
Guard(int reg, Relation op, int value)
: reg_(reg),
op_(op),
value_(value) { }
int reg() { return reg_; }
Relation op() { return op_; }
int value() { return value_; }
private:
int reg_;
Relation op_;
int value_;
};
class GuardedAlternative {
public:
explicit GuardedAlternative(RegExpNode* node) : node_(node), guards_(NULL
) { }
void AddGuard(Guard* guard, Zone* zone);
RegExpNode* node() { return node_; }
void set_node(RegExpNode* node) { node_ = node; }
ZoneList<Guard*>* guards() { return guards_; }
private:
RegExpNode* node_;
ZoneList<Guard*>* guards_;
};
class AlternativeGeneration;
class ChoiceNode: public RegExpNode {
public:
explicit ChoiceNode(int expected_size, Zone* zone)
: RegExpNode(zone),
alternatives_(new(zone)
ZoneList<GuardedAlternative>(expected_size, zone)),
table_(NULL),
not_at_start_(false),
being_calculated_(false) { }
virtual void Accept(NodeVisitor* visitor);
void AddAlternative(GuardedAlternative node) {
alternatives()->Add(node, zone());
}
ZoneList<GuardedAlternative>* alternatives() { return alternatives_; }
DispatchTable* GetTable(bool ignore_case);
virtual void Emit(RegExpCompiler* compiler, Trace* trace);
virtual int EatsAtLeast(int still_to_find,
int recursion_depth,
bool not_at_start);
int EatsAtLeastHelper(int still_to_find,
int recursion_depth,
RegExpNode* ignore_this_node,
bool not_at_start);
virtual void GetQuickCheckDetails(QuickCheckDetails* details,
RegExpCompiler* compiler,
int characters_filled_in,
bool not_at_start);
virtual void FillInBMInfo(int offset,
int recursion_depth,
int budget,
BoyerMooreLookahead* bm,
bool not_at_start);
bool being_calculated() { return being_calculated_; }
bool not_at_start() { return not_at_start_; }
void set_not_at_start() { not_at_start_ = true; }
void set_being_calculated(bool b) { being_calculated_ = b; }
virtual bool try_to_emit_quick_check_for_alternative(int i) { return true
; }
virtual RegExpNode* FilterASCII(int depth);
protected:
int GreedyLoopTextLengthForAlternative(GuardedAlternative* alternative);
ZoneList<GuardedAlternative>* alternatives_;
private:
friend class DispatchTableConstructor;
friend class Analysis;
void GenerateGuard(RegExpMacroAssembler* macro_assembler,
Guard* guard,
Trace* trace);
int CalculatePreloadCharacters(RegExpCompiler* compiler, int eats_at_leas
t);
void EmitOutOfLineContinuation(RegExpCompiler* compiler,
Trace* trace,
GuardedAlternative alternative,
AlternativeGeneration* alt_gen,
int preload_characters,
bool next_expects_preload);
DispatchTable* table_;
// If true, this node is never checked at the start of the input.
// Allows a new trace to start with at_start() set to false.
bool not_at_start_;
bool being_calculated_;
};
class NegativeLookaheadChoiceNode: public ChoiceNode {
public:
explicit NegativeLookaheadChoiceNode(GuardedAlternative this_must_fail,
GuardedAlternative then_do_this,
Zone* zone)
: ChoiceNode(2, zone) {
AddAlternative(this_must_fail);
AddAlternative(then_do_this);
}
virtual int EatsAtLeast(int still_to_find,
int recursion_depth,
bool not_at_start);
virtual void GetQuickCheckDetails(QuickCheckDetails* details,
RegExpCompiler* compiler,
int characters_filled_in,
bool not_at_start);
virtual void FillInBMInfo(int offset,
int recursion_depth,
int budget,
BoyerMooreLookahead* bm,
bool not_at_start) {
alternatives_->at(1).node()->FillInBMInfo(
offset, recursion_depth + 1, budget - 1, bm, not_at_start);
if (offset == 0) set_bm_info(not_at_start, bm);
}
// For a negative lookahead we don't emit the quick check for the
// alternative that is expected to fail. This is because quick check cod
e
// starts by loading enough characters for the alternative that takes few
est
// characters, but on a negative lookahead the negative branch did not ta
ke
// part in that calculation (EatsAtLeast) so the assumptions don't hold.
virtual bool try_to_emit_quick_check_for_alternative(int i) { return i !=
0; }
virtual RegExpNode* FilterASCII(int depth);
};
class LoopChoiceNode: public ChoiceNode {
public:
explicit LoopChoiceNode(bool body_can_be_zero_length, Zone* zone)
: ChoiceNode(2, zone),
loop_node_(NULL),
continue_node_(NULL),
body_can_be_zero_length_(body_can_be_zero_length) { }
void AddLoopAlternative(GuardedAlternative alt);
void AddContinueAlternative(GuardedAlternative alt);
virtual void Emit(RegExpCompiler* compiler, Trace* trace);
virtual int EatsAtLeast(int still_to_find,
int recursion_depth,
bool not_at_start);
virtual void GetQuickCheckDetails(QuickCheckDetails* details,
RegExpCompiler* compiler,
int characters_filled_in,
bool not_at_start);
virtual void FillInBMInfo(int offset,
int recursion_depth,
int budget,
BoyerMooreLookahead* bm,
bool not_at_start);
RegExpNode* loop_node() { return loop_node_; }
RegExpNode* continue_node() { return continue_node_; }
bool body_can_be_zero_length() { return body_can_be_zero_length_; }
virtual void Accept(NodeVisitor* visitor);
virtual RegExpNode* FilterASCII(int depth);
private:
// AddAlternative is made private for loop nodes because alternatives
// should not be added freely, we need to keep track of which node
// goes back to the node itself.
void AddAlternative(GuardedAlternative node) {
ChoiceNode::AddAlternative(node);
}
RegExpNode* loop_node_;
RegExpNode* continue_node_;
bool body_can_be_zero_length_;
};
// Improve the speed that we scan for an initial point where a non-anchored
// regexp can match by using a Boyer-Moore-like table. This is done by
// identifying non-greedy non-capturing loops in the nodes that eat any
// character one at a time. For example in the middle of the regexp
// /foo[\s\S]*?bar/ we find such a loop. There is also such a loop implici
tly
// inserted at the start of any non-anchored regexp.
//
// When we have found such a loop we look ahead in the nodes to find the se
t of
// characters that can come at given distances. For example for the regexp
// /.?foo/ we know that there are at least 3 characters ahead of us, and th
e
// sets of characters that can occur are [any, [f, o], [o]]. We find a rang
e in
// the lookahead info where the set of characters is reasonably constrained
. In
// our example this is from index 1 to 2 (0 is not constrained). We can now
// look 3 characters ahead and if we don't find one of [f, o] (the union of
// [f, o] and [o]) then we can skip forwards by the range size (in this cas
e 2).
//
// For Unicode input strings we do the same, but modulo 128.
//
// We also look at the first string fed to the regexp and use that to get a
hint
// of the character frequencies in the inputs. This affects the assessment
of
// whether the set of characters is 'reasonably constrained'.
//
// We also have another lookahead mechanism (called quick check in the code
),
// which uses a wide load of multiple characters followed by a mask and com
pare
// to determine whether a match is possible at this point.
enum ContainedInLattice {
kNotYet = 0,
kLatticeIn = 1,
kLatticeOut = 2,
kLatticeUnknown = 3 // Can also mean both in and out.
};
inline ContainedInLattice Combine(ContainedInLattice a, ContainedInLattice
b) {
return static_cast<ContainedInLattice>(a | b);
}
ContainedInLattice AddRange(ContainedInLattice a,
const int* ranges,
int ranges_size,
Interval new_range);
class BoyerMoorePositionInfo : public ZoneObject {
public:
explicit BoyerMoorePositionInfo(Zone* zone)
: map_(new(zone) ZoneList<bool>(kMapSize, zone)),
map_count_(0),
w_(kNotYet),
s_(kNotYet),
d_(kNotYet),
surrogate_(kNotYet) {
for (int i = 0; i < kMapSize; i++) {
map_->Add(false, zone);
}
}
bool& at(int i) { return map_->at(i); }
static const int kMapSize = 128;
static const int kMask = kMapSize - 1;
int map_count() const { return map_count_; }
void Set(int character);
void SetInterval(const Interval& interval);
void SetAll();
bool is_non_word() { return w_ == kLatticeOut; }
bool is_word() { return w_ == kLatticeIn; }
private:
ZoneList<bool>* map_;
int map_count_; // Number of set bits in the map.
ContainedInLattice w_; // The \w character class.
ContainedInLattice s_; // The \s character class.
ContainedInLattice d_; // The \d character class.
ContainedInLattice surrogate_; // Surrogate UTF-16 code units.
};
class BoyerMooreLookahead : public ZoneObject {
public:
BoyerMooreLookahead(int length, RegExpCompiler* compiler, Zone* zone);
int length() { return length_; }
int max_char() { return max_char_; }
RegExpCompiler* compiler() { return compiler_; }
int Count(int map_number) {
return bitmaps_->at(map_number)->map_count();
}
BoyerMoorePositionInfo* at(int i) { return bitmaps_->at(i); }
void Set(int map_number, int character) {
if (character > max_char_) return;
BoyerMoorePositionInfo* info = bitmaps_->at(map_number);
info->Set(character);
}
void SetInterval(int map_number, const Interval& interval) {
if (interval.from() > max_char_) return;
BoyerMoorePositionInfo* info = bitmaps_->at(map_number);
if (interval.to() > max_char_) {
info->SetInterval(Interval(interval.from(), max_char_));
} else {
info->SetInterval(interval);
}
}
void SetAll(int map_number) {
bitmaps_->at(map_number)->SetAll();
}
void SetRest(int from_map) {
for (int i = from_map; i < length_; i++) SetAll(i);
}
bool EmitSkipInstructions(RegExpMacroAssembler* masm);
private:
// This is the value obtained by EatsAtLeast. If we do not have at least
this
// many characters left in the sample string then the match is bound to f
ail.
// Therefore it is OK to read a character this far ahead of the current m
atch
// point.
int length_;
RegExpCompiler* compiler_;
// 0x7f for ASCII, 0xffff for UTF-16.
int max_char_;
ZoneList<BoyerMoorePositionInfo*>* bitmaps_;
int GetSkipTable(int min_lookahead,
int max_lookahead,
Handle<ByteArray> boolean_skip_table);
bool FindWorthwhileInterval(int* from, int* to);
int FindBestInterval(
int max_number_of_chars, int old_biggest_points, int* from, int* to);
};
// There are many ways to generate code for a node. This class encapsulate
s
// the current way we should be generating. In other words it encapsulates
// the current state of the code generator. The effect of this is that we
// generate code for paths that the matcher can take through the regular
// expression. A given node in the regexp can be code-generated several ti
mes
// as it can be part of several traces. For example for the regexp:
// /foo(bar|ip)baz/ the code to match baz will be generated twice, once as
part
// of the foo-bar-baz trace and once as part of the foo-ip-baz trace. The
code
// to match foo is generated only once (the traces have a common prefix).
The
// code to store the capture is deferred and generated (twice) after the pl
aces
// where baz has been matched.
class Trace {
public:
// A value for a property that is either known to be true, know to be fal
se,
// or not known.
enum TriBool {
UNKNOWN = -1, FALSE = 0, TRUE = 1
};
class DeferredAction {
public:
DeferredAction(ActionNode::Type type, int reg)
: type_(type), reg_(reg), next_(NULL) { }
DeferredAction* next() { return next_; }
bool Mentions(int reg);
int reg() { return reg_; }
ActionNode::Type type() { return type_; }
private:
ActionNode::Type type_;
int reg_;
DeferredAction* next_;
friend class Trace;
};
class DeferredCapture : public DeferredAction {
public:
DeferredCapture(int reg, bool is_capture, Trace* trace)
: DeferredAction(ActionNode::STORE_POSITION, reg),
cp_offset_(trace->cp_offset()),
is_capture_(is_capture) { }
int cp_offset() { return cp_offset_; }
bool is_capture() { return is_capture_; }
private:
int cp_offset_;
bool is_capture_;
void set_cp_offset(int cp_offset) { cp_offset_ = cp_offset; }
};
class DeferredSetRegister : public DeferredAction {
public:
DeferredSetRegister(int reg, int value)
: DeferredAction(ActionNode::SET_REGISTER, reg),
value_(value) { }
int value() { return value_; }
private:
int value_;
};
class DeferredClearCaptures : public DeferredAction {
public:
explicit DeferredClearCaptures(Interval range)
: DeferredAction(ActionNode::CLEAR_CAPTURES, -1),
range_(range) { }
Interval range() { return range_; }
private:
Interval range_;
};
class DeferredIncrementRegister : public DeferredAction {
public:
explicit DeferredIncrementRegister(int reg)
: DeferredAction(ActionNode::INCREMENT_REGISTER, reg) { }
};
Trace()
: cp_offset_(0),
actions_(NULL),
backtrack_(NULL),
stop_node_(NULL),
loop_label_(NULL),
characters_preloaded_(0),
bound_checked_up_to_(0),
flush_budget_(100),
at_start_(UNKNOWN) { }
// End the trace. This involves flushing the deferred actions in the tra
ce
// and pushing a backtrack location onto the backtrack stack. Once this
is
// done we can start a new trace or go to one that has already been
// generated.
void Flush(RegExpCompiler* compiler, RegExpNode* successor);
int cp_offset() { return cp_offset_; }
DeferredAction* actions() { return actions_; }
// A trivial trace is one that has no deferred actions or other state tha
t
// affects the assumptions used when generating code. There is no record
ed
// backtrack location in a trivial trace, so with a trivial trace we will
// generate code that, on a failure to match, gets the backtrack location
// from the backtrack stack rather than using a direct jump instruction.
We
// always start code generation with a trivial trace and non-trivial trac
es
// are created as we emit code for nodes or add to the list of deferred
// actions in the trace. The location of the code generated for a node u
sing
// a trivial trace is recorded in a label in the node so that gotos can b
e
// generated to that code.
bool is_trivial() {
return backtrack_ == NULL &&
actions_ == NULL &&
cp_offset_ == 0 &&
characters_preloaded_ == 0 &&
bound_checked_up_to_ == 0 &&
quick_check_performed_.characters() == 0 &&
at_start_ == UNKNOWN;
}
TriBool at_start() { return at_start_; }
void set_at_start(bool at_start) { at_start_ = at_start ? TRUE : FALSE; }
Label* backtrack() { return backtrack_; }
Label* loop_label() { return loop_label_; }
RegExpNode* stop_node() { return stop_node_; }
int characters_preloaded() { return characters_preloaded_; }
int bound_checked_up_to() { return bound_checked_up_to_; }
int flush_budget() { return flush_budget_; }
QuickCheckDetails* quick_check_performed() { return &quick_check_performe
d_; }
bool mentions_reg(int reg);
// Returns true if a deferred position store exists to the specified
// register and stores the offset in the out-parameter. Otherwise
// returns false.
bool GetStoredPosition(int reg, int* cp_offset);
// These set methods and AdvanceCurrentPositionInTrace should be used onl
y on
// new traces - the intention is that traces are immutable after creation
.
void add_action(DeferredAction* new_action) {
ASSERT(new_action->next_ == NULL);
new_action->next_ = actions_;
actions_ = new_action;
}
void set_backtrack(Label* backtrack) { backtrack_ = backtrack; }
void set_stop_node(RegExpNode* node) { stop_node_ = node; }
void set_loop_label(Label* label) { loop_label_ = label; }
void set_characters_preloaded(int count) { characters_preloaded_ = count;
}
void set_bound_checked_up_to(int to) { bound_checked_up_to_ = to; }
void set_flush_budget(int to) { flush_budget_ = to; }
void set_quick_check_performed(QuickCheckDetails* d) {
quick_check_performed_ = *d;
}
void InvalidateCurrentCharacter();
void AdvanceCurrentPositionInTrace(int by, RegExpCompiler* compiler);
private:
int FindAffectedRegisters(OutSet* affected_registers, Zone* zone);
void PerformDeferredActions(RegExpMacroAssembler* macro,
int max_register,
OutSet& affected_registers,
OutSet* registers_to_pop,
OutSet* registers_to_clear,
Zone* zone);
void RestoreAffectedRegisters(RegExpMacroAssembler* macro,
int max_register,
OutSet& registers_to_pop,
OutSet& registers_to_clear);
int cp_offset_;
DeferredAction* actions_;
Label* backtrack_;
RegExpNode* stop_node_;
Label* loop_label_;
int characters_preloaded_;
int bound_checked_up_to_;
QuickCheckDetails quick_check_performed_;
int flush_budget_;
TriBool at_start_;
};
class NodeVisitor {
public:
virtual ~NodeVisitor() { }
#define DECLARE_VISIT(Type) \
virtual void Visit##Type(Type##Node* that) = 0;
FOR_EACH_NODE_TYPE(DECLARE_VISIT)
#undef DECLARE_VISIT
virtual void VisitLoopChoice(LoopChoiceNode* that) { VisitChoice(that); }
};
// Node visitor used to add the start set of the alternatives to the
// dispatch table of a choice node.
class DispatchTableConstructor: public NodeVisitor {
public:
DispatchTableConstructor(DispatchTable* table, bool ignore_case,
Zone* zone)
: table_(table),
choice_index_(-1),
ignore_case_(ignore_case),
zone_(zone) { }
void BuildTable(ChoiceNode* node);
void AddRange(CharacterRange range) {
table()->AddRange(range, choice_index_, zone_);
}
void AddInverse(ZoneList<CharacterRange>* ranges);
#define DECLARE_VISIT(Type) \
virtual void Visit##Type(Type##Node* that);
FOR_EACH_NODE_TYPE(DECLARE_VISIT)
#undef DECLARE_VISIT
DispatchTable* table() { return table_; }
void set_choice_index(int value) { choice_index_ = value; }
protected:
DispatchTable* table_;
int choice_index_;
bool ignore_case_;
Zone* zone_;
};
// Assertion propagation moves information about assertions such as
// \b to the affected nodes. For instance, in /.\b./ information must
// be propagated to the first '.' that whatever follows needs to know
// if it matched a word or a non-word, and to the second '.' that it
// has to check if it succeeds a word or non-word. In this case the
// result will be something like:
//
// +-------+ +------------+
// | . | | . |
// +-------+ ---> +------------+
// | word? | | check word |
// +-------+ +------------+
class Analysis: public NodeVisitor {
public:
Analysis(bool ignore_case, bool is_ascii)
: ignore_case_(ignore_case),
is_ascii_(is_ascii),
error_message_(NULL) { }
void EnsureAnalyzed(RegExpNode* node);
#define DECLARE_VISIT(Type) \
virtual void Visit##Type(Type##Node* that);
FOR_EACH_NODE_TYPE(DECLARE_VISIT)
#undef DECLARE_VISIT
virtual void VisitLoopChoice(LoopChoiceNode* that);
bool has_failed() { return error_message_ != NULL; }
const char* error_message() {
ASSERT(error_message_ != NULL);
return error_message_;
}
void fail(const char* error_message) {
error_message_ = error_message;
}
private:
bool ignore_case_;
bool is_ascii_;
const char* error_message_;
DISALLOW_IMPLICIT_CONSTRUCTORS(Analysis);
};
struct RegExpCompileData {
RegExpCompileData()
: tree(NULL),
node(NULL),
simple(true),
contains_anchor(false),
capture_count(0) { }
RegExpTree* tree;
RegExpNode* node;
bool simple;
bool contains_anchor;
Handle<String> error;
int capture_count;
};
class RegExpEngine: public AllStatic {
public:
struct CompilationResult {
explicit CompilationResult(const char* error_message)
: error_message(error_message),
code(HEAP->the_hole_value()),
num_registers(0) {}
CompilationResult(Object* code, int registers)
: error_message(NULL),
code(code),
num_registers(registers) {}
const char* error_message;
Object* code;
int num_registers;
};
static CompilationResult Compile(RegExpCompileData* input,
bool ignore_case,
bool global,
bool multiline,
Handle<String> pattern,
Handle<String> sample_subject,
bool is_ascii, Zone* zone);
static void DotPrint(const char* label, RegExpNode* node, bool ignore_cas
e);
};
class OffsetsVector {
public:
inline OffsetsVector(int num_registers, Isolate* isolate)
: offsets_vector_length_(num_registers) {
if (offsets_vector_length_ > Isolate::kJSRegexpStaticOffsetsVectorSize)
{
vector_ = NewArray<int>(offsets_vector_length_);
} else {
vector_ = isolate->jsregexp_static_offsets_vector();
}
}
inline ~OffsetsVector() {
if (offsets_vector_length_ > Isolate::kJSRegexpStaticOffsetsVectorSize)
{
DeleteArray(vector_);
vector_ = NULL;
}
}
inline int* vector() { return vector_; }
inline int length() { return offsets_vector_length_; }
static const int kStaticOffsetsVectorSize =
Isolate::kJSRegexpStaticOffsetsVectorSize;
private:
static Address static_offsets_vector_address(Isolate* isolate) {
return reinterpret_cast<Address>(isolate->jsregexp_static_offsets_vecto
r());
}
int* vector_;
int offsets_vector_length_;
friend class ExternalReference;
};
extern JSBool } } // namespace v8::internal
js_SetLastIndex(JSContext *cx, JSObject *obj, jsdouble lastIndex);
#endif /* jsregexp_h___ */ #endif // V8_JSREGEXP_H_
 End of changes. 5 change blocks. 
203 lines changed or deleted 1694 lines changed or added


 list.h   list.h 
// list.h // Copyright 2011 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials provided
// with the distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef V8_LIST_H_
#define V8_LIST_H_
#include "utils.h"
namespace v8 {
namespace internal {
// ------------------------------------------------------------------------
----
// The list is a template for very light-weight lists. We are not
// using the STL because we want full control over space and speed of
// the code. This implementation is based on code by Robert Griesemer
// and Rob Pike.
//
// The list is parameterized by the type of its elements (T) and by an
// allocation policy (P). The policy is used for allocating lists in
// the C free store or the zone; see zone.h.
// Forward defined as
// template <typename T,
// class AllocationPolicy = FreeStoreAllocationPolicy> class List
;
template <typename T, class AllocationPolicy>
class List {
public:
explicit List(AllocationPolicy allocator = AllocationPolicy()) {
Initialize(0, allocator);
}
INLINE(explicit List(int capacity,
AllocationPolicy allocator = AllocationPolicy())) {
Initialize(capacity, allocator);
}
INLINE(~List()) { DeleteData(data_); }
// Deallocates memory used by the list and leaves the list in a consisten
t
// empty state.
void Free() {
DeleteData(data_);
Initialize(0);
}
INLINE(void* operator new(size_t size,
AllocationPolicy allocator = AllocationPolicy()
)) {
return allocator.New(static_cast<int>(size));
}
INLINE(void operator delete(void* p)) {
AllocationPolicy::Delete(p);
}
// Please the MSVC compiler. We should never have to execute this.
INLINE(void operator delete(void* p, AllocationPolicy allocator)) {
UNREACHABLE();
}
// Returns a reference to the element at index i. This reference is
// not safe to use after operations that can change the list's
// backing store (e.g. Add).
inline T& operator[](int i) const {
ASSERT(0 <= i);
ASSERT(i < length_);
return data_[i];
}
inline T& at(int i) const { return operator[](i); }
inline T& last() const { return at(length_ - 1); }
inline T& first() const { return at(0); }
INLINE(bool is_empty() const) { return length_ == 0; }
INLINE(int length() const) { return length_; }
INLINE(int capacity() const) { return capacity_; }
Vector<T> ToVector() const { return Vector<T>(data_, length_); }
Vector<const T> ToConstVector() { return Vector<const T>(data_, length_);
}
// Adds a copy of the given 'element' to the end of the list,
// expanding the list if necessary.
void Add(const T& element, AllocationPolicy allocator = AllocationPolicy(
));
// Add all the elements from the argument list to this list.
void AddAll(const List<T, AllocationPolicy>& other,
AllocationPolicy allocator = AllocationPolicy());
// Add all the elements from the vector to this list.
void AddAll(const Vector<T>& other,
AllocationPolicy allocator = AllocationPolicy());
// Inserts the element at the specific index.
void InsertAt(int index, const T& element,
AllocationPolicy allocator = AllocationPolicy());
// Added 'count' elements with the value 'value' and returns a
// vector that allows access to the elements. The vector is valid
// until the next change is made to this list.
Vector<T> AddBlock(T value, int count,
AllocationPolicy allocator = AllocationPolicy());
// Removes the i'th element without deleting it even if T is a
// pointer type; moves all elements above i "down". Returns the
// removed element. This function's complexity is linear in the
// size of the list.
T Remove(int i);
// Remove the given element from the list. Returns whether or not
// the input is included in the list in the first place.
bool RemoveElement(const T& elm);
// Removes the last element without deleting it even if T is a
// pointer type. Returns the removed element.
INLINE(T RemoveLast()) { return Remove(length_ - 1); }
// Deletes current list contents and allocates space for 'length' element
s.
INLINE(void Allocate(int length,
AllocationPolicy allocator = AllocationPolicy()));
// Clears the list by setting the length to zero. Even if T is a
// pointer type, clearing the list doesn't delete the entries.
INLINE(void Clear());
// Drops all but the first 'pos' elements from the list.
INLINE(void Rewind(int pos));
// Drop the last 'count' elements from the list.
INLINE(void RewindBy(int count)) { Rewind(length_ - count); }
bool Contains(const T& elm) const;
int CountOccurrences(const T& elm, int start, int end) const;
// Iterate through all list entries, starting at index 0.
void Iterate(void (*callback)(T* x));
template<class Visitor>
void Iterate(Visitor* visitor);
// Sort all list entries (using QuickSort)
void Sort(int (*cmp)(const T* x, const T* y));
void Sort();
INLINE(void Initialize(int capacity,
AllocationPolicy allocator = AllocationPolicy()));
private:
T* data_;
int capacity_;
int length_;
INLINE(T* NewData(int n, AllocationPolicy allocator)) {
return static_cast<T*>(allocator.New(n * sizeof(T)));
}
INLINE(void DeleteData(T* data)) {
AllocationPolicy::Delete(data);
}
// Increase the capacity of a full list, and add an element.
// List must be full already.
void ResizeAdd(const T& element, AllocationPolicy allocator);
// Inlined implementation of ResizeAdd, shared by inlined and
// non-inlined versions of ResizeAdd.
void ResizeAddInternal(const T& element, AllocationPolicy allocator);
/** // Resize the list.
* Copyright (C) 2008 10gen Inc. void Resize(int new_capacity, AllocationPolicy allocator);
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License, version 3
,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public Licen
se
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
namespace mongo {
/* DON'T USE THIS. it was a dumb idea.
this class uses a mutex for writes, but not for reads.
we can get fancier later...
struct Member : public List1<Member>::Base {
const char *host;
int port;
};
List1<Member> _members;
_members.head()->next();
*/
template<typename T>
class List1 : boost::noncopyable {
public:
/* next() and head() return 0 at end of list */
List1() : _head(0), _m("List1"), _orphans(0) { }
class Base {
friend class List1;
T *_next;
public:
Base() : _next(0){}
~Base() { wassert(false); } // we never want this to happen
T* next() const { return _next; }
};
/** note this is safe:
T* p = mylist.head();
if( p )
use(p);
and this is not:
if( mylist.head() )
use( mylist.head() ); // could become 0
*/
T* head() const { return (T*) _head; }
void push(T* t) {
verify( t->_next == 0 );
scoped_lock lk(_m);
t->_next = (T*) _head;
_head = t;
}
// intentionally leaks.
void orphanAll() {
scoped_lock lk(_m);
_head = 0;
}
/* t is not deleted, but is removed from the list. (orphaned) */
void orphan(T* t) {
scoped_lock lk(_m);
T *&prev = (T*&) _head;
T *n = prev;
while( n != t ) {
uassert( 14050 , "List1: item to orphan not in list", n );
prev = n->_next;
n = prev;
}
prev = t->_next;
if( ++_orphans > 500 )
log() << "warning List1 orphans=" << _orphans << endl;
}
private:
volatile T *_head;
mongo::mutex _m;
int _orphans;
};
DISALLOW_COPY_AND_ASSIGN(List);
}; };
class Map;
class Code;
template<typename T> class Handle;
typedef List<Map*> MapList;
typedef List<Code*> CodeList;
typedef List<Handle<Map> > MapHandleList;
typedef List<Handle<Code> > CodeHandleList;
// Perform binary search for an element in an already sorted
// list. Returns the index of the element of -1 if it was not found.
// |cmp| is a predicate that takes a pointer to an element of the List
// and returns +1 if it is greater, -1 if it is less than the element
// being searched.
template <typename T, class P>
int SortedListBSearch(const List<T>& list, P cmp);
template <typename T>
int SortedListBSearch(const List<T>& list, T elem);
} } // namespace v8::internal
#endif // V8_LIST_H_
 End of changes. 4 change blocks. 
98 lines changed or deleted 194 lines changed or added


 namespace_details-inl.h   namespace_details-inl.h 
skipping to change at line 59 skipping to change at line 59
inline int NamespaceDetails::idxNo(const IndexDetails& idx) { inline int NamespaceDetails::idxNo(const IndexDetails& idx) {
IndexIterator i = ii(); IndexIterator i = ii();
while( i.more() ) { while( i.more() ) {
if( &i.next() == &idx ) if( &i.next() == &idx )
return i.pos()-1; return i.pos()-1;
} }
massert( 10349 , "E12000 idxNo fails", false); massert( 10349 , "E12000 idxNo fails", false);
return -1; return -1;
} }
inline int NamespaceDetails::findIndexByKeyPattern(const BSONObj& keyPa inline int NamespaceDetails::findIndexByKeyPattern(const BSONObj& keyPa
ttern) { ttern,
IndexIterator i = ii(); bool includeBackgrou
ndInProgress) {
IndexIterator i = ii(includeBackgroundInProgress);
while( i.more() ) { while( i.more() ) {
if( i.next().keyPattern() == keyPattern ) if( i.next().keyPattern() == keyPattern )
return i.pos()-1; return i.pos()-1;
} }
return -1; return -1;
} }
inline const IndexDetails* NamespaceDetails::findIndexByPrefix( const B SONObj &keyPattern , inline const IndexDetails* NamespaceDetails::findIndexByPrefix( const B SONObj &keyPattern ,
bool re quireSingleKey ) { bool re quireSingleKey ) {
const IndexDetails* bestMultiKeyIndex = NULL; const IndexDetails* bestMultiKeyIndex = NULL;
skipping to change at line 86 skipping to change at line 87
return &currentIndex; return &currentIndex;
} else { } else {
bestMultiKeyIndex = &currentIndex; bestMultiKeyIndex = &currentIndex;
} }
} }
} }
return requireSingleKey ? NULL : bestMultiKeyIndex; return requireSingleKey ? NULL : bestMultiKeyIndex;
} }
// @return offset in indexes[] // @return offset in indexes[]
inline int NamespaceDetails::findIndexByName(const char *name) { inline int NamespaceDetails::findIndexByName(const char *name,
IndexIterator i = ii(); bool includeBackgroundInPr
ogress) {
IndexIterator i = ii(includeBackgroundInProgress);
while( i.more() ) { while( i.more() ) {
if ( strcmp(i.next().info.obj().getStringField("name"),name) == 0 ) if ( strcmp(i.next().info.obj().getStringField("name"),name) == 0 )
return i.pos()-1; return i.pos()-1;
} }
return -1; return -1;
} }
inline NamespaceDetails::IndexIterator::IndexIterator(NamespaceDetails *_d, inline NamespaceDetails::IndexIterator::IndexIterator(NamespaceDetails *_d,
bool includeBackg roundInProgress) { bool includeBackg roundInProgress) {
d = _d; d = _d;
 End of changes. 2 change blocks. 
5 lines changed or deleted 9 lines changed or added


 namespace_details.h   namespace_details.h 
skipping to change at line 294 skipping to change at line 294
*/ */
double N = min(nIndexes,7) + 3; double N = min(nIndexes,7) + 3;
double x = _paddingFactor + (0.001 * N); double x = _paddingFactor + (0.001 * N);
if ( x <= 2.0 ) { if ( x <= 2.0 ) {
setPaddingFactor( x ); setPaddingFactor( x );
} }
} }
} }
// @return offset in indexes[] // @return offset in indexes[]
int findIndexByName(const char *name); int findIndexByName(const char *name, bool includeBackgroundInProgr ess = false);
// @return offset in indexes[] // @return offset in indexes[]
int findIndexByKeyPattern(const BSONObj& keyPattern); int findIndexByKeyPattern(const BSONObj& keyPattern,
bool includeBackgroundInProgress = false)
;
void findIndexByType( const string& name , vector<int>& matches ) { void findIndexByType( const string& name , vector<int>& matches ) {
IndexIterator i = ii(); IndexIterator i = ii();
while ( i.more() ) { while ( i.more() ) {
if ( i.next().getSpec().getTypeName() == name ) if ( i.next().getSpec().getTypeName() == name )
matches.push_back( i.pos() - 1 ); matches.push_back( i.pos() - 1 );
} }
} }
/* Returns the index entry for the first index whose prefix contain s /* Returns the index entry for the first index whose prefix contain s
 End of changes. 2 change blocks. 
2 lines changed or deleted 4 lines changed or added


 rs.h   rs.h 
skipping to change at line 335 skipping to change at line 335
PRESTART=0, LOADINGCONFIG=1, BADCONFIG=2, EMPTYCONFIG=3, PRESTART=0, LOADINGCONFIG=1, BADCONFIG=2, EMPTYCONFIG=3,
EMPTYUNREACHABLE=4, STARTED=5, SOON=6 EMPTYUNREACHABLE=4, STARTED=5, SOON=6
}; };
static StartupStatus startupStatus; static StartupStatus startupStatus;
static DiagStr startupStatusMsg; static DiagStr startupStatusMsg;
static string stateAsHtml(MemberState state); static string stateAsHtml(MemberState state);
/* todo thread */ /* todo thread */
void msgUpdateHBInfo(HeartbeatInfo); void msgUpdateHBInfo(HeartbeatInfo);
/**
* Updates the lastHeartbeatRecv of Member with the given id.
*/
void msgUpdateHBRecv(unsigned id, time_t newTime);
StateBox box; StateBox box;
OpTime lastOpTimeWritten; OpTime lastOpTimeWritten;
long long lastH; // hash we use to make sure we are reading the rig ht flow of ops and aren't on an out-of-date "fork" long long lastH; // hash we use to make sure we are reading the rig ht flow of ops and aren't on an out-of-date "fork"
bool forceSyncFrom(const string& host, string& errmsg, BSONObjBuild er& result); bool forceSyncFrom(const string& host, string& errmsg, BSONObjBuild er& result);
// Check if the current sync target is suboptimal. This must be cal led while holding a mutex // Check if the current sync target is suboptimal. This must be cal led while holding a mutex
// that prevents the sync source from changing. // that prevents the sync source from changing.
bool shouldChangeSyncTarget(const OpTime& target) const; bool shouldChangeSyncTarget(const OpTime& target) const;
/** /**
 End of changes. 1 change blocks. 
0 lines changed or deleted 5 lines changed or added


 rs_member.h   rs_member.h 
skipping to change at line 103 skipping to change at line 103
bool up() const { return health > 0; } bool up() const { return health > 0; }
/** health is set to -1 on startup. that means we haven't even che cked yet. 0 means we checked and it failed. */ /** health is set to -1 on startup. that means we haven't even che cked yet. 0 means we checked and it failed. */
bool maybeUp() const { return health != 0; } bool maybeUp() const { return health != 0; }
long long timeDown() const; // ms long long timeDown() const; // ms
/* true if changed in a way of interest to the repl set manager. */ /* true if changed in a way of interest to the repl set manager. */
bool changed(const HeartbeatInfo& old) const; bool changed(const HeartbeatInfo& old) const;
void recvHeartbeat(); /**
* Updates this with the info received from the command result we g
ot from
* the last replSetHeartbeat.
*/
void updateFromLastPoll(const HeartbeatInfo& newInfo);
}; };
inline HeartbeatInfo::HeartbeatInfo(unsigned id) : inline HeartbeatInfo::HeartbeatInfo(unsigned id) :
_id(id), _id(id),
lastHeartbeatRecv(0), lastHeartbeatRecv(0),
authIssue(false), authIssue(false),
ping(0) { ping(0) {
hbstate = MemberState::RS_UNKNOWN; hbstate = MemberState::RS_UNKNOWN;
health = -1.0; health = -1.0;
downSince = 0; downSince = 0;
 End of changes. 1 change blocks. 
1 lines changed or deleted 6 lines changed or added


 string_data-inl.h   string_data-inl.h 
skipping to change at line 93 skipping to change at line 93
mx -= needleSize; mx -= needleSize;
for ( size_t i = 0; i <= mx; i++ ) { for ( size_t i = 0; i <= mx; i++ ) {
if ( memcmp( _data + i, needle._data, needleSize ) == 0 ) if ( memcmp( _data + i, needle._data, needleSize ) == 0 )
return i; return i;
} }
return string::npos; return string::npos;
} }
inline size_t StringData::rfind( char c, size_t fromPos ) const {
const size_t sz = size();
if ( fromPos > sz )
fromPos = sz;
for ( const char* cur = _data + fromPos; cur > _data; --cur ) {
if ( *(cur - 1) == c )
return (cur - _data) - 1;
}
return string::npos;
}
inline StringData StringData::substr( size_t pos, size_t n ) const { inline StringData StringData::substr( size_t pos, size_t n ) const {
if ( pos > size() ) if ( pos > size() )
throw std::out_of_range( "out of range" ); throw std::out_of_range( "out of range" );
// truncate to end of string // truncate to end of string
if ( n > size() - pos ) if ( n > size() - pos )
n = size() - pos; n = size() - pos;
return StringData( _data + pos, n ); return StringData( _data + pos, n );
} }
 End of changes. 1 change blocks. 
0 lines changed or deleted 12 lines changed or added


 string_data.h   string_data.h 
skipping to change at line 101 skipping to change at line 101
void copyTo( char* dest, bool includeEndingNull ) const; void copyTo( char* dest, bool includeEndingNull ) const;
StringData substr( size_t pos, size_t n = std::numeric_limits<size_ t>::max() ) const; StringData substr( size_t pos, size_t n = std::numeric_limits<size_ t>::max() ) const;
// //
// finders // finders
// //
size_t find( char c , size_t fromPos = 0 ) const; size_t find( char c , size_t fromPos = 0 ) const;
size_t find( const StringData& needle ) const; size_t find( const StringData& needle ) const;
size_t rfind( char c, size_t fromPos = string::npos ) const;
/** /**
* Returns true if 'prefix' is a substring of this instance, anchor ed at position 0. * Returns true if 'prefix' is a substring of this instance, anchor ed at position 0.
*/ */
bool startsWith( const StringData& prefix ) const; bool startsWith( const StringData& prefix ) const;
/** /**
* Returns true if 'suffix' is a substring of this instance, anchor ed at the end. * Returns true if 'suffix' is a substring of this instance, anchor ed at the end.
*/ */
bool endsWith( const StringData& suffix ) const; bool endsWith( const StringData& suffix ) const;
skipping to change at line 128 skipping to change at line 129
* null-terminated, so if using this without checking size(), you a re likely doing * null-terminated, so if using this without checking size(), you a re likely doing
* something wrong. * something wrong.
*/ */
const char* rawData() const { return _data; } const char* rawData() const { return _data; }
size_t size() const { fillSize(); return _size; } size_t size() const { fillSize(); return _size; }
bool empty() const { return size() == 0; } bool empty() const { return size() == 0; }
string toString() const { return string(_data, size()); } string toString() const { return string(_data, size()); }
char operator[] ( unsigned pos ) const { return _data[pos]; } char operator[] ( unsigned pos ) const { return _data[pos]; }
/**
* Functor compatible with std::hash for std::unordered_{map,set}
* Warning: The hash function is subject to change. Do not use in c
ases where hashes need
* to be consistent across versions.
*/
struct Hasher {
size_t operator() (const StringData& str) const;
};
private: private:
const char* _data; // is not guaranted to be null terminated (see "notes" above) const char* _data; // is not guaranted to be null terminated (see "notes" above)
mutable size_t _size; // 'size' does not include the null termi nator mutable size_t _size; // 'size' does not include the null termi nator
void fillSize() const { void fillSize() const {
if (_size == string::npos) { if (_size == string::npos) {
_size = strlen(_data); _size = strlen(_data);
} }
} }
}; };
 End of changes. 2 change blocks. 
0 lines changed or deleted 11 lines changed or added


 unordered_fast_key_table.h   unordered_fast_key_table.h 
skipping to change at line 65 skipping to change at line 65
size_t curHash; size_t curHash;
value_type data; value_type data;
}; };
struct Area { struct Area {
Area( unsigned capacity, double maxProbeRatio ); Area( unsigned capacity, double maxProbeRatio );
Area( const Area& other ); Area( const Area& other );
int find( const K_L& key, size_t hash, int* firstEmpty, const U norderedFastKeyTable& sm ) const; int find( const K_L& key, size_t hash, int* firstEmpty, const U norderedFastKeyTable& sm ) const;
void transfer( Area* newArea, const UnorderedFastKeyTable& sm ) const; bool transfer( Area* newArea, const UnorderedFastKeyTable& sm ) const;
void swap( Area* other ) { void swap( Area* other ) {
using std::swap; using std::swap;
swap( _capacity, other->_capacity ); swap( _capacity, other->_capacity );
swap( _maxProbe, other->_maxProbe ); swap( _maxProbe, other->_maxProbe );
swap( _entries, other->_entries ); swap( _entries, other->_entries );
} }
unsigned _capacity; unsigned _capacity;
unsigned _maxProbe; unsigned _maxProbe;
 End of changes. 1 change blocks. 
1 lines changed or deleted 1 lines changed or added


 unordered_fast_key_table_internal.h   unordered_fast_key_table_internal.h 
skipping to change at line 79 skipping to change at line 79
} }
// hashes and strings are equal // hashes and strings are equal
// yay! // yay!
return pos; return pos;
} }
return -1; return -1;
} }
template< typename K_L, typename K_S, typename V, typename H, typename E, typename C, typename C_LS > template< typename K_L, typename K_S, typename V, typename H, typename E, typename C, typename C_LS >
inline void UnorderedFastKeyTable<K_L, K_S, V, H, E, C, C_LS>::Area::tr ansfer( inline bool UnorderedFastKeyTable<K_L, K_S, V, H, E, C, C_LS>::Area::tr ansfer(
Area* newArea, Area* newArea,
const UnorderedFastKeyTable& sm) const { const UnorderedFastKeyTable& sm) const {
for ( unsigned i = 0; i < _capacity; i++ ) { for ( unsigned i = 0; i < _capacity; i++ ) {
if ( ! _entries[i].used ) if ( ! _entries[i].used )
continue; continue;
int firstEmpty = -1; int firstEmpty = -1;
int loc = newArea->find( sm._convertor( _entries[i].data.first ), int loc = newArea->find( sm._convertor( _entries[i].data.first ),
_entries[i].curHash, _entries[i].curHash,
&firstEmpty, &firstEmpty,
sm ); sm );
verify( loc == -1 ); verify( loc == -1 );
verify( firstEmpty >= 0 ); if ( firstEmpty < 0 ) {
return false;
}
newArea->_entries[firstEmpty] = _entries[i]; newArea->_entries[firstEmpty] = _entries[i];
} }
return true;
} }
template< typename K_L, typename K_S, typename V, typename H, typename E, typename C, typename C_LS > template< typename K_L, typename K_S, typename V, typename H, typename E, typename C, typename C_LS >
inline UnorderedFastKeyTable<K_L, K_S, V, H, E, C, C_LS>::UnorderedFast KeyTable( inline UnorderedFastKeyTable<K_L, K_S, V, H, E, C, C_LS>::UnorderedFast KeyTable(
unsigned startingCapacity, unsigned startingCapacity,
double maxProbeRatio) double maxProbeRatio)
: _maxProbeRatio( maxProbeRatio ), _area( startingCapacity, maxProb eRatio ) { : _maxProbeRatio( maxProbeRatio ), _area( startingCapacity, maxProb eRatio ) {
_size = 0; _size = 0;
} }
skipping to change at line 132 skipping to change at line 135
out->_maxProbeRatio = _maxProbeRatio; out->_maxProbeRatio = _maxProbeRatio;
Area x( _area ); Area x( _area );
out->_area.swap( &x ); out->_area.swap( &x );
} }
template< typename K_L, typename K_S, typename V, typename H, typename E, typename C, typename C_LS > template< typename K_L, typename K_S, typename V, typename H, typename E, typename C, typename C_LS >
inline V& UnorderedFastKeyTable<K_L, K_S, V, H, E, C, C_LS>::get( const K_L& key ) { inline V& UnorderedFastKeyTable<K_L, K_S, V, H, E, C, C_LS>::get( const K_L& key ) {
const size_t hash = _hash( key ); const size_t hash = _hash( key );
for ( int numGrowTries = 0; numGrowTries < 10; numGrowTries++ ) { for ( int numGrowTries = 0; numGrowTries < 5; numGrowTries++ ) {
int firstEmpty = -1; int firstEmpty = -1;
int pos = _area.find( key, hash, &firstEmpty, *this ); int pos = _area.find( key, hash, &firstEmpty, *this );
if ( pos >= 0 ) if ( pos >= 0 )
return _area._entries[pos].data.second; return _area._entries[pos].data.second;
// key not in map // key not in map
// need to add // need to add
if ( firstEmpty >= 0 ) { if ( firstEmpty >= 0 ) {
_size++; _size++;
_area._entries[firstEmpty].used = true; _area._entries[firstEmpty].used = true;
skipping to change at line 171 skipping to change at line 174
if ( pos < 0 ) if ( pos < 0 )
return 0; return 0;
_area._entries[pos].used = false; _area._entries[pos].used = false;
_area._entries[pos].data.second = V(); _area._entries[pos].data.second = V();
return 1; return 1;
} }
template< typename K_L, typename K_S, typename V, typename H, typename E, typename C, typename C_LS > template< typename K_L, typename K_S, typename V, typename H, typename E, typename C, typename C_LS >
inline void UnorderedFastKeyTable<K_L, K_S, V, H, E, C, C_LS>::_grow() { inline void UnorderedFastKeyTable<K_L, K_S, V, H, E, C, C_LS>::_grow() {
Area newArea( _area._capacity * 2, _maxProbeRatio ); unsigned capacity = _area._capacity;
_area.transfer( &newArea, *this ); for ( int numGrowTries = 0; numGrowTries < 5; numGrowTries++ ) {
_area.swap( &newArea ); capacity *= 2;
Area newArea( capacity, _maxProbeRatio );
bool success = _area.transfer( &newArea, *this );
if ( !success ) {
continue;
}
_area.swap( &newArea );
return;
}
msgasserted( 16845,
"UnorderedFastKeyTable::_grow couldn't add entry after
growing many times" );
} }
template< typename K_L, typename K_S, typename V, typename H, typename E, typename C, typename C_LS > template< typename K_L, typename K_S, typename V, typename H, typename E, typename C, typename C_LS >
inline typename UnorderedFastKeyTable<K_L, K_S, V, H, E, C, C_LS>::cons t_iterator inline typename UnorderedFastKeyTable<K_L, K_S, V, H, E, C, C_LS>::cons t_iterator
UnorderedFastKeyTable<K_L, K_S, V, H, E, C, C_LS>::find( const K_L& key ) const { UnorderedFastKeyTable<K_L, K_S, V, H, E, C, C_LS>::find( const K_L& key ) const {
if ( _size == 0 ) if ( _size == 0 )
return const_iterator(); return const_iterator();
int pos = _area.find( key, _hash(key), 0, *this ); int pos = _area.find( key, _hash(key), 0, *this );
if ( pos < 0 ) if ( pos < 0 )
return const_iterator(); return const_iterator();
 End of changes. 5 change blocks. 
6 lines changed or deleted 20 lines changed or added


 v8_db.h   v8_db.h 
skipping to change at line 30 skipping to change at line 30
#include <boost/function.hpp> #include <boost/function.hpp>
#include <v8.h> #include <v8.h>
#include "mongo/scripting/engine_v8.h" #include "mongo/scripting/engine_v8.h"
namespace mongo { namespace mongo {
class DBClientBase; class DBClientBase;
/** /**
* install database access functions
*/
void installDBAccess(V8Scope* scope);
/**
* install BSON types and helpers
*/
void installBSONTypes(V8Scope* scope);
/**
* get the DBClientBase connection from JS args * get the DBClientBase connection from JS args
*/ */
mongo::DBClientBase* getConnection(const v8::Arguments& args); mongo::DBClientBase* getConnection(V8Scope* scope, const v8::Arguments&
args);
// Internal Cursor
v8::Handle<v8::FunctionTemplate> getInternalCursorFunctionTemplate(V8Sc
ope* scope);
// Mongo constructors // Mongo constructors
v8::Handle<v8::Value> mongoConsLocal(V8Scope* scope, const v8::Argument s& args); v8::Handle<v8::Value> mongoConsLocal(V8Scope* scope, const v8::Argument s& args);
v8::Handle<v8::Value> mongoConsExternal(V8Scope* scope, const v8::Argum ents& args); v8::Handle<v8::Value> mongoConsExternal(V8Scope* scope, const v8::Argum ents& args);
v8::Handle<v8::FunctionTemplate> getMongoFunctionTemplate(V8Scope* scop e, bool local); v8::Handle<v8::FunctionTemplate> getMongoFunctionTemplate(V8Scope* scop e, bool local);
// Mongo member functions // Mongo member functions
v8::Handle<v8::Value> mongoFind(V8Scope* scope, const v8::Arguments& ar gs); v8::Handle<v8::Value> mongoFind(V8Scope* scope, const v8::Arguments& ar gs);
v8::Handle<v8::Value> mongoInsert(V8Scope* scope, const v8::Arguments& args); v8::Handle<v8::Value> mongoInsert(V8Scope* scope, const v8::Arguments& args);
v8::Handle<v8::Value> mongoRemove(V8Scope* scope, const v8::Arguments& args); v8::Handle<v8::Value> mongoRemove(V8Scope* scope, const v8::Arguments& args);
skipping to change at line 71 skipping to change at line 64
v8::Handle<v8::Value> internalCursorObjsLeftInBatch(V8Scope* scope, con st v8::Arguments& args); v8::Handle<v8::Value> internalCursorObjsLeftInBatch(V8Scope* scope, con st v8::Arguments& args);
v8::Handle<v8::Value> internalCursorReadOnly(V8Scope* scope, const v8:: Arguments& args); v8::Handle<v8::Value> internalCursorReadOnly(V8Scope* scope, const v8:: Arguments& args);
// BinData object // BinData object
v8::Handle<v8::Value> binDataInit(V8Scope* scope, const v8::Arguments& args); v8::Handle<v8::Value> binDataInit(V8Scope* scope, const v8::Arguments& args);
v8::Handle<v8::Value> binDataToString(V8Scope* scope, const v8::Argumen ts& args); v8::Handle<v8::Value> binDataToString(V8Scope* scope, const v8::Argumen ts& args);
v8::Handle<v8::Value> binDataToBase64(V8Scope* scope, const v8::Argumen ts& args); v8::Handle<v8::Value> binDataToBase64(V8Scope* scope, const v8::Argumen ts& args);
v8::Handle<v8::Value> binDataToHex(V8Scope* scope, const v8::Arguments& args); v8::Handle<v8::Value> binDataToHex(V8Scope* scope, const v8::Arguments& args);
// NumberLong object // NumberLong object
long long numberLongVal(V8Scope* scope, const v8::Handle<v8::Object>& i t);
v8::Handle<v8::Value> numberLongInit(V8Scope* scope, const v8::Argument s& args); v8::Handle<v8::Value> numberLongInit(V8Scope* scope, const v8::Argument s& args);
v8::Handle<v8::Value> numberLongToNumber(V8Scope* scope, const v8::Argu ments& args); v8::Handle<v8::Value> numberLongToNumber(V8Scope* scope, const v8::Argu ments& args);
v8::Handle<v8::Value> numberLongValueOf(V8Scope* scope, const v8::Argum ents& args); v8::Handle<v8::Value> numberLongValueOf(V8Scope* scope, const v8::Argum ents& args);
v8::Handle<v8::Value> numberLongToString(V8Scope* scope, const v8::Argu ments& args); v8::Handle<v8::Value> numberLongToString(V8Scope* scope, const v8::Argu ments& args);
// Number object // NumberInt object
int numberIntVal(V8Scope* scope, const v8::Handle<v8::Object>& it);
v8::Handle<v8::Value> numberIntInit(V8Scope* scope, const v8::Arguments & args); v8::Handle<v8::Value> numberIntInit(V8Scope* scope, const v8::Arguments & args);
v8::Handle<v8::Value> numberIntToNumber(V8Scope* scope, const v8::Argum ents& args); v8::Handle<v8::Value> numberIntToNumber(V8Scope* scope, const v8::Argum ents& args);
v8::Handle<v8::Value> numberIntValueOf(V8Scope* scope, const v8::Argume nts& args); v8::Handle<v8::Value> numberIntValueOf(V8Scope* scope, const v8::Argume nts& args);
v8::Handle<v8::Value> numberIntToString(V8Scope* scope, const v8::Argum ents& args); v8::Handle<v8::Value> numberIntToString(V8Scope* scope, const v8::Argum ents& args);
// DBQuery object // DBQuery object
v8::Handle<v8::Value> dbQueryInit(V8Scope* scope, const v8::Arguments& args); v8::Handle<v8::Value> dbQueryInit(V8Scope* scope, const v8::Arguments& args);
v8::Handle<v8::Value> dbQueryIndexAccess(::uint32_t index, const v8::Ac cessorInfo& info); v8::Handle<v8::Value> dbQueryIndexAccess(::uint32_t index, const v8::Ac cessorInfo& info);
// db constructor // db constructor
 End of changes. 4 change blocks. 
12 lines changed or deleted 9 lines changed or added


 v8_utils.h   v8_utils.h 
skipping to change at line 26 skipping to change at line 26
*/ */
#pragma once #pragma once
#include <cstdio> #include <cstdio>
#include <cstdlib> #include <cstdlib>
#include <iostream> #include <iostream>
#include <string> #include <string>
#include <v8.h> #include <v8.h>
#include <mongo/base/string_data.h>
#include <mongo/util/assert_util.h>
namespace mongo { namespace mongo {
#define jsassert(x,msg) uassert(16664, (msg), (x)) #define jsassert(x,msg) uassert(16664, (msg), (x))
#define argumentCheck(mustBeTrue, errorMessage) \ #define argumentCheck(mustBeTrue, errorMessage) \
if (!(mustBeTrue)) { \ if (!(mustBeTrue)) { \
return v8AssertionException((errorMessage)); \ return v8AssertionException((errorMessage)); \
} }
std::ostream& operator<<(std::ostream& s, const v8::Handle<v8::Value>& o); std::ostream& operator<<(std::ostream& s, const v8::Handle<v8::Value>& o);
std::ostream& operator<<(std::ostream& s, const v8::Handle<v8::TryCatch >* try_catch); std::ostream& operator<<(std::ostream& s, const v8::Handle<v8::TryCatch >* try_catch);
/** Simple v8 object to string conversion helper */ /** Simple v8 object to string conversion helper */
std::string toSTLString(const v8::Handle<v8::Value>& o); std::string toSTLString(const v8::Handle<v8::Value>& o);
/** Like toSTLString but doesn't allocate a new std::string
*
* This owns the string's memory so you need to be careful not to let
the
* converted StringDatas outlive the V8Scope object. These rules are t
he
* same as converting from a std::string into a StringData.
*
* Safe:
* void someFunction(StringData argument);
* v8::Handle<v8::String> aString;
*
* someFunction(V8String(aString)); // passing down stack as tempo
rary
*
* V8String named (aString);
* someFunction(named); // passing up stack as named value
*
* StringData sd = named; // scope of sd is less than named
*
* Unsafe:
* StringData _member;
*
* StringData returningFunction() {
* StringData sd = V8String(aString); // sd outlives the tempo
rary
*
* V8String named(aString)
* _member = named; // _member outlives named scope
*
* return V8String(aString); // passing up stack
* }
*/
class V8String {
public:
explicit V8String(const v8::Handle<v8::Value>& o) :_str(o) {
massert(16686, "error converting js type to Utf8Value", *_str);
}
operator StringData () const { return StringData(*_str, _str.length
()); }
private:
v8::String::Utf8Value _str;
};
/** Get the properties of an object (and it's prototype) as a comma-del imited string */ /** Get the properties of an object (and it's prototype) as a comma-del imited string */
std::string v8ObjectToString(const v8::Handle<v8::Object>& o); std::string v8ObjectToString(const v8::Handle<v8::Object>& o);
class V8Scope; class V8Scope;
void installFork(V8Scope* scope, void installFork(V8Scope* scope,
v8::Handle<v8::Object>& global, v8::Handle<v8::Object>& global,
v8::Handle<v8::Context>& context); v8::Handle<v8::Context>& context);
/** Throw a V8 exception from Mongo callback code; message text will be preceded by "Error: ". /** Throw a V8 exception from Mongo callback code; message text will be preceded by "Error: ".
* Note: this function should be used for text that did not originate from the JavaScript * Note: this function should be used for text that did not originate from the JavaScript
 End of changes. 2 change blocks. 
0 lines changed or deleted 47 lines changed or added


 value.h   value.h 
/* @file value.h
concurrency helpers DiagStr, Guarded
*/
/** /**
* Copyright (C) 2008 10gen Inc. * Copyright (c) 2011 10gen Inc.
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License, version 3 * it under the terms of the GNU Affero General Public License, version 3,
, * as published by the Free Software Foundation.
* as published by the Free Software Foundation. *
* * This program is distributed in the hope that it will be useful,
* This program is distributed in the hope that it will be useful,b * but WITHOUT ANY WARRANTY; without even the implied warranty of
* but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details.
* GNU Affero General Public License for more details. *
* * You should have received a copy of the GNU Affero General Public License
* You should have received a copy of the GNU Affero General Public Licen * along with this program. If not, see <http://www.gnu.org/licenses/>.
se */
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once #pragma once
#include "spin_lock.h" #include "mongo/db/pipeline/value_internal.h"
namespace mongo { namespace mongo {
class BSONElement;
class Builder;
/** declare that a variable that is "guarded" by a mutex. /** A variant type that can hold any type of data representable in BSON
*
The decl documents the rule. For example "counta and countb are gu * Small values are stored inline, but some values, such as large stri
arded by xyzMutex": ngs,
* are heap allocated. It has smart pointer capabilities built-in so i
Guarded<int, xyzMutex> counta; t is
Guarded<int, xyzMutex> countb; * safe and recommended to pass these around and return them by value.
*
Upon use, specify the scoped_lock object. This makes it hard for s * Values are immutable, but can be assigned. This means that once you
omeone have
later to forget to be in the lock. Check is made that it is the ri * a Value, you can be assured that none of the data in that Value wil
ght lock in _DEBUG l
builds at runtime. * change. However if you have a non-const Value you replace it with
*/ * operator=. These rules are the same as BSONObj, and similar to
template <typename T, SimpleMutex& BY> * shared_ptr<const Object> with stronger guarantees of constness. Thi
class Guarded { s is
T _val; * also the same as Java's String type.
*
* Thread-safety: A single Value instance can be safely shared between
* threads as long as there are no writers while other threads are
* accessing the object. Any number of threads can read from a Value
* concurrently. There are no restrictions on how threads access Value
* instances exclusively owned by them, even if they reference the sam
e
* storage as Value in other threads.
*/
class Value {
public: public:
T& ref(const SimpleMutex::scoped_lock& lk) { /** Construct a Value
dassert( &lk.m() == &BY ); *
return _val; * All types not listed will be rejected rather than converted (se
e private for why)
*
* Note: Currently these are all explicit conversions.
* I'm not sure if we want implicit or not.
* //TODO decide
*/
Value(): _storage() {} // "Missing" value
explicit Value(bool value) : _storage(Bool, value) {
}
explicit Value(int value) : _storage(NumberInt, val
ue) {}
explicit Value(long long value) : _storage(NumberLong, va
lue) {}
explicit Value(double value) : _storage(NumberDouble,
value) {}
explicit Value(const OpTime& value) : _storage(Timestamp, val
ue.asDate()) {}
explicit Value(const OID& value) : _storage(jstOID, value)
{}
explicit Value(const StringData& value) : _storage(String, value)
{}
explicit Value(const string& value) : _storage(String, String
Data(value)) {}
explicit Value(const char* value) : _storage(String, String
Data(value)) {}
explicit Value(const Document& doc) : _storage(Object, doc) {
}
explicit Value(const BSONObj& obj);// : _storage(Object, Docume
nt(obj)) {} // in cpp
explicit Value(const vector<Value>& vec) : _storage(Array, new RCV
ector(vec)) {}
explicit Value(const BSONBinData& bd) : _storage(BinData, bd) {
}
explicit Value(const BSONRegEx& re) : _storage(RegEx, re) {}
explicit Value(const BSONCodeWScope& cws) : _storage(CodeWScope, cw
s) {}
explicit Value(const BSONDBRef& dbref) : _storage(DBRef, dbref)
{}
explicit Value(const BSONSymbol& sym) : _storage(Symbol, sym.sy
mbol) {}
explicit Value(const BSONCode& code) : _storage(Code, code.cod
e) {}
explicit Value(const NullLabeler&) : _storage(jstNULL) {}
// BSONNull
explicit Value(const UndefinedLabeler&) : _storage(Undefined) {}
// BSONUndefined
explicit Value(const MinKeyLabeler&) : _storage(MinKey) {}
// MINKEY
explicit Value(const MaxKeyLabeler&) : _storage(MaxKey) {}
// MAXKEY
explicit Value(const Date_t& date)
: _storage(Date, static_cast<long long>(date.millis)) // millis
really signed
{}
/** Creates an empty or zero value of specified type.
* This is currently the only way to create Undefined or Null Valu
es.
*/
explicit Value(BSONType type);
// TODO: add an unsafe version that can share storage with the BSON
Element
/// Deep-convert from BSONElement to Value
explicit Value(const BSONElement& elem);
/** Construct a long or integer-valued Value.
*
* Used when preforming arithmetic operations with int where the
* result may be too large and need to be stored as long. The Valu
e
* will be an int if value fits, otherwise it will be a long.
*/
static Value createIntOrLong(long long value);
/** A "missing" value indicates the lack of a Value.
* This is similar to undefined/null but should not appear in outp
ut to BSON.
* Missing Values are returned by Document when accessing non-exis
tent fields.
*/
bool missing() const { return _storage.type == EOO; }
/// true if missing() or type is jstNULL or Undefined
bool nullish() const {
return missing()
|| _storage.type == jstNULL
|| _storage.type == Undefined;
} }
};
// todo: rename this to ThreadSafeString or something /// true if type represents a number
/** there is now one mutex per DiagStr. If you have hundreds or millio bool numeric() const {
ns of return _storage.type == NumberDouble
DiagStrs you'll need to do something different. || _storage.type == NumberLong
*/ || _storage.type == NumberInt;
class DiagStr {
mutable SpinLock m;
string _s;
public:
DiagStr(const DiagStr& r) : _s(r.get()) { }
DiagStr(const string& r) : _s(r) { }
DiagStr() { }
bool empty() const {
scoped_spinlock lk(m);
return _s.empty();
}
string get() const {
scoped_spinlock lk(m);
return _s;
}
void set(const char *s) {
scoped_spinlock lk(m);
_s = s;
} }
void set(const string& s) {
scoped_spinlock lk(m); /// Get the BSON type of the field.
_s = s; BSONType getType() const { return _storage.bsonType(); }
/** Exact type getters.
* Asserts if the requested value type is not exactly correct.
* See coerceTo methods below for a more type-flexible alternative
.
*/
double getDouble() const;
string getString() const;
Document getDocument() const;
OID getOid() const;
bool getBool() const;
long long getDate() const; // in milliseconds
OpTime getTimestamp() const;
const char* getRegex() const;
const char* getRegexFlags() const;
string getSymbol() const;
string getCode() const;
int getInt() const;
long long getLong() const;
const vector<Value>& getArray() const { return _storage.getArray();
}
size_t getArrayLength() const;
/// Access an element of a subarray. Returns Value() if missing or
getType() != Array
Value operator[] (size_t index) const;
/// Access a field of a subdocument. Returns Value() if missing or
getType() != Object
Value operator[] (StringData name) const;
/// Add this value to the BSON object under construction.
void addToBsonObj(BSONObjBuilder* pBuilder, StringData fieldName) c
onst;
/// Add this field to the BSON array under construction.
void addToBsonArray(BSONArrayBuilder* pBuilder) const;
// Support BSONObjBuilder and BSONArrayBuilder "stream" API
friend BSONObjBuilder& operator << (BSONObjBuilderValueStream& buil
der, const Value& val);
/** Coerce a value to a bool using BSONElement::trueValue() rules.
* Some types unsupported. SERVER-6120
*/
bool coerceToBool() const;
/** Coercion operators to extract values with fuzzy type logic.
*
* These currently assert if called on an unconvertible type.
* TODO: decided how to handle unsupported types.
*/
string coerceToString() const;
int coerceToInt() const;
long long coerceToLong() const;
double coerceToDouble() const;
OpTime coerceToTimestamp() const;
long long coerceToDate() const;
time_t coerceToTimeT() const;
tm coerceToTm() const; // broken-out time struct (see man gmtime)
/** Compare two Values.
* @returns an integer less than zero, zero, or an integer greater
than
* zero, depending on whether lhs < rhs, lhs == rhs, or l
hs > rhs
* Warning: may return values other than -1, 0, or 1
*/
static int compare(const Value& lhs, const Value& rhs);
friend
bool operator==(const Value& v1, const Value& v2) {
if (v1._storage.identical(v2._storage)) {
// Simple case
return true;
}
return (Value::compare(v1, v2) == 0);
} }
operator string() const { return get(); }
void operator=(const string& s) { set(s); } /// This is for debugging, logging, etc. See getString() for how to
void operator=(const DiagStr& rhs) { extract a string.
set( rhs.get() ); string toString() const;
friend ostream& operator << (ostream& out, const Value& v);
void swap(Value& rhs) {
_storage.swap(rhs._storage);
} }
// == is not defined. use get() == ... instead. done this way so /** Figure out what the widest of two numeric types is.
one thinks about if composing multiple operations *
bool operator==(const string& s) const; * Widest can be thought of as "most capable," or "able to hold th
e
* largest or most precise value." The progression is Int, Long,
Double.
*/
static BSONType getWidestNumeric(BSONType lType, BSONType rType);
/// Get the approximate memory size of the value, in bytes. Include
s sizeof(Value)
size_t getApproximateSize() const;
/** Calculate a hash value.
*
* Meant to be used to create composite hashes suitable for
* hashed container classes such as unordered_map<>.
*/
void hash_combine(size_t& seed) const;
/// struct Hash is defined to enable the use of Values as keys in u
nordered_map.
struct Hash : unary_function<const Value&, size_t> {
size_t operator()(const Value& rV) const;
};
/// Call this after memcpying to update ref counts if needed
void memcpyed() const { _storage.memcpyed(); }
// LEGACY creation functions
static Value createFromBsonElement(const BSONElement* pBsonElement)
;
static Value createInt(int value) { return Value(value); }
static Value createLong(long long value) { return Value(value); }
static Value createDouble(double value) { return Value(value); }
static Value createTimestamp(const OpTime& value) { return Value(va
lue); }
static Value createString(const string& value) { return Value(value
); }
static Value createDocument(const Document& doc) { return Value(doc
); }
static Value createArray(const vector<Value>& vec) { return Value(v
ec); }
static Value createDate(const long long value);
private:
/** This is a "honeypot" to prevent unexpected implicit conversions
to the accepted argument
* types. bool is especially bad since without this it will accept
any pointer.
*
* Template argument name was chosen to make produced error easier
to read.
*/
template <typename InvalidArgumentType>
explicit Value(const InvalidArgumentType& invalidArgument);
// does no type checking
StringData getStringData() const; // May contain embedded NUL bytes
ValueStorage _storage;
friend class MutableValue; // gets and sets _storage.genericRCPtr
}; };
BOOST_STATIC_ASSERT(sizeof(Value) == 16);
}
namespace std {
// This is used by std::sort and others
template <>
inline void swap(mongo::Value& lhs, mongo::Value& rhs) { lhs.swap(rhs);
}
} }
/* ======================= INLINED IMPLEMENTATIONS ========================
== */
namespace mongo {
inline size_t Value::getArrayLength() const {
verify(getType() == Array);
return getArray().size();
}
inline size_t Value::Hash::operator()(const Value& v) const {
size_t seed = 0xf0afbeef;
v.hash_combine(seed);
return seed;
}
inline StringData Value::getStringData() const {
return _storage.getString();
}
inline string Value::getString() const {
verify(getType() == String);
return _storage.getString().toString();
}
inline OID Value::getOid() const {
verify(getType() == jstOID);
return OID(_storage.oid);
}
inline bool Value::getBool() const {
verify(getType() == Bool);
return _storage.boolValue;
}
inline long long Value::getDate() const {
verify(getType() == Date);
return _storage.dateValue;
}
inline OpTime Value::getTimestamp() const {
verify(getType() == Timestamp);
return _storage.timestampValue;
}
inline const char* Value::getRegex() const {
verify(getType() == RegEx);
return _storage.getString().rawData(); // this is known to be NUL t
erminated
}
inline const char* Value::getRegexFlags() const {
verify(getType() == RegEx);
const char* pattern = _storage.getString().rawData(); // this is kn
own to be NUL terminated
const char* flags = pattern + strlen(pattern) + 1; // first byte af
ter pattern's NUL
dassert(flags + strlen(flags) == pattern + _storage.getString().siz
e());
return flags;
}
inline string Value::getSymbol() const {
verify(getType() == Symbol);
return _storage.getString().toString();
}
inline string Value::getCode() const {
verify(getType() == Code);
return _storage.getString().toString();
}
inline int Value::getInt() const {
verify(getType() == NumberInt);
return _storage.intValue;
}
inline long long Value::getLong() const {
BSONType type = getType();
if (type == NumberInt)
return _storage.intValue;
verify(type == NumberLong);
return _storage.longValue;
}
};
 End of changes. 14 change blocks. 
75 lines changed or deleted 298 lines changed or added

This html diff was produced by rfcdiff 1.41. The latest version is available from http://tools.ietf.org/tools/rfcdiff/