1// Copyright 2011 the V8 project authors. All rights reserved. 2// Redistribution and use in source and binary forms, with or without 3// modification, are permitted provided that the following conditions are 4// met: 5// 6// * Redistributions of source code must retain the above copyright 7// notice, this list of conditions and the following disclaimer. 8// * Redistributions in binary form must reproduce the above 9// copyright notice, this list of conditions and the following 10// disclaimer in the documentation and/or other materials provided 11// with the distribution. 12// * Neither the name of Google Inc. nor the names of its 13// contributors may be used to endorse or promote products derived 14// from this software without specific prior written permission. 15// 16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 28#ifdef _MSC_VER 29#define V8_WIN32_LEAN_AND_MEAN 30#include "win32-headers.h" 31#endif 32 33#include "../include/v8-preparser.h" 34 35#include "globals.h" 36#include "checks.h" 37#include "allocation.h" 38#include "utils.h" 39#include "list.h" 40#include "hashmap.h" 41#include "preparse-data-format.h" 42#include "preparse-data.h" 43#include "preparser.h" 44 45namespace v8 { 46namespace internal { 47 48// UTF16Buffer based on a v8::UnicodeInputStream. 49class InputStreamUtf16Buffer : public Utf16CharacterStream { 50 public: 51 /* The InputStreamUtf16Buffer maintains an internal buffer 52 * that is filled in chunks from the Utf16CharacterStream. 53 * It also maintains unlimited pushback capability, but optimized 54 * for small pushbacks. 55 * The pushback_buffer_ pointer points to the limit of pushbacks 56 * in the current buffer. There is room for a few pushback'ed chars before 57 * the buffer containing the most recently read chunk. If this is overflowed, 58 * an external buffer is allocated/reused to hold further pushbacks, and 59 * pushback_buffer_ and buffer_cursor_/buffer_end_ now points to the 60 * new buffer. When this buffer is read to the end again, the cursor is 61 * switched back to the internal buffer 62 */ 63 explicit InputStreamUtf16Buffer(v8::UnicodeInputStream* stream) 64 : Utf16CharacterStream(), 65 stream_(stream), 66 pushback_buffer_(buffer_), 67 pushback_buffer_end_cache_(NULL), 68 pushback_buffer_backing_(NULL), 69 pushback_buffer_backing_size_(0) { 70 buffer_cursor_ = buffer_end_ = buffer_ + kPushBackSize; 71 } 72 73 virtual ~InputStreamUtf16Buffer() { 74 if (pushback_buffer_backing_ != NULL) { 75 DeleteArray(pushback_buffer_backing_); 76 } 77 } 78 79 virtual void PushBack(uc32 ch) { 80 ASSERT(pos_ > 0); 81 if (ch == kEndOfInput) { 82 pos_--; 83 return; 84 } 85 if (buffer_cursor_ <= pushback_buffer_) { 86 // No more room in the current buffer to do pushbacks. 87 if (pushback_buffer_end_cache_ == NULL) { 88 // We have overflowed the pushback space at the beginning of buffer_. 89 // Switch to using a separate allocated pushback buffer. 90 if (pushback_buffer_backing_ == NULL) { 91 // Allocate a buffer the first time we need it. 92 pushback_buffer_backing_ = NewArray<uc16>(kPushBackSize); 93 pushback_buffer_backing_size_ = kPushBackSize; 94 } 95 pushback_buffer_ = pushback_buffer_backing_; 96 pushback_buffer_end_cache_ = buffer_end_; 97 buffer_end_ = pushback_buffer_backing_ + pushback_buffer_backing_size_; 98 buffer_cursor_ = buffer_end_ - 1; 99 } else { 100 // Hit the bottom of the allocated pushback buffer. 101 // Double the buffer and continue. 102 uc16* new_buffer = NewArray<uc16>(pushback_buffer_backing_size_ * 2); 103 memcpy(new_buffer + pushback_buffer_backing_size_, 104 pushback_buffer_backing_, 105 pushback_buffer_backing_size_); 106 DeleteArray(pushback_buffer_backing_); 107 buffer_cursor_ = new_buffer + pushback_buffer_backing_size_; 108 pushback_buffer_backing_ = pushback_buffer_ = new_buffer; 109 buffer_end_ = pushback_buffer_backing_ + pushback_buffer_backing_size_; 110 } 111 } 112 pushback_buffer_[buffer_cursor_ - pushback_buffer_- 1] = 113 static_cast<uc16>(ch); 114 pos_--; 115 } 116 117 protected: 118 virtual bool ReadBlock() { 119 if (pushback_buffer_end_cache_ != NULL) { 120 buffer_cursor_ = buffer_; 121 buffer_end_ = pushback_buffer_end_cache_; 122 pushback_buffer_end_cache_ = NULL; 123 return buffer_end_ > buffer_cursor_; 124 } 125 // Copy the top of the buffer into the pushback area. 126 int32_t value; 127 uc16* buffer_start = buffer_ + kPushBackSize; 128 buffer_cursor_ = buffer_end_ = buffer_start; 129 while ((value = stream_->Next()) >= 0) { 130 if (value > 131 static_cast<int32_t>(unibrow::Utf16::kMaxNonSurrogateCharCode)) { 132 buffer_start[buffer_end_++ - buffer_start] = 133 unibrow::Utf16::LeadSurrogate(value); 134 buffer_start[buffer_end_++ - buffer_start] = 135 unibrow::Utf16::TrailSurrogate(value); 136 } else { 137 // buffer_end_ is a const pointer, but buffer_ is writable. 138 buffer_start[buffer_end_++ - buffer_start] = static_cast<uc16>(value); 139 } 140 // Stop one before the end of the buffer in case we get a surrogate pair. 141 if (buffer_end_ <= buffer_ + 1 + kPushBackSize + kBufferSize) break; 142 } 143 return buffer_end_ > buffer_start; 144 } 145 146 virtual unsigned SlowSeekForward(unsigned pos) { 147 // Seeking in the input is not used by preparsing. 148 // It's only used by the real parser based on preparser data. 149 UNIMPLEMENTED(); 150 return 0; 151 } 152 153 private: 154 static const unsigned kBufferSize = 512; 155 static const unsigned kPushBackSize = 16; 156 v8::UnicodeInputStream* const stream_; 157 // Buffer holding first kPushBackSize characters of pushback buffer, 158 // then kBufferSize chars of read-ahead. 159 // The pushback buffer is only used if pushing back characters past 160 // the start of a block. 161 uc16 buffer_[kPushBackSize + kBufferSize]; 162 // Limit of pushbacks before new allocation is necessary. 163 uc16* pushback_buffer_; 164 // Only if that pushback buffer at the start of buffer_ isn't sufficient 165 // is the following used. 166 const uc16* pushback_buffer_end_cache_; 167 uc16* pushback_buffer_backing_; 168 unsigned pushback_buffer_backing_size_; 169}; 170 171 172// Functions declared by allocation.h and implemented in both api.cc (for v8) 173// or here (for a stand-alone preparser). 174 175void FatalProcessOutOfMemory(const char* reason) { 176 V8_Fatal(__FILE__, __LINE__, reason); 177} 178 179bool EnableSlowAsserts() { return true; } 180 181} // namespace internal. 182 183 184UnicodeInputStream::~UnicodeInputStream() { } 185 186 187PreParserData Preparse(UnicodeInputStream* input, size_t max_stack) { 188 internal::InputStreamUtf16Buffer buffer(input); 189 uintptr_t stack_limit = reinterpret_cast<uintptr_t>(&buffer) - max_stack; 190 internal::UnicodeCache unicode_cache; 191 internal::Scanner scanner(&unicode_cache); 192 scanner.Initialize(&buffer); 193 internal::CompleteParserRecorder recorder; 194 preparser::PreParser::PreParseResult result = 195 preparser::PreParser::PreParseProgram(&scanner, 196 &recorder, 197 internal::kAllowLazy, 198 stack_limit); 199 if (result == preparser::PreParser::kPreParseStackOverflow) { 200 return PreParserData::StackOverflow(); 201 } 202 internal::Vector<unsigned> pre_data = recorder.ExtractData(); 203 size_t size = pre_data.length() * sizeof(pre_data[0]); 204 unsigned char* data = reinterpret_cast<unsigned char*>(pre_data.start()); 205 return PreParserData(size, data); 206} 207 208} // namespace v8. 209 210 211// Used by ASSERT macros and other immediate exits. 212extern "C" void V8_Fatal(const char* file, int line, const char* format, ...) { 213 exit(EXIT_FAILURE); 214} 215