~james-page/ubuntu/precise/nodejs/0.6.x-merge

« back to all changes in this revision

Viewing changes to deps/v8/src/x64/jump-target-x64.cc

  • Committer: James Page
  • Date: 2012-03-30 12:09:16 UTC
  • mfrom: (7.1.23 sid)
  • Revision ID: james.page@canonical.com-20120330120916-40hfu9o00qr5t87b
* Merge from Debian unstable:
  - New upstream release (LP: #892034).
  - This package is x86/arm only. Update control to match
  - d/patches/2009_increase_test_timeout.patch: Increased default test
    timeout from 60 to 120 seconds to support reliable execution of all
    tests on armhf/armel architectures.
  - d/patches/2005_expected_failing_tests.patch: 
    - Allow racey tests to fail: test-cluster-kill-workers,
      test-child-process-fork2 
    - Allow test-fs-watch to fail as LP buildd's don't support
      inotify.
    - Revert all other Ubuntu changes as no longer required.
* Update Standards-Version to 3.9.3.
* Patch wscript to enable build on mipsel arch, libv8 being available.
  Upstream does not support that arch, failure expected.
* test-cluster-kill-workers is expected to fail on armhf,
  Bug#660802 will be closed when test pass.
* test-buffer is expected to fail on armel,
  Bug#660800 will be closed when test pass.
* Add epoch to dependency on libev >= 1:4.11. Closes: bug#658441.
* Remove tools/doc because node-doc-generator has no license for now.
* Add copyright for doc/sh* files (shjs).
* source.lintian-overrides : source-contains-waf-binary tools/node-waf
  it is simply not the case here.
* test-stream-pipe-multi expected to timeout sometimes on busy builds. 
* New upstream release.
* Remove upstream patches.
* test-dgram-pingpong expected to timeout, the test itself is buggy.
* test-buffer expected to fail on armel, allow building package to make
  it easier to find the cause of the failure.
  Closes: bug#639636.
* Expect tests dgram-multicast and broadcast to fail.
  debian/patches/2005_expected_failing_tests.patch
* Drop dpkg-source local-options: Defaults since dpkg-source 1.16.1.
* New upstream release.
* Depend on libev-dev 4.11, see bug#657080.
* Bump dependency on openssl to 1.0.0g.
* Remove useless uv_loop_refcount from libuv,
  refreshed 2009_fix_shared_ev.patch.
* Apply to upstream patches landed after 0.6.10 release,
  to fix debugger repl and http client.
* New upstream release. Closes:bug#650661
* Repackage to remove non-dfsg font files ./deps/npm/html/*/*.ttf
* Remove unneeded bundled dependencies: lighter tarball,
  debian/copyright is easier to maintain.
* Drop unneeded build-dependency on scons.
* Depend on zlib1g, libc-ares, libev.
  Patches done to support building with those shared libs.
* Fix DEB_UPSTREAM_URL in debian/rules, and debian/watch.
* nodejs.pc file for pkgconfig is no more available.
* Build-depend on procps package, a test is using /bin/ps.
* Refreshed debian/patches/2005_expected_failing_tests.patch,
  only for tests that need networking.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
// Copyright 2010 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
 
#include "v8.h"
29
 
 
30
 
#if defined(V8_TARGET_ARCH_X64)
31
 
 
32
 
#include "codegen-inl.h"
33
 
#include "jump-target-inl.h"
34
 
#include "register-allocator-inl.h"
35
 
#include "virtual-frame-inl.h"
36
 
 
37
 
namespace v8 {
38
 
namespace internal {
39
 
 
40
 
// -------------------------------------------------------------------------
41
 
// JumpTarget implementation.
42
 
 
43
 
#define __ ACCESS_MASM(cgen()->masm())
44
 
 
45
 
void JumpTarget::DoJump() {
46
 
  ASSERT(cgen()->has_valid_frame());
47
 
  // Live non-frame registers are not allowed at unconditional jumps
48
 
  // because we have no way of invalidating the corresponding results
49
 
  // which are still live in the C++ code.
50
 
  ASSERT(cgen()->HasValidEntryRegisters());
51
 
 
52
 
  if (is_bound()) {
53
 
    // Backward jump.  There is an expected frame to merge to.
54
 
    ASSERT(direction_ == BIDIRECTIONAL);
55
 
    cgen()->frame()->PrepareMergeTo(entry_frame_);
56
 
    cgen()->frame()->MergeTo(entry_frame_);
57
 
    cgen()->DeleteFrame();
58
 
    __ jmp(&entry_label_);
59
 
  } else if (entry_frame_ != NULL) {
60
 
    // Forward jump with a preconfigured entry frame.  Assert the
61
 
    // current frame matches the expected one and jump to the block.
62
 
    ASSERT(cgen()->frame()->Equals(entry_frame_));
63
 
    cgen()->DeleteFrame();
64
 
    __ jmp(&entry_label_);
65
 
  } else {
66
 
    // Forward jump.  Remember the current frame and emit a jump to
67
 
    // its merge code.
68
 
    AddReachingFrame(cgen()->frame());
69
 
    RegisterFile empty;
70
 
    cgen()->SetFrame(NULL, &empty);
71
 
    __ jmp(&merge_labels_.last());
72
 
  }
73
 
}
74
 
 
75
 
 
76
 
void JumpTarget::DoBranch(Condition cc, Hint b) {
77
 
  ASSERT(cgen() != NULL);
78
 
  ASSERT(cgen()->has_valid_frame());
79
 
 
80
 
  if (is_bound()) {
81
 
    ASSERT(direction_ == BIDIRECTIONAL);
82
 
    // Backward branch.  We have an expected frame to merge to on the
83
 
    // backward edge.
84
 
 
85
 
    // Swap the current frame for a copy (we do the swapping to get
86
 
    // the off-frame registers off the fall through) to use for the
87
 
    // branch.
88
 
    VirtualFrame* fall_through_frame = cgen()->frame();
89
 
    VirtualFrame* branch_frame = new VirtualFrame(fall_through_frame);
90
 
    RegisterFile non_frame_registers;
91
 
    cgen()->SetFrame(branch_frame, &non_frame_registers);
92
 
 
93
 
    // Check if we can avoid merge code.
94
 
    cgen()->frame()->PrepareMergeTo(entry_frame_);
95
 
    if (cgen()->frame()->Equals(entry_frame_)) {
96
 
      // Branch right in to the block.
97
 
      cgen()->DeleteFrame();
98
 
      __ j(cc, &entry_label_);
99
 
      cgen()->SetFrame(fall_through_frame, &non_frame_registers);
100
 
      return;
101
 
    }
102
 
 
103
 
    // Check if we can reuse existing merge code.
104
 
    for (int i = 0; i < reaching_frames_.length(); i++) {
105
 
      if (reaching_frames_[i] != NULL &&
106
 
          cgen()->frame()->Equals(reaching_frames_[i])) {
107
 
        // Branch to the merge code.
108
 
        cgen()->DeleteFrame();
109
 
        __ j(cc, &merge_labels_[i]);
110
 
        cgen()->SetFrame(fall_through_frame, &non_frame_registers);
111
 
        return;
112
 
      }
113
 
    }
114
 
 
115
 
    // To emit the merge code here, we negate the condition and branch
116
 
    // around the merge code on the fall through path.
117
 
    Label original_fall_through;
118
 
    __ j(NegateCondition(cc), &original_fall_through);
119
 
    cgen()->frame()->MergeTo(entry_frame_);
120
 
    cgen()->DeleteFrame();
121
 
    __ jmp(&entry_label_);
122
 
    cgen()->SetFrame(fall_through_frame, &non_frame_registers);
123
 
    __ bind(&original_fall_through);
124
 
 
125
 
  } else if (entry_frame_ != NULL) {
126
 
    // Forward branch with a preconfigured entry frame.  Assert the
127
 
    // current frame matches the expected one and branch to the block.
128
 
    ASSERT(cgen()->frame()->Equals(entry_frame_));
129
 
    // Explicitly use the macro assembler instead of __ as forward
130
 
    // branches are expected to be a fixed size (no inserted
131
 
    // coverage-checking instructions please).  This is used in
132
 
    // Reference::GetValue.
133
 
    cgen()->masm()->j(cc, &entry_label_);
134
 
 
135
 
  } else {
136
 
    // Forward branch.  A copy of the current frame is remembered and
137
 
    // a branch to the merge code is emitted.  Explicitly use the
138
 
    // macro assembler instead of __ as forward branches are expected
139
 
    // to be a fixed size (no inserted coverage-checking instructions
140
 
    // please).  This is used in Reference::GetValue.
141
 
    AddReachingFrame(new VirtualFrame(cgen()->frame()));
142
 
    cgen()->masm()->j(cc, &merge_labels_.last());
143
 
  }
144
 
}
145
 
 
146
 
 
147
 
void JumpTarget::Call() {
148
 
  // Call is used to push the address of the catch block on the stack as
149
 
  // a return address when compiling try/catch and try/finally.  We
150
 
  // fully spill the frame before making the call.  The expected frame
151
 
  // at the label (which should be the only one) is the spilled current
152
 
  // frame plus an in-memory return address.  The "fall-through" frame
153
 
  // at the return site is the spilled current frame.
154
 
  ASSERT(cgen() != NULL);
155
 
  ASSERT(cgen()->has_valid_frame());
156
 
  // There are no non-frame references across the call.
157
 
  ASSERT(cgen()->HasValidEntryRegisters());
158
 
  ASSERT(!is_linked());
159
 
 
160
 
  cgen()->frame()->SpillAll();
161
 
  VirtualFrame* target_frame = new VirtualFrame(cgen()->frame());
162
 
  target_frame->Adjust(1);
163
 
  // We do not expect a call with a preconfigured entry frame.
164
 
  ASSERT(entry_frame_ == NULL);
165
 
  AddReachingFrame(target_frame);
166
 
  __ call(&merge_labels_.last());
167
 
}
168
 
 
169
 
 
170
 
void JumpTarget::DoBind() {
171
 
  ASSERT(cgen() != NULL);
172
 
  ASSERT(!is_bound());
173
 
 
174
 
  // Live non-frame registers are not allowed at the start of a basic
175
 
  // block.
176
 
  ASSERT(!cgen()->has_valid_frame() || cgen()->HasValidEntryRegisters());
177
 
 
178
 
  // Fast case: the jump target was manually configured with an entry
179
 
  // frame to use.
180
 
  if (entry_frame_ != NULL) {
181
 
    // Assert no reaching frames to deal with.
182
 
    ASSERT(reaching_frames_.is_empty());
183
 
    ASSERT(!cgen()->has_valid_frame());
184
 
 
185
 
    RegisterFile empty;
186
 
    if (direction_ == BIDIRECTIONAL) {
187
 
      // Copy the entry frame so the original can be used for a
188
 
      // possible backward jump.
189
 
      cgen()->SetFrame(new VirtualFrame(entry_frame_), &empty);
190
 
    } else {
191
 
      // Take ownership of the entry frame.
192
 
      cgen()->SetFrame(entry_frame_, &empty);
193
 
      entry_frame_ = NULL;
194
 
    }
195
 
    __ bind(&entry_label_);
196
 
    return;
197
 
  }
198
 
 
199
 
  if (!is_linked()) {
200
 
    ASSERT(cgen()->has_valid_frame());
201
 
    if (direction_ == FORWARD_ONLY) {
202
 
      // Fast case: no forward jumps and no possible backward jumps.
203
 
      // The stack pointer can be floating above the top of the
204
 
      // virtual frame before the bind.  Afterward, it should not.
205
 
      VirtualFrame* frame = cgen()->frame();
206
 
      int difference = frame->stack_pointer_ - (frame->element_count() - 1);
207
 
      if (difference > 0) {
208
 
        frame->stack_pointer_ -= difference;
209
 
        __ addq(rsp, Immediate(difference * kPointerSize));
210
 
      }
211
 
    } else {
212
 
      ASSERT(direction_ == BIDIRECTIONAL);
213
 
      // Fast case: no forward jumps, possible backward ones.  Remove
214
 
      // constants and copies above the watermark on the fall-through
215
 
      // frame and use it as the entry frame.
216
 
      cgen()->frame()->MakeMergable();
217
 
      entry_frame_ = new VirtualFrame(cgen()->frame());
218
 
    }
219
 
    __ bind(&entry_label_);
220
 
    return;
221
 
  }
222
 
 
223
 
  if (direction_ == FORWARD_ONLY &&
224
 
      !cgen()->has_valid_frame() &&
225
 
      reaching_frames_.length() == 1) {
226
 
    // Fast case: no fall-through, a single forward jump, and no
227
 
    // possible backward jumps.  Pick up the only reaching frame, take
228
 
    // ownership of it, and use it for the block about to be emitted.
229
 
    VirtualFrame* frame = reaching_frames_[0];
230
 
    RegisterFile empty;
231
 
    cgen()->SetFrame(frame, &empty);
232
 
    reaching_frames_[0] = NULL;
233
 
    __ bind(&merge_labels_[0]);
234
 
 
235
 
    // The stack pointer can be floating above the top of the
236
 
    // virtual frame before the bind.  Afterward, it should not.
237
 
    int difference = frame->stack_pointer_ - (frame->element_count() - 1);
238
 
    if (difference > 0) {
239
 
      frame->stack_pointer_ -= difference;
240
 
      __ addq(rsp, Immediate(difference * kPointerSize));
241
 
    }
242
 
 
243
 
    __ bind(&entry_label_);
244
 
    return;
245
 
  }
246
 
 
247
 
  // If there is a current frame, record it as the fall-through.  It
248
 
  // is owned by the reaching frames for now.
249
 
  bool had_fall_through = false;
250
 
  if (cgen()->has_valid_frame()) {
251
 
    had_fall_through = true;
252
 
    AddReachingFrame(cgen()->frame());  // Return value ignored.
253
 
    RegisterFile empty;
254
 
    cgen()->SetFrame(NULL, &empty);
255
 
  }
256
 
 
257
 
  // Compute the frame to use for entry to the block.
258
 
  ComputeEntryFrame();
259
 
 
260
 
  // Some moves required to merge to an expected frame require purely
261
 
  // frame state changes, and do not require any code generation.
262
 
  // Perform those first to increase the possibility of finding equal
263
 
  // frames below.
264
 
  for (int i = 0; i < reaching_frames_.length(); i++) {
265
 
    if (reaching_frames_[i] != NULL) {
266
 
      reaching_frames_[i]->PrepareMergeTo(entry_frame_);
267
 
    }
268
 
  }
269
 
 
270
 
  if (is_linked()) {
271
 
    // There were forward jumps.  Handle merging the reaching frames
272
 
    // to the entry frame.
273
 
 
274
 
    // Loop over the (non-null) reaching frames and process any that
275
 
    // need merge code.  Iterate backwards through the list to handle
276
 
    // the fall-through frame first.  Set frames that will be
277
 
    // processed after 'i' to NULL if we want to avoid processing
278
 
    // them.
279
 
    for (int i = reaching_frames_.length() - 1; i >= 0; i--) {
280
 
      VirtualFrame* frame = reaching_frames_[i];
281
 
 
282
 
      if (frame != NULL) {
283
 
        // Does the frame (probably) need merge code?
284
 
        if (!frame->Equals(entry_frame_)) {
285
 
          // We could have a valid frame as the fall through to the
286
 
          // binding site or as the fall through from a previous merge
287
 
          // code block.  Jump around the code we are about to
288
 
          // generate.
289
 
          if (cgen()->has_valid_frame()) {
290
 
            cgen()->DeleteFrame();
291
 
            __ jmp(&entry_label_);
292
 
          }
293
 
          // Pick up the frame for this block.  Assume ownership if
294
 
          // there cannot be backward jumps.
295
 
          RegisterFile empty;
296
 
          if (direction_ == BIDIRECTIONAL) {
297
 
            cgen()->SetFrame(new VirtualFrame(frame), &empty);
298
 
          } else {
299
 
            cgen()->SetFrame(frame, &empty);
300
 
            reaching_frames_[i] = NULL;
301
 
          }
302
 
          __ bind(&merge_labels_[i]);
303
 
 
304
 
          // Loop over the remaining (non-null) reaching frames,
305
 
          // looking for any that can share merge code with this one.
306
 
          for (int j = 0; j < i; j++) {
307
 
            VirtualFrame* other = reaching_frames_[j];
308
 
            if (other != NULL && other->Equals(cgen()->frame())) {
309
 
              // Set the reaching frame element to null to avoid
310
 
              // processing it later, and then bind its entry label.
311
 
              reaching_frames_[j] = NULL;
312
 
              __ bind(&merge_labels_[j]);
313
 
            }
314
 
          }
315
 
 
316
 
          // Emit the merge code.
317
 
          cgen()->frame()->MergeTo(entry_frame_);
318
 
        } else if (i == reaching_frames_.length() - 1 && had_fall_through) {
319
 
          // If this is the fall through frame, and it didn't need
320
 
          // merge code, we need to pick up the frame so we can jump
321
 
          // around subsequent merge blocks if necessary.
322
 
          RegisterFile empty;
323
 
          cgen()->SetFrame(frame, &empty);
324
 
          reaching_frames_[i] = NULL;
325
 
        }
326
 
      }
327
 
    }
328
 
 
329
 
    // The code generator may not have a current frame if there was no
330
 
    // fall through and none of the reaching frames needed merging.
331
 
    // In that case, clone the entry frame as the current frame.
332
 
    if (!cgen()->has_valid_frame()) {
333
 
      RegisterFile empty;
334
 
      cgen()->SetFrame(new VirtualFrame(entry_frame_), &empty);
335
 
    }
336
 
 
337
 
    // There may be unprocessed reaching frames that did not need
338
 
    // merge code.  They will have unbound merge labels.  Bind their
339
 
    // merge labels to be the same as the entry label and deallocate
340
 
    // them.
341
 
    for (int i = 0; i < reaching_frames_.length(); i++) {
342
 
      if (!merge_labels_[i].is_bound()) {
343
 
        reaching_frames_[i] = NULL;
344
 
        __ bind(&merge_labels_[i]);
345
 
      }
346
 
    }
347
 
 
348
 
    // There are non-NULL reaching frames with bound labels for each
349
 
    // merge block, but only on backward targets.
350
 
  } else {
351
 
    // There were no forward jumps.  There must be a current frame and
352
 
    // this must be a bidirectional target.
353
 
    ASSERT(reaching_frames_.length() == 1);
354
 
    ASSERT(reaching_frames_[0] != NULL);
355
 
    ASSERT(direction_ == BIDIRECTIONAL);
356
 
 
357
 
    // Use a copy of the reaching frame so the original can be saved
358
 
    // for possible reuse as a backward merge block.
359
 
    RegisterFile empty;
360
 
    cgen()->SetFrame(new VirtualFrame(reaching_frames_[0]), &empty);
361
 
    __ bind(&merge_labels_[0]);
362
 
    cgen()->frame()->MergeTo(entry_frame_);
363
 
  }
364
 
 
365
 
  __ bind(&entry_label_);
366
 
}
367
 
 
368
 
 
369
 
void BreakTarget::Jump() {
370
 
  // Drop leftover statement state from the frame before merging, without
371
 
  // emitting code.
372
 
  ASSERT(cgen()->has_valid_frame());
373
 
  int count = cgen()->frame()->height() - expected_height_;
374
 
  cgen()->frame()->ForgetElements(count);
375
 
  DoJump();
376
 
}
377
 
 
378
 
 
379
 
void BreakTarget::Jump(Result* arg) {
380
 
  // Drop leftover statement state from the frame before merging, without
381
 
  // emitting code.
382
 
  ASSERT(cgen()->has_valid_frame());
383
 
  int count = cgen()->frame()->height() - expected_height_;
384
 
  cgen()->frame()->ForgetElements(count);
385
 
  cgen()->frame()->Push(arg);
386
 
  DoJump();
387
 
}
388
 
 
389
 
 
390
 
void BreakTarget::Bind() {
391
 
#ifdef DEBUG
392
 
  // All the forward-reaching frames should have been adjusted at the
393
 
  // jumps to this target.
394
 
  for (int i = 0; i < reaching_frames_.length(); i++) {
395
 
    ASSERT(reaching_frames_[i] == NULL ||
396
 
           reaching_frames_[i]->height() == expected_height_);
397
 
  }
398
 
#endif
399
 
  // Drop leftover statement state from the frame before merging, even on
400
 
  // the fall through.  This is so we can bind the return target with state
401
 
  // on the frame.
402
 
  if (cgen()->has_valid_frame()) {
403
 
    int count = cgen()->frame()->height() - expected_height_;
404
 
    cgen()->frame()->ForgetElements(count);
405
 
  }
406
 
  DoBind();
407
 
}
408
 
 
409
 
 
410
 
void BreakTarget::Bind(Result* arg) {
411
 
#ifdef DEBUG
412
 
  // All the forward-reaching frames should have been adjusted at the
413
 
  // jumps to this target.
414
 
  for (int i = 0; i < reaching_frames_.length(); i++) {
415
 
    ASSERT(reaching_frames_[i] == NULL ||
416
 
           reaching_frames_[i]->height() == expected_height_ + 1);
417
 
  }
418
 
#endif
419
 
  // Drop leftover statement state from the frame before merging, even on
420
 
  // the fall through.  This is so we can bind the return target with state
421
 
  // on the frame.
422
 
  if (cgen()->has_valid_frame()) {
423
 
    int count = cgen()->frame()->height() - expected_height_;
424
 
    cgen()->frame()->ForgetElements(count);
425
 
    cgen()->frame()->Push(arg);
426
 
  }
427
 
  DoBind();
428
 
  *arg = cgen()->frame()->Pop();
429
 
}
430
 
 
431
 
 
432
 
#undef __
433
 
 
434
 
 
435
 
} }  // namespace v8::internal
436
 
 
437
 
#endif  // V8_TARGET_ARCH_X64