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 45 namespace v8 { 46 namespace internal { 47 48 // UTF16Buffer based on a v8::UnicodeInputStream. 49 class 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 175 void FatalProcessOutOfMemory(const char* reason) { 176 V8_Fatal(__FILE__, __LINE__, reason); 177 } 178 179 bool EnableSlowAsserts() { return true; } 180 181 } // namespace internal. 182 183 184 UnicodeInputStream::~UnicodeInputStream() { } 185 186 187 PreParserData 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. 212 extern "C" void V8_Fatal(const char* file, int line, const char* format, ...) { 213 exit(EXIT_FAILURE); 214 } 215