Fast For-In in V8

Automotive
For-in is a widely used language feature present in many frameworks. Despite its ubiquity, it is one of the more obscure language constructs from an implementation perspective. V8 went to great lengths to make this feature as fast as possible. Over the course of the past year, for-in became fully spec compliant and up to 3 times faster, depending on the context.

Many popular websites rely heavily on for-in and benefit from its optimization. For example, in early 2016 Facebook spent roughly 7% of its total JavaScript time during startup in the implementation of for-in itself. On Wikipedia this number was even higher at around 8%. By improving the performance of certain slow cases, Chrome 51 significantly improved the performance on these two websites:




Facebook and Wikipedia both improved their total script time by 4% due to various for-in improvements. Note that during the same period, the rest of V8 also got faster, which yielded a total scripting improvement of more than 4%.

In the rest of this blog post we will explain how we managed to speed up this core language feature and fix a long-standing spec violation at the same time.

The Spec

TL;DR; The for-in iteration semantics are fuzzy for performance reasons.

When we look at the spec-text of for-in, it’s written in an unexpectedly fuzzy way,which is observable across different implementations. Let's look at an example when iterating over a Proxy object with the proper traps set.
let proxy = new Proxy({a:1, b:1},{
getPrototypeOf(target) {
console.log("getPrototypeOf");
return null;
},
ownKeys(target) {
console.log("ownKeys");
return Reflect.ownKeys(target);
},
getOwnPropertyDescriptor(target, prop) {
console.log("getOwnPropertyDescriptor name=" + prop);
return Reflect.getOwnPropertyDescriptor(target, prop);
}
});

In V8/Chrome 56 you get the following output:
ownKeys
getPrototypeOf
getOwnPropertyDescriptor name=a
a
getOwnPropertyDescriptor name=b
b

In contrast, you will see a different order of statements for the same snippet in Firefox 51:
ownKeys 
getOwnPropertyDescriptor name=a
getOwnPropertyDescriptor name=b
getPrototypeOf
a
b

Both browsers respect the spec, but for once the spec does not enforce an explicit order of instructions. To understand these loop holes properly, let's have a look at the spec text:
EnumerateObjectProperties ( O )
When the abstract operation EnumerateObjectProperties is called with argument O, the following steps are taken:
  1. Assert: Type(O) is Object. 
  2. Return an Iterator object (25.1.1.2) whose next method iterates over all the String-valued keys of enumerable properties of O. The iterator object is never directly accessible to ECMAScript code. The mechanics and order of enumerating the properties is not specified but must conform to the rules specified below. 
Now, usually spec instructions are precise in what exact steps are required. But in this case they refer to a simple list of prose, and even the order of execution is left to implementers. Typically, the reason for this is that such parts of the spec were written after the fact where JavaScript engines already had different implementations. The spec tries to tie the loose ends by providing the following instructions:
  1. The iterator's throw and return methods are null and are never invoked. 
  2. The iterator's next method processes object properties to determine whether the property key should be returned as an iterator value. 
  3. Returned property keys do not include keys that are Symbols. 
  4. Properties of the target object may be deleted during enumeration. 
  5. A property that is deleted before it is processed by the iterator's next method is ignored. If new properties are added to the target object during enumeration, the newly added properties are not guaranteed to be processed in the active enumeration. 
  6. A property name will be returned by the iterator's next method at most once in any enumeration. 
  7. Enumerating the properties of the target object includes enumerating properties of its prototype, and the prototype of the prototype, and so on, recursively; but a property of a prototype is not processed if it has the same name as a property that has already been processed by the iterator's next method. 
  8. The values of [[Enumerable]] attributes are not considered when determining if a property of a prototype object has already been processed. 
  9. The enumerable property names of prototype objects must be obtained by invoking EnumerateObjectProperties passing the prototype object as the argument. 
  10. EnumerateObjectProperties must obtain the own property keys of the target object by calling its [[OwnPropertyKeys]] internal method. 
