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: