Array.prototype.push

I’m always amazed by the excellent readability of V8’s source code. I think everyone should have a rough idea about where to look for specific implementation details of the most common JavaScript functions.

As an example, let’s look at how Array#push is implemented in V8. V8 implements all (well, most) Array.prototype functions as BIFs in src/js/array.js:

// Copyright 2012 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// Appends the arguments to the end of the array and returns the new
// length of the array. See ECMA-262, section 15.4.4.7.
function ArrayPush() {
  CHECK_OBJECT_COERCIBLE(this, "Array.prototype.push");

  var array = TO_OBJECT(this);
  var n = TO_LENGTH(array.length);
  var m = arguments.length;

  // Subtract n from kMaxSafeInteger rather than testing m + n >
  // kMaxSafeInteger. n may already be kMaxSafeInteger. In that case adding
  // e.g., 1 would not be safe.
  if (m > kMaxSafeInteger - n) throw MakeTypeError(kPushPastSafeLength, m, n);

  for (var i = 0; i < m; i++) {
    array[i+n] = arguments[i];
  }

  var new_length = n + m;
  array.length = new_length;
  return new_length;
}

Pretty readable, right?

CHECK_OBJECT_COERCIBLE is a macro. The V8 codebase uses quite a lot of custom macros defined in macros.py:

# Macro for ES6 CheckObjectCoercible
# Will throw a TypeError of the form "[functionName] called on null or undefined".
macro CHECK_OBJECT_COERCIBLE(arg, functionName) = if (IS_NULL(%IS_VAR(arg)) || IS_UNDEFINED(arg)) throw MakeTypeError(kCalledOnNullOrUndefined, functionName);

CHECK_OBJECT_COERCIBLE throws an error if Array.prototype.push is called on null or undefined. Makes sense, right? You can easily try this out in your console:

Array.prototype.push.call(null, 1)
  // #=> throws TypeError: Array.prototype.push called on null or undefined

IS_NULL and IS_UNDEFINED are macros as well. Interestingly V8 never seems to use undefined, but always void 0. I assume this is because you used to be able to globally override window.undefined.

The rest is pretty intuitive…

Disclaimer: I’m not working on V8.


Further reading:

 
8
Kudos
 
8
Kudos

Now read this

Minimal Node.JS logger for 12-factor apps

A twelve-factor app never concerns itself with routing or storage of its output stream. It should not attempt to write to or manage logfiles. Instead, each running process writes its event stream, unbuffered, to stdout. During local... Continue →