These steps sound tedious, however the specification also contains an example implementation which is explicit and much more readable:
function* EnumerateObjectProperties(obj) {
const visited = new Set();
for (const key of Reflect.ownKeys(obj)) {
if (typeof key === "symbol") continue;
const desc = Reflect.getOwnPropertyDescriptor(obj, key);
if (desc && !visited.has(key)) {
visited.add(key);
if (desc.enumerable) yield key;
}
}
const proto = Reflect.getPrototypeOf(obj);
if (proto === null) return;
for (const protoKey of EnumerateObjectProperties(proto)) {
if (!visited.has(protoKey)) yield protoKey;
}
}

Now that you've made it this far, you might have noticed from the previous example that V8 does not exactly follow the spec example implementation. As a start, the example for-in generator works incrementally, while V8 collects all keys upfront - mostly for performance reasons. This is perfectly fine, and in fact the spec text explicitly states that the order of operations A - J is not defined. Nevertheless, as you will find out later in this post, there are some corner cases where V8 did not fully respect the specification until 2016.

The Enum Cache

The example implementation of the for-in generator follows an incremental pattern of collecting and yielding keys. In V8 the property keys are collected in a first step and only then used in the iteration phase. For V8 this makes a few things easier. To understand why, we need to have a look at the object model.

A simple object such as {a:"value a", b:"value b", c:"value c"} can have various internal representations in V8 as we will show in a detailed follow-up post on properties. This means that depending on what type of properties we have—in-object, fast or slow—the actual property names are stored in different places. This makes collecting enumerable keys a non-trivial undertaking.

V8 keeps track of the object's structure by means of a hidden class or so-called Map. Objects with the same Map have the same structure. Additionally each Map has a shared data-structure, the descriptor array, which contains details about each property, such as where the properties are stored on the object, the property name, and details such as enumerability.

Let’s for a moment assume that our JavaScript object has reached its final shape and no more properties will be added or removed. In this case we could use the descriptor array as a source for the keys. This works if there are only enumerable properties. To avoid the overhead of filtering out non-enumerable properties each time V8 uses a separate EnumCache accessible via the Map's descriptor array.


Given that V8 expects that slow dictionary objects frequently change, (i.e. through addition and removal of properties), there is no descriptor array for slow objects with dictionary properties. Hence, V8 does not provide an EnumCache for slow properties. Similar assumptions hold for indexed properties, and as such they are excluded from the EnumCache as well.

Let’s summarize the important facts:
  • Maps are used to keep track of object shapes. 
  • Descriptor arrays store information about properties (name, configurability, visibility). 
  • Descriptor arrays can be shared between Maps. 
  • Each descriptor array can have an EnumCache listing only the enumerable named keys, not indexed property names.

The Mechanics of For-In

Now you know partially how Maps work and how the EnumCache relates to the descriptor array. V8 executes JavaScript via Ignition, a bytecode interpreter, and TurboFan, the optimizing compiler, which both deal with for-in in similar ways. For simplicity we will use a pseudo-C++ style to explain how for-in is implemented internally:

// For-In Prepare:
FixedArray* keys = nullptr;
Map* original_map = object->map();
if (original_map->HasEnumCache()) {
if (object->HasNoElements()) {
keys = original_map->GetCachedEnumKeys();
} else {
keys = object->GetCachedEnumKeysWithElements();
}
} else {
keys = object->GetEnumKeys();
}

