diff options
| author | Joshua Peek <josh@joshpeek.com> | 2012-07-23 15:52:49 -0500 |
|---|---|---|
| committer | Joshua Peek <josh@joshpeek.com> | 2012-07-23 15:52:49 -0500 |
| commit | 7b6caa0f6c7603aabb5e6ed657e24aaddbeafc78 (patch) | |
| tree | ec0522eae75bb04ae73d28ae3f599682a2bfdaeb /samples/C++ | |
| parent | 314f0e485227915931db361be14d308a210bedea (diff) | |
Rename samples subdirectories
Diffstat (limited to 'samples/C++')
| -rw-r--r-- | samples/C++/bar.h | 10 | ||||
| -rw-r--r-- | samples/C++/bar.hpp | 10 | ||||
| -rw-r--r-- | samples/C++/cuda.cu | 39 | ||||
| -rw-r--r-- | samples/C++/env.cpp | 81 | ||||
| -rw-r--r-- | samples/C++/env.h | 52 | ||||
| -rw-r--r-- | samples/C++/hello.cpp | 8 | ||||
| -rw-r--r-- | samples/C++/key.cpp | 382 | ||||
| -rw-r--r-- | samples/C++/key.h | 162 | ||||
| -rw-r--r-- | samples/C++/main.cpp | 74 | ||||
| -rw-r--r-- | samples/C++/scanner.cc | 1088 | ||||
| -rw-r--r-- | samples/C++/scanner.h | 576 | ||||
| -rw-r--r-- | samples/C++/utils.h | 71 | ||||
| -rw-r--r-- | samples/C++/v8.cc | 288 | ||||
| -rw-r--r-- | samples/C++/v8.h | 152 |
14 files changed, 2993 insertions, 0 deletions
diff --git a/samples/C++/bar.h b/samples/C++/bar.h new file mode 100644 index 0000000..a87343c --- /dev/null +++ b/samples/C++/bar.h @@ -0,0 +1,10 @@ +class Bar +{ + protected: + + char *name; + + public: + + void hello(); +} diff --git a/samples/C++/bar.hpp b/samples/C++/bar.hpp new file mode 100644 index 0000000..a87343c --- /dev/null +++ b/samples/C++/bar.hpp @@ -0,0 +1,10 @@ +class Bar +{ + protected: + + char *name; + + public: + + void hello(); +} diff --git a/samples/C++/cuda.cu b/samples/C++/cuda.cu new file mode 100644 index 0000000..ddef40c --- /dev/null +++ b/samples/C++/cuda.cu @@ -0,0 +1,39 @@ +void foo() +{ + cudaArray* cu_array; + texture<float, 2, cudaReadModeElementType> tex; + + // Allocate array + cudaChannelFormatDesc description = cudaCreateChannelDesc<float>(); + cudaMallocArray(&cu_array, &description, width, height); + + // Copy image data to array + cudaMemcpyToArray(cu_array, image, width*height*sizeof(float), cudaMemcpyHostToDevice); + + // Set texture parameters (default) + tex.addressMode[0] = cudaAddressModeClamp; + tex.addressMode[1] = cudaAddressModeClamp; + tex.filterMode = cudaFilterModePoint; + tex.normalized = false; // do not normalize coordinates + + // Bind the array to the texture + cudaBindTextureToArray(tex, cu_array); + + // Run kernel + dim3 blockDim(16, 16, 1); + dim3 gridDim((width + blockDim.x - 1)/ blockDim.x, (height + blockDim.y - 1) / blockDim.y, 1); + kernel<<< gridDim, blockDim, 0 >>>(d_data, height, width); + + // Unbind the array from the texture + cudaUnbindTexture(tex); +} //end foo() + +__global__ void kernel(float* odata, int height, int width) +{ + unsigned int x = blockIdx.x*blockDim.x + threadIdx.x; + unsigned int y = blockIdx.y*blockDim.y + threadIdx.y; + if (x < width && y < height) { + float c = tex2D(tex, x, y); + odata[y*width+x] = c; + } +} diff --git a/samples/C++/env.cpp b/samples/C++/env.cpp new file mode 100644 index 0000000..beddc19 --- /dev/null +++ b/samples/C++/env.cpp @@ -0,0 +1,81 @@ +/* + This file is part of the PhantomJS project from Ofi Labs. + + Copyright (C) 2012 execjosh, http://execjosh.blogspot.com + + 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 the <organization> 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 <COPYRIGHT HOLDER> BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include "env.h" + +#include <QCoreApplication> +#include <QString> +#include <QVariantMap> + +static Env *env_instance = (Env *)NULL; + +Env *Env::instance() +{ + if ((Env *)NULL == env_instance) + env_instance = new Env(); + + return env_instance; +} + +Env::Env() + : QObject(QCoreApplication::instance()) +{ +} + +// public: + +void Env::parse(const char **envp) +{ + const char **env = (const char **)NULL; + QString envvar, name, value; + int indexOfEquals; + // Loop for each of the <NAME>=<VALUE> pairs and split them into a map + for (env = envp; *env != (const char *)NULL; env++) { + envvar = QString(*env); + indexOfEquals = envvar.indexOf('='); + if (0 >= indexOfEquals) { + // Should never happen because names cannot contain "=" and cannot + // be empty. If it does happen, then just ignore this record. + // See: http://pubs.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap08.html + continue; + } + // Extract name and value (if it exists) from envvar + // NOTE: + // QString::mid() will gracefully return an empty QString when the + // specified position index is >= the length() of the string + name = envvar.left(indexOfEquals); + value = envvar.mid(indexOfEquals + 1); + m_map.insert(name, value); + } +} + +QVariantMap Env::asVariantMap() const +{ + return m_map; +} diff --git a/samples/C++/env.h b/samples/C++/env.h new file mode 100644 index 0000000..6d72b39 --- /dev/null +++ b/samples/C++/env.h @@ -0,0 +1,52 @@ +/* + This file is part of the PhantomJS project from Ofi Labs. + + Copyright (C) 2012 execjosh, http://execjosh.blogspot.com + + 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 the <organization> 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 <COPYRIGHT HOLDER> 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 ENV_H +#define ENV_H + +#include <QObject> +#include <QVariantMap> + +class Env : public QObject +{ + Q_OBJECT + +public: + static Env *instance(); + + void parse(const char ** envp); + QVariantMap asVariantMap() const; + +private: + Env(); + + QVariantMap m_map; +}; + +#endif // ENV_H diff --git a/samples/C++/hello.cpp b/samples/C++/hello.cpp new file mode 100644 index 0000000..d36f6e6 --- /dev/null +++ b/samples/C++/hello.cpp @@ -0,0 +1,8 @@ +#include <iostream> + +using namespace std; + +int main() +{ + cout << "Hello World" << endl; +} diff --git a/samples/C++/key.cpp b/samples/C++/key.cpp new file mode 100644 index 0000000..57ab842 --- /dev/null +++ b/samples/C++/key.cpp @@ -0,0 +1,382 @@ +// Copyright (c) 2009-2012 The Bitcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include <map> + +#include <openssl/ecdsa.h> +#include <openssl/obj_mac.h> + +#include "key.h" + +// Generate a private key from just the secret parameter +int EC_KEY_regenerate_key(EC_KEY *eckey, BIGNUM *priv_key) +{ + int ok = 0; + BN_CTX *ctx = NULL; + EC_POINT *pub_key = NULL; + + if (!eckey) return 0; + + const EC_GROUP *group = EC_KEY_get0_group(eckey); + + if ((ctx = BN_CTX_new()) == NULL) + goto err; + + pub_key = EC_POINT_new(group); + + if (pub_key == NULL) + goto err; + + if (!EC_POINT_mul(group, pub_key, priv_key, NULL, NULL, ctx)) + goto err; + + EC_KEY_set_private_key(eckey,priv_key); + EC_KEY_set_public_key(eckey,pub_key); + + ok = 1; + +err: + + if (pub_key) + EC_POINT_free(pub_key); + if (ctx != NULL) + BN_CTX_free(ctx); + + return(ok); +} + +// Perform ECDSA key recovery (see SEC1 4.1.6) for curves over (mod p)-fields +// recid selects which key is recovered +// if check is nonzero, additional checks are performed +int ECDSA_SIG_recover_key_GFp(EC_KEY *eckey, ECDSA_SIG *ecsig, const unsigned char *msg, int msglen, int recid, int check) +{ + if (!eckey) return 0; + + int ret = 0; + BN_CTX *ctx = NULL; + + BIGNUM *x = NULL; + BIGNUM *e = NULL; + BIGNUM *order = NULL; + BIGNUM *sor = NULL; + BIGNUM *eor = NULL; + BIGNUM *field = NULL; + EC_POINT *R = NULL; + EC_POINT *O = NULL; + EC_POINT *Q = NULL; + BIGNUM *rr = NULL; + BIGNUM *zero = NULL; + int n = 0; + int i = recid / 2; + + const EC_GROUP *group = EC_KEY_get0_group(eckey); + if ((ctx = BN_CTX_new()) == NULL) { ret = -1; goto err; } + BN_CTX_start(ctx); + order = BN_CTX_get(ctx); + if (!EC_GROUP_get_order(group, order, ctx)) { ret = -2; goto err; } + x = BN_CTX_get(ctx); + if (!BN_copy(x, order)) { ret=-1; goto err; } + if (!BN_mul_word(x, i)) { ret=-1; goto err; } + if (!BN_add(x, x, ecsig->r)) { ret=-1; goto err; } + field = BN_CTX_get(ctx); + if (!EC_GROUP_get_curve_GFp(group, field, NULL, NULL, ctx)) { ret=-2; goto err; } + if (BN_cmp(x, field) >= 0) { ret=0; goto err; } + if ((R = EC_POINT_new(group)) == NULL) { ret = -2; goto err; } + if (!EC_POINT_set_compressed_coordinates_GFp(group, R, x, recid % 2, ctx)) { ret=0; goto err; } + if (check) + { + if ((O = EC_POINT_new(group)) == NULL) { ret = -2; goto err; } + if (!EC_POINT_mul(group, O, NULL, R, order, ctx)) { ret=-2; goto err; } + if (!EC_POINT_is_at_infinity(group, O)) { ret = 0; goto err; } + } + if ((Q = EC_POINT_new(group)) == NULL) { ret = -2; goto err; } + n = EC_GROUP_get_degree(group); + e = BN_CTX_get(ctx); + if (!BN_bin2bn(msg, msglen, e)) { ret=-1; goto err; } + if (8*msglen > n) BN_rshift(e, e, 8-(n & 7)); + zero = BN_CTX_get(ctx); + if (!BN_zero(zero)) { ret=-1; goto err; } + if (!BN_mod_sub(e, zero, e, order, ctx)) { ret=-1; goto err; } + rr = BN_CTX_get(ctx); + if (!BN_mod_inverse(rr, ecsig->r, order, ctx)) { ret=-1; goto err; } + sor = BN_CTX_get(ctx); + if (!BN_mod_mul(sor, ecsig->s, rr, order, ctx)) { ret=-1; goto err; } + eor = BN_CTX_get(ctx); + if (!BN_mod_mul(eor, e, rr, order, ctx)) { ret=-1; goto err; } + if (!EC_POINT_mul(group, Q, eor, R, sor, ctx)) { ret=-2; goto err; } + if (!EC_KEY_set_public_key(eckey, Q)) { ret=-2; goto err; } + + ret = 1; + +err: + if (ctx) { + BN_CTX_end(ctx); + BN_CTX_free(ctx); + } + if (R != NULL) EC_POINT_free(R); + if (O != NULL) EC_POINT_free(O); + if (Q != NULL) EC_POINT_free(Q); + return ret; +} + +void CKey::SetCompressedPubKey() +{ + EC_KEY_set_conv_form(pkey, POINT_CONVERSION_COMPRESSED); + fCompressedPubKey = true; +} + +void CKey::Reset() +{ + fCompressedPubKey = false; + pkey = EC_KEY_new_by_curve_name(NID_secp256k1); + if (pkey == NULL) + throw key_error("CKey::CKey() : EC_KEY_new_by_curve_name failed"); + fSet = false; +} + +CKey::CKey() +{ + Reset(); +} + +CKey::CKey(const CKey& b) +{ + pkey = EC_KEY_dup(b.pkey); + if (pkey == NULL) + throw key_error("CKey::CKey(const CKey&) : EC_KEY_dup failed"); + fSet = b.fSet; +} + +CKey& CKey::operator=(const CKey& b) +{ + if (!EC_KEY_copy(pkey, b.pkey)) + throw key_error("CKey::operator=(const CKey&) : EC_KEY_copy failed"); + fSet = b.fSet; + return (*this); +} + +CKey::~CKey() +{ + EC_KEY_free(pkey); +} + +bool CKey::IsNull() const +{ + return !fSet; +} + +bool CKey::IsCompressed() const +{ + return fCompressedPubKey; +} + +void CKey::MakeNewKey(bool fCompressed) +{ + if (!EC_KEY_generate_key(pkey)) + throw key_error("CKey::MakeNewKey() : EC_KEY_generate_key failed"); + if (fCompressed) + SetCompressedPubKey(); + fSet = true; +} + +bool CKey::SetPrivKey(const CPrivKey& vchPrivKey) +{ + const unsigned char* pbegin = &vchPrivKey[0]; + if (!d2i_ECPrivateKey(&pkey, &pbegin, vchPrivKey.size())) + return false; + fSet = true; + return true; +} + +bool CKey::SetSecret(const CSecret& vchSecret, bool fCompressed) +{ + EC_KEY_free(pkey); + pkey = EC_KEY_new_by_curve_name(NID_secp256k1); + if (pkey == NULL) + throw key_error("CKey::SetSecret() : EC_KEY_new_by_curve_name failed"); + if (vchSecret.size() != 32) + throw key_error("CKey::SetSecret() : secret must be 32 bytes"); + BIGNUM *bn = BN_bin2bn(&vchSecret[0],32,BN_new()); + if (bn == NULL) + throw key_error("CKey::SetSecret() : BN_bin2bn failed"); + if (!EC_KEY_regenerate_key(pkey,bn)) + { + BN_clear_free(bn); + throw key_error("CKey::SetSecret() : EC_KEY_regenerate_key failed"); + } + BN_clear_free(bn); + fSet = true; + if (fCompressed || fCompressedPubKey) + SetCompressedPubKey(); + return true; +} + +CSecret CKey::GetSecret(bool &fCompressed) const +{ + CSecret vchRet; + vchRet.resize(32); + const BIGNUM *bn = EC_KEY_get0_private_key(pkey); + int nBytes = BN_num_bytes(bn); + if (bn == NULL) + throw key_error("CKey::GetSecret() : EC_KEY_get0_private_key failed"); + int n=BN_bn2bin(bn,&vchRet[32 - nBytes]); + if (n != nBytes) + throw key_error("CKey::GetSecret(): BN_bn2bin failed"); + fCompressed = fCompressedPubKey; + return vchRet; +} + +CPrivKey CKey::GetPrivKey() const +{ + int nSize = i2d_ECPrivateKey(pkey, NULL); + if (!nSize) + throw key_error("CKey::GetPrivKey() : i2d_ECPrivateKey failed"); + CPrivKey vchPrivKey(nSize, 0); + unsigned char* pbegin = &vchPrivKey[0]; + if (i2d_ECPrivateKey(pkey, &pbegin) != nSize) + throw key_error("CKey::GetPrivKey() : i2d_ECPrivateKey returned unexpected size"); + return vchPrivKey; +} + +bool CKey::SetPubKey(const CPubKey& vchPubKey) +{ + const unsigned char* pbegin = &vchPubKey.vchPubKey[0]; + if (!o2i_ECPublicKey(&pkey, &pbegin, vchPubKey.vchPubKey.size())) + return false; + fSet = true; + if (vchPubKey.vchPubKey.size() == 33) + SetCompressedPubKey(); + return true; +} + +CPubKey CKey::GetPubKey() const +{ + int nSize = i2o_ECPublicKey(pkey, NULL); + if (!nSize) + throw key_error("CKey::GetPubKey() : i2o_ECPublicKey failed"); + std::vector<unsigned char> vchPubKey(nSize, 0); + unsigned char* pbegin = &vchPubKey[0]; + if (i2o_ECPublicKey(pkey, &pbegin) != nSize) + throw key_error("CKey::GetPubKey() : i2o_ECPublicKey returned unexpected size"); + return CPubKey(vchPubKey); +} + +bool CKey::Sign(uint256 hash, std::vector<unsigned char>& vchSig) +{ + unsigned int nSize = ECDSA_size(pkey); + vchSig.resize(nSize); // Make sure it is big enough + if (!ECDSA_sign(0, (unsigned char*)&hash, sizeof(hash), &vchSig[0], &nSize, pkey)) + { + vchSig.clear(); + return false; + } + vchSig.resize(nSize); // Shrink to fit actual size + return true; +} + +// create a compact signature (65 bytes), which allows reconstructing the used public key +// The format is one header byte, followed by two times 32 bytes for the serialized r and s values. +// The header byte: 0x1B = first key with even y, 0x1C = first key with odd y, +// 0x1D = second key with even y, 0x1E = second key with odd y +bool CKey::SignCompact(uint256 hash, std::vector<unsigned char>& vchSig) +{ + bool fOk = false; + ECDSA_SIG *sig = ECDSA_do_sign((unsigned char*)&hash, sizeof(hash), pkey); + if (sig==NULL) + return false; + vchSig.clear(); + vchSig.resize(65,0); + int nBitsR = BN_num_bits(sig->r); + int nBitsS = BN_num_bits(sig->s); + if (nBitsR <= 256 && nBitsS <= 256) + { + int nRecId = -1; + for (int i=0; i<4; i++) + { + CKey keyRec; + keyRec.fSet = true; + if (fCompressedPubKey) + keyRec.SetCompressedPubKey(); + if (ECDSA_SIG_recover_key_GFp(keyRec.pkey, sig, (unsigned char*)&hash, sizeof(hash), i, 1) == 1) + if (keyRec.GetPubKey() == this->GetPubKey()) + { + nRecId = i; + break; + } + } + + if (nRecId == -1) + throw key_error("CKey::SignCompact() : unable to construct recoverable key"); + + vchSig[0] = nRecId+27+(fCompressedPubKey ? 4 : 0); + BN_bn2bin(sig->r,&vchSig[33-(nBitsR+7)/8]); + BN_bn2bin(sig->s,&vchSig[65-(nBitsS+7)/8]); + fOk = true; + } + ECDSA_SIG_free(sig); + return fOk; +} + +// reconstruct public key from a compact signature +// This is only slightly more CPU intensive than just verifying it. +// If this function succeeds, the recovered public key is guaranteed to be valid +// (the signature is a valid signature of the given data for that key) +bool CKey::SetCompactSignature(uint256 hash, const std::vector<unsigned char>& vchSig) +{ + if (vchSig.size() != 65) + return false; + int nV = vchSig[0]; + if (nV<27 || nV>=35) + return false; + ECDSA_SIG *sig = ECDSA_SIG_new(); + BN_bin2bn(&vchSig[1],32,sig->r); + BN_bin2bn(&vchSig[33],32,sig->s); + + EC_KEY_free(pkey); + pkey = EC_KEY_new_by_curve_name(NID_secp256k1); + if (nV >= 31) + { + SetCompressedPubKey(); + nV -= 4; + } + if (ECDSA_SIG_recover_key_GFp(pkey, sig, (unsigned char*)&hash, sizeof(hash), nV - 27, 0) == 1) + { + fSet = true; + ECDSA_SIG_free(sig); + return true; + } + return false; +} + +bool CKey::Verify(uint256 hash, const std::vector<unsigned char>& vchSig) +{ + // -1 = error, 0 = bad sig, 1 = good + if (ECDSA_verify(0, (unsigned char*)&hash, sizeof(hash), &vchSig[0], vchSig.size(), pkey) != 1) + return false; + + return true; +} + +bool CKey::VerifyCompact(uint256 hash, const std::vector<unsigned char>& vchSig) +{ + CKey key; + if (!key.SetCompactSignature(hash, vchSig)) + return false; + if (GetPubKey() != key.GetPubKey()) + return false; + + return true; +} + +bool CKey::IsValid() +{ + if (!fSet) + return false; + + bool fCompr; + CSecret secret = GetSecret(fCompr); + CKey key2; + key2.SetSecret(secret, fCompr); + return GetPubKey() == key2.GetPubKey(); +} diff --git a/samples/C++/key.h b/samples/C++/key.h new file mode 100644 index 0000000..945c499 --- /dev/null +++ b/samples/C++/key.h @@ -0,0 +1,162 @@ +// Copyright (c) 2009-2010 Satoshi Nakamoto +// Copyright (c) 2009-2012 The Bitcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. +#ifndef BITCOIN_KEY_H +#define BITCOIN_KEY_H + +#include <stdexcept> +#include <vector> + +#include "allocators.h" +#include "serialize.h" +#include "uint256.h" +#include "util.h" + +#include <openssl/ec.h> // for EC_KEY definition + +// secp160k1 +// const unsigned int PRIVATE_KEY_SIZE = 192; +// const unsigned int PUBLIC_KEY_SIZE = 41; +// const unsigned int SIGNATURE_SIZE = 48; +// +// secp192k1 +// const unsigned int PRIVATE_KEY_SIZE = 222; +// const unsigned int PUBLIC_KEY_SIZE = 49; +// const unsigned int SIGNATURE_SIZE = 57; +// +// secp224k1 +// const unsigned int PRIVATE_KEY_SIZE = 250; +// const unsigned int PUBLIC_KEY_SIZE = 57; +// const unsigned int SIGNATURE_SIZE = 66; +// +// secp256k1: +// const unsigned int PRIVATE_KEY_SIZE = 279; +// const unsigned int PUBLIC_KEY_SIZE = 65; +// const unsigned int SIGNATURE_SIZE = 72; +// +// see www.keylength.com +// script supports up to 75 for single byte push + +class key_error : public std::runtime_error +{ +public: + explicit key_error(const std::string& str) : std::runtime_error(str) {} +}; + +/** A reference to a CKey: the Hash160 of its serialized public key */ +class CKeyID : public uint160 +{ +public: + CKeyID() : uint160(0) { } + CKeyID(const uint160 &in) : uint160(in) { } +}; + +/** A reference to a CScript: the Hash160 of its serialization (see script.h) */ +class CScriptID : public uint160 +{ +public: + CScriptID() : uint160(0) { } + CScriptID(const uint160 &in) : uint160(in) { } +}; + +/** An encapsulated public key. */ +class CPubKey { +private: + std::vector<unsigned char> vchPubKey; + friend class CKey; + +public: + CPubKey() { } + CPubKey(const std::vector<unsigned char> &vchPubKeyIn) : vchPubKey(vchPubKeyIn) { } + friend bool operator==(const CPubKey &a, const CPubKey &b) { return a.vchPubKey == b.vchPubKey; } + friend bool operator!=(const CPubKey &a, const CPubKey &b) { return a.vchPubKey != b.vchPubKey; } + friend bool operator<(const CPubKey &a, const CPubKey &b) { return a.vchPubKey < b.vchPubKey; } + + IMPLEMENT_SERIALIZE( + READWRITE(vchPubKey); + ) + + CKeyID GetID() const { + return CKeyID(Hash160(vchPubKey)); + } + + uint256 GetHash() const { + return Hash(vchPubKey.begin(), vchPubKey.end()); + } + + bool IsValid() const { + return vchPubKey.size() == 33 || vchPubKey.size() == 65; + } + + bool IsCompressed() const { + return vchPubKey.size() == 33; + } + + std::vector<unsigned char> Raw() const { + return vchPubKey; + } +}; + + +// secure_allocator is defined in serialize.h +// CPrivKey is a serialized private key, with all parameters included (279 bytes) +typedef std::vector<unsigned char, secure_allocator<unsigned char> > CPrivKey; +// CSecret is a serialization of just the secret parameter (32 bytes) +typedef std::vector<unsigned char, secure_allocator<unsigned char> > CSecret; + +/** An encapsulated OpenSSL Elliptic Curve key (public and/or private) */ +class CKey +{ +protected: + EC_KEY* pkey; + bool fSet; + bool fCompressedPubKey; + + void SetCompressedPubKey(); + +public: + + void Reset(); + + CKey(); + CKey(const CKey& b); + + CKey& operator=(const CKey& b); + + ~CKey(); + + bool IsNull() const; + bool IsCompressed() const; + + void MakeNewKey(bool fCompressed); + bool SetPrivKey(const CPrivKey& vchPrivKey); + bool SetSecret(const CSecret& vchSecret, bool fCompressed = false); + CSecret GetSecret(bool &fCompressed) const; + CPrivKey GetPrivKey() const; + bool SetPubKey(const CPubKey& vchPubKey); + CPubKey GetPubKey() const; + + bool Sign(uint256 hash, std::vector<unsigned char>& vchSig); + + // create a compact signature (65 bytes), which allows reconstructing the used public key + // The format is one header byte, followed by two times 32 bytes for the serialized r and s values. + // The header byte: 0x1B = first key with even y, 0x1C = first key with odd y, + // 0x1D = second key with even y, 0x1E = second key with odd y + bool SignCompact(uint256 hash, std::vector<unsigned char>& vchSig); + + // reconstruct public key from a compact signature + // This is only slightly more CPU intensive than just verifying it. + // If this function succeeds, the recovered public key is guaranteed to be valid + // (the signature is a valid signature of the given data for that key) + bool SetCompactSignature(uint256 hash, const std::vector<unsigned char>& vchSig); + + bool Verify(uint256 hash, const std::vector<unsigned char>& vchSig); + + // Verify a compact signature + bool VerifyCompact(uint256 hash, const std::vector<unsigned char>& vchSig); + + bool IsValid(); +}; + +#endif diff --git a/samples/C++/main.cpp b/samples/C++/main.cpp new file mode 100644 index 0000000..8ca481d --- /dev/null +++ b/samples/C++/main.cpp @@ -0,0 +1,74 @@ +/* + This file is part of the PhantomJS project from Ofi Labs. + + Copyright (C) 2011 Ariya Hidayat <ariya.hidayat@gmail.com> + + 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 the <organization> 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 <COPYRIGHT HOLDER> BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include "consts.h" +#include "utils.h" +#include "env.h" +#include "phantom.h" + +#ifdef Q_OS_LINUX +#include "client/linux/handler/exception_handler.h" +#endif + +#include <QApplication> + +#if QT_VERSION != QT_VERSION_CHECK(4, 8, 0) +#error Something is wrong with the setup. Please report to the mailing list! +#endif + +int main(int argc, char** argv, const char** envp) +{ +#ifdef Q_OS_LINUX + google_breakpad::ExceptionHandler eh("/tmp", NULL, Utils::exceptionHandler, NULL, true); +#endif + + // Registering an alternative Message Handler + qInstallMsgHandler(Utils::messageHandler); + + QApplication app(argc, argv); + +#ifdef STATIC_BUILD + Q_INIT_RESOURCE(WebKit); + Q_INIT_RESOURCE(InspectorBackendStub); +#endif + + app.setWindowIcon(QIcon(":/phantomjs-icon.png")); + app.setApplicationName("PhantomJS"); + app.setOrganizationName("Ofi Labs"); + app.setOrganizationDomain("www.ofilabs.com"); + app.setApplicationVersion(PHANTOMJS_VERSION_STRING); + + Env::instance()->parse(envp); + + Phantom phantom; + if (phantom.execute()) { + app.exec(); + } + return phantom.returnValue(); +} diff --git a/samples/C++/scanner.cc b/samples/C++/scanner.cc new file mode 100644 index 0000000..f24af2e --- /dev/null +++ b/samples/C++/scanner.cc @@ -0,0 +1,1088 @@ +// 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. + +// Features shared by parsing and pre-parsing scanners. + +#include "scanner.h" + +#include "../include/v8stdint.h" +#include "char-predicates-inl.h" + +namespace v8 { +namespace internal { + +// ---------------------------------------------------------------------------- +// Scanner + +Scanner::Scanner(UnicodeCache* unicode_cache) + : unicode_cache_(unicode_cache), + octal_pos_(Location::invalid()), + harmony_scoping_(false), + harmony_modules_(false) { } + + +void Scanner::Initialize(Utf16CharacterStream* source) { + source_ = source; + // Need to capture identifiers in order to recognize "get" and "set" + // in object literals. + Init(); + // Skip initial whitespace allowing HTML comment ends just like + // after a newline and scan first token. + has_line_terminator_before_next_ = true; + SkipWhiteSpace(); + Scan(); +} + + +uc32 Scanner::ScanHexNumber(int expected_length) { + ASSERT(expected_length <= 4); // prevent overflow + + uc32 digits[4] = { 0, 0, 0, 0 }; + uc32 x = 0; + for (int i = 0; i < expected_length; i++) { + digits[i] = c0_; + int d = HexValue(c0_); + if (d < 0) { + // According to ECMA-262, 3rd, 7.8.4, page 18, these hex escapes + // should be illegal, but other JS VMs just return the + // non-escaped version of the original character. + + // Push back digits that we have advanced past. + for (int j = i-1; j >= 0; j--) { + PushBack(digits[j]); + } + return -1; + } + x = x * 16 + d; + Advance(); + } + + return x; +} + + +// Ensure that tokens can be stored in a byte. +STATIC_ASSERT(Token::NUM_TOKENS <= 0x100); + +// Table of one-character tokens, by character (0x00..0x7f only). +static const byte one_char_tokens[] = { + Token::ILLEGAL, + Token::ILLEGAL, + Token::ILLEGAL, + Token::ILLEGAL, + Token::ILLEGAL, + Token::ILLEGAL, + Token::ILLEGAL, + Token::ILLEGAL, + Token::ILLEGAL, + Token::ILLEGAL, + Token::ILLEGAL, + Token::ILLEGAL, + Token::ILLEGAL, + Token::ILLEGAL, + Token::ILLEGAL, + Token::ILLEGAL, + Token::ILLEGAL, + Token::ILLEGAL, + Token::ILLEGAL, + Token::ILLEGAL, + Token::ILLEGAL, + Token::ILLEGAL, + Token::ILLEGAL, + Token::ILLEGAL, + Token::ILLEGAL, + Token::ILLEGAL, + Token::ILLEGAL, + Token::ILLEGAL, + Token::ILLEGAL, + Token::ILLEGAL, + Token::ILLEGAL, + Token::ILLEGAL, + Token::ILLEGAL, + Token::ILLEGAL, + Token::ILLEGAL, + Token::ILLEGAL, + Token::ILLEGAL, + Token::ILLEGAL, + Token::ILLEGAL, + Token::ILLEGAL, + Token::LPAREN, // 0x28 + Token::RPAREN, // 0x29 + Token::ILLEGAL, + Token::ILLEGAL, + Token::COMMA, // 0x2c + Token::ILLEGAL, + Token::ILLEGAL, + Token::ILLEGAL, + Token::ILLEGAL, + Token::ILLEGAL, + Token::ILLEGAL, + Token::ILLEGAL, + Token::ILLEGAL, + Token::ILLEGAL, + Token::ILLEGAL, + Token::ILLEGAL, + Token::ILLEGAL, + Token::ILLEGAL, + Token::COLON, // 0x3a + Token::SEMICOLON, // 0x3b + Token::ILLEGAL, + Token::ILLEGAL, + Token::ILLEGAL, + Token::CONDITIONAL, // 0x3f + Token::ILLEGAL, + Token::ILLEGAL, + Token::ILLEGAL, + Token::ILLEGAL, + Token::ILLEGAL, + Token::ILLEGAL, + Token::ILLEGAL, + Token::ILLEGAL, + Token::ILLEGAL, + Token::ILLEGAL, + Token::ILLEGAL, + Token::ILLEGAL, + Token::ILLEGAL, + Token::ILLEGAL, + Token::ILLEGAL, + Token::ILLEGAL, + Token::ILLEGAL, + Token::ILLEGAL, + Token::ILLEGAL, + Token::ILLEGAL, + Token::ILLEGAL, + Token::ILLEGAL, + Token::ILLEGAL, + Token::ILLEGAL, + Token::ILLEGAL, + Token::ILLEGAL, + Token::ILLEGAL, + Token::LBRACK, // 0x5b + Token::ILLEGAL, + Token::RBRACK, // 0x5d + Token::ILLEGAL, + Token::ILLEGAL, + Token::ILLEGAL, + Token::ILLEGAL, + Token::ILLEGAL, + Token::ILLEGAL, + Token::ILLEGAL, + Token::ILLEGAL, + Token::ILLEGAL, + Token::ILLEGAL, + Token::ILLEGAL, + Token::ILLEGAL, + Token::ILLEGAL, + Token::ILLEGAL, + Token::ILLEGAL, + Token::ILLEGAL, + Token::ILLEGAL, + Token::ILLEGAL, + Token::ILLEGAL, + Token::ILLEGAL, + Token::ILLEGAL, + Token::ILLEGAL, + Token::ILLEGAL, + Token::ILLEGAL, + Token::ILLEGAL, + Token::ILLEGAL, + Token::ILLEGAL, + Token::ILLEGAL, + Token::ILLEGAL, + Token::LBRACE, // 0x7b + Token::ILLEGAL, + Token::RBRACE, // 0x7d + Token::BIT_NOT, // 0x7e + Token::ILLEGAL +}; + + +Token::Value Scanner::Next() { + current_ = next_; + has_line_terminator_before_next_ = false; + has_multiline_comment_before_next_ = false; + if (static_cast<unsigned>(c0_) <= 0x7f) { + Token::Value token = static_cast<Token::Value>(one_char_tokens[c0_]); + if (token != Token::ILLEGAL) { + int pos = source_pos(); + next_.token = token; + next_.location.beg_pos = pos; + next_.location.end_pos = pos + 1; + Advance(); + return current_.token; + } + } + Scan(); + return current_.token; +} + + +static inline bool IsByteOrderMark(uc32 c) { + // The Unicode value U+FFFE is guaranteed never to be assigned as a + // Unicode character; this implies that in a Unicode context the + // 0xFF, 0xFE byte pattern can only be interpreted as the U+FEFF + // character expressed in little-endian byte order (since it could + // not be a U+FFFE character expressed in big-endian byte + // order). Nevertheless, we check for it to be compatible with + // Spidermonkey. + return c == 0xFEFF || c == 0xFFFE; +} + + +bool Scanner::SkipWhiteSpace() { + int start_position = source_pos(); + + while (true) { + // We treat byte-order marks (BOMs) as whitespace for better + // compatibility with Spidermonkey and other JavaScript engines. + while (unicode_cache_->IsWhiteSpace(c0_) || IsByteOrderMark(c0_)) { + // IsWhiteSpace() includes line terminators! + if (unicode_cache_->IsLineTerminator(c0_)) { + // Ignore line terminators, but remember them. This is necessary + // for automatic semicolon insertion. + has_line_terminator_before_next_ = true; + } + Advance(); + } + + // If there is an HTML comment end '-->' at the beginning of a + // line (with only whitespace in front of it), we treat the rest + // of the line as a comment. This is in line with the way + // SpiderMonkey handles it. + if (c0_ == '-' && has_line_terminator_before_next_) { + Advance(); + if (c0_ == '-') { + Advance(); + if (c0_ == '>') { + // Treat the rest of the line as a comment. + SkipSingleLineComment(); + // Continue skipping white space after the comment. + continue; + } + PushBack('-'); // undo Advance() + } + PushBack('-'); // undo Advance() + } + // Return whether or not we skipped any characters. + return source_pos() != start_position; + } +} + + +Token::Value Scanner::SkipSingleLineComment() { + Advance(); + + // The line terminator at the end of the line is not considered + // to be part of the single-line comment; it is recognized + // separately by the lexical grammar and becomes part of the + // stream of input elements for the syntactic grammar (see + // ECMA-262, section 7.4). + while (c0_ >= 0 && !unicode_cache_->IsLineTerminator(c0_)) { + Advance(); + } + + return Token::WHITESPACE; +} + + +Token::Value Scanner::SkipMultiLineComment() { + ASSERT(c0_ == '*'); + Advance(); + + while (c0_ >= 0) { + uc32 ch = c0_; + Advance(); + if (unicode_cache_->IsLineTerminator(ch)) { + // Following ECMA-262, section 7.4, a comment containing + // a newline will make the comment count as a line-terminator. + has_multiline_comment_before_next_ = true; + } + // If we have reached the end of the multi-line comment, we + // consume the '/' and insert a whitespace. This way all + // multi-line comments are treated as whitespace. + if (ch == '*' && c0_ == '/') { + c0_ = ' '; + return Token::WHITESPACE; + } + } + + // Unterminated multi-line comment. + return Token::ILLEGAL; +} + + +Token::Value Scanner::ScanHtmlComment() { + // Check for <!-- comments. + ASSERT(c0_ == '!'); + Advance(); + if (c0_ == '-') { + Advance(); + if (c0_ == '-') return SkipSingleLineComment(); + PushBack('-'); // undo Advance() + } + PushBack('!'); // undo Advance() + ASSERT(c0_ == '!'); + return Token::LT; +} + + +void Scanner::Scan() { + next_.literal_chars = NULL; + Token::Value token; + do { + // Remember the position of the next token + next_.location.beg_pos = source_pos(); + + switch (c0_) { + case ' ': + case '\t': + Advance(); + token = Token::WHITESPACE; + break; + + case '\n': + Advance(); + has_line_terminator_before_next_ = true; + token = Token::WHITESPACE; + break; + + case '"': case '\'': + token = ScanString(); + break; + + case '<': + // < <= << <<= <!-- + Advance(); + if (c0_ == '=') { + token = Select(Token::LTE); + } else if (c0_ == '<') { + token = Select('=', Token::ASSIGN_SHL, Token::SHL); + } else if (c0_ == '!') { + token = ScanHtmlComment(); + } else { + token = Token::LT; + } + break; + + case '>': + // > >= >> >>= >>> >>>= + Advance(); + if (c0_ == '=') { + token = Select(Token::GTE); + } else if (c0_ == '>') { + // >> >>= >>> >>>= + Advance(); + if (c0_ == '=') { + token = Select(Token::ASSIGN_SAR); + } else if (c0_ == '>') { + token = Select('=', Token::ASSIGN_SHR, Token::SHR); + } else { + token = Token::SAR; + } + } else { + token = Token::GT; + } + break; + + case '=': + // = == === + Advance(); + if (c0_ == '=') { + token = Select('=', Token::EQ_STRICT, Token::EQ); + } else { + token = Token::ASSIGN; + } + break; + + case '!': + // ! != !== + Advance(); + if (c0_ == '=') { + token = Select('=', Token::NE_STRICT, Token::NE); + } else { + token = Token::NOT; + } + break; + + case '+': + // + ++ += + Advance(); + if (c0_ == '+') { + token = Select(Token::INC); + } else if (c0_ == '=') { + token = Select(Token::ASSIGN_ADD); + } else { + token = Token::ADD; + } + break; + + case '-': + // - -- --> -= + Advance(); + if (c0_ == '-') { + Advance(); + if (c0_ == '>' && has_line_terminator_before_next_) { + // For compatibility with SpiderMonkey, we skip lines that + // start with an HTML comment end '-->'. + token = SkipSingleLineComment(); + } else { + token = Token::DEC; + } + } else if (c0_ == '=') { + token = Select(Token::ASSIGN_SUB); + } else { + token = Token::SUB; + } + break; + + case '*': + // * *= + token = Select('=', Token::ASSIGN_MUL, Token::MUL); + break; + + case '%': + // % %= + token = Select('=', Token::ASSIGN_MOD, Token::MOD); + break; + + case '/': + // / // /* /= + Advance(); + if (c0_ == '/') { + token = SkipSingleLineComment(); + } else if (c0_ == '*') { + token = SkipMultiLineComment(); + } else if (c0_ == '=') { + token = Select(Token::ASSIGN_DIV); + } else { + token = Token::DIV; + } + break; + + case '&': + // & && &= + Advance(); + if (c0_ == '&') { + token = Select(Token::AND); + } else if (c0_ == '=') { + token = Select(Token::ASSIGN_BIT_AND); + } else { + token = Token::BIT_AND; + } + break; + + case '|': + // | || |= + Advance(); + if (c0_ == '|') { + token = Select(Token::OR); + } else if (c0_ == '=') { + token = Select(Token::ASSIGN_BIT_OR); + } else { + token = Token::BIT_OR; + } + break; + + case '^': + // ^ ^= + token = Select('=', Token::ASSIGN_BIT_XOR, Token::BIT_XOR); + break; + + case '.': + // . Number + Advance(); + if (IsDecimalDigit(c0_)) { + token = ScanNumber(true); + } else { + token = Token::PERIOD; + } + break; + + case ':': + token = Select(Token::COLON); + break; + + case ';': + token = Select(Token::SEMICOLON); + break; + + case ',': + token = Select(Token::COMMA); + break; + + case '(': + token = Select(Token::LPAREN); + break; + + case ')': + token = Select(Token::RPAREN); + break; + + case '[': + token = Select(Token::LBRACK); + break; + + case ']': + token = Select(Token::RBRACK); + break; + + case '{': + token = Select(Token::LBRACE); + break; + + case '}': + token = Select(Token::RBRACE); + break; + + case '?': + token = Select(Token::CONDITIONAL); + break; + + case '~': + token = Select(Token::BIT_NOT); + break; + + default: + if (unicode_cache_->IsIdentifierStart(c0_)) { + token = ScanIdentifierOrKeyword(); + } else if (IsDecimalDigit(c0_)) { + token = ScanNumber(false); + } else if (SkipWhiteSpace()) { + token = Token::WHITESPACE; + } else if (c0_ < 0) { + token = Token::EOS; + } else { + token = Select(Token::ILLEGAL); + } + break; + } + + // Continue scanning for tokens as long as we're just skipping + // whitespace. + } while (token == Token::WHITESPACE); + + next_.location.end_pos = source_pos(); + next_.token = token; +} + + +void Scanner::SeekForward(int pos) { + // After this call, we will have the token at the given position as + // the "next" token. The "current" token will be invalid. + if (pos == next_.location.beg_pos) return; + int current_pos = source_pos(); + ASSERT_EQ(next_.location.end_pos, current_pos); + // Positions inside the lookahead token aren't supported. + ASSERT(pos >= current_pos); + if (pos != current_pos) { + source_->SeekForward(pos - source_->pos()); + Advance(); + // This function is only called to seek to the location + // of the end of a function (at the "}" token). It doesn't matter + // whether there was a line terminator in the part we skip. + has_line_terminator_before_next_ = false; + has_multiline_comment_before_next_ = false; + } + Scan(); +} + + +bool Scanner::ScanEscape() { + uc32 c = c0_; + Advance(); + + // Skip escaped newlines. + if (unicode_cache_->IsLineTerminator(c)) { + // Allow CR+LF newlines in multiline string literals. + if (IsCarriageReturn(c) && IsLineFeed(c0_)) Advance(); + // Allow LF+CR newlines in multiline string literals. + if (IsLineFeed(c) && IsCarriageReturn(c0_)) Advance(); + return true; + } + + switch (c) { + case '\'': // fall through + case '"' : // fall through + case '\\': break; + case 'b' : c = '\b'; break; + case 'f' : c = '\f'; break; + case 'n' : c = '\n'; break; + case 'r' : c = '\r'; break; + case 't' : c = '\t'; break; + case 'u' : { + c = ScanHexNumber(4); + if (c < 0) return false; + break; + } + case 'v' : c = '\v'; break; + case 'x' : { + c = ScanHexNumber(2); + if (c < 0) return false; + break; + } + case '0' : // fall through + case '1' : // fall through + case '2' : // fall through + case '3' : // fall through + case '4' : // fall through + case '5' : // fall through + case '6' : // fall through + case '7' : c = ScanOctalEscape(c, 2); break; + } + + // According to ECMA-262, section 7.8.4, characters not covered by the + // above cases should be illegal, but they are commonly handled as + // non-escaped characters by JS VMs. + AddLiteralChar(c); + return true; +} + + +// Octal escapes of the forms '\0xx' and '\xxx' are not a part of +// ECMA-262. Other JS VMs support them. +uc32 Scanner::ScanOctalEscape(uc32 c, int length) { + uc32 x = c - '0'; + int i = 0; + for (; i < length; i++) { + int d = c0_ - '0'; + if (d < 0 || d > 7) break; + int nx = x * 8 + d; + if (nx >= 256) break; + x = nx; + Advance(); + } + // Anything except '\0' is an octal escape sequence, illegal in strict mode. + // Remember the position of octal escape sequences so that an error + // can be reported later (in strict mode). + // We don't report the error immediately, because the octal escape can + // occur before the "use strict" directive. + if (c != '0' || i > 0) { + octal_pos_ = Location(source_pos() - i - 1, source_pos() - 1); + } + return x; +} + + +Token::Value Scanner::ScanString() { + uc32 quote = c0_; + Advance(); // consume quote + + LiteralScope literal(this); + while (c0_ != quote && c0_ >= 0 + && !unicode_cache_->IsLineTerminator(c0_)) { + uc32 c = c0_; + Advance(); + if (c == '\\') { + if (c0_ < 0 || !ScanEscape()) return Token::ILLEGAL; + } else { + AddLiteralChar(c); + } + } + if (c0_ != quote) return Token::ILLEGAL; + literal.Complete(); + + Advance(); // consume quote + return Token::STRING; +} + + +void Scanner::ScanDecimalDigits() { + while (IsDecimalDigit(c0_)) + AddLiteralCharAdvance(); +} + + +Token::Value Scanner::ScanNumber(bool seen_period) { + ASSERT(IsDecimalDigit(c0_)); // the first digit of the number or the fraction + + enum { DECIMAL, HEX, OCTAL } kind = DECIMAL; + + LiteralScope literal(this); + if (seen_period) { + // we have already seen a decimal point of the float + AddLiteralChar('.'); + ScanDecimalDigits(); // we know we have at least one digit + + } else { + // if the first character is '0' we must check for octals and hex + if (c0_ == '0') { + int start_pos = source_pos(); // For reporting octal positions. + AddLiteralCharAdvance(); + + // either 0, 0exxx, 0Exxx, 0.xxx, an octal number, or a hex number + if (c0_ == 'x' || c0_ == 'X') { + // hex number + kind = HEX; + AddLiteralCharAdvance(); + if (!IsHexDigit(c0_)) { + // we must have at least one hex digit after 'x'/'X' + return Token::ILLEGAL; + } + while (IsHexDigit(c0_)) { + AddLiteralCharAdvance(); + } + } else if ('0' <= c0_ && c0_ <= '7') { + // (possible) octal number + kind = OCTAL; + while (true) { + if (c0_ == '8' || c0_ == '9') { + kind = DECIMAL; + break; + } + if (c0_ < '0' || '7' < c0_) { + // Octal literal finished. + octal_pos_ = Location(start_pos, source_pos()); + break; + } + AddLiteralCharAdvance(); + } + } + } + + // Parse decimal digits and allow trailing fractional part. + if (kind == DECIMAL) { + ScanDecimalDigits(); // optional + if (c0_ == '.') { + AddLiteralCharAdvance(); + ScanDecimalDigits(); // optional + } + } + } + + // scan exponent, if any + if (c0_ == 'e' || c0_ == 'E') { + ASSERT(kind != HEX); // 'e'/'E' must be scanned as part of the hex number + if (kind == OCTAL) return Token::ILLEGAL; // no exponent for octals allowed + // scan exponent + AddLiteralCharAdvance(); + if (c0_ == '+' || c0_ == '-') + AddLiteralCharAdvance(); + if (!IsDecimalDigit(c0_)) { + // we must have at least one decimal digit after 'e'/'E' + return Token::ILLEGAL; + } + ScanDecimalDigits(); + } + + // The source character immediately following a numeric literal must + // not be an identifier start or a decimal digit; see ECMA-262 + // section 7.8.3, page 17 (note that we read only one decimal digit + // if the value is 0). + if (IsDecimalDigit(c0_) || unicode_cache_->IsIdentifierStart(c0_)) + return Token::ILLEGAL; + + literal.Complete(); + + return Token::NUMBER; +} + + +uc32 Scanner::ScanIdentifierUnicodeEscape() { + Advance(); + if (c0_ != 'u') return -1; + Advance(); + uc32 result = ScanHexNumber(4); + if (result < 0) PushBack('u'); + return result; +} + + +// ---------------------------------------------------------------------------- +// Keyword Matcher + +#define KEYWORDS(KEYWORD_GROUP, KEYWORD) \ + KEYWORD_GROUP('b') \ + KEYWORD("break", Token::BREAK) \ + KEYWORD_GROUP('c') \ + KEYWORD("case", Token::CASE) \ + KEYWORD("catch", Token::CATCH) \ + KEYWORD("class", Token::FUTURE_RESERVED_WORD) \ + KEYWORD("const", Token::CONST) \ + KEYWORD("continue", Token::CONTINUE) \ + KEYWORD_GROUP('d') \ + KEYWORD("debugger", Token::DEBUGGER) \ + KEYWORD("default", Token::DEFAULT) \ + KEYWORD("delete", Token::DELETE) \ + KEYWORD("do", Token::DO) \ + KEYWORD_GROUP('e') \ + KEYWORD("else", Token::ELSE) \ + KEYWORD("enum", Token::FUTURE_RESERVED_WORD) \ + KEYWORD("export", harmony_modules \ + ? Token::EXPORT : Token::FUTURE_RESERVED_WORD) \ + KEYWORD("extends", Token::FUTURE_RESERVED_WORD) \ + KEYWORD_GROUP('f') \ + KEYWORD("false", Token::FALSE_LITERAL) \ + KEYWORD("finally", Token::FINALLY) \ + KEYWORD("for", Token::FOR) \ + KEYWORD("function", Token::FUNCTION) \ + KEYWORD_GROUP('i') \ + KEYWORD("if", Token::IF) \ + KEYWORD("implements", Token::FUTURE_STRICT_RESERVED_WORD) \ + KEYWORD("import", harmony_modules \ + ? Token::IMPORT : Token::FUTURE_RESERVED_WORD) \ + KEYWORD("in", Token::IN) \ + KEYWORD("instanceof", Token::INSTANCEOF) \ + KEYWORD("interface", Token::FUTURE_STRICT_RESERVED_WORD) \ + KEYWORD_GROUP('l') \ + KEYWORD("let", harmony_scoping \ + ? Token::LET : Token::FUTURE_STRICT_RESERVED_WORD) \ + KEYWORD_GROUP('n') \ + KEYWORD("new", Token::NEW) \ + KEYWORD("null", Token::NULL_LITERAL) \ + KEYWORD_GROUP('p') \ + KEYWORD("package", Token::FUTURE_STRICT_RESERVED_WORD) \ + KEYWORD("private", Token::FUTURE_STRICT_RESERVED_WORD) \ + KEYWORD("protected", Token::FUTURE_STRICT_RESERVED_WORD) \ + KEYWORD("public", Token::FUTURE_STRICT_RESERVED_WORD) \ + KEYWORD_GROUP('r') \ + KEYWORD("return", Token::RETURN) \ + KEYWORD_GROUP('s') \ + KEYWORD("static", Token::FUTURE_STRICT_RESERVED_WORD) \ + KEYWORD("super", Token::FUTURE_RESERVED_WORD) \ + KEYWORD("switch", Token::SWITCH) \ + KEYWORD_GROUP('t') \ + KEYWORD("this", Token::THIS) \ + KEYWORD("throw", Token::THROW) \ + KEYWORD("true", Token::TRUE_LITERAL) \ + KEYWORD("try", Token::TRY) \ + KEYWORD("typeof", Token::TYPEOF) \ + KEYWORD_GROUP('v') \ + KEYWORD("var", Token::VAR) \ + KEYWORD("void", Token::VOID) \ + KEYWORD_GROUP('w') \ + KEYWORD("while", Token::WHILE) \ + KEYWORD("with", Token::WITH) \ + KEYWORD_GROUP('y') \ + KEYWORD("yield", Token::FUTURE_STRICT_RESERVED_WORD) + + +static Token::Value KeywordOrIdentifierToken(const char* input, + int input_length, + bool harmony_scoping, + bool harmony_modules) { + ASSERT(input_length >= 1); + const int kMinLength = 2; + const int kMaxLength = 10; + if (input_length < kMinLength || input_length > kMaxLength) { + return Token::IDENTIFIER; + } + switch (input[0]) { + default: +#define KEYWORD_GROUP_CASE(ch) \ + break; \ + case ch: +#define KEYWORD(keyword, token) \ + { \ + /* 'keyword' is a char array, so sizeof(keyword) is */ \ + /* strlen(keyword) plus 1 for the NUL char. */ \ + const int keyword_length = sizeof(keyword) - 1; \ + STATIC_ASSERT(keyword_length >= kMinLength); \ + STATIC_ASSERT(keyword_length <= kMaxLength); \ + if (input_length == keyword_length && \ + input[1] == keyword[1] && \ + (keyword_length <= 2 || input[2] == keyword[2]) && \ + (keyword_length <= 3 || input[3] == keyword[3]) && \ + (keyword_length <= 4 || input[4] == keyword[4]) && \ + (keyword_length <= 5 || input[5] == keyword[5]) && \ + (keyword_length <= 6 || input[6] == keyword[6]) && \ + (keyword_length <= 7 || input[7] == keyword[7]) && \ + (keyword_length <= 8 || input[8] == keyword[8]) && \ + (keyword_length <= 9 || input[9] == keyword[9])) { \ + return token; \ + } \ + } + KEYWORDS(KEYWORD_GROUP_CASE, KEYWORD) + } + return Token::IDENTIFIER; +} + + +Token::Value Scanner::ScanIdentifierOrKeyword() { + ASSERT(unicode_cache_->IsIdentifierStart(c0_)); + LiteralScope literal(this); + // Scan identifier start character. + if (c0_ == '\\') { + uc32 c = ScanIdentifierUnicodeEscape(); + // Only allow legal identifier start characters. + if (c < 0 || + c == '\\' || // No recursive escapes. + !unicode_cache_->IsIdentifierStart(c)) { + return Token::ILLEGAL; + } + AddLiteralChar(c); + return ScanIdentifierSuffix(&literal); + } + + uc32 first_char = c0_; + Advance(); + AddLiteralChar(first_char); + + // Scan the rest of the identifier characters. + while (unicode_cache_->IsIdentifierPart(c0_)) { + if (c0_ != '\\') { + uc32 next_char = c0_; + Advance(); + AddLiteralChar(next_char); + continue; + } + // Fallthrough if no longer able to complete keyword. + return ScanIdentifierSuffix(&literal); + } + + literal.Complete(); + + if (next_.literal_chars->is_ascii()) { + Vector<const char> chars = next_.literal_chars->ascii_literal(); + return KeywordOrIdentifierToken(chars.start(), + chars.length(), + harmony_scoping_, + harmony_modules_); + } + + return Token::IDENTIFIER; +} + + +Token::Value Scanner::ScanIdentifierSuffix(LiteralScope* literal) { + // Scan the rest of the identifier characters. + while (unicode_cache_->IsIdentifierPart(c0_)) { + if (c0_ == '\\') { + uc32 c = ScanIdentifierUnicodeEscape(); + // Only allow legal identifier part characters. + if (c < 0 || + c == '\\' || + !unicode_cache_->IsIdentifierPart(c)) { + return Token::ILLEGAL; + } + AddLiteralChar(c); + } else { + AddLiteralChar(c0_); + Advance(); + } + } + literal->Complete(); + + return Token::IDENTIFIER; +} + + +bool Scanner::ScanRegExpPattern(bool seen_equal) { + // Scan: ('/' | '/=') RegularExpressionBody '/' RegularExpressionFlags + bool in_character_class = false; + + // Previous token is either '/' or '/=', in the second case, the + // pattern starts at =. + next_.location.beg_pos = source_pos() - (seen_equal ? 2 : 1); + next_.location.end_pos = source_pos() - (seen_equal ? 1 : 0); + + // Scan regular expression body: According to ECMA-262, 3rd, 7.8.5, + // the scanner should pass uninterpreted bodies to the RegExp + // constructor. + LiteralScope literal(this); + if (seen_equal) { + AddLiteralChar('='); + } + + while (c0_ != '/' || in_character_class) { + if (unicode_cache_->IsLineTerminator(c0_) || c0_ < 0) return false; + if (c0_ == '\\') { // Escape sequence. + AddLiteralCharAdvance(); + if (unicode_cache_->IsLineTerminator(c0_) || c0_ < 0) return false; + AddLiteralCharAdvance(); + // If the escape allows more characters, i.e., \x??, \u????, or \c?, + // only "safe" characters are allowed (letters, digits, underscore), + // otherwise the escape isn't valid and the invalid character has + // its normal meaning. I.e., we can just continue scanning without + // worrying whether the following characters are part of the escape + // or not, since any '/', '\\' or '[' is guaranteed to not be part + // of the escape sequence. + + // TODO(896): At some point, parse RegExps more throughly to capture + // octal esacpes in strict mode. + } else { // Unescaped character. + if (c0_ == '[') in_character_class = true; + if (c0_ == ']') in_character_class = false; + AddLiteralCharAdvance(); + } + } + Advance(); // consume '/' + + literal.Complete(); + + return true; +} + + +bool Scanner::ScanLiteralUnicodeEscape() { + ASSERT(c0_ == '\\'); + uc32 chars_read[6] = {'\\', 'u', 0, 0, 0, 0}; + Advance(); + int i = 1; + if (c0_ == 'u') { + i++; + while (i < 6) { + Advance(); + if (!IsHexDigit(c0_)) break; + chars_read[i] = c0_; + i++; + } + } + if (i < 6) { + // Incomplete escape. Undo all advances and return false. + while (i > 0) { + i--; + PushBack(chars_read[i]); + } + return false; + } + // Complete escape. Add all chars to current literal buffer. + for (int i = 0; i < 6; i++) { + AddLiteralChar(chars_read[i]); + } + return true; +} + + +bool Scanner::ScanRegExpFlags() { + // Scan regular expression flags. + LiteralScope literal(this); + while (unicode_cache_->IsIdentifierPart(c0_)) { + if (c0_ != '\\') { + AddLiteralCharAdvance(); + } else { + if (!ScanLiteralUnicodeEscape()) { + break; + } + } + } + literal.Complete(); + + next_.location.end_pos = source_pos() - 1; + return true; +} + +} } // namespace v8::internal diff --git a/samples/C++/scanner.h b/samples/C++/scanner.h new file mode 100644 index 0000000..4de413b --- /dev/null +++ b/samples/C++/scanner.h @@ -0,0 +1,576 @@ +// 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. + +// Features shared by parsing and pre-parsing scanners. + +#ifndef V8_SCANNER_H_ +#define V8_SCANNER_H_ + +#include "allocation.h" +#include "char-predicates.h" +#include "checks.h" +#include "globals.h" +#include "token.h" +#include "unicode-inl.h" +#include "utils.h" + +namespace v8 { +namespace internal { + + +// General collection of (multi-)bit-flags that can be passed to scanners and +// parsers to signify their (initial) mode of operation. +enum ParsingFlags { + kNoParsingFlags = 0, + // Embed LanguageMode values in parsing flags, i.e., equivalent to: + // CLASSIC_MODE = 0, + // STRICT_MODE, + // EXTENDED_MODE, + kLanguageModeMask = 0x03, + kAllowLazy = 0x04, + kAllowNativesSyntax = 0x08, + kAllowModules = 0x10 +}; + +STATIC_ASSERT((kLanguageModeMask & CLASSIC_MODE) == CLASSIC_MODE); +STATIC_ASSERT((kLanguageModeMask & STRICT_MODE) == STRICT_MODE); +STATIC_ASSERT((kLanguageModeMask & EXTENDED_MODE) == EXTENDED_MODE); + + +// Returns the value (0 .. 15) of a hexadecimal character c. +// If c is not a legal hexadecimal character, returns a value < 0. +inline int HexValue(uc32 c) { + c -= '0'; + if (static_cast<unsigned>(c) <= 9) return c; + c = (c | 0x20) - ('a' - '0'); // detect 0x11..0x16 and 0x31..0x36. + if (static_cast<unsigned>(c) <= 5) return c + 10; + return -1; +} + + +// --------------------------------------------------------------------- +// Buffered stream of UTF-16 code units, using an internal UTF-16 buffer. +// A code unit is a 16 bit value representing either a 16 bit code point +// or one part of a surrogate pair that make a single 21 bit code point. + +class Utf16CharacterStream { + public: + Utf16CharacterStream() : pos_(0) { } + virtual ~Utf16CharacterStream() { } + + // Returns and advances past the next UTF-16 code unit in the input + // stream. If there are no more code units, it returns a negative + // value. + inline uc32 Advance() { + if (buffer_cursor_ < buffer_end_ || ReadBlock()) { + pos_++; + return static_cast<uc32>(*(buffer_cursor_++)); + } + // Note: currently the following increment is necessary to avoid a + // parser problem! The scanner treats the final kEndOfInput as + // a code unit with a position, and does math relative to that + // position. + pos_++; + + return kEndOfInput; + } + + // Return the current position in the code unit stream. + // Starts at zero. + inline unsigned pos() const { return pos_; } + + // Skips forward past the next code_unit_count UTF-16 code units + // in the input, or until the end of input if that comes sooner. + // Returns the number of code units actually skipped. If less + // than code_unit_count, + inline unsigned SeekForward(unsigned code_unit_count) { + unsigned buffered_chars = + static_cast<unsigned>(buffer_end_ - buffer_cursor_); + if (code_unit_count <= buffered_chars) { + buffer_cursor_ += code_unit_count; + pos_ += code_unit_count; + return code_unit_count; + } + return SlowSeekForward(code_unit_count); + } + + // Pushes back the most recently read UTF-16 code unit (or negative + // value if at end of input), i.e., the value returned by the most recent + // call to Advance. + // Must not be used right after calling SeekForward. + virtual void PushBack(int32_t code_unit) = 0; + + protected: + static const uc32 kEndOfInput = -1; + + // Ensures that the buffer_cursor_ points to the code_unit at + // position pos_ of the input, if possible. If the position + // is at or after the end of the input, return false. If there + // are more code_units available, return true. + virtual bool ReadBlock() = 0; + virtual unsigned SlowSeekForward(unsigned code_unit_count) = 0; + + const uc16* buffer_cursor_; + const uc16* buffer_end_; + unsigned pos_; +}; + + +class UnicodeCache { +// --------------------------------------------------------------------- +// Caching predicates used by scanners. + public: + UnicodeCache() {} + typedef unibrow::Utf8InputBuffer<1024> Utf8Decoder; + + StaticResource<Utf8Decoder>* utf8_decoder() { + return &utf8_decoder_; + } + + bool IsIdentifierStart(unibrow::uchar c) { return kIsIdentifierStart.get(c); } + bool IsIdentifierPart(unibrow::uchar c) { return kIsIdentifierPart.get(c); } + bool IsLineTerminator(unibrow::uchar c) { return kIsLineTerminator.get(c); } + bool IsWhiteSpace(unibrow::uchar c) { return kIsWhiteSpace.get(c); } + + private: + unibrow::Predicate<IdentifierStart, 128> kIsIdentifierStart; + unibrow::Predicate<IdentifierPart, 128> kIsIdentifierPart; + unibrow::Predicate<unibrow::LineTerminator, 128> kIsLineTerminator; + unibrow::Predicate<unibrow::WhiteSpace, 128> kIsWhiteSpace; + StaticResource<Utf8Decoder> utf8_decoder_; + + DISALLOW_COPY_AND_ASSIGN(UnicodeCache); +}; + + +// ---------------------------------------------------------------------------- +// LiteralBuffer - Collector of chars of literals. + +class LiteralBuffer { + public: + LiteralBuffer() : is_ascii_(true), position_(0), backing_store_() { } + + ~LiteralBuffer() { + if (backing_store_.length() > 0) { + backing_store_.Dispose(); + } + } + + INLINE(void AddChar(uint32_t code_unit)) { + if (position_ >= backing_store_.length()) ExpandBuffer(); + if (is_ascii_) { + if (code_unit < kMaxAsciiCharCodeU) { + backing_store_[position_] = static_cast<byte>(code_unit); + position_ += kASCIISize; + return; + } + ConvertToUtf16(); + } + ASSERT(code_unit < 0x10000u); + *reinterpret_cast<uc16*>(&backing_store_[position_]) = code_unit; + position_ += kUC16Size; + } + + bool is_ascii() { return is_ascii_; } + + Vector<const uc16> utf16_literal() { + ASSERT(!is_ascii_); + ASSERT((position_ & 0x1) == 0); + return Vector<const uc16>( + reinterpret_cast<const uc16*>(backing_store_.start()), + position_ >> 1); + } + + Vector<const char> ascii_literal() { + ASSERT(is_ascii_); + return Vector<const char>( + reinterpret_cast<const char*>(backing_store_.start()), + position_); + } + + int length() { + return is_ascii_ ? position_ : (position_ >> 1); + } + + void Reset() { + position_ = 0; + is_ascii_ = true; + } + + private: + static const int kInitialCapacity = 16; + static const int kGrowthFactory = 4; + static const int kMinConversionSlack = 256; + static const int kMaxGrowth = 1 * MB; + inline int NewCapacity(int min_capacity) { + int capacity = Max(min_capacity, backing_store_.length()); + int new_capacity = Min(capacity * kGrowthFactory, capacity + kMaxGrowth); + return new_capacity; + } + + void ExpandBuffer() { + Vector<byte> new_store = Vector<byte>::New(NewCapacity(kInitialCapacity)); + memcpy(new_store.start(), backing_store_.start(), position_); + backing_store_.Dispose(); + backing_store_ = new_store; + } + + void ConvertToUtf16() { + ASSERT(is_ascii_); + Vector<byte> new_store; + int new_content_size = position_ * kUC16Size; + if (new_content_size >= backing_store_.length()) { + // Ensure room for all currently read code units as UC16 as well + // as the code unit about to be stored. + new_store = Vector<byte>::New(NewCapacity(new_content_size)); + } else { + new_store = backing_store_; + } + char* src = reinterpret_cast<char*>(backing_store_.start()); + uc16* dst = reinterpret_cast<uc16*>(new_store.start()); + for (int i = position_ - 1; i >= 0; i--) { + dst[i] = src[i]; + } + if (new_store.start() != backing_store_.start()) { + backing_store_.Dispose(); + backing_store_ = new_store; + } + position_ = new_content_size; + is_ascii_ = false; + } + + bool is_ascii_; + int position_; + Vector<byte> backing_store_; + + DISALLOW_COPY_AND_ASSIGN(LiteralBuffer); +}; + + +// ---------------------------------------------------------------------------- +// JavaScript Scanner. + +class Scanner { + public: + // Scoped helper for literal recording. Automatically drops the literal + // if aborting the scanning before it's complete. + class LiteralScope { + public: + explicit LiteralScope(Scanner* self) + : scanner_(self), complete_(false) { + scanner_->StartLiteral(); + } + ~LiteralScope() { + if (!complete_) scanner_->DropLiteral(); + } + void Complete() { + scanner_->TerminateLiteral(); + complete_ = true; + } + + private: + Scanner* scanner_; + bool complete_; + }; + + // Representation of an interval of source positions. + struct Location { + Location(int b, int e) : beg_pos(b), end_pos(e) { } + Location() : beg_pos(0), end_pos(0) { } + + bool IsValid() const { + return beg_pos >= 0 && end_pos >= beg_pos; + } + + static Location invalid() { return Location(-1, -1); } + + int beg_pos; + int end_pos; + }; + + // -1 is outside of the range of any real source code. + static const int kNoOctalLocation = -1; + + typedef unibrow::Utf8InputBuffer<1024> Utf8Decoder; + + explicit Scanner(UnicodeCache* scanner_contants); + + void Initialize(Utf16CharacterStream* source); + + // Returns the next token and advances input. + Token::Value Next(); + // Returns the current token again. + Token::Value current_token() { return current_.token; } + // Returns the location information for the current token + // (the token last returned by Next()). + Location location() const { return current_.location; } + // Returns the literal string, if any, for the current token (the + // token last returned by Next()). The string is 0-terminated. + // Literal strings are collected for identifiers, strings, and + // numbers. + // These functions only give the correct result if the literal + // was scanned between calls to StartLiteral() and TerminateLiteral(). + Vector<const char> literal_ascii_string() { + ASSERT_NOT_NULL(current_.literal_chars); + return current_.literal_chars->ascii_literal(); + } + Vector<const uc16> literal_utf16_string() { + ASSERT_NOT_NULL(current_.literal_chars); + return current_.literal_chars->utf16_literal(); + } + bool is_literal_ascii() { + ASSERT_NOT_NULL(current_.literal_chars); + return current_.literal_chars->is_ascii(); + } + int literal_length() const { + ASSERT_NOT_NULL(current_.literal_chars); + return current_.literal_chars->length(); + } + + bool literal_contains_escapes() const { + Location location = current_.location; + int source_length = (location.end_pos - location.beg_pos); + if (current_.token == Token::STRING) { + // Subtract delimiters. + source_length -= 2; + } + return current_.literal_chars->length() != source_length; + } + + // Similar functions for the upcoming token. + + // One token look-ahead (past the token returned by Next()). + Token::Value peek() const { return next_.token; } + + Location peek_location() const { return next_.location; } + + // Returns the literal string for the next token (the token that + // would be returned if Next() were called). + Vector<const char> next_literal_ascii_string() { + ASSERT_NOT_NULL(next_.literal_chars); + return next_.literal_chars->ascii_literal(); + } + Vector<const uc16> next_literal_utf16_string() { + ASSERT_NOT_NULL(next_.literal_chars); + return next_.literal_chars->utf16_literal(); + } + bool is_next_literal_ascii() { + ASSERT_NOT_NULL(next_.literal_chars); + return next_.literal_chars->is_ascii(); + } + int next_literal_length() const { + ASSERT_NOT_NULL(next_.literal_chars); + return next_.literal_chars->length(); + } + + UnicodeCache* unicode_cache() { return unicode_cache_; } + + static const int kCharacterLookaheadBufferSize = 1; + + // Scans octal escape sequence. Also accepts "\0" decimal escape sequence. + uc32 ScanOctalEscape(uc32 c, int length); + + // Returns the location of the last seen octal literal. + Location octal_position() const { return octal_pos_; } + void clear_octal_position() { octal_pos_ = Location::invalid(); } + + // Seek forward to the given position. This operation does not + // work in general, for instance when there are pushed back + // characters, but works for seeking forward until simple delimiter + // tokens, which is what it is used for. + void SeekForward(int pos); + + bool HarmonyScoping() const { + return harmony_scoping_; + } + void SetHarmonyScoping(bool scoping) { + harmony_scoping_ = scoping; + } + bool HarmonyModules() const { + return harmony_modules_; + } + void SetHarmonyModules(bool modules) { + harmony_modules_ = modules; + } + + + // Returns true if there was a line terminator before the peek'ed token, + // possibly inside a multi-line comment. + bool HasAnyLineTerminatorBeforeNext() const { + return has_line_terminator_before_next_ || + has_multiline_comment_before_next_; + } + + // Scans the input as a regular expression pattern, previous + // character(s) must be /(=). Returns true if a pattern is scanned. + bool ScanRegExpPattern(bool seen_equal); + // Returns true if regexp flags are scanned (always since flags can + // be empty). + bool ScanRegExpFlags(); + + // Tells whether the buffer contains an identifier (no escapes). + // Used for checking if a property name is an identifier. + static bool IsIdentifier(unibrow::CharacterStream* buffer); + + private: + // The current and look-ahead token. + struct TokenDesc { + Token::Value token; + Location location; + LiteralBuffer* literal_chars; + }; + + // Call this after setting source_ to the input. + void Init() { + // Set c0_ (one character ahead) + STATIC_ASSERT(kCharacterLookaheadBufferSize == 1); + Advance(); + // Initialize current_ to not refer to a literal. + current_.literal_chars = NULL; + } + + // Literal buffer support + inline void StartLiteral() { + LiteralBuffer* free_buffer = (current_.literal_chars == &literal_buffer1_) ? + &literal_buffer2_ : &literal_buffer1_; + free_buffer->Reset(); + next_.literal_chars = free_buffer; + } + + INLINE(void AddLiteralChar(uc32 c)) { + ASSERT_NOT_NULL(next_.literal_chars); + next_.literal_chars->AddChar(c); + } + + // Complete scanning of a literal. + inline void TerminateLiteral() { + // Does nothing in the current implementation. + } + + // Stops scanning of a literal and drop the collected characters, + // e.g., due to an encountered error. + inline void DropLiteral() { + next_.literal_chars = NULL; + } + + inline void AddLiteralCharAdvance() { + AddLiteralChar(c0_); + Advance(); + } + + // Low-level scanning support. + void Advance() { c0_ = source_->Advance(); } + void PushBack(uc32 ch) { + source_->PushBack(c0_); + c0_ = ch; + } + + inline Token::Value Select(Token::Value tok) { + Advance(); + return tok; + } + + inline Token::Value Select(uc32 next, Token::Value then, Token::Value else_) { + Advance(); + if (c0_ == next) { + Advance(); + return then; + } else { + return else_; + } + } + + uc32 ScanHexNumber(int expected_length); + + // Scans a single JavaScript token. + void Scan(); + + bool SkipWhiteSpace(); + Token::Value SkipSingleLineComment(); + Token::Value SkipMultiLineComment(); + // Scans a possible HTML comment -- begins with '<!'. + Token::Value ScanHtmlComment(); + + void ScanDecimalDigits(); + Token::Value ScanNumber(bool seen_period); + Token::Value ScanIdentifierOrKeyword(); + Token::Value ScanIdentifierSuffix(LiteralScope* literal); + + Token::Value ScanString(); + + // Scans an escape-sequence which is part of a string and adds the + // decoded character to the current literal. Returns true if a pattern + // is scanned. + bool ScanEscape(); + // Decodes a Unicode escape-sequence which is part of an identifier. + // If the escape sequence cannot be decoded the result is kBadChar. + uc32 ScanIdentifierUnicodeEscape(); + // Scans a Unicode escape-sequence and adds its characters, + // uninterpreted, to the current literal. Used for parsing RegExp + // flags. + bool ScanLiteralUnicodeEscape(); + + // Return the current source position. + int source_pos() { + return source_->pos() - kCharacterLookaheadBufferSize; + } + + UnicodeCache* unicode_cache_; + + // Buffers collecting literal strings, numbers, etc. + LiteralBuffer literal_buffer1_; + LiteralBuffer literal_buffer2_; + + TokenDesc current_; // desc for current token (as returned by Next()) + TokenDesc next_; // desc for next token (one token look-ahead) + + // Input stream. Must be initialized to an Utf16CharacterStream. + Utf16CharacterStream* source_; + + + // Start position of the octal literal last scanned. + Location octal_pos_; + + // One Unicode character look-ahead; c0_ < 0 at the end of the input. + uc32 c0_; + + // Whether there is a line terminator whitespace character after + // the current token, and before the next. Does not count newlines + // inside multiline comments. + bool has_line_terminator_before_next_; + // Whether there is a multi-line comment that contains a + // line-terminator after the current token, and before the next. + bool has_multiline_comment_before_next_; + // Whether we scan 'let' as a keyword for harmony block-scoped let bindings. + bool harmony_scoping_; + // Whether we scan 'module', 'import', 'export' as keywords. + bool harmony_modules_; +}; + +} } // namespace v8::internal + +#endif // V8_SCANNER_H_ diff --git a/samples/C++/utils.h b/samples/C++/utils.h new file mode 100644 index 0000000..cbc993e --- /dev/null +++ b/samples/C++/utils.h @@ -0,0 +1,71 @@ +/* + This file is part of the PhantomJS project from Ofi Labs. + + Copyright (C) 2011 Ariya Hidayat <ariya.hidayat@gmail.com> + Copyright (C) 2011 Ivan De Marino <ivan.de.marino@gmail.com> + + 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 the <organization> 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 <COPYRIGHT HOLDER> 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 UTILS_H +#define UTILS_H + +#include <QtGlobal> +#include <QWebFrame> +#include <QFile> + +#include "csconverter.h" +#include "encoding.h" + +class QTemporaryFile; +/** + * Aggregate common utility functions. + * Functions are static methods. + * It's important to notice that, at the moment, this class can't be instantiated by design. + */ +class Utils +{ +public: + static void showUsage(); + static void messageHandler(QtMsgType type, const char *msg); + static bool exceptionHandler(const char* dump_path, const char* minidump_id, void* context, bool succeeded); + static QVariant coffee2js(const QString &script); + static bool injectJsInFrame(const QString &jsFilePath, const QString &libraryPath, QWebFrame *targetFrame, const bool startingScript = false); + static bool injectJsInFrame(const QString &jsFilePath, const Encoding &jsFileEnc, const QString &libraryPath, QWebFrame *targetFrame, const bool startingScript = false); + static QString readResourceFileUtf8(const QString &resourceFilePath); + + static bool loadJSForDebug(const QString &jsFilePath, const Encoding &jsFileEnc, const QString &libraryPath, QWebFrame *targetFrame, const bool autorun = false); + static bool loadJSForDebug(const QString &jsFilePath, const QString &libraryPath, QWebFrame *targetFrame, const bool autorun = false); + static void cleanupFromDebug(); + +private: + static QString findScript(const QString &jsFilePath, const QString& libraryPath); + static QString jsFromScriptFile(const QString& scriptPath, const Encoding& enc); + Utils(); //< This class shouldn't be instantiated + + static QTemporaryFile* m_tempHarness; //< We want to make sure to clean up after ourselves + static QTemporaryFile* m_tempWrapper; +}; + +#endif // UTILS_H diff --git a/samples/C++/v8.cc b/samples/C++/v8.cc new file mode 100644 index 0000000..2910a07 --- /dev/null +++ b/samples/C++/v8.cc @@ -0,0 +1,288 @@ +// 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. + +#include "v8.h" + +#include "assembler.h" +#include "isolate.h" +#include "elements.h" +#include "bootstrapper.h" +#include "debug.h" +#include "deoptimizer.h" +#include "frames.h" +#include "heap-profiler.h" +#include "hydrogen.h" +#include "lithium-allocator.h" +#include "log.h" +#include "once.h" +#include "platform.h" +#include "runtime-profiler.h" +#include "serialize.h" +#include "store-buffer.h" + +namespace v8 { +namespace internal { + +V8_DECLARE_ONCE(init_once); + +bool V8::is_running_ = false; +bool V8::has_been_set_up_ = false; +bool V8::has_been_disposed_ = false; +bool V8::has_fatal_error_ = false; +bool V8::use_crankshaft_ = true; +List<CallCompletedCallback>* V8::call_completed_callbacks_ = NULL; + +static LazyMutex entropy_mutex = LAZY_MUTEX_INITIALIZER; + +static EntropySource entropy_source; + + +bool V8::Initialize(Deserializer* des) { + FlagList::EnforceFlagImplications(); + + InitializeOncePerProcess(); + + // The current thread may not yet had entered an isolate to run. + // Note the Isolate::Current() may be non-null because for various + // initialization purposes an initializing thread may be assigned an isolate + // but not actually enter it. + if (i::Isolate::CurrentPerIsolateThreadData() == NULL) { + i::Isolate::EnterDefaultIsolate(); + } + + ASSERT(i::Isolate::CurrentPerIsolateThreadData() != NULL); + ASSERT(i::Isolate::CurrentPerIsolateThreadData()->thread_id().Equals( + i::ThreadId::Current())); + ASSERT(i::Isolate::CurrentPerIsolateThreadData()->isolate() == + i::Isolate::Current()); + + if (IsDead()) return false; + + Isolate* isolate = Isolate::Current(); + if (isolate->IsInitialized()) return true; + + is_running_ = true; + has_been_set_up_ = true; + has_fatal_error_ = false; + has_been_disposed_ = false; + + return isolate->Init(des); +} + + +void V8::SetFatalError() { + is_running_ = false; + has_fatal_error_ = true; +} + + +void V8::TearDown() { + Isolate* isolate = Isolate::Current(); + ASSERT(isolate->IsDefaultIsolate()); + + if (!has_been_set_up_ || has_been_disposed_) return; + + ElementsAccessor::TearDown(); + LOperand::TearDownCaches(); + RegisteredExtension::UnregisterAll(); + + isolate->TearDown(); + delete isolate; + + is_running_ = false; + has_been_disposed_ = true; + + delete call_completed_callbacks_; + call_completed_callbacks_ = NULL; + + OS::TearDown(); +} + + +static void seed_random(uint32_t* state) { + for (int i = 0; i < 2; ++i) { + if (FLAG_random_seed != 0) { + state[i] = FLAG_random_seed; + } else if (entropy_source != NULL) { + uint32_t val; + ScopedLock lock(entropy_mutex.Pointer()); + entropy_source(reinterpret_cast<unsigned char*>(&val), sizeof(uint32_t)); + state[i] = val; + } else { + state[i] = random(); + } + } +} + + +// Random number generator using George Marsaglia's MWC algorithm. +static uint32_t random_base(uint32_t* state) { + // Initialize seed using the system random(). + // No non-zero seed will ever become zero again. + if (state[0] == 0) seed_random(state); + + // Mix the bits. Never replaces state[i] with 0 if it is nonzero. + state[0] = 18273 * (state[0] & 0xFFFF) + (state[0] >> 16); + state[1] = 36969 * (state[1] & 0xFFFF) + (state[1] >> 16); + + return (state[0] << 14) + (state[1] & 0x3FFFF); +} + + +void V8::SetEntropySource(EntropySource source) { + entropy_source = source; +} + + +void V8::SetReturnAddressLocationResolver( + ReturnAddressLocationResolver resolver) { + StackFrame::SetReturnAddressLocationResolver(resolver); +} + + +// Used by JavaScript APIs +uint32_t V8::Random(Context* context) { + ASSERT(context->IsGlobalContext()); + ByteArray* seed = context->random_seed(); + return random_base(reinterpret_cast<uint32_t*>(seed->GetDataStartAddress())); +} + + +// Used internally by the JIT and memory allocator for security +// purposes. So, we keep a different state to prevent informations +// leaks that could be used in an exploit. +uint32_t V8::RandomPrivate(Isolate* isolate) { + ASSERT(isolate == Isolate::Current()); + return random_base(isolate->private_random_seed()); +} + + +bool V8::IdleNotification(int hint) { + // Returning true tells the caller that there is no need to call + // IdleNotification again. + if (!FLAG_use_idle_notification) return true; + + // Tell the heap that it may want to adjust. + return HEAP->IdleNotification(hint); +} + + +void V8::AddCallCompletedCallback(CallCompletedCallback callback) { + if (call_completed_callbacks_ == NULL) { // Lazy init. + call_completed_callbacks_ = new List<CallCompletedCallback>(); + } + for (int i = 0; i < call_completed_callbacks_->length(); i++) { + if (callback == call_completed_callbacks_->at(i)) return; + } + call_completed_callbacks_->Add(callback); +} + + +void V8::RemoveCallCompletedCallback(CallCompletedCallback callback) { + if (call_completed_callbacks_ == NULL) return; + for (int i = 0; i < call_completed_callbacks_->length(); i++) { + if (callback == call_completed_callbacks_->at(i)) { + call_completed_callbacks_->Remove(i); + } + } +} + + +void V8::FireCallCompletedCallback(Isolate* isolate) { + if (call_completed_callbacks_ == NULL) return; + HandleScopeImplementer* handle_scope_implementer = + isolate->handle_scope_implementer(); + if (!handle_scope_implementer->CallDepthIsZero()) return; + // Fire callbacks. Increase call depth to prevent recursive callbacks. + handle_scope_implementer->IncrementCallDepth(); + for (int i = 0; i < call_completed_callbacks_->length(); i++) { + call_completed_callbacks_->at(i)(); + } + handle_scope_implementer->DecrementCallDepth(); +} + + +// Use a union type to avoid type-aliasing optimizations in GCC. +typedef union { + double double_value; + uint64_t uint64_t_value; +} double_int_union; + + +Object* V8::FillHeapNumberWithRandom(Object* heap_number, + Context* context) { + double_int_union r; + uint64_t random_bits = Random(context); + // Convert 32 random bits to 0.(32 random bits) in a double + // by computing: + // ( 1.(20 0s)(32 random bits) x 2^20 ) - (1.0 x 2^20)). + static const double binary_million = 1048576.0; + r.double_value = binary_million; + r.uint64_t_value |= random_bits; + r.double_value -= binary_million; + + HeapNumber::cast(heap_number)->set_value(r.double_value); + return heap_number; +} + +void V8::InitializeOncePerProcessImpl() { + OS::SetUp(); + + use_crankshaft_ = FLAG_crankshaft; + + if (Serializer::enabled()) { + use_crankshaft_ = false; + } + + CPU::SetUp(); + if (!CPU::SupportsCrankshaft()) { + use_crankshaft_ = false; + } + + OS::PostSetUp(); + + RuntimeProfiler::GlobalSetUp(); + + ElementsAccessor::InitializeOncePerProcess(); + + if (FLAG_stress_compaction) { + FLAG_force_marking_deque_overflows = true; + FLAG_gc_global = true; + FLAG_max_new_space_size = (1 << (kPageSizeBits - 10)) * 2; + } + + LOperand::SetUpCaches(); + SetUpJSCallerSavedCodeData(); + SamplerRegistry::SetUp(); + ExternalReference::SetUp(); +} + +void V8::InitializeOncePerProcess() { + CallOnce(&init_once, &InitializeOncePerProcessImpl); +} + +} } // namespace v8::internal diff --git a/samples/C++/v8.h b/samples/C++/v8.h new file mode 100644 index 0000000..67716d8 --- /dev/null +++ b/samples/C++/v8.h @@ -0,0 +1,152 @@ +// 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. + +// +// Top include for all V8 .cc files. +// + +#ifndef V8_V8_H_ +#define V8_V8_H_ + +#if defined(GOOGLE3) +// Google3 special flag handling. +#if defined(DEBUG) && defined(NDEBUG) +// V8 only uses DEBUG and whenever it is set we are building a debug +// version of V8. We do not use NDEBUG and simply undef it here for +// consistency. +#undef NDEBUG +#endif +#endif // defined(GOOGLE3) + +// V8 only uses DEBUG, but included external files +// may use NDEBUG - make sure they are consistent. +#if defined(DEBUG) && defined(NDEBUG) +#error both DEBUG and NDEBUG are set +#endif + +// Basic includes +#include "../include/v8.h" +#include "v8globals.h" +#include "v8checks.h" +#include "allocation.h" +#include "v8utils.h" +#include "flags.h" + +// Objects & heap +#include "objects-inl.h" +#include "spaces-inl.h" +#include "heap-inl.h" +#include "incremental-marking-inl.h" +#include "mark-compact-inl.h" +#include "log-inl.h" +#include "cpu-profiler-inl.h" +#include "handles-inl.h" +#include "zone-inl.h" + +namespace v8 { +namespace internal { + +class Deserializer; + +class V8 : public AllStatic { + public: + // Global actions. + + // If Initialize is called with des == NULL, the initial state is + // created from scratch. If a non-null Deserializer is given, the + // initial state is created by reading the deserialized data into an + // empty heap. + static bool Initialize(Deserializer* des); + static void TearDown(); + static bool IsRunning() { return is_running_; } + static bool UseCrankshaft() { return use_crankshaft_; } + // To be dead you have to have lived + // TODO(isolates): move IsDead to Isolate. + static bool IsDead() { return has_fatal_error_ || has_been_disposed_; } + static void SetFatalError(); + + // Report process out of memory. Implementation found in api.cc. + static void FatalProcessOutOfMemory(const char* location, + bool take_snapshot = false); + + // Allows an entropy source to be provided for use in random number + // generation. + static void SetEntropySource(EntropySource source); + // Support for return-address rewriting profilers. + static void SetReturnAddressLocationResolver( + ReturnAddressLocationResolver resolver); + // Random number generation support. Not cryptographically safe. + static uint32_t Random(Context* context); + // We use random numbers internally in memory allocation and in the + // compilers for security. In order to prevent information leaks we + // use a separate random state for internal random number + // generation. + static uint32_t RandomPrivate(Isolate* isolate); + static Object* FillHeapNumberWithRandom(Object* heap_number, + Context* context); + + // Idle notification directly from the API. + static bool IdleNotification(int hint); + + static void AddCallCompletedCallback(CallCompletedCallback callback); + static void RemoveCallCompletedCallback(CallCompletedCallback callback); + static void FireCallCompletedCallback(Isolate* isolate); + + private: + static void InitializeOncePerProcessImpl(); + static void InitializeOncePerProcess(); + + // True if engine is currently running + static bool is_running_; + // True if V8 has ever been run + static bool has_been_set_up_; + // True if error has been signaled for current engine + // (reset to false if engine is restarted) + static bool has_fatal_error_; + // True if engine has been shut down + // (reset if engine is restarted) + static bool has_been_disposed_; + // True if we are using the crankshaft optimizing compiler. + static bool use_crankshaft_; + // List of callbacks when a Call completes. + static List<CallCompletedCallback>* call_completed_callbacks_; +}; + + +// JavaScript defines two kinds of 'nil'. +enum NilValue { kNullValue, kUndefinedValue }; + + +// JavaScript defines two kinds of equality. +enum EqualityKind { kStrictEquality, kNonStrictEquality }; + + +} } // namespace v8::internal + +namespace i = v8::internal; + +#endif // V8_V8_H_ |
