summaryrefslogtreecommitdiff
path: root/src/3rdparty/v8/src/preparser-api.cc
blob: 61e9e7e03549a8da31132c67f6e88026ab5b33ea (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
// Copyright 2010 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 "../include/v8-preparser.h"

#include "globals.h"
#include "checks.h"
#include "allocation.h"
#include "utils.h"
#include "list.h"
#include "scanner-base.h"
#include "preparse-data.h"
#include "preparser.h"

namespace v8 {
namespace internal {

// UTF16Buffer based on a v8::UnicodeInputStream.
class InputStreamUTF16Buffer : public UC16CharacterStream {
 public:
  /* The InputStreamUTF16Buffer maintains an internal buffer
   * that is filled in chunks from the UC16CharacterStream.
   * It also maintains unlimited pushback capability, but optimized
   * for small pushbacks.
   * The pushback_buffer_ pointer points to the limit of pushbacks
   * in the current buffer. There is room for a few pushback'ed chars before
   * the buffer containing the most recently read chunk. If this is overflowed,
   * an external buffer is allocated/reused to hold further pushbacks, and
   * pushback_buffer_ and buffer_cursor_/buffer_end_ now points to the
   * new buffer. When this buffer is read to the end again, the cursor is
   * switched back to the internal buffer
   */
  explicit InputStreamUTF16Buffer(v8::UnicodeInputStream* stream)
      : UC16CharacterStream(),
        stream_(stream),
        pushback_buffer_(buffer_),
        pushback_buffer_end_cache_(NULL),
        pushback_buffer_backing_(NULL),
        pushback_buffer_backing_size_(0) {
    buffer_cursor_ = buffer_end_ = buffer_ + kPushBackSize;
  }

  virtual ~InputStreamUTF16Buffer() {
    if (pushback_buffer_backing_ != NULL) {
      DeleteArray(pushback_buffer_backing_);
    }
  }

  virtual void PushBack(uc32 ch) {
    ASSERT(pos_ > 0);
    if (ch == kEndOfInput) {
      pos_--;
      return;
    }
    if (buffer_cursor_ <= pushback_buffer_) {
      // No more room in the current buffer to do pushbacks.
      if (pushback_buffer_end_cache_ == NULL) {
        // We have overflowed the pushback space at the beginning of buffer_.
        // Switch to using a separate allocated pushback buffer.
        if (pushback_buffer_backing_ == NULL) {
          // Allocate a buffer the first time we need it.
          pushback_buffer_backing_ = NewArray<uc16>(kPushBackSize);
          pushback_buffer_backing_size_ = kPushBackSize;
        }
        pushback_buffer_ = pushback_buffer_backing_;
        pushback_buffer_end_cache_ = buffer_end_;
        buffer_end_ = pushback_buffer_backing_ + pushback_buffer_backing_size_;
        buffer_cursor_ = buffer_end_ - 1;
      } else {
        // Hit the bottom of the allocated pushback buffer.
        // Double the buffer and continue.
        uc16* new_buffer = NewArray<uc16>(pushback_buffer_backing_size_ * 2);
        memcpy(new_buffer + pushback_buffer_backing_size_,
               pushback_buffer_backing_,
               pushback_buffer_backing_size_);
        DeleteArray(pushback_buffer_backing_);
        buffer_cursor_ = new_buffer + pushback_buffer_backing_size_;
        pushback_buffer_backing_ = pushback_buffer_ = new_buffer;
        buffer_end_ = pushback_buffer_backing_ + pushback_buffer_backing_size_;
      }
    }
    pushback_buffer_[buffer_cursor_ - pushback_buffer_- 1] =
        static_cast<uc16>(ch);
    pos_--;
  }

 protected:
  virtual bool ReadBlock() {
    if (pushback_buffer_end_cache_ != NULL) {
      buffer_cursor_ = buffer_;
      buffer_end_ = pushback_buffer_end_cache_;
      pushback_buffer_end_cache_ = NULL;
      return buffer_end_ > buffer_cursor_;
    }
    // Copy the top of the buffer into the pushback area.
    int32_t value;
    uc16* buffer_start = buffer_ + kPushBackSize;
    buffer_cursor_ = buffer_end_ = buffer_start;
    while ((value = stream_->Next()) >= 0) {
      if (value > static_cast<int32_t>(unibrow::Utf8::kMaxThreeByteChar)) {
        value = unibrow::Utf8::kBadChar;
      }
      // buffer_end_ is a const pointer, but buffer_ is writable.
      buffer_start[buffer_end_++ - buffer_start] = static_cast<uc16>(value);
      if (buffer_end_ == buffer_ + kPushBackSize + kBufferSize) break;
    }
    return buffer_end_ > buffer_start;
  }

  virtual unsigned SlowSeekForward(unsigned pos) {
    // Seeking in the input is not used by preparsing.
    // It's only used by the real parser based on preparser data.
    UNIMPLEMENTED();
    return 0;
  }

 private:
  static const unsigned kBufferSize = 512;
  static const unsigned kPushBackSize = 16;
  v8::UnicodeInputStream* const stream_;
  // Buffer holding first kPushBackSize characters of pushback buffer,
  // then kBufferSize chars of read-ahead.
  // The pushback buffer is only used if pushing back characters past
  // the start of a block.
  uc16 buffer_[kPushBackSize + kBufferSize];
  // Limit of pushbacks before new allocation is necessary.
  uc16* pushback_buffer_;
  // Only if that pushback buffer at the start of buffer_ isn't sufficient
  // is the following used.
  const uc16* pushback_buffer_end_cache_;
  uc16* pushback_buffer_backing_;
  unsigned pushback_buffer_backing_size_;
};


class StandAloneJavaScriptScanner : public JavaScriptScanner {
 public:
  explicit StandAloneJavaScriptScanner(ScannerConstants* scanner_constants)
      : JavaScriptScanner(scanner_constants) { }

  void Initialize(UC16CharacterStream* source) {
    source_ = source;
    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();
  }
};


// Functions declared by allocation.h and implemented in both api.cc (for v8)
// or here (for a stand-alone preparser).

void FatalProcessOutOfMemory(const char* reason) {
  V8_Fatal(__FILE__, __LINE__, reason);
}

bool EnableSlowAsserts() { return true; }

}  // namespace internal.


UnicodeInputStream::~UnicodeInputStream() { }


PreParserData Preparse(UnicodeInputStream* input, size_t max_stack) {
  internal::InputStreamUTF16Buffer buffer(input);
  uintptr_t stack_limit = reinterpret_cast<uintptr_t>(&buffer) - max_stack;
  internal::ScannerConstants scanner_constants;
  internal::StandAloneJavaScriptScanner scanner(&scanner_constants);
  scanner.Initialize(&buffer);
  internal::CompleteParserRecorder recorder;
  preparser::PreParser::PreParseResult result =
      preparser::PreParser::PreParseProgram(&scanner,
                                            &recorder,
                                            true,
                                            stack_limit);
  if (result == preparser::PreParser::kPreParseStackOverflow) {
    return PreParserData::StackOverflow();
  }
  internal::Vector<unsigned> pre_data = recorder.ExtractData();
  size_t size = pre_data.length() * sizeof(pre_data[0]);
  unsigned char* data = reinterpret_cast<unsigned char*>(pre_data.start());
  return PreParserData(size, data);
}

}  // namespace v8.


// Used by ASSERT macros and other immediate exits.
extern "C" void V8_Fatal(const char* file, int line, const char* format, ...) {
  exit(EXIT_FAILURE);
}