// For-In Body:
for (size_t i = 0; i < keys->length(); i++) {
// For-In Next:
String* key = keys[i];
if (!object->HasProperty(key) continue;
EVALUATE_FOR_IN_BODY();
}

For-in can be separated into three main steps:
  1. Preparing the keys to iterate over, 
  2. Getting the next key, 
  3. Evaluating the for-in body. 

The “prepare”-step is the most complex out of these three and this is the place where the EnumCache comes into play. In the example above you can see that V8 directly uses the EnumCache if it exists and if there are no elements (integer indexed properties) on the object (and its prototype). For the case where there are indexed property names, V8 jumps to a runtime function implemented in C++ which prepends them to the existing enum cache, as illustrated by the following example:

FixedArray* JSObject::GetCachedEnumKeysWithElements() {
FixedArray* keys = object->map()->GetCachedEnumKeys();
return object->GetElementsAccessor()->PrependElementIndices(object, keys);
}

FixedArray* Map::GetCachedEnumKeys() {
// Get the enumerable property keys from a possibly shared enum cache
FixedArray* keys_cache = descriptors()->enum_cache()->keys_cache();
if (enum_length() == keys_cache->length()) return keys_cache;
return keys_cache->CopyUpTo(enum_length());
}

FixedArray* FastElementsAccessor::PrependElementIndices(
JSObject* object, FixedArray* property_keys) {
Assert(object->HasFastElements());
FixedArray* elements = object->elements();
int nof_indices = CountElements(elements)
FixedArray* result = FixedArray::Allocate(property_keys->length() + nof_indices);
int insertion_index = 0;
for (int i = 0; i < elements->length(); i++) {
if (!HasElement(elements, i)) continue;
result[insertion_index++] = String::FromInt(i);
}
// Insert property keys at the end.
property_keys->CopyTo(result, nof_indices - 1);
return result;
}

In the case where no existing EnumCache was found we jump again to C++ and follow the initially presented spec steps:

FixedArray* JSObject::GetEnumKeys() {
// Get the receiver’s enum keys.
FixedArray* keys = this->GetOwnEnumKeys();
// Walk up the prototype chain.
for (JSObject* object : GetPrototypeIterator()) {
// Append non-duplicate keys to the list.
keys = keys->UnionOfKeys(object->GetOwnEnumKeys());
}
return keys;
}

FixedArray* JSObject::GetOwnEnumKeys() {
FixedArray* keys;
if (this->HasEnumCache()) {
keys = this->map()->GetCachedEnumKeys();
} else {
keys = this->GetEnumPropertyKeys();
}
if (this->HasFastProperties()) this->map()->FillEnumCache(keys);
return object->GetElementsAccessor()->PrependElementIndices(object, keys);
}


FixedArray* FixedArray::UnionOfKeys(FixedArray* other) {
int length = this->length();
FixedArray* result = FixedArray::Allocate(length + other->length());
this->CopyTo(result, 0);
int insertion_index = length;
for (int i = 0; i < other->length(); i++) {
String* key = other->get(i);
if (other->IndexOf(key) == -1) {
result->set(insertion_index, key);
insertion_index++;
}
}
result->Shrink(insertion_index);
return result;
}

This simplified C++ code corresponds to the implementation in V8 until early 2016 when we started to look at the UnionOfKeys method. If you look closely you notice that we used a naive algorithm to exclude duplicates from the list which might yield bad performance if we have many keys on the prototype chain. This is how we decided to pursue the optimizations in following section.

Problems with For-In

As we already hinted in the previous section, the UnionOfKeys method has bad worst-case performance. It was based on the valid assumption that most objects have fast properties and thus will benefit from an EnumCache. The second assumption is that there are only few enumerable properties on the prototype chain limiting the time spent in finding duplicates. However, if the object has slow dictionary properties and many keys on the prototype chain, UnionOfKeys becomes a bottleneck as we have to collect the enumerable property names each time we enter for-in.

Next to performance issues, there was another problem with the existing algorithm in that it’s not spec compliant. V8 got the following example wrong for many years:
var o = { 
__proto__ : {b: 3},
a: 1
};
Object.defineProperty(o, “b”, {});

for (var k in o) print(k);
Output:
 "a"
"b"
Perhaps counterintuitively this should just print out “a” instead of “a” and “b”. If you recall the spec text at the beginning of this post, steps G and J imply that non-enumerable properties on the receiver shadow properties on the prototype chain.

To make things more complicated, ES6 introduced the proxy object. This broke a lot of assumptions of the V8 code. To implement for-in in a spec-compliant manner, we have to trigger the following 5 out of a total of 13 different proxy traps.


Internal Method
Handler Method
[[GetPrototypeOf]]
getPrototypeOf
[[GetOwnProperty]]
getOwnPropertyDescriptor
[[HasProperty]]
has
[[Get]]
get
[[OwnPropertyKeys]]
ownKeys

This required a duplicate version of the original GetEnumKeys code which tried to follow the spec example implementation more closely. ES6 Proxies and lack of handling shadowing properties were the core motivation for us to refactor how we extract all the keys for for-in in early 2016.

The KeyAccumulator

We introduced a separate helper class, the KeyAccumulator, which dealt with the complexities of collecting the keys for for-in. With growth of the ES6 spec, new features like Object.keys or Reflect.ownKeys required their own slightly modified version of collecting keys. By having a single configurable place we could improve the performance of for-in and avoid duplicated code.

The KeyAccumulator consists of a fast part that only supports a limited set of actions but is able to complete them very efficiently. The slow accumulator supports all the complex cases, like ES6 Proxies.

In order to properly filter out shadowing properties we have to maintain a separate list of non-enumerable properties that we have seen so far. For performance reasons we only do this after we figure out that there are enumerable properties on the prototype chain of an object.

Performance Improvements

With the KeyAccumulator in place, a few more patterns became feasible to optimize. The first one was to avoid the nested loop of the original UnionOfKeys method which caused slow corner cases. In a second step we performed more detailed pre-checks to make use of existing EnumCaches and avoid unnecessary copy steps.

To illustrate that the spec-compliant implementation is faster, let’s have a look at the following four different objects:

var fastProperties = {
__proto__ : null,
“property 1” : 1,

“property 10” : n
}

var fastPropertiesWithPrototype = {
“property 1” : 1,

“property 10” : n
}

var slowProperties = {
__proto__ : null,
“dummy”: null,
“property 1” : 1,

“property 10” : n
}
delete slowProperties[“dummy”]

var elements = {
__proto__: null,

“1” : 1,

“10” : n
}

  • The fastProperties object has standard fast properties. 
  • The fastPropertiesWithPrototype object has additional non-enumerable properties on the prototype chain by using the Object.prototype. 
  • The slowProperties object has slow dictionary properties. 
  • The elements object has only indexed properties. 

The following graph compares the original performance of running a for-in loop a million times in a tight loop without the help of our optimizing compiler.


As we've outlined in the introduction, these improvements became very visible on Facebook and Wikipedia in particular. 




Besides the initial improvements available in Chrome 51, a second performance tweak yielded another significant improvement. The following graph shows our tracking data of the total time spent in scripting during startup on a Facebook page. The selected range around V8 revision 37937 corresponds to an additional 4% performance improvement!


To underline the importance of improving for-in we can rely on the data from a tool we built back in 2016 that allows us to extract V8 measurements over a set of websites. The following table shows the relative time spent in V8 C++ entry points (runtime functions and builtins) for Chrome 49 over a set of roughly 25 representative real-world websites.

Position
Name
Total Time
1
CreateObjectLiteral
1.10%
2
NewObject
0.90%
3
KeyedGetProperty
0.70%
4
GetProperty
0.60%
5
ForInEnumerate
0.60%
6
SetProperty
0.50%
7
StringReplaceGlobalRegExpWithString
0.30%
8
HandleApiCallConstruct
0.30%
9
RegExpExec
0.30%
10
ObjectProtoToString
0.30%
11
ArrayPush
0.20%
12
NewClosure
0.20%
13
NewClosure_Tenured
0.20%
14
ObjectDefineProperty
0.20%
15
HasProperty
0.20%
16
StringSplit
0.20%
17
ForInFilter
0.10%

The most important for-in helpers are at position 5 and 17, accounting for an average of 0.7% percent of the total time spent in scripting on a website. In Chrome 57 ForInEnumerate has dropped to 0.2% of the total time and ForInFilter is below the measuring threshold due to a fast path written in assembler.

Posted by Camillo Bruni, @camillobruni
Automotive
8:03:00 AM

Automotive technology

Automotive

Labels

1904 Columbus 1940 Ford 1964 Worlds Fair 1969 Camaro 1969 Dodge Coronet Super Bee 2014 2016 Sales 2017 The Bad 8 2017 The Good 12 3 wheeler 4 G 407 407 ex2 427 AC Cobra 440 six pack 442 4x 4x4 55 Chevy 57 Chevy 5th wheel AAR abandoned abs abuse by law enforcement AC Cobra Acadian accessories accident Acoustic processing Active noise control (ANC) Acura Acura Reviews adaptive cruise control ADAS Adobe AIR ads adventurers advertising aerodynamics Aircraft engines airlines airplane Airstream Alfa Alfa Romeo Alfa-Romeo All Cars Rankings All SUV Rankings All Vehicle Rankings Alpina Alpine AMBR winner ambulance AMC America's greatest photographers American LaFrance amphib AMX AMX-3 Andorra Andrew Poliak Android Andy Gryc anti lock braking system App World Apps Arab-Supercar area controller Ariel-Nomad ARM-based devices art Art Arfons Art Deco artist Asset management system Aston Martin Aston-Martin atv auction Audi Audi Reviews audio Augmented reality Austin Austin Healey Australia Austria Auto Accident Attorney auto car donate auto car donation Auto Donate Auto Donation California Auto hobby books Auto Sales By Brand auto show Auto Story in Pictures Wednesday auto taxi Autocar automobile automobile donation AUTOMOBILE INSURANCE automobile parts automobile safety system automobule donate Autonomous cars Awards awesome B 29 B 52 BAIC Baja racing Baker banners barn find barn finds barnfind barnfinds Barracuda Barris barum BatBerry Batman Batteries battery beautiful engine Beautiful paint before and after Belgium Bello's belly tanker Bentley Best Sellers Best Selling American Cars Best Selling Cars Best Selling Luxury Best Selling SUVs Best Selling Trucks Best Selling Vehicles bicycle bicycles Big 3 Swap Meet big wheel bike messengers bike rack biofuel biography BlackBerry BlackBerry Radar BlackBerry-QNX blink code blink code checkup blink code error blink code troubleshooting Blog blogs BMW BMW Audi Mercedes Benz Daimler jeep GM toyota Chrysler VW volkswagon nissan infiniti ford unique rare Bntley boardtrack Boats boattail Bonneville book review bookmobile Boss 302 Boss 429 brake brakes braking system Brand Marketshare brass era breedlove Brewster Brian Salisbury Bricklin bridge British Britten brochure Bugatti Buick Bulgaria burnout bus Buses buying selling cash tips money advice BYD c C-type Jag Cadillac Cadillac Reviews Camaro Can Am Canada Canada 2016 Sales Canada All Cars Rankings Canada All SUV Rankings Canada All Vehicle Rankings Canada Auto Sales Canada Auto Sales By Brand Canada Best Sellers Canada Compact Car Sales Canada December 2016 Canada Entry Luxury Car Sales Canada February 2017 Canada January 2017 Canada Large Car Sales Canada Large Luxury Car Sales Canada Large Luxury SUV Sales Canada Large SUV Sales Canada March 2017 Canada Midsize Car Sales Canada Midsize Luxury Car Sales Canada Midsize Luxury SUV Sales Canada Midsize SUV Sales Canada Minivan Sales Canada November 2016 Canada October 2016 Canada Premium Sporty Car Sales Canada September 2016 Canada Small Luxury SUV Sales Canada Small SUV Sales Canada Sporty Car Sales Canada Truck Sales Canada Van Sales Canada Worst Sellers car care car chase scene car clubs car collections car collectors Car Donate car donate california car donation Car Donations California Car or the Future car wash carbs carrozzeria cart caterpillar tracked vehicle CCS celebrities celebrity Certicom CES CESA 2012 CESA 3.0 Chademo Challenger Chaparral Charger Charity Charity auction charity car donation Charity Car Donation Program Charity Car With Your Credit Card cheating Checker Chery Chevelle Chevrolet Chevrolet Reviews Chevy 2 China chopper Christian Sobottka Christie Christmas Chrysler Citroen Citroën classics cleaning clip Cloud connectivity CO2 Cobra Cobra Daytona Coupe Cobra Mustang Cobra Torino COE Cogent collection collector College Colombia commercial common rail direct injection Compact Car Sales companies comparison compliment components components of anti-lock braking system concept Concept car Concept team Connected Car construction Consumer Electronics Show consumers Contest convertible Coronet Corvair corvette Corvettes Costa Rica coupe coventry cragar crash crde crdi Croatia Crosley crossover Cruise 4 Kids crypto cryptography CTS Cuda Cunningham Curtiss Aerocar Custom customer satisfaction cutaway display cycle car Cyclone Cyprus Czech Republic dacia Daihatsu Dan Gurney dart Datsun Daytona ddis DDS dealers Dealership Dean Martin December 2016 Degree delivery truck Delorean Delphi Demon Denmark Derek Kuhn design deuce devices Dick Landy dicor Digital instrument clusters digital spark ignition Diner with car theme direction injection Disney display diy Dodge domain controller Donate Donate A Car Tax Deduction Donate Automobile To Charity Donate Car To Charity Tax Deduction Donate Vehicles To Charity donation donation auto car donation vehicles to charity Doug Newcomb Drag racing drag strip Dragonsnake dragsters DREAM drifting Driven Driver distraction driving assistance drunk driver DS dtsi dual carbs dual engined dualie Ducati dump truck dvla E-type Jag ECC economy ECU Ecuador electric electric car Electric cars electromagnetic brake Elliptic Curve Cryptography EMF Emil Dautovic Endurance racing engine engine accessories Engine sound enhancement engines Entry Luxury Car Sales enzo Erskine Essex estate Estonia etc EUCAR Europe EV Business Case Evel Knievel event experience experiment extreme sports video F1 Factor-Aurelio Factory lightweight Factory race car Fairlane Falcon Fast boot Fast-Charging FCA FCEV February 2017 Ferrari Fiat Fiat Botafogo finance Finland fips fire engine fire fighting fire trucks Firebird Firestone firetrucks Fisker flamejob fleet management Ford ford escort Ford Reviews Fordson tractor Forecasts FOTA found around the neighborhood France Franklin Free Car Donation Freescale french fuel fuel injection fuel injection system Fuel Tanker fuel-cell fun Funny car Futurliner gadgets Galpin Ford game garage garner gas mileage gas stations Gasser Gauges GCBC Awards GCBC Most Popular Geely Gene Winfield General Motors German Germany give your car to charity GM GM MyLink GNX Go cart good news Goodwood Goodyear gourmet food vans GPU Graham Gran Prix Grand National Roadster Show 2017 Grand Sport Corvette Graph Great Wall Motors Greece green Green car Gremlin GT GT 350 GT 40 GT 500 gt40 GTO GTX Gulf race car Gullwing Guy Martin Hands-free systems Harley Harley Davidson hauler Hawaii helicopter hemi hemmings Hennessey Henry J hero Hertz hire Hispano-Suiza historical history HMIs Holden Hollywood Holman Moody Honda Honda Reviews Honda Sales Hong Kong Hood ornaments hood scoops Horizon 2020 horse carriage horse wagon host blog info about auto Hot rods Hot Wheels Housekeeping How To Donate How To Donate A Car For Tax Deduction How To Donate Car To Charity how to donation car to charity HRM HTML5 Hudson Hummer humor humour Humvee Hungary Hupmobile Hurst Hurst SC Rambler hybrid Hybrid cars hydrogen hypervisor Hyundai Hyundai Reviews Ian Roussel Iceland ID4 Car ignition IIoT immitation Impala india Indian Indianapolis industry news infiniti Infiniti Reviews Info infographic informative Infotainment Injury Lawyer Innotrans innova innovation innovative instrument panel insurance intake Intel interior International Harvester Internet of Things Internet radio invitation IoT Ireland iris iris details iris engine details iris technical Isetta Iskenderian Isky Isle of Man ISO 26262 Israel issues Isuzu Italian Italy ITS ITU IVI Jaguar January 2017 Japan Japanese Javelin Jay Leno Jean-François Tarabbia Jeep Jeep Wrangler JLR John D'Agostino John Deere John Wall Justin Moon jv Kaivan Karimi Kandi kawasaki Ken Block Kerry Johnson Kia kids Kim Cairns Kissel Kombi Kroy Zeviar Kurtis La Carrera Panamerica lace paint Lamborghini Lamborghini Revuelto Lancia Land Cruiser Land Rover Land Rover Sales land speed record holder Land-Rover Large Car Sales Large Luxury Car Sales Large Luxury SUV Sales Large SUV Sales Larry Wood LaSalle Latvia launch law enforcement lawnmower laws Le Mans legends Leno Lexus license plates Lidar Life Insurance limited Lincoln Lincoln MKZ Linda Campbell Linda Vaughn links lists Lithuania live Loans Locomobile logging train logging trucks Lola London to Brighton Looking for EV's Los Angeles Lotus lowrider LSR Luxembourg luxury Lyft Lynn Gayowski Mach 1 machine shop Mack Mad Max magazine magazines magic iris mags Malaysia March 2017 Mario Andretti Mark Donohue marketing Marketshare Maserati Matt Watson Maverick Mazda Mazda Reviews MB McLaren mechanic Megan Alink meme Memory Lane Men Micro Mercedes Mercedes Benz Mercedes-Benz Mercer Cobra Mercury Metallica Metro Mexico Miata microkernal Midsize Car Sales Midsize Luxury Car Sales Midsize Luxury SUV Sales Midsize SUV Sales Military Miller race car mini mini bike miniature Minivan Sales MirrorLink mission-critical Mitsubishi Miura MMI Mobile connectivity Mobile World Congress mod top Model Model A model T modifications Momo Monaco Monster Truck Moon Moon eyes Mopar Mopar parts Morgan Morocco morons mot Motor shows motor wheel Motorcycle Motorcycles motorhomes Mouse movie movies mpv Multicore Munsters Muntz muscle cars musclecars museum music video Mustang NAIAS Nancy Young Nascar Nash Navigation naza neglec neglected Netherlands new tv show New York New Zealand news ni Nissan Nissan Reviews Nomad Norway nos nose art Nova November 2016 Nurburgring Object Management group October 2016 off roading offenhauser Oldsmobile OMG Online College OnStar Opel Open source Open standards OpenGL ES option orders original owner Ormond Beach land speed racing pace car Packard Pagani Paige pamphlet panel paint Paris to Peking race parking parts Patryk Fournier Paul Leroux Paul Newman Paul Sykes Pebble Beach pedal car perodua personal Peter McCarthy petrol petroliana Peugeot Phoenix Injury photographer photography pics pictures Pierce Arrow Pike's Peak Pinin Farina pinstriping Pit row Pits Pixar PKI plank road PlayBook Plymouth Point Grey Camera Poland pole wheel police Polysynch Pontiac Porsche Porsche 917 Porsche Carrera Portugal POSIX pre 1930's gas station Premium Sporty Car Sales President of the USA Preview prices prius project prooject Proton prototype PSA Peugeot Citroen public key cryptography Pullman QNX QNX CAR QNX Garage QNX OS Qualcomm quiz quote race cars racing racing. LSR Radar radio Raid Data rail railcars railroad ralliart Rally rallying Ram range rover rant Rapid Transit System advertsing rare Real time Innovations recall recommended shop record setter Red Bull Sports Reference vehicle Reliability Rémi Bastien RemoteLink Renault Renesas Renntransporter rentals REO repair reports resarch research restoration restoration shop review Richard Bishop Ridler Award Winner rims river bank cars road and highway Road Runner roadster Robot OS Robot wars Roewe Roger Penske Rolls Royce Romain Saha Romania ROS Roth RTI RTI Connext rumble seat Russia Ruxton RV Safety Safety systems safety-certified sales Sales By Model Sales Stats samba sampan Saoutchik Satellite satnav Scaglietti scallops Scat Pack SCCA racecar School bus sci-fi Scooter SCORE Baja trucks Scott Pennock Scout sculpture Security sedan segway semi sensor extension cable sensor fusion September 2016 service service repair automotive vehicle car buying selling mission statement blog free broker shay drive locomotive Shelby shifter shop Show cars sidecars signs skateboarding Skoda slicks slingshot dragster Slovakia Slovenia Small Luxury SUV Sales Small SUV Sales Smart Smartphones snow machines snowmobile Soapbox South Africa South Korea Sox and Martin Spain spare tire spark ignition spark plug spark plugs Spatial auditory displays special edition Mustangs Speech interfaces speed limit Speed Record speedfest speedster sports car sports cars Sporty Car Sales spy shots spyker Sri Lanka SS SS/AH Stagecoach Stanley Station Wagon steam locomotive steam powered steam shovel steampunk steering wheel Steve McQueen Stig Stirling Moss Stolen streamliner street cars Street Van studebaker stunt stunts Stutz Stutz Blackhawk Subaru Sunbeam Super Bee Super Stock Superbird Supercar supercharger survey suv Suzuki Sweden Swift Switzerland System development Life Cycle Tablets Tach takeover tank tata tata magic iris tata vehicles tax Tax Deduction For Car Donation taxi taxi cab TCS tdi teardrop technical technology Telematics Telematics Detroit Telematics Update tempo Tempo Matador Terlingua Racing Team Terry Staycer Tesla test testdrive Texas Instruments The Race Of Gentlemen Thomas Bloor thoughts three wheeler Thunderbird ticket Tiger Tim Neil Tina Jeffrey tips tires tool tool kit toolbox tools Top Gear top ten list Torino tour bus tourbus towtruck Toyota Toyota Entune Toyota Reviews tractor trailer train train wreck trains Trans Am transmission Transporter Traval trike Triumph trivia trolley Troy Trepanier truck Truck Sales trucking trucks Tucker turbocharger turbojet turbonique Turkey tv tv cars twin spark type 1 type 2 tyres UAE Uber UK UK Auto Sales UK Best Sellers uk market Ukraine Unimog unique University of Waterloo Unser unusual unveil upgrade US US 2016 Sales US All Cars Rankings US All SUV Rankings US All Vehicle Rankings US Auto Sales US Auto Sales By Brand US Best Sellers US Compact Car Sales US December 2016 US Entry Luxury Car Sales US February 2017 US January 2017 US Large Car Sales US Large Luxury Car Sales US Large Luxury SUV Sales US Large SUV Sales US March 2017 US Midsize Car Sales US Midsize Luxury Car Sales US Midsize Luxury SUV Sales US Midsize SUV Sales US Minivan Sales US Navy US November 2016 US October 2016 US September 2016 US Small Luxury SUV Sales US Small SUV Sales US Sporty Car Sales US Truck Sales US US Auto Sales US Van Sales US Worst Sellers USA used cars V2X van Van Sales vauxhall VeDeCoM Vehicle Donation California Velodyne Vespa Video vintage vintage racing Virtual mechanic Virtualization VOIP Guide Volkswagen Volkswagen Reviews Volkswagen Sales Volvo Von Dutch vote VW VW bug W3C wagon train wall of death washer washer fluid Watson's Webinars website what is donation what is it wheel speed sensor wheelchair White williams Willys windshield washer wing Wireless framework women woodlight headlights Woody work truck working principle of anti-lock braking system workshop World Worst Sellers wreck Wrongful Death WW1 WW2 XK SS Yoram Berholtz Yoshiki Chubachi Z 11 Z-28 Z28 zamboni ZL1 Zotye