Browse Source

Merge branch 'master' into net2

v0.7.4-release
Ryan Dahl 15 years ago
parent
commit
c6cc386819
  1. 9
      Makefile
  2. 2
      benchmark/http_simple.js
  3. 2
      benchmark/static_http_server.js
  4. 5
      deps/evcom/evcom.c
  5. 8
      deps/v8/ChangeLog
  6. 4
      deps/v8/src/SConscript
  7. 29
      deps/v8/src/arm/codegen-arm.cc
  8. 12
      deps/v8/src/arm/codegen-arm.h
  9. 33
      deps/v8/src/arm/fast-codegen-arm.cc
  10. 11
      deps/v8/src/ast.h
  11. 3
      deps/v8/src/codegen.cc
  12. 6
      deps/v8/src/codegen.h
  13. 53
      deps/v8/src/compiler.h
  14. 9
      deps/v8/src/debug-delay.js
  15. 3
      deps/v8/src/fast-codegen.cc
  16. 9
      deps/v8/src/fast-codegen.h
  17. 5
      deps/v8/src/frame-element.h
  18. 2
      deps/v8/src/heap.cc
  19. 4
      deps/v8/src/heap.h
  20. 111
      deps/v8/src/ia32/codegen-ia32.cc
  21. 17
      deps/v8/src/ia32/codegen-ia32.h
  22. 744
      deps/v8/src/ia32/fast-codegen-ia32.cc
  23. 155
      deps/v8/src/ia32/fast-codegen-ia32.h
  24. 50
      deps/v8/src/ia32/virtual-frame-ia32.cc
  25. 12
      deps/v8/src/ia32/virtual-frame-ia32.h
  26. 2
      deps/v8/src/jump-target-inl.h
  27. 2
      deps/v8/src/jump-target.cc
  28. 8
      deps/v8/src/macros.py
  29. 11
      deps/v8/src/mips/codegen-mips.cc
  30. 4
      deps/v8/src/mips/codegen-mips.h
  31. 31
      deps/v8/src/mirror-delay.js
  32. 2
      deps/v8/src/objects.h
  33. 2
      deps/v8/src/register-allocator.h
  34. 128
      deps/v8/src/runtime.cc
  35. 7
      deps/v8/src/runtime.js
  36. 2
      deps/v8/src/scopeinfo.cc
  37. 4
      deps/v8/src/serialize.cc
  38. 2
      deps/v8/src/spaces-inl.h
  39. 100
      deps/v8/src/string.js
  40. 14
      deps/v8/src/stub-cache.cc
  41. 6
      deps/v8/src/utils.h
  42. 4
      deps/v8/src/version.cc
  43. 40
      deps/v8/src/x64/assembler-x64.cc
  44. 94
      deps/v8/src/x64/assembler-x64.h
  45. 26
      deps/v8/src/x64/codegen-x64.cc
  46. 12
      deps/v8/src/x64/codegen-x64.h
  47. 36
      deps/v8/src/x64/fast-codegen-x64.cc
  48. 2
      deps/v8/src/x64/macro-assembler-x64.h
  49. 62
      deps/v8/test/mjsunit/bugs/bug-619.js
  50. 37
      deps/v8/test/mjsunit/debug-evaluate.js
  51. 4
      deps/v8/tools/gyp/v8.gyp
  52. 2
      deps/v8/tools/visual_studio/v8_base.vcproj
  53. 98
      doc/api.txt
  54. 2
      doc/index.html
  55. 7
      lib/http.js
  56. 61
      lib/sys.js
  57. 34
      src/node.cc
  58. 28
      src/node.js
  59. 75
      src/node_file.cc
  60. 3
      src/node_signal_handler.cc
  61. 2
      test/common.js
  62. 0
      test/disabled/test-cat.js
  63. 0
      test/disabled/test-dns.js
  64. 0
      test/disabled/test-eio-race3.js
  65. 0
      test/disabled/test-fs-sendfile.js
  66. 0
      test/disabled/test-http-stress.js
  67. 0
      test/fixtures/a.js
  68. 0
      test/fixtures/b/c.js
  69. 0
      test/fixtures/b/d.js
  70. 0
      test/fixtures/b/package/index.js
  71. 0
      test/fixtures/cycles/folder/foo.js
  72. 0
      test/fixtures/cycles/root.js
  73. 0
      test/fixtures/echo.js
  74. 0
      test/fixtures/multipart.js
  75. 0
      test/fixtures/nested-index/one/hello.js
  76. 0
      test/fixtures/nested-index/one/index.js
  77. 0
      test/fixtures/nested-index/two/hello.js
  78. 0
      test/fixtures/nested-index/two/index.js
  79. 0
      test/fixtures/print-chars.js
  80. 0
      test/fixtures/readdir/are
  81. 0
      test/fixtures/readdir/dir/empty
  82. 0
      test/fixtures/readdir/empty
  83. 0
      test/fixtures/readdir/files
  84. 0
      test/fixtures/readdir/for
  85. 0
      test/fixtures/readdir/just
  86. 0
      test/fixtures/readdir/testing.js
  87. 0
      test/fixtures/readdir/these
  88. 0
      test/fixtures/test_ca.pem
  89. 0
      test/fixtures/test_cert.pem
  90. 0
      test/fixtures/test_key.pem
  91. 0
      test/fixtures/throws_error.js
  92. 0
      test/fixtures/x.txt
  93. 1
      test/internet/internet.status
  94. 21
      test/internet/testcfg.py
  95. 40
      test/mjsunit/test-readdir.js
  96. 5
      test/mjsunit/test-sync-fileread.js
  97. 1
      test/pummel/pummel.status
  98. 2
      test/pummel/test-http-client-reconnect-bug.js
  99. 4
      test/pummel/test-keep-alive.js
  100. 8
      test/pummel/test-multipart.js

9
Makefile

@ -24,6 +24,15 @@ test-all: all
test-debug: all
python tools/test.py --mode=debug
test-simple: all
python tools/test.py simple
test-pummel: all
python tools/test.py pummel
test-internet: all
python tools/test.py internet
benchmark: all
build/default/node benchmark/run.js

2
benchmark/http_simple.js

@ -47,7 +47,7 @@ http.createServer(function (req, res) {
var content_length = body.length.toString();
res.writeHeader( status
res.writeHead( status
, { "Content-Type": "text/plain"
, "Content-Length": content_length
}

2
benchmark/static_http_server.js

@ -16,7 +16,7 @@ for (var i = 0; i < bytes; i++) {
}
var server = http.createServer(function (req, res) {
res.writeHeader(200, {
res.writeHead(200, {
"Content-Type": "text/plain",
"Content-Length": body.length
});

5
deps/evcom/evcom.c

@ -1018,6 +1018,11 @@ on_timeout (EV_P_ ev_timer *watcher, int revents)
if (stream->on_timeout) stream->on_timeout(stream);
// Hack to get error in Node on 'close' event.
// should probably be made into a proper error code.
stream->errorno = 1;
ev_timer_stop(EV_A_ watcher);
evcom_stream_force_close(stream);
if (stream->on_close) stream->on_close(stream);

8
deps/v8/ChangeLog

@ -1,3 +1,11 @@
2010-02-23: Version 2.1.2
Fix a crash bug caused by wrong assert.
Fix a bug with register names on 64-bit V8 (issue 615).
Performance improvements on all platforms.
2010-02-19: Version 2.1.1
[ES5] Implemented Object.defineProperty.

4
deps/v8/src/SConscript

@ -57,7 +57,6 @@ SOURCES = {
disassembler.cc
execution.cc
factory.cc
fast-codegen.cc
flags.cc
frame-element.cc
frames.cc
@ -109,6 +108,7 @@ SOURCES = {
zone.cc
"""),
'arch:arm': Split("""
fast-codegen.cc
arm/builtins-arm.cc
arm/codegen-arm.cc
arm/constants-arm.cc
@ -133,6 +133,7 @@ SOURCES = {
arm/assembler-thumb2.cc
"""),
'arch:mips': Split("""
fast-codegen.cc
mips/assembler-mips.cc
mips/builtins-mips.cc
mips/codegen-mips.cc
@ -169,6 +170,7 @@ SOURCES = {
ia32/virtual-frame-ia32.cc
"""),
'arch:x64': Split("""
fast-codegen.cc
x64/assembler-x64.cc
x64/builtins-x64.cc
x64/codegen-x64.cc

29
deps/v8/src/arm/codegen-arm.cc

@ -142,7 +142,7 @@ Scope* CodeGenerator::scope() { return info_->function()->scope(); }
// r1: called JS function
// cp: callee's context
void CodeGenerator::Generate(CompilationInfo* info, Mode mode) {
void CodeGenerator::Generate(CompilationInfo* info) {
// Record the position for debugging purposes.
CodeForFunctionPosition(info->function());
@ -174,7 +174,7 @@ void CodeGenerator::Generate(CompilationInfo* info, Mode mode) {
}
#endif
if (mode == PRIMARY) {
if (info->mode() == CompilationInfo::PRIMARY) {
frame_->Enter();
// tos: code slot
@ -277,6 +277,12 @@ void CodeGenerator::Generate(CompilationInfo* info, Mode mode) {
frame_->Adjust(4);
allocator_->Unuse(r1);
allocator_->Unuse(lr);
// Bind all the bailout labels to the beginning of the function.
List<CompilationInfo::Bailout*>* bailouts = info->bailouts();
for (int i = 0; i < bailouts->length(); i++) {
__ bind(bailouts->at(i)->label());
}
}
// Initialize the function return target after the locals are set
@ -3420,6 +3426,25 @@ void CodeGenerator::GenerateIsArray(ZoneList<Expression*>* args) {
}
void CodeGenerator::GenerateIsRegExp(ZoneList<Expression*>* args) {
VirtualFrame::SpilledScope spilled_scope;
ASSERT(args->length() == 1);
LoadAndSpill(args->at(0));
JumpTarget answer;
// We need the CC bits to come out as not_equal in the case where the
// object is a smi. This can't be done with the usual test opcode so
// we use XOR to get the right CC bits.
frame_->EmitPop(r0);
__ and_(r1, r0, Operand(kSmiTagMask));
__ eor(r1, r1, Operand(kSmiTagMask), SetCC);
answer.Branch(ne);
// It is a heap object - get the map. Check if the object is a regexp.
__ CompareObjectType(r0, r1, r1, JS_REGEXP_TYPE);
answer.Bind();
cc_reg_ = eq;
}
void CodeGenerator::GenerateIsObject(ZoneList<Expression*>* args) {
// This generates a fast version of:
// (typeof(arg) === 'object' || %_ClassOf(arg) == 'RegExp')

12
deps/v8/src/arm/codegen-arm.h

@ -150,15 +150,6 @@ class CodeGenState BASE_EMBEDDED {
class CodeGenerator: public AstVisitor {
public:
// Compilation mode. Either the compiler is used as the primary
// compiler and needs to setup everything or the compiler is used as
// the secondary compiler for split compilation and has to handle
// bailouts.
enum Mode {
PRIMARY,
SECONDARY
};
// Takes a function literal, generates code for it. This function should only
// be called by compiler.cc.
static Handle<Code> MakeCode(CompilationInfo* info);
@ -244,7 +235,7 @@ class CodeGenerator: public AstVisitor {
inline void VisitStatementsAndSpill(ZoneList<Statement*>* statements);
// Main code generation function
void Generate(CompilationInfo* info, Mode mode);
void Generate(CompilationInfo* info);
// The following are used by class Reference.
void LoadReference(Reference* ref);
@ -359,6 +350,7 @@ class CodeGenerator: public AstVisitor {
void GenerateIsSmi(ZoneList<Expression*>* args);
void GenerateIsNonNegativeSmi(ZoneList<Expression*>* args);
void GenerateIsArray(ZoneList<Expression*>* args);
void GenerateIsRegExp(ZoneList<Expression*>* args);
void GenerateIsObject(ZoneList<Expression*>* args);
void GenerateIsFunction(ZoneList<Expression*>* args);
void GenerateIsUndetectableObject(ZoneList<Expression*>* args);

33
deps/v8/src/arm/fast-codegen-arm.cc

@ -148,17 +148,25 @@ void FastCodeGenerator::EmitBitOr() {
if (!destination().is(no_reg)) {
__ orr(destination(), accumulator1(), Operand(accumulator0()));
}
} else if (destination().is(no_reg)) {
// Result is not needed but do not clobber the operands in case of
// bailout.
__ orr(scratch0(), accumulator1(), Operand(accumulator0()));
__ BranchOnNotSmi(scratch0(), bailout());
} else {
// Preserve the destination operand in a scratch register in case of
// bailout.
__ mov(scratch0(), destination());
// Left is in accumulator1, right in accumulator0.
if (destination().is(accumulator0())) {
__ mov(scratch0(), accumulator0());
__ orr(destination(), accumulator1(), Operand(accumulator1()));
Label* bailout =
info()->AddBailout(accumulator1(), scratch0()); // Left, right.
__ BranchOnNotSmi(destination(), bailout);
} else if (destination().is(accumulator1())) {
__ mov(scratch0(), accumulator1());
__ orr(destination(), accumulator1(), Operand(accumulator0()));
__ BranchOnNotSmi(destination(), bailout());
Label* bailout = info()->AddBailout(scratch0(), accumulator0());
__ BranchOnNotSmi(destination(), bailout);
} else {
ASSERT(destination().is(no_reg));
__ orr(scratch0(), accumulator1(), Operand(accumulator0()));
Label* bailout = info()->AddBailout(accumulator1(), accumulator0());
__ BranchOnNotSmi(scratch0(), bailout);
}
}
// If we didn't bailout, the result (in fact, both inputs too) is known to
@ -179,6 +187,7 @@ void FastCodeGenerator::Generate(CompilationInfo* compilation_info) {
// Note that we keep a live register reference to cp (context) at
// this point.
Label* bailout_to_beginning = info()->AddBailout();
// Receiver (this) is allocated to a fixed register.
if (info()->has_this_properties()) {
Comment cmnt(masm(), ";; MapCheck(this)");
@ -189,7 +198,7 @@ void FastCodeGenerator::Generate(CompilationInfo* compilation_info) {
Handle<HeapObject> object = Handle<HeapObject>::cast(info()->receiver());
Handle<Map> map(object->map());
EmitLoadReceiver();
__ CheckMap(receiver_reg(), scratch0(), map, bailout(), false);
__ CheckMap(receiver_reg(), scratch0(), map, bailout_to_beginning, false);
}
// If there is a global variable access check if the global object is the
@ -202,7 +211,7 @@ void FastCodeGenerator::Generate(CompilationInfo* compilation_info) {
ASSERT(info()->has_global_object());
Handle<Map> map(info()->global_object()->map());
__ ldr(scratch0(), CodeGenerator::GlobalObject());
__ CheckMap(scratch0(), scratch1(), map, bailout(), true);
__ CheckMap(scratch0(), scratch1(), map, bailout_to_beginning, true);
}
VisitStatements(function()->body());
@ -217,8 +226,6 @@ void FastCodeGenerator::Generate(CompilationInfo* compilation_info) {
int32_t sp_delta = (scope()->num_parameters() + 1) * kPointerSize;
__ add(sp, sp, Operand(sp_delta));
__ Jump(lr);
__ bind(&bailout_);
}

11
deps/v8/src/ast.h

@ -1,4 +1,4 @@
// Copyright 2006-2008 the V8 project authors. All rights reserved.
// 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:
@ -199,6 +199,10 @@ class Expression: public AstNode {
// evaluated.
virtual bool IsLeaf() { return false; }
// True if the expression has no side effects and is safe to
// evaluate out of order.
virtual bool IsTrivial() { return false; }
// Mark the expression as being compiled as an expression
// statement. This is used to transform postfix increments to
// (faster) prefix increments.
@ -738,6 +742,7 @@ class Literal: public Expression {
}
virtual bool IsLeaf() { return true; }
virtual bool IsTrivial() { return true; }
// Identity testers.
bool IsNull() const { return handle_.is_identical_to(Factory::null_value()); }
@ -926,6 +931,10 @@ class VariableProxy: public Expression {
return var()->is_global() || var()->rewrite()->IsLeaf();
}
// Reading from a mutable variable is a side effect, but 'this' is
// immutable.
virtual bool IsTrivial() { return is_this(); }
bool IsVariable(Handle<String> n) {
return !is_this() && name().is_identical_to(n);
}

3
deps/v8/src/codegen.cc

@ -248,7 +248,7 @@ Handle<Code> CodeGenerator::MakeCode(CompilationInfo* info) {
CodeGenerator cgen(&masm);
CodeGeneratorScope scope(&cgen);
live_edit_tracker.RecordFunctionScope(info->function()->scope());
cgen.Generate(info, PRIMARY);
cgen.Generate(info);
if (cgen.HasStackOverflow()) {
ASSERT(!Top::has_pending_exception());
return Handle<Code>::null();
@ -360,6 +360,7 @@ CodeGenerator::InlineRuntimeLUT CodeGenerator::kInlineRuntimeLUT[] = {
{&CodeGenerator::GenerateIsSmi, "_IsSmi"},
{&CodeGenerator::GenerateIsNonNegativeSmi, "_IsNonNegativeSmi"},
{&CodeGenerator::GenerateIsArray, "_IsArray"},
{&CodeGenerator::GenerateIsRegExp, "_IsRegExp"},
{&CodeGenerator::GenerateIsConstructCall, "_IsConstructCall"},
{&CodeGenerator::GenerateArgumentsLength, "_ArgumentsLength"},
{&CodeGenerator::GenerateArgumentsAccess, "_Arguments"},

6
deps/v8/src/codegen.h

@ -518,14 +518,14 @@ class CallFunctionStub: public CodeStub {
}
#endif
// Minor key encoding in 31 bits AAAAAAAAAAAAAAAAAAAAAFI A(rgs)F(lag)I(nloop).
// Minor key encoding in 32 bits with Bitfield <Type, shift, size>.
class InLoopBits: public BitField<InLoopFlag, 0, 1> {};
class FlagBits: public BitField<CallFunctionFlags, 1, 1> {};
class ArgcBits: public BitField<int, 2, 29> {};
class ArgcBits: public BitField<int, 2, 32 - 2> {};
Major MajorKey() { return CallFunction; }
int MinorKey() {
// Encode the parameters in a unique 31 bit value.
// Encode the parameters in a unique 32 bit value.
return InLoopBits::encode(in_loop_)
| FlagBits::encode(flags_)
| ArgcBits::encode(argc_);

53
deps/v8/src/compiler.h

@ -41,6 +41,37 @@ namespace internal {
// is constructed based on the resources available at compile-time.
class CompilationInfo BASE_EMBEDDED {
public:
// Compilation mode. Either the compiler is used as the primary
// compiler and needs to setup everything or the compiler is used as
// the secondary compiler for split compilation and has to handle
// bailouts.
enum Mode {
PRIMARY,
SECONDARY
};
// A description of the compilation state at a bailout to the secondary
// code generator.
//
// The state is currently simple: there are no parameters or local
// variables to worry about ('this' can be found in the stack frame).
// There are at most two live values.
//
// There is a label that should be bound to the beginning of the bailout
// stub code.
class Bailout : public ZoneObject {
public:
Bailout(Register left, Register right) : left_(left), right_(right) {}
Label* label() { return &label_; }
private:
Register left_;
Register right_;
Label label_;
};
// Lazy compilation of a JSFunction.
CompilationInfo(Handle<JSFunction> closure,
int loop_nesting,
@ -117,9 +148,13 @@ class CompilationInfo BASE_EMBEDDED {
int loop_nesting() { return loop_nesting_; }
bool has_receiver() { return !receiver_.is_null(); }
Handle<Object> receiver() { return receiver_; }
List<Bailout*>* bailouts() { return &bailouts_; }
// Accessors for mutable fields, possibly set by analysis passes with
// Accessors for mutable fields (possibly set by analysis passes) with
// default values given by Initialize.
Mode mode() { return mode_; }
void set_mode(Mode mode) { mode_ = mode; }
bool has_this_properties() { return has_this_properties_; }
void set_has_this_properties(bool flag) { has_this_properties_ = flag; }
@ -137,8 +172,19 @@ class CompilationInfo BASE_EMBEDDED {
// Derived accessors.
Scope* scope() { return function()->scope(); }
// Add a bailout with two live values.
Label* AddBailout(Register left, Register right) {
Bailout* bailout = new Bailout(left, right);
bailouts_.Add(bailout);
return bailout->label();
}
// Add a bailout with no live values.
Label* AddBailout() { return AddBailout(no_reg, no_reg); }
private:
void Initialize() {
mode_ = PRIMARY;
has_this_properties_ = false;
has_globals_ = false;
}
@ -148,6 +194,7 @@ class CompilationInfo BASE_EMBEDDED {
Handle<Script> script_;
FunctionLiteral* function_;
Mode mode_;
bool is_eval_;
int loop_nesting_;
@ -157,6 +204,10 @@ class CompilationInfo BASE_EMBEDDED {
bool has_this_properties_;
bool has_globals_;
// An ordered list of bailout points encountered during fast-path
// compilation.
List<Bailout*> bailouts_;
DISALLOW_COPY_AND_ASSIGN(CompilationInfo);
};

9
deps/v8/src/debug-delay.js

@ -1202,12 +1202,17 @@ DebugCommandProcessor.prototype.processDebugJSONRequest = function(json_request)
throw new Error('Command not specified');
}
if (request.arguments) {
var args = request.arguments;
// TODO(yurys): remove request.arguments.compactFormat check once
// ChromeDevTools are switched to 'inlineRefs'
if (request.arguments && (request.arguments.inlineRefs ||
request.arguments.compactFormat)) {
if (args.inlineRefs || args.compactFormat) {
response.setOption('inlineRefs', true);
}
if (!IS_UNDEFINED(args.maxStringLength)) {
response.setOption('maxStringLength', args.maxStringLength);
}
}
if (request.command == 'continue') {
this.continueRequest_(request, response);

3
deps/v8/src/fast-codegen.cc

@ -456,7 +456,8 @@ Handle<Code> FastCodeGenerator::MakeCode(CompilationInfo* info) {
// macro assembler.
CodeGenerator cgen(&masm);
CodeGeneratorScope scope(&cgen);
cgen.Generate(info, CodeGenerator::SECONDARY);
info->set_mode(CompilationInfo::SECONDARY);
cgen.Generate(info);
if (cgen.HasStackOverflow()) {
ASSERT(!Top::has_pending_exception());
return Handle<Code>::null();

9
deps/v8/src/fast-codegen.h

@ -28,10 +28,15 @@
#ifndef V8_FAST_CODEGEN_H_
#define V8_FAST_CODEGEN_H_
#if V8_TARGET_ARCH_IA32
#include "ia32/fast-codegen-ia32.h"
#else
#include "v8.h"
#include "ast.h"
#include "compiler.h"
#include "list.h"
namespace v8 {
namespace internal {
@ -76,7 +81,6 @@ class FastCodeGenerator: public AstVisitor {
private:
MacroAssembler* masm() { return masm_; }
CompilationInfo* info() { return info_; }
Label* bailout() { return &bailout_; }
Register destination() { return destination_; }
void set_destination(Register reg) { destination_ = reg; }
@ -142,7 +146,6 @@ class FastCodeGenerator: public AstVisitor {
MacroAssembler* masm_;
CompilationInfo* info_;
Label bailout_;
Register destination_;
uint32_t smi_bits_;
@ -152,4 +155,6 @@ class FastCodeGenerator: public AstVisitor {
} } // namespace v8::internal
#endif // V8_TARGET_ARCH_IA32
#endif // V8_FAST_CODEGEN_H_

5
deps/v8/src/frame-element.h

@ -65,6 +65,9 @@ class FrameElement BASE_EMBEDDED {
}
inline void set_number_info(NumberInfo::Type info) {
// Copied elements do not have number info. Instead
// we have to inspect their backing element in the frame.
ASSERT(!is_copy());
value_ = value_ & ~NumberInfoField::mask();
value_ = value_ | NumberInfoField::encode(info);
}
@ -250,7 +253,7 @@ class FrameElement BASE_EMBEDDED {
class CopiedField: public BitField<bool, 3, 1> {};
class SyncedField: public BitField<bool, 4, 1> {};
class NumberInfoField: public BitField<NumberInfo::Type, 5, 3> {};
class DataField: public BitField<uint32_t, 8, 32 - 9> {};
class DataField: public BitField<uint32_t, 8, 32 - 8> {};
friend class VirtualFrame;
};

2
deps/v8/src/heap.cc

@ -4111,7 +4111,7 @@ int KeyedLookupCache::Hash(Map* map, String* name) {
// Uses only lower 32 bits if pointers are larger.
uintptr_t addr_hash =
static_cast<uint32_t>(reinterpret_cast<uintptr_t>(map)) >> kMapHashShift;
return (addr_hash ^ name->Hash()) & kCapacityMask;
return static_cast<uint32_t>((addr_hash ^ name->Hash()) & kCapacityMask);
}

4
deps/v8/src/heap.h

@ -1383,9 +1383,9 @@ class DescriptorLookupCache {
private:
static int Hash(DescriptorArray* array, String* name) {
// Uses only lower 32 bits if pointers are larger.
uintptr_t array_hash =
uint32_t array_hash =
static_cast<uint32_t>(reinterpret_cast<uintptr_t>(array)) >> 2;
uintptr_t name_hash =
uint32_t name_hash =
static_cast<uint32_t>(reinterpret_cast<uintptr_t>(name)) >> 2;
return (array_hash ^ name_hash) % kLength;
}

111
deps/v8/src/ia32/codegen-ia32.cc

@ -125,7 +125,7 @@ Scope* CodeGenerator::scope() { return info_->function()->scope(); }
// edi: called JS function
// esi: callee's context
void CodeGenerator::Generate(CompilationInfo* info, Mode mode) {
void CodeGenerator::Generate(CompilationInfo* info) {
// Record the position for debugging purposes.
CodeForFunctionPosition(info->function());
@ -164,7 +164,7 @@ void CodeGenerator::Generate(CompilationInfo* info, Mode mode) {
// esi: callee's context
allocator_->Initialize();
if (mode == PRIMARY) {
if (info->mode() == CompilationInfo::PRIMARY) {
frame_->Enter();
// Allocate space for locals and initialize them.
@ -255,6 +255,12 @@ void CodeGenerator::Generate(CompilationInfo* info, Mode mode) {
// frame to match this state.
frame_->Adjust(3);
allocator_->Unuse(edi);
// Bind all the bailout labels to the beginning of the function.
List<CompilationInfo::Bailout*>* bailouts = info->bailouts();
for (int i = 0; i < bailouts->length(); i++) {
__ bind(bailouts->at(i)->label());
}
}
// Initialize the function return target after the locals are set
@ -689,6 +695,11 @@ void CodeGenerator::LoadReference(Reference* ref) {
// The expression is a variable proxy that does not rewrite to a
// property. Global variables are treated as named property references.
if (var->is_global()) {
// If eax is free, the register allocator prefers it. Thus the code
// generator will load the global object into eax, which is where
// LoadIC wants it. Most uses of Reference call LoadIC directly
// after the reference is created.
frame_->Spill(eax);
LoadGlobal();
ref->set_type(Reference::NAMED);
} else {
@ -4307,6 +4318,10 @@ Result CodeGenerator::LoadFromGlobalSlotCheckExtensions(
// All extension objects were empty and it is safe to use a global
// load IC call.
// The register allocator prefers eax if it is free, so the code generator
// will load the global object directly into eax, which is where the LoadIC
// expects it.
frame_->Spill(eax);
LoadGlobal();
frame_->Push(slot->var()->name());
RelocInfo::Mode mode = (typeof_state == INSIDE_TYPEOF)
@ -4592,8 +4607,8 @@ void CodeGenerator::VisitObjectLiteral(ObjectLiteral* node) {
// Duplicate the object as the IC receiver.
frame_->Dup();
Load(property->value());
frame_->Push(key);
Result ignored = frame_->CallStoreIC();
Result dummy = frame_->CallStoreIC(Handle<String>::cast(key), false);
dummy.Unuse();
break;
}
// Fall through
@ -4762,26 +4777,33 @@ void CodeGenerator::EmitNamedPropertyAssignment(Assignment* node) {
Property* prop = node->target()->AsProperty();
ASSERT(var == NULL || (prop == NULL && var->is_global()));
// Initialize name and evaluate the receiver subexpression.
// Initialize name and evaluate the receiver subexpression if necessary.
Handle<String> name;
bool is_trivial_receiver = false;
if (var != NULL) {
name = var->name();
LoadGlobal();
} else {
Literal* lit = prop->key()->AsLiteral();
ASSERT(lit != NULL);
ASSERT_NOT_NULL(lit);
name = Handle<String>::cast(lit->handle());
Load(prop->obj());
// Do not materialize the receiver on the frame if it is trivial.
is_trivial_receiver = prop->obj()->IsTrivial();
if (!is_trivial_receiver) Load(prop->obj());
}
if (node->starts_initialization_block()) {
ASSERT_EQ(NULL, var);
// Change to slow case in the beginning of an initialization block to
// avoid the quadratic behavior of repeatedly adding fast properties.
if (is_trivial_receiver) {
frame()->Push(prop->obj());
} else {
frame()->Dup();
}
Result ignored = frame()->CallRuntime(Runtime::kToSlowProperties, 1);
}
if (node->ends_initialization_block()) {
if (node->ends_initialization_block() && !is_trivial_receiver) {
// Add an extra copy of the receiver to the frame, so that it can be
// converted back to fast case after the assignment.
frame()->Dup();
@ -4789,7 +4811,16 @@ void CodeGenerator::EmitNamedPropertyAssignment(Assignment* node) {
// Evaluate the right-hand side.
if (node->is_compound()) {
if (is_trivial_receiver) {
frame()->Push(prop->obj());
} else if (var != NULL) {
// The LoadIC stub expects the object in eax.
// Freeing eax causes the code generator to load the global into it.
frame_->Spill(eax);
LoadGlobal();
} else {
frame()->Dup();
}
Result value = EmitNamedLoad(name, var != NULL);
frame()->Push(&value);
Load(node->value());
@ -4806,23 +4837,34 @@ void CodeGenerator::EmitNamedPropertyAssignment(Assignment* node) {
// Perform the assignment. It is safe to ignore constants here.
ASSERT(var == NULL || var->mode() != Variable::CONST);
ASSERT(node->op() != Token::INIT_CONST);
ASSERT_NE(Token::INIT_CONST, node->op());
if (is_trivial_receiver) {
Result value = frame()->Pop();
frame()->Push(prop->obj());
frame()->Push(&value);
}
CodeForSourcePosition(node->position());
Result answer = EmitNamedStore(name);
bool is_contextual = (var != NULL);
Result answer = EmitNamedStore(name, is_contextual);
frame()->Push(&answer);
if (node->ends_initialization_block()) {
// The argument to the runtime call is the extra copy of the receiver,
// which is below the value of the assignment. Swap the receiver and
// the value of the assignment expression.
ASSERT_EQ(NULL, var);
// The argument to the runtime call is the receiver.
if (is_trivial_receiver) {
frame()->Push(prop->obj());
} else {
// A copy of the receiver is below the value of the assignment. Swap
// the receiver and the value of the assignment expression.
Result result = frame()->Pop();
Result receiver = frame()->Pop();
frame()->Push(&result);
frame()->Push(&receiver);
}
Result ignored = frame_->CallRuntime(Runtime::kToFastProperties, 1);
}
ASSERT(frame()->height() == original_height + 1);
ASSERT_EQ(frame()->height(), original_height + 1);
}
@ -4832,7 +4874,7 @@ void CodeGenerator::EmitKeyedPropertyAssignment(Assignment* node) {
#endif
Comment cmnt(masm_, "[ Named Property Assignment");
Property* prop = node->target()->AsProperty();
ASSERT(prop != NULL);
ASSERT_NOT_NULL(prop);
// Evaluate the receiver subexpression.
Load(prop->obj());
@ -5399,6 +5441,25 @@ void CodeGenerator::GenerateIsArray(ZoneList<Expression*>* args) {
}
void CodeGenerator::GenerateIsRegExp(ZoneList<Expression*>* args) {
ASSERT(args->length() == 1);
Load(args->at(0));
Result value = frame_->Pop();
value.ToRegister();
ASSERT(value.is_valid());
__ test(value.reg(), Immediate(kSmiTagMask));
destination()->false_target()->Branch(equal);
// It is a heap object - get map.
Result temp = allocator()->Allocate();
ASSERT(temp.is_valid());
// Check if the object is a regexp.
__ CmpObjectType(value.reg(), JS_REGEXP_TYPE, temp.reg());
value.Unuse();
temp.Unuse();
destination()->Split(equal);
}
void CodeGenerator::GenerateIsObject(ZoneList<Expression*>* args) {
// This generates a fast version of:
// (typeof(arg) === 'object' || %_ClassOf(arg) == 'RegExp')
@ -6347,13 +6408,10 @@ void CodeGenerator::VisitCompareOperation(CompareOperation* node) {
__ movzx_b(temp.reg(), FieldOperand(temp.reg(), Map::kBitFieldOffset));
__ test(temp.reg(), Immediate(1 << Map::kIsUndetectable));
destination()->false_target()->Branch(not_zero);
__ mov(temp.reg(), FieldOperand(answer.reg(), HeapObject::kMapOffset));
__ movzx_b(temp.reg(),
FieldOperand(temp.reg(), Map::kInstanceTypeOffset));
__ cmp(temp.reg(), FIRST_NONSTRING_TYPE);
__ CmpObjectType(answer.reg(), FIRST_NONSTRING_TYPE, temp.reg());
temp.Unuse();
answer.Unuse();
destination()->Split(less);
destination()->Split(below);
} else if (check->Equals(Heap::boolean_symbol())) {
__ cmp(answer.reg(), Factory::true_value());
@ -6734,14 +6792,13 @@ Result CodeGenerator::EmitNamedLoad(Handle<String> name, bool is_contextual) {
}
Result CodeGenerator::EmitNamedStore(Handle<String> name) {
Result CodeGenerator::EmitNamedStore(Handle<String> name, bool is_contextual) {
#ifdef DEBUG
int original_height = frame()->height();
int expected_height = frame()->height() - (is_contextual ? 1 : 2);
#endif
frame()->Push(name);
Result result = frame()->CallStoreIC();
Result result = frame()->CallStoreIC(name, is_contextual);
ASSERT(frame()->height() == original_height - 2);
ASSERT_EQ(expected_height, frame()->height());
return result;
}
@ -7058,7 +7115,7 @@ void Reference::SetValue(InitState init_state) {
case NAMED: {
Comment cmnt(masm, "[ Store to named Property");
Result answer = cgen_->EmitNamedStore(GetName());
Result answer = cgen_->EmitNamedStore(GetName(), false);
cgen_->frame()->Push(&answer);
set_unloaded();
break;

17
deps/v8/src/ia32/codegen-ia32.h

@ -294,15 +294,6 @@ enum ArgumentsAllocationMode {
class CodeGenerator: public AstVisitor {
public:
// Compilation mode. Either the compiler is used as the primary
// compiler and needs to setup everything or the compiler is used as
// the secondary compiler for split compilation and has to handle
// bailouts.
enum Mode {
PRIMARY,
SECONDARY
};
// Takes a function literal, generates code for it. This function should only
// be called by compiler.cc.
static Handle<Code> MakeCode(CompilationInfo* info);
@ -384,7 +375,7 @@ class CodeGenerator: public AstVisitor {
void VisitStatementsAndSpill(ZoneList<Statement*>* statements);
// Main code generation function
void Generate(CompilationInfo* info, Mode mode);
void Generate(CompilationInfo* info);
// Generate the return sequence code. Should be called no more than
// once per compiled function, immediately after binding the return
@ -447,8 +438,9 @@ class CodeGenerator: public AstVisitor {
// Receiver is passed on the frame and consumed.
Result EmitNamedLoad(Handle<String> name, bool is_contextual);
// Reciever and value are passed on the frame and consumed.
Result EmitNamedStore(Handle<String> name);
// If the store is contextual, value is passed on the frame and consumed.
// Otherwise, receiver and value are passed on the frame and consumed.
Result EmitNamedStore(Handle<String> name, bool is_contextual);
// Receiver and key are passed on the frame and consumed.
Result EmitKeyedLoad();
@ -551,6 +543,7 @@ class CodeGenerator: public AstVisitor {
void GenerateIsSmi(ZoneList<Expression*>* args);
void GenerateIsNonNegativeSmi(ZoneList<Expression*>* args);
void GenerateIsArray(ZoneList<Expression*>* args);
void GenerateIsRegExp(ZoneList<Expression*>* args);
void GenerateIsObject(ZoneList<Expression*>* args);
void GenerateIsFunction(ZoneList<Expression*>* args);
void GenerateIsUndetectableObject(ZoneList<Expression*>* args);

744
deps/v8/src/ia32/fast-codegen-ia32.cc

@ -29,12 +29,445 @@
#include "codegen-inl.h"
#include "fast-codegen.h"
#include "data-flow.h"
#include "scopes.h"
namespace v8 {
namespace internal {
#define BAILOUT(reason) \
do { \
if (FLAG_trace_bailout) { \
PrintF("%s\n", reason); \
} \
has_supported_syntax_ = false; \
return; \
} while (false)
#define CHECK_BAILOUT \
do { \
if (!has_supported_syntax_) return; \
} while (false)
void FastCodeGenSyntaxChecker::Check(CompilationInfo* info) {
info_ = info;
// We do not specialize if we do not have a receiver or if it is not a
// JS object with fast mode properties.
if (!info->has_receiver()) BAILOUT("No receiver");
if (!info->receiver()->IsJSObject()) BAILOUT("Receiver is not an object");
Handle<JSObject> object = Handle<JSObject>::cast(info->receiver());
if (!object->HasFastProperties()) BAILOUT("Receiver is in dictionary mode");
// We do not support stack or heap slots (both of which require
// allocation).
Scope* scope = info->scope();
if (scope->num_stack_slots() > 0) {
BAILOUT("Function has stack-allocated locals");
}
if (scope->num_heap_slots() > 0) {
BAILOUT("Function has context-allocated locals");
}
VisitDeclarations(scope->declarations());
CHECK_BAILOUT;
// We do not support empty function bodies.
if (info->function()->body()->is_empty()) {
BAILOUT("Function has an empty body");
}
VisitStatements(info->function()->body());
}
void FastCodeGenSyntaxChecker::VisitDeclarations(
ZoneList<Declaration*>* decls) {
if (!decls->is_empty()) BAILOUT("Function has declarations");
}
void FastCodeGenSyntaxChecker::VisitStatements(ZoneList<Statement*>* stmts) {
if (stmts->length() != 1) {
BAILOUT("Function body is not a singleton statement.");
}
Visit(stmts->at(0));
}
void FastCodeGenSyntaxChecker::VisitDeclaration(Declaration* decl) {
UNREACHABLE();
}
void FastCodeGenSyntaxChecker::VisitBlock(Block* stmt) {
VisitStatements(stmt->statements());
}
void FastCodeGenSyntaxChecker::VisitExpressionStatement(
ExpressionStatement* stmt) {
Visit(stmt->expression());
}
void FastCodeGenSyntaxChecker::VisitEmptyStatement(EmptyStatement* stmt) {
// Supported.
}
void FastCodeGenSyntaxChecker::VisitIfStatement(IfStatement* stmt) {
BAILOUT("IfStatement");
}
void FastCodeGenSyntaxChecker::VisitContinueStatement(ContinueStatement* stmt) {
BAILOUT("Continuestatement");
}
void FastCodeGenSyntaxChecker::VisitBreakStatement(BreakStatement* stmt) {
BAILOUT("BreakStatement");
}
void FastCodeGenSyntaxChecker::VisitReturnStatement(ReturnStatement* stmt) {
BAILOUT("ReturnStatement");
}
void FastCodeGenSyntaxChecker::VisitWithEnterStatement(
WithEnterStatement* stmt) {
BAILOUT("WithEnterStatement");
}
void FastCodeGenSyntaxChecker::VisitWithExitStatement(WithExitStatement* stmt) {
BAILOUT("WithExitStatement");
}
void FastCodeGenSyntaxChecker::VisitSwitchStatement(SwitchStatement* stmt) {
BAILOUT("SwitchStatement");
}
void FastCodeGenSyntaxChecker::VisitDoWhileStatement(DoWhileStatement* stmt) {
BAILOUT("DoWhileStatement");
}
void FastCodeGenSyntaxChecker::VisitWhileStatement(WhileStatement* stmt) {
BAILOUT("WhileStatement");
}
void FastCodeGenSyntaxChecker::VisitForStatement(ForStatement* stmt) {
BAILOUT("ForStatement");
}
void FastCodeGenSyntaxChecker::VisitForInStatement(ForInStatement* stmt) {
BAILOUT("ForInStatement");
}
void FastCodeGenSyntaxChecker::VisitTryCatchStatement(TryCatchStatement* stmt) {
BAILOUT("TryCatchStatement");
}
void FastCodeGenSyntaxChecker::VisitTryFinallyStatement(
TryFinallyStatement* stmt) {
BAILOUT("TryFinallyStatement");
}
void FastCodeGenSyntaxChecker::VisitDebuggerStatement(
DebuggerStatement* stmt) {
BAILOUT("DebuggerStatement");
}
void FastCodeGenSyntaxChecker::VisitFunctionLiteral(FunctionLiteral* expr) {
BAILOUT("FunctionLiteral");
}
void FastCodeGenSyntaxChecker::VisitFunctionBoilerplateLiteral(
FunctionBoilerplateLiteral* expr) {
BAILOUT("FunctionBoilerplateLiteral");
}
void FastCodeGenSyntaxChecker::VisitConditional(Conditional* expr) {
BAILOUT("Conditional");
}
void FastCodeGenSyntaxChecker::VisitSlot(Slot* expr) {
UNREACHABLE();
}
void FastCodeGenSyntaxChecker::VisitVariableProxy(VariableProxy* expr) {
// Only global variable references are supported.
Variable* var = expr->var();
if (!var->is_global() || var->is_this()) BAILOUT("Non-global variable");
// Check if the global variable is existing and non-deletable.
if (info()->has_global_object()) {
LookupResult lookup;
info()->global_object()->Lookup(*expr->name(), &lookup);
if (!lookup.IsProperty()) {
BAILOUT("Non-existing global variable");
}
// We do not handle global variables with accessors or interceptors.
if (lookup.type() != NORMAL) {
BAILOUT("Global variable with accessors or interceptors.");
}
// We do not handle deletable global variables.
if (!lookup.IsDontDelete()) {
BAILOUT("Deletable global variable");
}
}
}
void FastCodeGenSyntaxChecker::VisitLiteral(Literal* expr) {
BAILOUT("Literal");
}
void FastCodeGenSyntaxChecker::VisitRegExpLiteral(RegExpLiteral* expr) {
BAILOUT("RegExpLiteral");
}
void FastCodeGenSyntaxChecker::VisitObjectLiteral(ObjectLiteral* expr) {
BAILOUT("ObjectLiteral");
}
void FastCodeGenSyntaxChecker::VisitArrayLiteral(ArrayLiteral* expr) {
BAILOUT("ArrayLiteral");
}
void FastCodeGenSyntaxChecker::VisitCatchExtensionObject(
CatchExtensionObject* expr) {
BAILOUT("CatchExtensionObject");
}
void FastCodeGenSyntaxChecker::VisitAssignment(Assignment* expr) {
// Simple assignments to (named) this properties are supported.
if (expr->op() != Token::ASSIGN) BAILOUT("Non-simple assignment");
Property* prop = expr->target()->AsProperty();
if (prop == NULL) BAILOUT("Non-property assignment");
VariableProxy* proxy = prop->obj()->AsVariableProxy();
if (proxy == NULL || !proxy->var()->is_this()) {
BAILOUT("Non-this-property assignment");
}
if (!prop->key()->IsPropertyName()) {
BAILOUT("Non-named-property assignment");
}
// We will only specialize for fields on the object itself.
// Expression::IsPropertyName implies that the name is a literal
// symbol but we do not assume that.
Literal* key = prop->key()->AsLiteral();
if (key != NULL && key->handle()->IsString()) {
Handle<Object> receiver = info()->receiver();
Handle<String> name = Handle<String>::cast(key->handle());
LookupResult lookup;
receiver->Lookup(*name, &lookup);
if (!lookup.IsProperty()) {
BAILOUT("Assigned property not found at compile time");
}
if (lookup.holder() != *receiver) BAILOUT("Non-own property assignment");
if (!lookup.type() == FIELD) BAILOUT("Non-field property assignment");
} else {
UNREACHABLE();
BAILOUT("Unexpected non-string-literal property key");
}
Visit(expr->value());
}
void FastCodeGenSyntaxChecker::VisitThrow(Throw* expr) {
BAILOUT("Throw");
}
void FastCodeGenSyntaxChecker::VisitProperty(Property* expr) {
// We support named this property references.
VariableProxy* proxy = expr->obj()->AsVariableProxy();
if (proxy == NULL || !proxy->var()->is_this()) {
BAILOUT("Non-this-property reference");
}
if (!expr->key()->IsPropertyName()) {
BAILOUT("Non-named-property reference");
}
// We will only specialize for fields on the object itself.
// Expression::IsPropertyName implies that the name is a literal
// symbol but we do not assume that.
Literal* key = expr->key()->AsLiteral();
if (key != NULL && key->handle()->IsString()) {
Handle<Object> receiver = info()->receiver();
Handle<String> name = Handle<String>::cast(key->handle());
LookupResult lookup;
receiver->Lookup(*name, &lookup);
if (!lookup.IsProperty()) {
BAILOUT("Referenced property not found at compile time");
}
if (lookup.holder() != *receiver) BAILOUT("Non-own property reference");
if (!lookup.type() == FIELD) BAILOUT("Non-field property reference");
} else {
UNREACHABLE();
BAILOUT("Unexpected non-string-literal property key");
}
}
void FastCodeGenSyntaxChecker::VisitCall(Call* expr) {
BAILOUT("Call");
}
void FastCodeGenSyntaxChecker::VisitCallNew(CallNew* expr) {
BAILOUT("CallNew");
}
void FastCodeGenSyntaxChecker::VisitCallRuntime(CallRuntime* expr) {
BAILOUT("CallRuntime");
}
void FastCodeGenSyntaxChecker::VisitUnaryOperation(UnaryOperation* expr) {
BAILOUT("UnaryOperation");
}
void FastCodeGenSyntaxChecker::VisitCountOperation(CountOperation* expr) {
BAILOUT("CountOperation");
}
void FastCodeGenSyntaxChecker::VisitBinaryOperation(BinaryOperation* expr) {
// We support bitwise OR.
switch (expr->op()) {
case Token::COMMA:
BAILOUT("BinaryOperation COMMA");
case Token::OR:
BAILOUT("BinaryOperation OR");
case Token::AND:
BAILOUT("BinaryOperation AND");
case Token::BIT_OR:
// We support expressions nested on the left because they only require
// a pair of registers to keep all intermediate values in registers
// (i.e., the expression stack has height no more than two).
if (!expr->right()->IsLeaf()) BAILOUT("expression nested on right");
// We do not allow subexpressions with side effects because we
// (currently) bail out to the beginning of the full function. The
// only expressions with side effects that we would otherwise handle
// are assignments.
if (expr->left()->AsAssignment() != NULL ||
expr->right()->AsAssignment() != NULL) {
BAILOUT("subexpression of binary operation has side effects");
}
Visit(expr->left());
CHECK_BAILOUT;
Visit(expr->right());
break;
case Token::BIT_XOR:
BAILOUT("BinaryOperation BIT_XOR");
case Token::BIT_AND:
BAILOUT("BinaryOperation BIT_AND");
case Token::SHL:
BAILOUT("BinaryOperation SHL");
case Token::SAR:
BAILOUT("BinaryOperation SAR");
case Token::SHR:
BAILOUT("BinaryOperation SHR");
case Token::ADD:
BAILOUT("BinaryOperation ADD");
case Token::SUB:
BAILOUT("BinaryOperation SUB");
case Token::MUL:
BAILOUT("BinaryOperation MUL");
case Token::DIV:
BAILOUT("BinaryOperation DIV");
case Token::MOD:
BAILOUT("BinaryOperation MOD");
default:
UNREACHABLE();
}
}
void FastCodeGenSyntaxChecker::VisitCompareOperation(CompareOperation* expr) {
BAILOUT("CompareOperation");
}
void FastCodeGenSyntaxChecker::VisitThisFunction(ThisFunction* expr) {
BAILOUT("ThisFunction");
}
#undef BAILOUT
#undef CHECK_BAILOUT
#define __ ACCESS_MASM(masm())
Handle<Code> FastCodeGenerator::MakeCode(CompilationInfo* info) {
// Label the AST before calling MakeCodePrologue, so AST node numbers are
// printed with the AST.
AstLabeler labeler;
labeler.Label(info);
LivenessAnalyzer analyzer;
analyzer.Analyze(info->function());
CodeGenerator::MakeCodePrologue(info);
const int kInitialBufferSize = 4 * KB;
MacroAssembler masm(NULL, kInitialBufferSize);
// Generate the fast-path code.
FastCodeGenerator fast_cgen(&masm);
fast_cgen.Generate(info);
if (fast_cgen.HasStackOverflow()) {
ASSERT(!Top::has_pending_exception());
return Handle<Code>::null();
}
// Generate the full code for the function in bailout mode, using the same
// macro assembler.
CodeGenerator cgen(&masm);
CodeGeneratorScope scope(&cgen);
info->set_mode(CompilationInfo::SECONDARY);
cgen.Generate(info);
if (cgen.HasStackOverflow()) {
ASSERT(!Top::has_pending_exception());
return Handle<Code>::null();
}
Code::Flags flags = Code::ComputeFlags(Code::FUNCTION, NOT_IN_LOOP);
return CodeGenerator::MakeCodeEpilogue(&masm, flags, info);
}
Register FastCodeGenerator::accumulator0() { return eax; }
Register FastCodeGenerator::accumulator1() { return edx; }
Register FastCodeGenerator::scratch0() { return ecx; }
@ -155,20 +588,27 @@ void FastCodeGenerator::EmitBitOr() {
// commutative.
__ or_(destination(), Operand(other_accumulator(destination())));
}
} else if (destination().is(no_reg)) {
// Result is not needed but do not clobber the operands in case of
// bailout.
} else {
// Left is in accumulator1, right in accumulator0.
Label* bailout = NULL;
if (destination().is(accumulator0())) {
__ mov(scratch0(), accumulator0());
__ or_(destination(), Operand(accumulator1())); // Or is commutative.
__ test(destination(), Immediate(kSmiTagMask));
bailout = info()->AddBailout(accumulator1(), scratch0()); // Left, right.
} else if (destination().is(accumulator1())) {
__ mov(scratch0(), accumulator1());
__ or_(destination(), Operand(accumulator0()));
__ test(destination(), Immediate(kSmiTagMask));
bailout = info()->AddBailout(scratch0(), accumulator0());
} else {
ASSERT(destination().is(no_reg));
__ mov(scratch0(), accumulator1());
__ or_(scratch0(), Operand(accumulator0()));
__ test(scratch0(), Immediate(kSmiTagMask));
__ j(not_zero, bailout(), not_taken);
} else {
// Preserve the destination operand in a scratch register in case of
// bailout.
__ mov(scratch0(), destination());
__ or_(destination(), Operand(other_accumulator(destination())));
__ test(destination(), Immediate(kSmiTagMask));
__ j(not_zero, bailout(), not_taken);
bailout = info()->AddBailout(accumulator1(), accumulator0());
}
__ j(not_zero, bailout, not_taken);
}
// If we didn't bailout, the result (in fact, both inputs too) is known to
@ -191,6 +631,7 @@ void FastCodeGenerator::Generate(CompilationInfo* compilation_info) {
// Note that we keep a live register reference to esi (context) at this
// point.
Label* bailout_to_beginning = info()->AddBailout();
// Receiver (this) is allocated to a fixed register.
if (info()->has_this_properties()) {
Comment cmnt(masm(), ";; MapCheck(this)");
@ -201,7 +642,7 @@ void FastCodeGenerator::Generate(CompilationInfo* compilation_info) {
Handle<HeapObject> object = Handle<HeapObject>::cast(info()->receiver());
Handle<Map> map(object->map());
EmitLoadReceiver();
__ CheckMap(receiver_reg(), map, bailout(), false);
__ CheckMap(receiver_reg(), map, bailout_to_beginning, false);
}
// If there is a global variable access check if the global object is the
@ -214,7 +655,7 @@ void FastCodeGenerator::Generate(CompilationInfo* compilation_info) {
ASSERT(info()->has_global_object());
Handle<Map> map(info()->global_object()->map());
__ mov(scratch0(), CodeGenerator::GlobalObject());
__ CheckMap(scratch0(), map, bailout(), true);
__ CheckMap(scratch0(), map, bailout_to_beginning, true);
}
VisitStatements(function()->body());
@ -227,11 +668,286 @@ void FastCodeGenerator::Generate(CompilationInfo* compilation_info) {
__ mov(esp, ebp);
__ pop(ebp);
__ ret((scope()->num_parameters() + 1) * kPointerSize);
}
void FastCodeGenerator::VisitDeclaration(Declaration* decl) {
UNREACHABLE();
}
void FastCodeGenerator::VisitBlock(Block* stmt) {
VisitStatements(stmt->statements());
}
void FastCodeGenerator::VisitExpressionStatement(ExpressionStatement* stmt) {
Visit(stmt->expression());
}
void FastCodeGenerator::VisitEmptyStatement(EmptyStatement* stmt) {
// Nothing to do.
}
void FastCodeGenerator::VisitIfStatement(IfStatement* stmt) {
UNREACHABLE();
}
void FastCodeGenerator::VisitContinueStatement(ContinueStatement* stmt) {
UNREACHABLE();
}
void FastCodeGenerator::VisitBreakStatement(BreakStatement* stmt) {
UNREACHABLE();
}
void FastCodeGenerator::VisitReturnStatement(ReturnStatement* stmt) {
UNREACHABLE();
}
void FastCodeGenerator::VisitWithEnterStatement(WithEnterStatement* stmt) {
UNREACHABLE();
}
void FastCodeGenerator::VisitWithExitStatement(WithExitStatement* stmt) {
UNREACHABLE();
}
void FastCodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) {
UNREACHABLE();
}
void FastCodeGenerator::VisitDoWhileStatement(DoWhileStatement* stmt) {
UNREACHABLE();
}
void FastCodeGenerator::VisitWhileStatement(WhileStatement* stmt) {
UNREACHABLE();
}
void FastCodeGenerator::VisitForStatement(ForStatement* stmt) {
UNREACHABLE();
}
void FastCodeGenerator::VisitForInStatement(ForInStatement* stmt) {
UNREACHABLE();
}
void FastCodeGenerator::VisitTryCatchStatement(TryCatchStatement* stmt) {
UNREACHABLE();
}
void FastCodeGenerator::VisitTryFinallyStatement(TryFinallyStatement* stmt) {
UNREACHABLE();
}
void FastCodeGenerator::VisitDebuggerStatement(DebuggerStatement* stmt) {
UNREACHABLE();
}
void FastCodeGenerator::VisitFunctionLiteral(FunctionLiteral* expr) {
UNREACHABLE();
}
__ bind(&bailout_);
void FastCodeGenerator::VisitFunctionBoilerplateLiteral(
FunctionBoilerplateLiteral* expr) {
UNREACHABLE();
}
void FastCodeGenerator::VisitConditional(Conditional* expr) {
UNREACHABLE();
}
void FastCodeGenerator::VisitSlot(Slot* expr) {
UNREACHABLE();
}
void FastCodeGenerator::VisitVariableProxy(VariableProxy* expr) {
ASSERT(expr->var()->is_global() && !expr->var()->is_this());
// Check if we can compile a global variable load directly from the cell.
ASSERT(info()->has_global_object());
LookupResult lookup;
info()->global_object()->Lookup(*expr->name(), &lookup);
// We only support normal (non-accessor/interceptor) DontDelete properties
// for now.
ASSERT(lookup.IsProperty());
ASSERT_EQ(NORMAL, lookup.type());
ASSERT(lookup.IsDontDelete());
Handle<Object> cell(info()->global_object()->GetPropertyCell(&lookup));
// Global variable lookups do not have side effects, so we do not need to
// emit code if we are in an effect context.
if (!destination().is(no_reg)) {
Comment cmnt(masm(), ";; Global");
if (FLAG_print_ir) {
SmartPointer<char> name = expr->name()->ToCString();
PrintF("%d: t%d = Global(%s) // last_use = %d\n", expr->num(),
expr->num(), *name, expr->var_def()->last_use()->num());
}
EmitGlobalVariableLoad(cell);
}
}
void FastCodeGenerator::VisitLiteral(Literal* expr) {
UNREACHABLE();
}
void FastCodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) {
UNREACHABLE();
}
void FastCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
UNREACHABLE();
}
void FastCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
UNREACHABLE();
}
void FastCodeGenerator::VisitCatchExtensionObject(CatchExtensionObject* expr) {
UNREACHABLE();
}
void FastCodeGenerator::VisitAssignment(Assignment* expr) {
// Known to be a simple this property assignment. Effectively a unary
// operation.
{ Register my_destination = destination();
set_destination(accumulator0());
Visit(expr->value());
set_destination(my_destination);
}
Property* prop = expr->target()->AsProperty();
ASSERT_NOT_NULL(prop);
ASSERT_NOT_NULL(prop->obj()->AsVariableProxy());
ASSERT(prop->obj()->AsVariableProxy()->var()->is_this());
ASSERT(prop->key()->IsPropertyName());
Handle<String> name =
Handle<String>::cast(prop->key()->AsLiteral()->handle());
Comment cmnt(masm(), ";; Store to this");
if (FLAG_print_ir) {
SmartPointer<char> name_string = name->ToCString();
PrintF("%d: ", expr->num());
if (!destination().is(no_reg)) PrintF("t%d = ", expr->num());
PrintF("Store(this, \"%s\", t%d) // last_use(this) = %d\n", *name_string,
expr->value()->num(),
expr->var_def()->last_use()->num());
}
EmitThisPropertyStore(name);
}
void FastCodeGenerator::VisitThrow(Throw* expr) {
UNREACHABLE();
}
void FastCodeGenerator::VisitProperty(Property* expr) {
ASSERT_NOT_NULL(expr->obj()->AsVariableProxy());
ASSERT(expr->obj()->AsVariableProxy()->var()->is_this());
ASSERT(expr->key()->IsPropertyName());
if (!destination().is(no_reg)) {
Handle<String> name =
Handle<String>::cast(expr->key()->AsLiteral()->handle());
Comment cmnt(masm(), ";; Load from this");
if (FLAG_print_ir) {
SmartPointer<char> name_string = name->ToCString();
PrintF("%d: t%d = Load(this, \"%s\") // last_use(this) = %d\n",
expr->num(), expr->num(), *name_string,
expr->var_def()->last_use()->num());
}
EmitThisPropertyLoad(name);
}
}
void FastCodeGenerator::VisitCall(Call* expr) {
UNREACHABLE();
}
void FastCodeGenerator::VisitCallNew(CallNew* expr) {
UNREACHABLE();
}
void FastCodeGenerator::VisitCallRuntime(CallRuntime* expr) {
UNREACHABLE();
}
void FastCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
UNREACHABLE();
}
void FastCodeGenerator::VisitCountOperation(CountOperation* expr) {
UNREACHABLE();
}
void FastCodeGenerator::VisitBinaryOperation(BinaryOperation* expr) {
// We support limited binary operations: bitwise OR only allowed to be
// nested on the left.
ASSERT(expr->op() == Token::BIT_OR);
ASSERT(expr->right()->IsLeaf());
{ Register my_destination = destination();
set_destination(accumulator1());
Visit(expr->left());
set_destination(accumulator0());
Visit(expr->right());
set_destination(my_destination);
}
Comment cmnt(masm(), ";; BIT_OR");
if (FLAG_print_ir) {
PrintF("%d: ", expr->num());
if (!destination().is(no_reg)) PrintF("t%d = ", expr->num());
PrintF("BIT_OR(t%d, t%d)\n", expr->left()->num(), expr->right()->num());
}
EmitBitOr();
}
void FastCodeGenerator::VisitCompareOperation(CompareOperation* expr) {
UNREACHABLE();
}
void FastCodeGenerator::VisitThisFunction(ThisFunction* expr) {
UNREACHABLE();
}
#undef __

155
deps/v8/src/ia32/fast-codegen-ia32.h

@ -0,0 +1,155 @@
// 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.
#ifndef V8_FAST_CODEGEN_IA32_H_
#define V8_FAST_CODEGEN_IA32_H_
#include "v8.h"
#include "ast.h"
#include "compiler.h"
#include "list.h"
namespace v8 {
namespace internal {
class FastCodeGenSyntaxChecker: public AstVisitor {
public:
explicit FastCodeGenSyntaxChecker()
: info_(NULL), has_supported_syntax_(true) {
}
void Check(CompilationInfo* info);
CompilationInfo* info() { return info_; }
bool has_supported_syntax() { return has_supported_syntax_; }
private:
void VisitDeclarations(ZoneList<Declaration*>* decls);
void VisitStatements(ZoneList<Statement*>* stmts);
// AST node visit functions.
#define DECLARE_VISIT(type) virtual void Visit##type(type* node);
AST_NODE_LIST(DECLARE_VISIT)
#undef DECLARE_VISIT
CompilationInfo* info_;
bool has_supported_syntax_;
DISALLOW_COPY_AND_ASSIGN(FastCodeGenSyntaxChecker);
};
class FastCodeGenerator: public AstVisitor {
public:
explicit FastCodeGenerator(MacroAssembler* masm)
: masm_(masm), info_(NULL), destination_(no_reg), smi_bits_(0) {
}
static Handle<Code> MakeCode(CompilationInfo* info);
void Generate(CompilationInfo* compilation_info);
private:
MacroAssembler* masm() { return masm_; }
CompilationInfo* info() { return info_; }
Register destination() { return destination_; }
void set_destination(Register reg) { destination_ = reg; }
FunctionLiteral* function() { return info_->function(); }
Scope* scope() { return info_->scope(); }
// Platform-specific fixed registers, all guaranteed distinct.
Register accumulator0();
Register accumulator1();
Register scratch0();
Register scratch1();
Register receiver_reg();
Register context_reg();
Register other_accumulator(Register reg) {
ASSERT(reg.is(accumulator0()) || reg.is(accumulator1()));
return (reg.is(accumulator0())) ? accumulator1() : accumulator0();
}
// Flags are true if the respective register is statically known to hold a
// smi. We do not track every register, only the accumulator registers.
bool is_smi(Register reg) {
ASSERT(!reg.is(no_reg));
return (smi_bits_ & reg.bit()) != 0;
}
void set_as_smi(Register reg) {
ASSERT(!reg.is(no_reg));
smi_bits_ = smi_bits_ | reg.bit();
}
void clear_as_smi(Register reg) {
ASSERT(!reg.is(no_reg));
smi_bits_ = smi_bits_ & ~reg.bit();
}
// AST node visit functions.
#define DECLARE_VISIT(type) virtual void Visit##type(type* node);
AST_NODE_LIST(DECLARE_VISIT)
#undef DECLARE_VISIT
// Emit code to load the receiver from the stack into receiver_reg.
void EmitLoadReceiver();
// Emit code to load a global variable directly from a global property
// cell into the destination register.
void EmitGlobalVariableLoad(Handle<Object> cell);
// Emit a store to an own property of this. The stored value is expected
// in accumulator0 and the receiver in receiver_reg. The receiver
// register is preserved and the result (the stored value) is left in the
// destination register.
void EmitThisPropertyStore(Handle<String> name);
// Emit a load from an own property of this. The receiver is expected in
// receiver_reg. The receiver register is preserved and the result is
// left in the destination register.
void EmitThisPropertyLoad(Handle<String> name);
// Emit a bitwise or operation. The left operand is in accumulator1 and
// the right is in accumulator0. The result should be left in the
// destination register.
void EmitBitOr();
MacroAssembler* masm_;
CompilationInfo* info_;
Register destination_;
uint32_t smi_bits_;
DISALLOW_COPY_AND_ASSIGN(FastCodeGenerator);
};
} } // namespace v8::internal
#endif // V8_FAST_CODEGEN_IA32_H_

50
deps/v8/src/ia32/virtual-frame-ia32.cc

@ -948,27 +948,20 @@ Result VirtualFrame::CallKeyedLoadIC(RelocInfo::Mode mode) {
}
Result VirtualFrame::CallStoreIC() {
// Name, value, and receiver are on top of the frame. The IC
// expects name in ecx, value in eax, and receiver in edx.
Result VirtualFrame::CallStoreIC(Handle<String> name, bool is_contextual) {
// Value and (if not contextual) receiver are on top of the frame.
// The IC expects name in ecx, value in eax, and receiver in edx.
Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
Result name = Pop();
Result value = Pop();
if (is_contextual) {
PrepareForCall(0, 0);
value.ToRegister(eax);
__ mov(edx, Operand(esi, Context::SlotOffset(Context::GLOBAL_INDEX)));
__ mov(ecx, name);
} else {
Result receiver = Pop();
PrepareForCall(0, 0);
// Optimized for case in which name is a constant value.
if (name.is_register() && (name.reg().is(edx) || name.reg().is(eax))) {
if (!is_used(ecx)) {
name.ToRegister(ecx);
} else if (!is_used(ebx)) {
name.ToRegister(ebx);
} else {
ASSERT(!is_used(edi)); // Only three results are live, so edi is free.
name.ToRegister(edi);
}
}
// Now name is not in edx or eax, so we can fix them, then move name to ecx.
if (value.is_register() && value.reg().is(edx)) {
if (receiver.is_register() && receiver.reg().is(eax)) {
// Wrong registers.
@ -984,11 +977,9 @@ Result VirtualFrame::CallStoreIC() {
receiver.ToRegister(edx);
value.ToRegister(eax);
}
// Receiver and value are in the right place, so ecx is free for name.
name.ToRegister(ecx);
name.Unuse();
}
__ mov(ecx, name);
value.Unuse();
receiver.Unuse();
return RawCallCodeObject(ic, RelocInfo::CODE_TARGET);
}
@ -1175,6 +1166,25 @@ void VirtualFrame::EmitPush(Immediate immediate, NumberInfo::Type info) {
}
void VirtualFrame::Push(Expression* expr) {
ASSERT(expr->IsTrivial());
Literal* lit = expr->AsLiteral();
if (lit != NULL) {
Push(lit->handle());
return;
}
VariableProxy* proxy = expr->AsVariableProxy();
if (proxy != NULL && proxy->is_this()) {
PushParameterAt(-1);
return;
}
UNREACHABLE();
}
#undef __
} } // namespace v8::internal

12
deps/v8/src/ia32/virtual-frame-ia32.h

@ -339,12 +339,12 @@ class VirtualFrame: public ZoneObject {
Result CallLoadIC(RelocInfo::Mode mode);
// Call keyed load IC. Key and receiver are found on top of the
// frame. They are not dropped.
// frame. Both are dropped.
Result CallKeyedLoadIC(RelocInfo::Mode mode);
// Call store IC. Name, value, and receiver are found on top of the
// frame. Receiver is not dropped.
Result CallStoreIC();
// Call store IC. If the load is contextual, value is found on top of the
// frame. If not, value and receiver are on the frame. Both are dropped.
Result CallStoreIC(Handle<String> name, bool is_contextual);
// Call keyed store IC. Value, key, and receiver are found on top
// of the frame. Key and receiver are not dropped.
@ -415,6 +415,10 @@ class VirtualFrame: public ZoneObject {
result->Unuse();
}
// Pushing an expression expects that the expression is trivial (according
// to Expression::IsTrivial).
void Push(Expression* expr);
// Nip removes zero or more elements from immediately below the top
// of the frame, leaving the previous top-of-frame value on top of
// the frame. Nip(k) is equivalent to x = Pop(), Drop(k), Push(x).

2
deps/v8/src/jump-target-inl.h

@ -42,7 +42,7 @@ void JumpTarget::InitializeEntryElement(int index, FrameElement* target) {
} else if (target->is_copy()) {
entry_frame_->elements_[target->index()].set_copied();
}
if (direction_ == BIDIRECTIONAL) {
if (direction_ == BIDIRECTIONAL && !target->is_copy()) {
entry_frame_->elements_[index].set_number_info(NumberInfo::kUnknown);
}
}

2
deps/v8/src/jump-target.cc

@ -105,7 +105,6 @@ void JumpTarget::ComputeEntryFrame() {
FrameElement* other = &reaching_frames_[j]->elements_[i];
if (element != NULL && !element->is_copy()) {
ASSERT(other != NULL);
ASSERT(!other->is_copy());
// We overwrite the number information of one of the incoming frames.
// This is safe because we only use the frame for emitting merge code.
// The number information of incoming frames is not used anymore.
@ -128,7 +127,6 @@ void JumpTarget::ComputeEntryFrame() {
// elements as copied exactly when they have a copy. Undetermined
// elements are initially recorded as if in memory.
if (target != NULL) {
ASSERT(!target->is_copy()); // These initial elements are never copies.
entry_frame_->elements_[index] = *target;
InitializeEntryElement(index, target);
}

8
deps/v8/src/macros.py

@ -74,6 +74,10 @@ const kYearShift = 9;
const kMonthShift = 5;
# Type query macros.
#
# Note: We have special support for typeof(foo) === 'bar' in the compiler.
# It will *not* generate a runtime typeof call for the most important
# values of 'bar'.
macro IS_NULL(arg) = (arg === null);
macro IS_NULL_OR_UNDEFINED(arg) = (arg == null);
macro IS_UNDEFINED(arg) = (typeof(arg) === 'undefined');
@ -83,7 +87,7 @@ macro IS_BOOLEAN(arg) = (typeof(arg) === 'boolean');
macro IS_OBJECT(arg) = (%_IsObject(arg));
macro IS_ARRAY(arg) = (%_IsArray(arg));
macro IS_FUNCTION(arg) = (%_IsFunction(arg));
macro IS_REGEXP(arg) = (%_ClassOf(arg) === 'RegExp');
macro IS_REGEXP(arg) = (%_IsRegExp(arg));
macro IS_DATE(arg) = (%_ClassOf(arg) === 'Date');
macro IS_NUMBER_WRAPPER(arg) = (%_ClassOf(arg) === 'Number');
macro IS_STRING_WRAPPER(arg) = (%_ClassOf(arg) === 'String');
@ -100,6 +104,8 @@ macro NUMBER_IS_NAN(arg) = (!%_IsSmi(%IS_VAR(arg)) && !(arg == arg));
macro TO_INTEGER(arg) = (%_IsSmi(%IS_VAR(arg)) ? arg : ToInteger(arg));
macro TO_INT32(arg) = (%_IsSmi(%IS_VAR(arg)) ? arg : (arg >> 0));
macro TO_UINT32(arg) = (arg >>> 0);
macro TO_STRING_INLINE(arg) = (IS_STRING(%IS_VAR(arg)) ? arg : NonStringToString(arg));
# Macros implemented in Python.
python macro CHAR_CODE(str) = ord(str[1]);

11
deps/v8/src/mips/codegen-mips.cc

@ -305,6 +305,11 @@ void CodeGenerator::GenerateIsArray(ZoneList<Expression*>* args) {
}
void CodeGenerator::GenerateIsRegExp(ZoneList<Expression*>* args) {
UNIMPLEMENTED_MIPS();
}
void CodeGenerator::GenerateIsConstructCall(ZoneList<Expression*>* args) {
UNIMPLEMENTED_MIPS();
}
@ -365,6 +370,11 @@ void CodeGenerator::GenerateRegExpExec(ZoneList<Expression*>* args) {
}
void CodeGenerator::GenerateNumberToString(ZoneList<Expression*>* args) {
UNIMPLEMENTED_MIPS();
}
void CodeGenerator::VisitCallRuntime(CallRuntime* node) {
UNIMPLEMENTED_MIPS();
}
@ -498,4 +508,3 @@ int CompareStub::MinorKey() {
#undef __
} } // namespace v8::internal

4
deps/v8/src/mips/codegen-mips.h

@ -210,6 +210,7 @@ class CodeGenerator: public AstVisitor {
void GenerateIsSmi(ZoneList<Expression*>* args);
void GenerateIsNonNegativeSmi(ZoneList<Expression*>* args);
void GenerateIsArray(ZoneList<Expression*>* args);
void GenerateIsRegExp(ZoneList<Expression*>* args);
// Support for construct call checks.
void GenerateIsConstructCall(ZoneList<Expression*>* args);
@ -241,6 +242,8 @@ class CodeGenerator: public AstVisitor {
void GenerateSubString(ZoneList<Expression*>* args);
void GenerateStringCompare(ZoneList<Expression*>* args);
void GenerateRegExpExec(ZoneList<Expression*>* args);
void GenerateNumberToString(ZoneList<Expression*>* args);
// Fast support for Math.sin and Math.cos.
inline void GenerateMathSin(ZoneList<Expression*>* args);
@ -308,4 +311,3 @@ class CodeGenerator: public AstVisitor {
} } // namespace v8::internal
#endif // V8_MIPS_CODEGEN_MIPS_H_

31
deps/v8/src/mirror-delay.js

@ -553,14 +553,16 @@ StringMirror.prototype.length = function() {
return this.value_.length;
};
StringMirror.prototype.toText = function() {
if (this.length() > kMaxProtocolStringLength) {
return this.value_.substring(0, kMaxProtocolStringLength) +
StringMirror.prototype.getTruncatedValue = function(maxLength) {
if (maxLength != -1 && this.length() > maxLength) {
return this.value_.substring(0, maxLength) +
'... (length: ' + this.length() + ')';
} else {
}
return this.value_;
}
StringMirror.prototype.toText = function() {
return this.getTruncatedValue(kMaxProtocolStringLength);
}
@ -1955,6 +1957,15 @@ JSONProtocolSerializer.prototype.inlineRefs_ = function() {
}
JSONProtocolSerializer.prototype.maxStringLength_ = function() {
if (IS_UNDEFINED(this.options_) ||
IS_UNDEFINED(this.options_.maxStringLength)) {
return kMaxProtocolStringLength;
}
return this.options_.maxStringLength;
}
JSONProtocolSerializer.prototype.add_ = function(mirror) {
// If this mirror is already in the list just return.
for (var i = 0; i < this.mirrors_.length; i++) {
@ -1987,8 +1998,7 @@ JSONProtocolSerializer.prototype.serializeReferenceWithDisplayData_ =
o.value = mirror.value();
break;
case STRING_TYPE:
// Limit string length.
o.value = mirror.toText();
o.value = mirror.getTruncatedValue(this.maxStringLength_());
break;
case FUNCTION_TYPE:
o.name = mirror.name();
@ -2052,11 +2062,12 @@ JSONProtocolSerializer.prototype.serialize_ = function(mirror, reference,
case STRING_TYPE:
// String values might have their value cropped to keep down size.
if (mirror.length() > kMaxProtocolStringLength) {
var str = mirror.value().substring(0, kMaxProtocolStringLength);
if (this.maxStringLength_() != -1 &&
mirror.length() > this.maxStringLength_()) {
var str = mirror.getTruncatedValue(this.maxStringLength_());
content.value = str;
content.fromIndex = 0;
content.toIndex = kMaxProtocolStringLength;
content.toIndex = this.maxStringLength_();
} else {
content.value = mirror.value();
}

2
deps/v8/src/objects.h

@ -179,7 +179,7 @@ class PropertyDetails BASE_EMBEDDED {
class TypeField: public BitField<PropertyType, 0, 3> {};
class AttributesField: public BitField<PropertyAttributes, 3, 3> {};
class DeletedField: public BitField<uint32_t, 6, 1> {};
class IndexField: public BitField<uint32_t, 7, 31-7> {};
class IndexField: public BitField<uint32_t, 7, 32-7> {};
static const int kInitialIndex = 1;
private:

2
deps/v8/src/register-allocator.h

@ -141,7 +141,7 @@ class Result BASE_EMBEDDED {
class TypeField: public BitField<Type, 0, 2> {};
class NumberInfoField : public BitField<NumberInfo::Type, 2, 3> {};
class DataField: public BitField<uint32_t, 5, 32 - 6> {};
class DataField: public BitField<uint32_t, 5, 32 - 5> {};
inline void CopyTo(Result* destination) const;

128
deps/v8/src/runtime.cc

@ -2276,6 +2276,20 @@ static int SingleCharIndexOf(Vector<const schar> string,
return -1;
}
template <typename schar>
static int SingleCharLastIndexOf(Vector<const schar> string,
schar pattern_char,
int start_index) {
for (int i = start_index; i >= 0; i--) {
if (pattern_char == string[i]) {
return i;
}
}
return -1;
}
// Trivial string search for shorter strings.
// On return, if "complete" is set to true, the return value is the
// final result of searching for the patter in the subject.
@ -2352,7 +2366,7 @@ static int StringMatchStrategy(Vector<const schar> sub,
// We have an ASCII haystack and a non-ASCII needle. Check if there
// really is a non-ASCII character in the needle and bail out if there
// is.
if (sizeof(pchar) > 1 && sizeof(schar) == 1) {
if (sizeof(schar) == 1 && sizeof(pchar) > 1) {
for (int i = 0; i < pat.length(); i++) {
uc16 c = pat[i];
if (c > String::kMaxAsciiCharCode) {
@ -2455,40 +2469,116 @@ static Object* Runtime_StringIndexOf(Arguments args) {
}
template <typename schar, typename pchar>
static int StringMatchBackwards(Vector<const schar> sub,
Vector<const pchar> pat,
int idx) {
ASSERT(pat.length() >= 1);
ASSERT(idx + pat.length() <= sub.length());
if (sizeof(schar) == 1 && sizeof(pchar) > 1) {
for (int i = 0; i < pat.length(); i++) {
uc16 c = pat[i];
if (c > String::kMaxAsciiCharCode) {
return -1;
}
}
}
pchar pattern_first_char = pat[0];
for (int i = idx; i >= 0; i--) {
if (sub[i] != pattern_first_char) continue;
int j = 1;
while (j < pat.length()) {
if (pat[j] != sub[i+j]) {
break;
}
j++;
}
if (j == pat.length()) {
return i;
}
}
return -1;
}
static Object* Runtime_StringLastIndexOf(Arguments args) {
NoHandleAllocation ha;
HandleScope scope; // create a new handle scope
ASSERT(args.length() == 3);
CONVERT_CHECKED(String, sub, args[0]);
CONVERT_CHECKED(String, pat, args[1]);
Object* index = args[2];
sub->TryFlattenIfNotFlat();
pat->TryFlattenIfNotFlat();
CONVERT_ARG_CHECKED(String, sub, 0);
CONVERT_ARG_CHECKED(String, pat, 1);
Object* index = args[2];
uint32_t start_index;
if (!Array::IndexFromObject(index, &start_index)) return Smi::FromInt(-1);
uint32_t pattern_length = pat->length();
uint32_t pat_length = pat->length();
uint32_t sub_length = sub->length();
if (start_index + pattern_length > sub_length) {
start_index = sub_length - pattern_length;
if (start_index + pat_length > sub_length) {
start_index = sub_length - pat_length;
}
for (int i = start_index; i >= 0; i--) {
bool found = true;
for (uint32_t j = 0; j < pattern_length; j++) {
if (sub->Get(i + j) != pat->Get(j)) {
found = false;
break;
}
if (pat_length == 0) {
return Smi::FromInt(start_index);
}
if (found) return Smi::FromInt(i);
if (!sub->IsFlat()) {
FlattenString(sub);
}
if (pat_length == 1) {
AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
if (sub->IsAsciiRepresentation()) {
uc16 pchar = pat->Get(0);
if (pchar > String::kMaxAsciiCharCode) {
return Smi::FromInt(-1);
}
return Smi::FromInt(SingleCharLastIndexOf(sub->ToAsciiVector(),
static_cast<char>(pat->Get(0)),
start_index));
} else {
return Smi::FromInt(SingleCharLastIndexOf(sub->ToUC16Vector(),
pat->Get(0),
start_index));
}
}
if (!pat->IsFlat()) {
FlattenString(pat);
}
AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
int position = -1;
if (pat->IsAsciiRepresentation()) {
Vector<const char> pat_vector = pat->ToAsciiVector();
if (sub->IsAsciiRepresentation()) {
position = StringMatchBackwards(sub->ToAsciiVector(),
pat_vector,
start_index);
} else {
position = StringMatchBackwards(sub->ToUC16Vector(),
pat_vector,
start_index);
}
} else {
Vector<const uc16> pat_vector = pat->ToUC16Vector();
if (sub->IsAsciiRepresentation()) {
position = StringMatchBackwards(sub->ToAsciiVector(),
pat_vector,
start_index);
} else {
position = StringMatchBackwards(sub->ToUC16Vector(),
pat_vector,
start_index);
}
}
return Smi::FromInt(position);
}
static Object* Runtime_StringLocaleCompare(Arguments args) {

7
deps/v8/src/runtime.js

@ -529,6 +529,13 @@ function ToString(x) {
return (IS_NULL(x)) ? 'null' : %ToString(%DefaultString(x));
}
function NonStringToString(x) {
if (IS_NUMBER(x)) return %NumberToString(x);
if (IS_BOOLEAN(x)) return x ? 'true' : 'false';
if (IS_UNDEFINED(x)) return 'undefined';
return (IS_NULL(x)) ? 'null' : %ToString(%DefaultString(x));
}
// ECMA-262, section 9.9, page 36.
function ToObject(x) {

2
deps/v8/src/scopeinfo.cc

@ -536,7 +536,7 @@ int ContextSlotCache::Hash(Code* code, String* name) {
// Uses only lower 32 bits if pointers are larger.
uintptr_t addr_hash =
static_cast<uint32_t>(reinterpret_cast<uintptr_t>(code)) >> 2;
return (addr_hash ^ name->Hash()) % kLength;
return static_cast<int>((addr_hash ^ name->Hash()) % kLength);
}

4
deps/v8/src/serialize.cc

@ -852,10 +852,10 @@ void SnapshotByteSink::PutInt(uintptr_t integer, const char* description) {
const int max_shift = ((kPointerSize * kBitsPerByte) / 7) * 7;
for (int shift = max_shift; shift > 0; shift -= 7) {
if (integer >= static_cast<uintptr_t>(1u) << shift) {
Put(((integer >> shift) & 0x7f) | 0x80, "IntPart");
Put((static_cast<int>((integer >> shift)) & 0x7f) | 0x80, "IntPart");
}
}
PutSection(integer & 0x7f, "IntLastPart");
PutSection(static_cast<int>(integer & 0x7f), "IntLastPart");
}
#ifdef DEBUG

2
deps/v8/src/spaces-inl.h

@ -183,7 +183,7 @@ Page* MemoryAllocator::GetNextPage(Page* p) {
int MemoryAllocator::GetChunkId(Page* p) {
ASSERT(p->is_valid());
return p->opaque_header & Page::kPageAlignmentMask;
return static_cast<int>(p->opaque_header & Page::kPageAlignmentMask);
}

100
deps/v8/src/string.js

@ -34,7 +34,7 @@
// Set the String function and constructor.
%SetCode($String, function(x) {
var value = %_ArgumentsLength() == 0 ? '' : ToString(x);
var value = %_ArgumentsLength() == 0 ? '' : TO_STRING_INLINE(x);
if (%_IsConstructCall()) {
%_SetValueOf(this, value);
} else {
@ -64,7 +64,7 @@ function StringValueOf() {
function StringCharAt(pos) {
var char_code = %_FastCharCodeAt(this, pos);
if (!%_IsSmi(char_code)) {
var subject = ToString(this);
var subject = TO_STRING_INLINE(this);
var index = TO_INTEGER(pos);
if (index >= subject.length || index < 0) return "";
char_code = %StringCharCodeAt(subject, index);
@ -79,7 +79,7 @@ function StringCharCodeAt(pos) {
if (%_IsSmi(fast_answer)) {
return fast_answer;
}
var subject = ToString(this);
var subject = TO_STRING_INLINE(this);
var index = TO_INTEGER(pos);
return %StringCharCodeAt(subject, index);
}
@ -88,7 +88,7 @@ function StringCharCodeAt(pos) {
// ECMA-262, section 15.5.4.6
function StringConcat() {
var len = %_ArgumentsLength();
var this_as_string = IS_STRING(this) ? this : ToString(this);
var this_as_string = TO_STRING_INLINE(this);
if (len === 1) {
return this_as_string + %_Arguments(0);
}
@ -96,7 +96,7 @@ function StringConcat() {
parts[0] = this_as_string;
for (var i = 0; i < len; i++) {
var part = %_Arguments(i);
parts[i + 1] = IS_STRING(part) ? part : ToString(part);
parts[i + 1] = TO_STRING_INLINE(part);
}
return %StringBuilderConcat(parts, len + 1, "");
}
@ -107,8 +107,8 @@ function StringConcat() {
// ECMA-262 section 15.5.4.7
function StringIndexOf(searchString /* position */) { // length == 1
var subject_str = ToString(this);
var pattern_str = ToString(searchString);
var subject_str = TO_STRING_INLINE(this);
var pattern_str = TO_STRING_INLINE(searchString);
var subject_str_len = subject_str.length;
var pattern_str_len = pattern_str.length;
var index = 0;
@ -125,9 +125,9 @@ function StringIndexOf(searchString /* position */) { // length == 1
// ECMA-262 section 15.5.4.8
function StringLastIndexOf(searchString /* position */) { // length == 1
var sub = ToString(this);
var sub = TO_STRING_INLINE(this);
var subLength = sub.length;
var pat = ToString(searchString);
var pat = TO_STRING_INLINE(searchString);
var patLength = pat.length;
var index = subLength - patLength;
if (%_ArgumentsLength() > 1) {
@ -156,8 +156,8 @@ function StringLastIndexOf(searchString /* position */) { // length == 1
function StringLocaleCompare(other) {
if (%_ArgumentsLength() === 0) return 0;
var this_str = ToString(this);
var other_str = ToString(other);
var this_str = TO_STRING_INLINE(this);
var other_str = TO_STRING_INLINE(other);
return %StringLocaleCompare(this_str, other_str);
}
@ -165,7 +165,7 @@ function StringLocaleCompare(other) {
// ECMA-262 section 15.5.4.10
function StringMatch(regexp) {
if (!IS_REGEXP(regexp)) regexp = new ORIGINAL_REGEXP(regexp);
var subject = ToString(this);
var subject = TO_STRING_INLINE(this);
if (!regexp.global) return regexp.exec(subject);
%_Log('regexp', 'regexp-match,%0S,%1r', [subject, regexp]);
@ -200,7 +200,7 @@ var reusableMatchInfo = [2, "", "", -1, -1];
// ECMA-262, section 15.5.4.11
function StringReplace(search, replace) {
var subject = IS_STRING(this) ? this : ToString(this);
var subject = TO_STRING_INLINE(this);
// Delegate to one of the regular expression variants if necessary.
if (IS_REGEXP(search)) {
@ -213,7 +213,7 @@ function StringReplace(search, replace) {
}
// Convert the search argument to a string and search for it.
search = IS_STRING(search) ? search : ToString(search);
search = TO_STRING_INLINE(search);
var start = %StringIndexOf(subject, search, 0);
if (start < 0) return subject;
var end = start + search.length;
@ -228,7 +228,7 @@ function StringReplace(search, replace) {
} else {
reusableMatchInfo[CAPTURE0] = start;
reusableMatchInfo[CAPTURE1] = end;
if (!IS_STRING(replace)) replace = ToString(replace);
replace = TO_STRING_INLINE(replace);
ExpandReplacement(replace, subject, reusableMatchInfo, builder);
}
@ -241,7 +241,7 @@ function StringReplace(search, replace) {
// Helper function for regular expressions in String.prototype.replace.
function StringReplaceRegExp(subject, regexp, replace) {
replace = ToString(replace);
replace = TO_STRING_INLINE(replace);
return %StringReplaceRegExpWithString(subject,
regexp,
replace,
@ -462,7 +462,7 @@ function ApplyReplacementFunction(replace, matchInfo, subject) {
// ECMA-262 section 15.5.4.12
function StringSearch(re) {
var regexp = new ORIGINAL_REGEXP(re);
var s = ToString(this);
var s = TO_STRING_INLINE(this);
var last_idx = regexp.lastIndex; // keep old lastIndex
regexp.lastIndex = 0; // ignore re.global property
var result = regexp.exec(s);
@ -476,7 +476,7 @@ function StringSearch(re) {
// ECMA-262 section 15.5.4.13
function StringSlice(start, end) {
var s = ToString(this);
var s = TO_STRING_INLINE(this);
var s_len = s.length;
var start_i = TO_INTEGER(start);
var end_i = s_len;
@ -511,7 +511,7 @@ function StringSlice(start, end) {
// ECMA-262 section 15.5.4.14
function StringSplit(separator, limit) {
var subject = ToString(this);
var subject = TO_STRING_INLINE(this);
limit = (IS_UNDEFINED(limit)) ? 0xffffffff : TO_UINT32(limit);
if (limit === 0) return [];
@ -525,18 +525,35 @@ function StringSplit(separator, limit) {
}
var length = subject.length;
if (IS_REGEXP(separator)) {
%_Log('regexp', 'regexp-split,%0S,%1r', [subject, separator]);
} else {
separator = ToString(separator);
if (!IS_REGEXP(separator)) {
separator = TO_STRING_INLINE(separator);
var separator_length = separator.length;
// If the separator string is empty then return the elements in the subject.
if (separator.length == 0) {
if (separator_length === 0) {
var result = $Array(length);
for (var i = 0; i < length; i++) result[i] = subject[i];
return result;
}
var result = [];
var start_index = 0;
var index;
while (true) {
if (start_index + separator_length > length ||
(index = %StringIndexOf(subject, separator, start_index)) === -1) {
result.push(SubString(subject, start_index, length));
break;
}
if (result.push(SubString(subject, start_index, index)) === limit) break;
start_index = index + separator_length;
}
return result;
}
%_Log('regexp', 'regexp-split,%0S,%1r', [subject, separator]);
if (length === 0) {
if (splitMatch(separator, subject, 0, 0) != null) return [];
return [subject];
@ -571,7 +588,8 @@ function StringSplit(separator, limit) {
result[result.length] = SubString(subject, currentIndex, matchInfo[CAPTURE0]);
if (result.length === limit) return result;
for (var i = 2; i < NUMBER_OF_CAPTURES(matchInfo); i += 2) {
var num_captures = NUMBER_OF_CAPTURES(matchInfo);
for (var i = 2; i < num_captures; i += 2) {
var start = matchInfo[CAPTURE(i)];
var end = matchInfo[CAPTURE(i + 1)];
if (start != -1 && end != -1) {
@ -591,7 +609,6 @@ function StringSplit(separator, limit) {
// Helper function used by split. This version returns the matchInfo
// instead of allocating a new array with basically the same information.
function splitMatch(separator, subject, current_index, start_index) {
if (IS_REGEXP(separator)) {
var matchInfo = DoRegExpExec(separator, subject, start_index);
if (matchInfo == null) return null;
// Section 15.5.4.14 paragraph two says that we do not allow zero length
@ -600,19 +617,10 @@ function splitMatch(separator, subject, current_index, start_index) {
return matchInfo;
}
var separatorIndex = subject.indexOf(separator, start_index);
if (separatorIndex === -1) return null;
reusableMatchInfo[CAPTURE0] = separatorIndex;
reusableMatchInfo[CAPTURE1] = separatorIndex + separator.length;
return reusableMatchInfo;
};
// ECMA-262 section 15.5.4.15
function StringSubstring(start, end) {
var s = this;
if (!IS_STRING(s)) s = ToString(s);
var s = TO_STRING_INLINE(this);
var s_len = s.length;
var start_i = TO_INTEGER(start);
@ -643,7 +651,7 @@ function StringSubstring(start, end) {
// This is not a part of ECMA-262.
function StringSubstr(start, n) {
var s = ToString(this);
var s = TO_STRING_INLINE(this);
var len;
// Correct n: If not given, set to string length; if explicitly
@ -681,38 +689,38 @@ function StringSubstr(start, n) {
// ECMA-262, 15.5.4.16
function StringToLowerCase() {
return %StringToLowerCase(ToString(this));
return %StringToLowerCase(TO_STRING_INLINE(this));
}
// ECMA-262, 15.5.4.17
function StringToLocaleLowerCase() {
return %StringToLowerCase(ToString(this));
return %StringToLowerCase(TO_STRING_INLINE(this));
}
// ECMA-262, 15.5.4.18
function StringToUpperCase() {
return %StringToUpperCase(ToString(this));
return %StringToUpperCase(TO_STRING_INLINE(this));
}
// ECMA-262, 15.5.4.19
function StringToLocaleUpperCase() {
return %StringToUpperCase(ToString(this));
return %StringToUpperCase(TO_STRING_INLINE(this));
}
// ES5, 15.5.4.20
function StringTrim() {
return %StringTrim(ToString(this), true, true);
return %StringTrim(TO_STRING_INLINE(this), true, true);
}
function StringTrimLeft() {
return %StringTrim(ToString(this), true, false);
return %StringTrim(TO_STRING_INLINE(this), true, false);
}
function StringTrimRight() {
return %StringTrim(ToString(this), false, true);
return %StringTrim(TO_STRING_INLINE(this), false, true);
}
// ECMA-262, section 15.5.3.2
@ -731,7 +739,7 @@ function StringFromCharCode(code) {
// Helper function for very basic XSS protection.
function HtmlEscape(str) {
return ToString(str).replace(/</g, "&lt;")
return TO_STRING_INLINE(str).replace(/</g, "&lt;")
.replace(/>/g, "&gt;")
.replace(/"/g, "&quot;")
.replace(/'/g, "&#039;");
@ -813,7 +821,7 @@ function ReplaceResultBuilder(str) {
ReplaceResultBuilder.prototype.add = function(str) {
if (!IS_STRING(str)) str = ToString(str);
str = TO_STRING_INLINE(str);
if (str.length > 0) {
var elements = this.elements;
elements[elements.length] = str;

14
deps/v8/src/stub-cache.cc

@ -105,7 +105,7 @@ Object* StubCache::ComputeLoadField(String* name,
if (code->IsFailure()) return code;
LOG(CodeCreateEvent(Logger::LOAD_IC_TAG, Code::cast(code), name));
Object* result = receiver->map()->UpdateCodeCache(name, Code::cast(code));
if (result->IsFailure()) return code;
if (result->IsFailure()) return result;
}
return Set(name, receiver->map(), Code::cast(code));
}
@ -124,7 +124,7 @@ Object* StubCache::ComputeLoadCallback(String* name,
if (code->IsFailure()) return code;
LOG(CodeCreateEvent(Logger::LOAD_IC_TAG, Code::cast(code), name));
Object* result = receiver->map()->UpdateCodeCache(name, Code::cast(code));
if (result->IsFailure()) return code;
if (result->IsFailure()) return result;
}
return Set(name, receiver->map(), Code::cast(code));
}
@ -143,7 +143,7 @@ Object* StubCache::ComputeLoadConstant(String* name,
if (code->IsFailure()) return code;
LOG(CodeCreateEvent(Logger::LOAD_IC_TAG, Code::cast(code), name));
Object* result = receiver->map()->UpdateCodeCache(name, Code::cast(code));
if (result->IsFailure()) return code;
if (result->IsFailure()) return result;
}
return Set(name, receiver->map(), Code::cast(code));
}
@ -160,7 +160,7 @@ Object* StubCache::ComputeLoadInterceptor(String* name,
if (code->IsFailure()) return code;
LOG(CodeCreateEvent(Logger::LOAD_IC_TAG, Code::cast(code), name));
Object* result = receiver->map()->UpdateCodeCache(name, Code::cast(code));
if (result->IsFailure()) return code;
if (result->IsFailure()) return result;
}
return Set(name, receiver->map(), Code::cast(code));
}
@ -189,7 +189,7 @@ Object* StubCache::ComputeLoadGlobal(String* name,
if (code->IsFailure()) return code;
LOG(CodeCreateEvent(Logger::LOAD_IC_TAG, Code::cast(code), name));
Object* result = receiver->map()->UpdateCodeCache(name, Code::cast(code));
if (result->IsFailure()) return code;
if (result->IsFailure()) return result;
}
return Set(name, receiver->map(), Code::cast(code));
}
@ -351,7 +351,7 @@ Object* StubCache::ComputeStoreGlobal(String* name,
if (code->IsFailure()) return code;
LOG(CodeCreateEvent(Logger::LOAD_IC_TAG, Code::cast(code), name));
Object* result = receiver->map()->UpdateCodeCache(name, Code::cast(code));
if (result->IsFailure()) return code;
if (result->IsFailure()) return result;
}
return Set(name, receiver->map(), Code::cast(code));
}
@ -566,7 +566,7 @@ Object* StubCache::ComputeCallGlobal(int argc,
ASSERT_EQ(flags, Code::cast(code)->flags());
LOG(CodeCreateEvent(Logger::CALL_IC_TAG, Code::cast(code), name));
Object* result = receiver->map()->UpdateCodeCache(name, Code::cast(code));
if (result->IsFailure()) return code;
if (result->IsFailure()) return result;
}
return Set(name, receiver->map(), Code::cast(code));
}

6
deps/v8/src/utils.h

@ -157,7 +157,9 @@ class BitField {
// Returns a uint32_t mask of bit field.
static uint32_t mask() {
return (1U << (size + shift)) - (1U << shift);
// To use all bits of a uint32 in a bitfield without compiler warnings we
// have to compute 2^32 without using a shift count of 32.
return ((1U << shift) << size) - (1U << shift);
}
// Returns a uint32_t with the bit field value encoded.
@ -168,7 +170,7 @@ class BitField {
// Extracts the bit field from the value.
static T decode(uint32_t value) {
return static_cast<T>((value >> shift) & ((1U << (size)) - 1));
return static_cast<T>((value & mask()) >> shift);
}
};

4
deps/v8/src/version.cc

@ -34,8 +34,8 @@
// cannot be changed without changing the SCons build script.
#define MAJOR_VERSION 2
#define MINOR_VERSION 1
#define BUILD_NUMBER 1
#define PATCH_LEVEL 1
#define BUILD_NUMBER 2
#define PATCH_LEVEL 0
#define CANDIDATE_VERSION false
// Define SONAME to have the SCons build the put a specific SONAME into the

40
deps/v8/src/x64/assembler-x64.cc

@ -33,46 +33,6 @@
namespace v8 {
namespace internal {
// -----------------------------------------------------------------------------
// Implementation of Register
Register rax = { 0 };
Register rcx = { 1 };
Register rdx = { 2 };
Register rbx = { 3 };
Register rsp = { 4 };
Register rbp = { 5 };
Register rsi = { 6 };
Register rdi = { 7 };
Register r8 = { 8 };
Register r9 = { 9 };
Register r10 = { 10 };
Register r11 = { 11 };
Register r12 = { 12 };
Register r13 = { 13 };
Register r14 = { 14 };
Register r15 = { 15 };
Register no_reg = { -1 };
XMMRegister xmm0 = { 0 };
XMMRegister xmm1 = { 1 };
XMMRegister xmm2 = { 2 };
XMMRegister xmm3 = { 3 };
XMMRegister xmm4 = { 4 };
XMMRegister xmm5 = { 5 };
XMMRegister xmm6 = { 6 };
XMMRegister xmm7 = { 7 };
XMMRegister xmm8 = { 8 };
XMMRegister xmm9 = { 9 };
XMMRegister xmm10 = { 10 };
XMMRegister xmm11 = { 11 };
XMMRegister xmm12 = { 12 };
XMMRegister xmm13 = { 13 };
XMMRegister xmm14 = { 14 };
XMMRegister xmm15 = { 15 };
// -----------------------------------------------------------------------------
// Implementation of CpuFeatures

94
deps/v8/src/x64/assembler-x64.h

@ -118,51 +118,23 @@ struct Register {
int code_;
};
extern Register rax;
extern Register rcx;
extern Register rdx;
extern Register rbx;
extern Register rsp;
extern Register rbp;
extern Register rsi;
extern Register rdi;
extern Register r8;
extern Register r9;
extern Register r10;
extern Register r11;
extern Register r12;
extern Register r13;
extern Register r14;
extern Register r15;
extern Register no_reg;
struct MMXRegister {
bool is_valid() const { return 0 <= code_ && code_ < 2; }
int code() const {
ASSERT(is_valid());
return code_;
}
int code_;
};
extern MMXRegister mm0;
extern MMXRegister mm1;
extern MMXRegister mm2;
extern MMXRegister mm3;
extern MMXRegister mm4;
extern MMXRegister mm5;
extern MMXRegister mm6;
extern MMXRegister mm7;
extern MMXRegister mm8;
extern MMXRegister mm9;
extern MMXRegister mm10;
extern MMXRegister mm11;
extern MMXRegister mm12;
extern MMXRegister mm13;
extern MMXRegister mm14;
extern MMXRegister mm15;
const Register rax = { 0 };
const Register rcx = { 1 };
const Register rdx = { 2 };
const Register rbx = { 3 };
const Register rsp = { 4 };
const Register rbp = { 5 };
const Register rsi = { 6 };
const Register rdi = { 7 };
const Register r8 = { 8 };
const Register r9 = { 9 };
const Register r10 = { 10 };
const Register r11 = { 11 };
const Register r12 = { 12 };
const Register r13 = { 13 };
const Register r14 = { 14 };
const Register r15 = { 15 };
const Register no_reg = { -1 };
struct XMMRegister {
@ -186,22 +158,22 @@ struct XMMRegister {
int code_;
};
extern XMMRegister xmm0;
extern XMMRegister xmm1;
extern XMMRegister xmm2;
extern XMMRegister xmm3;
extern XMMRegister xmm4;
extern XMMRegister xmm5;
extern XMMRegister xmm6;
extern XMMRegister xmm7;
extern XMMRegister xmm8;
extern XMMRegister xmm9;
extern XMMRegister xmm10;
extern XMMRegister xmm11;
extern XMMRegister xmm12;
extern XMMRegister xmm13;
extern XMMRegister xmm14;
extern XMMRegister xmm15;
const XMMRegister xmm0 = { 0 };
const XMMRegister xmm1 = { 1 };
const XMMRegister xmm2 = { 2 };
const XMMRegister xmm3 = { 3 };
const XMMRegister xmm4 = { 4 };
const XMMRegister xmm5 = { 5 };
const XMMRegister xmm6 = { 6 };
const XMMRegister xmm7 = { 7 };
const XMMRegister xmm8 = { 8 };
const XMMRegister xmm9 = { 9 };
const XMMRegister xmm10 = { 10 };
const XMMRegister xmm11 = { 11 };
const XMMRegister xmm12 = { 12 };
const XMMRegister xmm13 = { 13 };
const XMMRegister xmm14 = { 14 };
const XMMRegister xmm15 = { 15 };
enum Condition {
// any value < 0 is considered no_condition

26
deps/v8/src/x64/codegen-x64.cc

@ -277,7 +277,7 @@ void CodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) {
}
void CodeGenerator::Generate(CompilationInfo* info, Mode mode) {
void CodeGenerator::Generate(CompilationInfo* info) {
// Record the position for debugging purposes.
CodeForFunctionPosition(info->function());
@ -316,7 +316,7 @@ void CodeGenerator::Generate(CompilationInfo* info, Mode mode) {
// rsi: callee's context
allocator_->Initialize();
if (mode == PRIMARY) {
if (info->mode() == CompilationInfo::PRIMARY) {
frame_->Enter();
// Allocate space for locals and initialize them.
@ -407,6 +407,12 @@ void CodeGenerator::Generate(CompilationInfo* info, Mode mode) {
// frame to match this state.
frame_->Adjust(3);
allocator_->Unuse(rdi);
// Bind all the bailout labels to the beginning of the function.
List<CompilationInfo::Bailout*>* bailouts = info->bailouts();
for (int i = 0; i < bailouts->length(); i++) {
__ bind(bailouts->at(i)->label());
}
}
// Initialize the function return target after the locals are set
@ -3627,6 +3633,22 @@ void CodeGenerator::GenerateIsArray(ZoneList<Expression*>* args) {
}
void CodeGenerator::GenerateIsRegExp(ZoneList<Expression*>* args) {
ASSERT(args->length() == 1);
Load(args->at(0));
Result value = frame_->Pop();
value.ToRegister();
ASSERT(value.is_valid());
Condition is_smi = masm_->CheckSmi(value.reg());
destination()->false_target()->Branch(is_smi);
// It is a heap object - get map.
// Check if the object is a regexp.
__ CmpObjectType(value.reg(), JS_REGEXP_TYPE, kScratchRegister);
value.Unuse();
destination()->Split(equal);
}
void CodeGenerator::GenerateIsObject(ZoneList<Expression*>* args) {
// This generates a fast version of:
// (typeof(arg) === 'object' || %_ClassOf(arg) == 'RegExp')

12
deps/v8/src/x64/codegen-x64.h

@ -294,15 +294,6 @@ enum ArgumentsAllocationMode {
class CodeGenerator: public AstVisitor {
public:
// Compilation mode. Either the compiler is used as the primary
// compiler and needs to setup everything or the compiler is used as
// the secondary compiler for split compilation and has to handle
// bailouts.
enum Mode {
PRIMARY,
SECONDARY
};
// Takes a function literal, generates code for it. This function should only
// be called by compiler.cc.
static Handle<Code> MakeCode(CompilationInfo* info);
@ -385,7 +376,7 @@ class CodeGenerator: public AstVisitor {
void VisitStatementsAndSpill(ZoneList<Statement*>* statements);
// Main code generation function
void Generate(CompilationInfo* info, Mode mode);
void Generate(CompilationInfo* info);
// Generate the return sequence code. Should be called no more than
// once per compiled function, immediately after binding the return
@ -536,6 +527,7 @@ class CodeGenerator: public AstVisitor {
void GenerateIsSmi(ZoneList<Expression*>* args);
void GenerateIsNonNegativeSmi(ZoneList<Expression*>* args);
void GenerateIsArray(ZoneList<Expression*>* args);
void GenerateIsRegExp(ZoneList<Expression*>* args);
void GenerateIsObject(ZoneList<Expression*>* args);
void GenerateIsFunction(ZoneList<Expression*>* args);
void GenerateIsUndetectableObject(ZoneList<Expression*>* args);

36
deps/v8/src/x64/fast-codegen-x64.cc

@ -156,20 +156,27 @@ void FastCodeGenerator::EmitBitOr() {
// commutative.
__ or_(destination(), other_accumulator(destination()));
}
} else if (destination().is(no_reg)) {
// Result is not needed but do not clobber the operands in case of
// bailout.
} else {
// Left is in accumulator1, right in accumulator0.
if (destination().is(accumulator0())) {
__ movq(scratch0(), accumulator0());
__ or_(destination(), accumulator1()); // Or is commutative.
Label* bailout =
info()->AddBailout(accumulator1(), scratch0()); // Left, right.
__ JumpIfNotSmi(destination(), bailout);
} else if (destination().is(accumulator1())) {
__ movq(scratch0(), accumulator1());
__ or_(scratch0(), accumulator0());
__ JumpIfNotSmi(scratch0(), bailout());
__ or_(destination(), accumulator0());
Label* bailout = info()->AddBailout(scratch0(), accumulator0());
__ JumpIfNotSmi(destination(), bailout);
} else {
// Preserve the destination operand in a scratch register in case of
// bailout.
__ movq(scratch0(), destination());
__ or_(destination(), other_accumulator(destination()));
__ JumpIfNotSmi(destination(), bailout());
ASSERT(destination().is(no_reg));
__ movq(scratch0(), accumulator1());
__ or_(scratch0(), accumulator0());
Label* bailout = info()->AddBailout(accumulator1(), accumulator0());
__ JumpIfNotSmi(scratch0(), bailout);
}
}
// If we didn't bailout, the result (in fact, both inputs too) is known to
// be a smi.
@ -191,6 +198,7 @@ void FastCodeGenerator::Generate(CompilationInfo* compilation_info) {
// Note that we keep a live register reference to esi (context) at this
// point.
Label* bailout_to_beginning = info()->AddBailout();
// Receiver (this) is allocated to a fixed register.
if (info()->has_this_properties()) {
Comment cmnt(masm(), ";; MapCheck(this)");
@ -201,7 +209,7 @@ void FastCodeGenerator::Generate(CompilationInfo* compilation_info) {
Handle<HeapObject> object = Handle<HeapObject>::cast(info()->receiver());
Handle<Map> map(object->map());
EmitLoadReceiver();
__ CheckMap(receiver_reg(), map, bailout(), false);
__ CheckMap(receiver_reg(), map, bailout_to_beginning, false);
}
// If there is a global variable access check if the global object is the
@ -214,7 +222,7 @@ void FastCodeGenerator::Generate(CompilationInfo* compilation_info) {
ASSERT(info()->has_global_object());
Handle<Map> map(info()->global_object()->map());
__ movq(scratch0(), CodeGenerator::GlobalObject());
__ CheckMap(scratch0(), map, bailout(), true);
__ CheckMap(scratch0(), map, bailout_to_beginning, true);
}
VisitStatements(info()->function()->body());
@ -227,8 +235,6 @@ void FastCodeGenerator::Generate(CompilationInfo* compilation_info) {
__ movq(rsp, rbp);
__ pop(rbp);
__ ret((scope()->num_parameters() + 1) * kPointerSize);
__ bind(&bailout_);
}

2
deps/v8/src/x64/macro-assembler-x64.h

@ -36,7 +36,7 @@ namespace internal {
// Default scratch register used by MacroAssembler (and other code that needs
// a spare register). The register isn't callee save, and not used by the
// function calling convention.
static const Register kScratchRegister = r10;
static const Register kScratchRegister = { 10 }; // r10.
// Convenience for platform-independent signatures.
typedef Operand MemOperand;

62
deps/v8/test/mjsunit/bugs/bug-619.js

@ -0,0 +1,62 @@
// 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.
// When this bug is corrected move to object-define-property and add
// additional tests for configurable in the same manner as existing tests
// there.
var obj = {};
obj[1] = 42;
assertEquals(42, obj[1]);
Object.defineProperty(obj, '1', {value:10, writable:false});
assertEquals(10, obj[1]);
// We should not be able to override obj[1].
obj[1] = 5;
assertEquals(10, obj[1]);
// Try on a range of numbers.
for(var i = 0; i < 1024; i++) {
obj[i] = 42;
}
for(var i = 0; i < 1024; i++) {
Object.defineProperty(obj, i, {value: i, writable:false});
}
for(var i = 0; i < 1024; i++) {
assertEquals(i, obj[i]);
}
for(var i = 0; i < 1024; i++) {
obj[1] = 5;
}
for(var i = 0; i < 1024; i++) {
assertEquals(i, obj[i]);
}

37
deps/v8/test/mjsunit/debug-evaluate.js

@ -87,6 +87,37 @@ function listener(event, exec_state, event_data, data) {
testRequest(dcp, '{"expression":"a","global":true}', true, 1);
testRequest(dcp, '{"expression":"this.a","global":true}', true, 1);
// Test that the whole string text is returned if maxStringLength
// parameter is passed.
testRequest(
dcp,
'{"expression":"this.longString","global":true,maxStringLength:-1}',
true,
longString);
testRequest(
dcp,
'{"expression":"this.longString","global":true,maxStringLength:' +
longString.length + '}',
true,
longString);
var truncatedStringSuffix = '... (length: ' + longString.length + ')';
testRequest(
dcp,
'{"expression":"this.longString","global":true,maxStringLength:0}',
true,
truncatedStringSuffix);
testRequest(
dcp,
'{"expression":"this.longString","global":true,maxStringLength:1}',
true,
longString.charAt(0) + truncatedStringSuffix);
// Test that by default string is truncated to first 80 chars.
testRequest(
dcp,
'{"expression":"this.longString","global":true}',
true,
longString.substring(0, 80) + truncatedStringSuffix);
// Indicate that all was processed.
listenerComplete = true;
}
@ -109,6 +140,12 @@ function g() {
a = 1;
// String which is longer than 80 chars.
var longString = "1234567890_";
for (var i = 0; i < 4; i++) {
longString += longString;
}
// Set a break point at return in f and invoke g to hit the breakpoint.
Debug.setBreakPoint(f, 2, 0);
g();

4
deps/v8/tools/gyp/v8.gyp

@ -269,7 +269,6 @@
'../../src/execution.h',
'../../src/factory.cc',
'../../src/factory.h',
'../../src/fast-codegen.cc',
'../../src/fast-codegen.h',
'../../src/flag-definitions.h',
'../../src/flags.cc',
@ -404,6 +403,7 @@
'../../src/arm',
],
'sources': [
'../../src/fast-codegen.cc',
'../../src/arm/assembler-arm-inl.h',
'../../src/arm/assembler-arm.cc',
'../../src/arm/assembler-arm.h',
@ -455,6 +455,7 @@
'../../src/ia32/debug-ia32.cc',
'../../src/ia32/disasm-ia32.cc',
'../../src/ia32/fast-codegen-ia32.cc',
'../../src/ia32/fast-codegen-ia32.h',
'../../src/ia32/frames-ia32.cc',
'../../src/ia32/frames-ia32.h',
'../../src/ia32/full-codegen-ia32.cc',
@ -475,6 +476,7 @@
'../../src/x64',
],
'sources': [
'../../src/fast-codegen.cc',
'../../src/x64/assembler-x64-inl.h',
'../../src/x64/assembler-x64.cc',
'../../src/x64/assembler-x64.h',

2
deps/v8/tools/visual_studio/v8_base.vcproj

@ -401,7 +401,7 @@
>
</File>
<File
RelativePath="..\..\src\fast-codegen.cc"
RelativePath="..\..\src\ia32\fast-codegen-ia32.h"
>
</File>
<File

98
doc/api.txt

@ -19,7 +19,7 @@ World":
var sys = require("sys"),
http = require("http");
http.createServer(function (request, response) {
response.writeHeader(200, {"Content-Type": "text/plain"});
response.writeHead(200, {"Content-Type": "text/plain"});
response.write("Hello World\n");
response.close();
}).listen(8000);
@ -113,11 +113,10 @@ What platform you're running on. +"linux2"+, +"darwin"+, etc.
Returns the memory usage of the Node process. It looks like this
+
----------------------
{
"rss": 4935680,
"vsize": 41893888,
"heapTotal": 1826816,
"heapUsed": 650472
{ rss: 4935680
, vsize: 41893888
, heapTotal: 1826816
, heapUsed: 650472
}
----------------------
+
@ -138,6 +137,9 @@ Returns the current working directory of the process.
+process.getuid(), process.setuid(id)+::
Gets/sets the user identity of the process. (See setuid(2).)
+process.getgid(), process.setgid(id)+::
Gets/sets the group identity of the process. (See setgid(2).)
+process.chdir(directory)+::
Changes the current working directory of the process.
@ -198,17 +200,30 @@ These function are in the module +"sys"+. Use +require("sys")+ to access
them.
+puts(string)+::
Outputs the +string+ and a trailing new-line to +stdout+.
Outputs +string+ and a trailing new-line to +stdout+.
+print(string)+::
Like +puts()+ but without the trailing new-line.
+debug(string)+::
A synchronous output function. Will block the process and
output the string immediately to stdout.
output +string+ immediately to +stdout+.
+inspect(object, showHidden, depth)+ ::
Return a string representation of +object+. (For debugging.)
+
If +showHidden+ is +true+, then the object's non-enumerable properties will be
shown too.
+
If +depth+ is provided, it tells +inspect+ how many times to recurse while
formatting the object. This is useful for inspecting large complicated objects.
The default is to only recurse twice. To make it recurse indefinitely, pass
in +null+ for +depth+.
+inspect(object, showHidden)+ ::
Return a string representation of the +object+. (For debugging.) If showHidden is true, then the object's non-enumerable properties will be shown too.
+exec(command, callback)+::
Executes the command as a child process, buffers the output and returns it
@ -227,7 +242,6 @@ will be +null+. On error +err+ will be an instance of +Error+ and +err.code+
will be the exit code of the child process.
== Events
Many objects in Node emit events: a TCP server emits an event each time
@ -608,6 +622,30 @@ See the +fs.Stats+ section below for more information.
Synchronous stat(2) or lstat(2). Returns an instance of +fs.Stats+.
+fs.link(srcpath, dstpath, callback)+ ::
Asynchronous link(2).
No arguments other than a possible exception are given to the completion callback.
+fs.linkSync(dstpath, srcpath)+ ::
Synchronous link(2).
+fs.symlink(linkdata, path, callback)+ ::
Asynchronous symlink(2).
No arguments other than a possible exception are given to the completion callback.
+fs.symlinkSync(linkdata, path)+ ::
Synchronous symlink(2).
+fs.readlink(path, callback)+ ::
Asynchronous readlink(2).
The callback gets two arguments +(err, resolvedPath)+.
+fs.readlinkSync(path)+ ::
Synchronous readlink(2). Returns the resolved path.
+fs.unlink(path, callback)+ ::
Asynchronous unlink(2).
No arguments other than a possible exception are given to the completion callback.
@ -867,11 +905,10 @@ If you would like to parse the URL into its parts, you can use
+
----------------------------------------
node> require("url").parse("/status?name=ryan")
{
"href": "/status?name=ryan",
"search": "?name=ryan",
"query": "name=ryan",
"pathname": "/status"
{ href: '/status?name=ryan'
, search: '?name=ryan'
, query: 'name=ryan'
, pathname: '/status'
}
----------------------------------------
+
@ -881,13 +918,10 @@ you can use the +require("querystring").parse+ function, or pass
+
----------------------------------------
node> require("url").parse("/status?name=ryan", true)
{
"href": "/status?name=ryan",
"search": "?name=ryan",
"query": {
"name": "ryan"
},
"pathname": "/status"
{ href: '/status?name=ryan'
, search: '?name=ryan'
, query: { name: 'ryan' }
, pathname: '/status'
}
----------------------------------------
+
@ -924,7 +958,7 @@ The +http.Connection+ object.
This object is created internally by a HTTP server--not by the user. It is
passed as the second parameter to the +"request"+ event.
+response.writeHeader(statusCode[, reasonPhrase] , headers)+ ::
+response.writeHead(statusCode[, reasonPhrase] , headers)+ ::
Sends a response header to the request. The status code is a 3-digit HTTP
status code, like +404+. The last argument, +headers+, are the response headers.
@ -935,7 +969,7 @@ Example:
+
----------------------------------------
var body = "hello world";
response.writeHeader(200, {
response.writeHead(200, {
"Content-Length": body.length,
"Content-Type": "text/plain"
});
@ -946,7 +980,7 @@ be called before +response.close()+ is called.
+response.write(chunk, encoding="ascii")+ ::
This method must be called after +writeHeader+ was
This method must be called after +writeHead+ was
called. It sends a chunk of the response body. This method may
be called multiple times to provide successive parts of the body.
+
@ -1270,7 +1304,7 @@ http.createServer(function (req, res) {
fields = {},
name, filename;
mp.addListener("error", function (er) {
res.writeHeader(400, {"content-type":"text/plain"});
res.writeHead(400, {"content-type":"text/plain"});
res.write("You sent a bad message!\n"+er.message);
res.close();
});
@ -1290,7 +1324,7 @@ http.createServer(function (req, res) {
});
mp.addListener("complete", function () {
var response = "You posted: \n" + sys.inspect(fields);
res.writeHeader(200, {
res.writeHead(200, {
"content-type" : "text/plain",
"content-length" : response.length
});
@ -1656,13 +1690,7 @@ Normalize an array of path parts, taking care of +".."+ and +"."+ parts. Exampl
path.normalizeArray(["",
"foo", "bar", "baz", "asdf", "quux", ".."])
// returns
[
"",
"foo",
"bar",
"baz",
"asdf"
]
[ '', 'foo', 'bar', 'baz', 'asdf' ]
------------------------------------
+

2
doc/index.html

@ -48,7 +48,7 @@ var sys = require('sys'),
http = require('http');
http.createServer(function (req, res) {
setTimeout(function () {
res.writeHeader(200, {'Content-Type': 'text/plain'});
res.writeHead(200, {'Content-Type': 'text/plain'});
res.write('Hello World');
res.close();
}, 2000);

7
lib/http.js

@ -257,7 +257,7 @@ sys.inherits(ServerResponse, OutgoingMessage);
exports.ServerResponse = ServerResponse;
ServerResponse.prototype.writeHeader = function (statusCode) {
ServerResponse.prototype.writeHead = function (statusCode) {
var reasonPhrase, headers, headerIndex;
if (typeof arguments[1] == 'string') {
@ -279,8 +279,9 @@ ServerResponse.prototype.writeHeader = function (statusCode) {
this.sendHeaderLines(status_line, headers);
};
// TODO eventually remove sendHeader()
ServerResponse.prototype.sendHeader = ServerResponse.prototype.writeHeader;
// TODO eventually remove sendHeader(), writeHeader()
ServerResponse.prototype.sendHeader = ServerResponse.prototype.writeHead;
ServerResponse.prototype.writeHeader = ServerResponse.prototype.writeHead;
function ClientRequest (method, url, headers) {
OutgoingMessage.call(this);

61
lib/sys.js

@ -29,13 +29,13 @@ exports.error = function (x) {
* @param {Object} value The object to print out
* @param {Boolean} showHidden Flag that shows hidden (not enumerable) properties of objects.
*/
exports.inspect = function (obj, showHidden) {
exports.inspect = function (obj, showHidden, depth) {
var seen = [];
function format(value) {
function format(value, recurseTimes) {
// Primitive types cannot have properties
switch (typeof value) {
case 'undefined': return 'undefined';
case 'string': return JSON.stringify(value);
case 'string': return JSON.stringify(value).replace(/'/g, "\\'").replace(/\\"/g, '"').replace(/(^"|"$)/g, "'");
case 'number': return '' + value;
case 'boolean': return '' + value;
}
@ -45,9 +45,12 @@ exports.inspect = function (obj, showHidden) {
}
// Look up the keys of the object.
var keys = showHidden ? Object.getOwnPropertyNames(value).map(function (key) {
return '' + key;
}) : Object.keys(value);
if (showHidden) {
var keys = Object.getOwnPropertyNames(value).map(function (key) { return '' + key; });
} else {
var keys = Object.keys(value);
}
var visible_keys = Object.keys(value);
// Functions without properties can be shortcutted.
@ -92,7 +95,15 @@ exports.inspect = function (obj, showHidden) {
return braces[0] + base + braces[1];
}
return braces[0] + base + "\n" + (keys.map(function (key) {
if( recurseTimes < 0 ) {
if (value instanceof RegExp) {
return '' + value;
} else {
return "[object Object]";
}
}
output = keys.map(function (key) {
var name, str;
if (value.__lookupGetter__) {
if (value.__lookupGetter__(key)) {
@ -112,7 +123,17 @@ exports.inspect = function (obj, showHidden) {
}
if (!str) {
if (seen.indexOf(value[key]) < 0) {
if ( recurseTimes === null) {
str = format(value[key]);
}
else {
str = format(value[key], recurseTimes - 1);
}
if( str.indexOf('\n') > -1 ) {
str = '\n' + str.split('\n').map(function(line) {
return ' ' + line;
}).join('\n');
}
} else {
str = '[Circular]';
}
@ -122,14 +143,32 @@ exports.inspect = function (obj, showHidden) {
return str;
}
name = JSON.stringify('' + key);
if( name.match(/^"([a-zA-Z_0-9]+)"$/) ) {
name = name.substr(1, name.length-2);
}
else {
name = name.replace(/'/g, "\\'").replace(/\\"/g, '"').replace(/(^"|"$)/g, "'");
}
}
return name + ": " + str;
}).join(",\n")).split("\n").map(function (line) {
return ' ' + line;
}).join('\n') + "\n" + braces[1];
});
var length = output.reduce(function(prev, cur) {
return prev + cur.length + 1;
},0);
if( length > 50 ) {
output = braces[0] + (base === '' ? '' : base + '\n,') + ' ' + output.join('\n, ') + '\n' +braces[1];
}
else {
output = braces[0] + base + ' ' + output.join(', ') + ' ' + braces[1];
}
return output;
}
return format(obj);
return format(obj, (typeof depth === 'undefined' ? 2 : depth));
};
exports.p = function () {

34
src/node.cc

@ -492,6 +492,29 @@ static Handle<Value> GetUid(const Arguments& args) {
return scope.Close(Integer::New(uid));
}
static Handle<Value> GetGid(const Arguments& args) {
HandleScope scope;
int gid = getgid();
return scope.Close(Integer::New(gid));
}
static Handle<Value> SetGid(const Arguments& args) {
HandleScope scope;
if (args.Length() < 1) {
return ThrowException(Exception::Error(
String::New("setgid requires 1 argument")));
}
Local<Integer> given_gid = args[0]->ToInteger();
int gid = given_gid->Int32Value();
int result;
if ((result == setgid(gid)) != 0) {
return ThrowException(Exception::Error(String::New(strerror(errno))));
}
return Undefined();
}
static Handle<Value> SetUid(const Arguments& args) {
HandleScope scope;
@ -1038,6 +1061,10 @@ static void Load(int argc, char *argv[]) {
NODE_SET_METHOD(process, "cwd", Cwd);
NODE_SET_METHOD(process, "getuid", GetUid);
NODE_SET_METHOD(process, "setuid", SetUid);
NODE_SET_METHOD(process, "setgid", SetGid);
NODE_SET_METHOD(process, "getgid", GetGid);
NODE_SET_METHOD(process, "umask", Umask);
NODE_SET_METHOD(process, "dlopen", DLOpen);
NODE_SET_METHOD(process, "kill", Kill);
@ -1165,7 +1192,8 @@ static void PrintHelp() {
printf("Usage: node [options] script.js [arguments] \n"
" -v, --version print node's version\n"
" --debug[=port] enable remote debugging via given TCP port\n"
" --debug-brk[=port] as above, but break in node.js and\n"
" without stopping the execution\n"
" --debug-brk[=port] as above, but break in script.js and\n"
" wait for remote debugger to connect\n"
" --cflags print pre-processor and compiler flags\n"
" --v8-options print v8 command line options\n\n"
@ -1180,7 +1208,7 @@ static void ParseArgs(int *argc, char **argv) {
const char *arg = argv[i];
if (strstr(arg, "--debug") == arg) {
ParseDebugOpt(arg);
argv[i] = reinterpret_cast<const char*>("");
argv[i] = const_cast<char*>("");
option_end_index = i;
} else if (strcmp(arg, "--version") == 0 || strcmp(arg, "-v") == 0) {
printf("%s\n", NODE_VERSION);
@ -1192,7 +1220,7 @@ static void ParseArgs(int *argc, char **argv) {
PrintHelp();
exit(0);
} else if (strcmp(arg, "--v8-options") == 0) {
argv[i] = reinterpret_cast<const char*>("--help");
argv[i] = const_cast<char*>("--help");
option_end_index = i+1;
} else if (argv[i][0] != '-') {
option_end_index = i-1;

28
src/node.js

@ -498,6 +498,30 @@ var fsModule = createInternalModule("fs", function (exports) {
return process.fs.stat(path);
};
exports.readlink = function (path, callback) {
process.fs.readlink(path, callback || noop);
};
exports.readlinkSync = function (path) {
return process.fs.readlink(path);
};
exports.symlink = function (destination, path, callback) {
process.fs.symlink(destination, path, callback || noop);
};
exports.symlinkSync = function (destination, path) {
return process.fs.symlink(destination, path);
};
exports.link = function (srcpath, dstpath, callback) {
process.fs.link(srcpath, dstpath, callback || noop);
};
exports.linkSync = function (srcpath, dstpath) {
return process.fs.link(srcpath, dstpath);
};
exports.unlink = function (path, callback) {
process.fs.unlink(path, callback || noop);
};
@ -530,7 +554,7 @@ var fsModule = createInternalModule("fs", function (exports) {
});
}
exports.writeFile = function (path, data, encoding_) {
exports.writeFile = function (path, data, encoding_, callback) {
var encoding = (typeof(encoding_) == 'string' ? encoding_ : 'utf8');
var callback_ = arguments[arguments.length - 1];
var callback = (typeof(callback_) == 'function' ? callback_ : null);
@ -574,7 +598,7 @@ var fsModule = createInternalModule("fs", function (exports) {
});
}
exports.readFile = function (path, encoding_) {
exports.readFile = function (path, encoding_, callback) {
var encoding = typeof(encoding_) == 'string' ? encoding : 'utf8';
var callback_ = arguments[arguments.length - 1];
var callback = (typeof(callback_) == 'function' ? callback_ : null);

75
src/node_file.cc

@ -10,6 +10,12 @@
#include <assert.h>
#include <string.h>
#include <errno.h>
#include <limits.h>
/* used for readlink, AIX doesn't provide it */
#ifndef PATH_MAX
#define PATH_MAX 4096
#endif
namespace node {
@ -53,6 +59,8 @@ static int After(eio_req *req) {
case EIO_RMDIR:
case EIO_MKDIR:
case EIO_FTRUNCATE:
case EIO_LINK:
case EIO_SYMLINK:
case EIO_CHMOD:
argc = 0;
break;
@ -77,6 +85,13 @@ static int After(eio_req *req) {
break;
}
case EIO_READLINK:
{
argc = 2;
argv[1] = String::New(static_cast<char*>(req->ptr2), req->result);
break;
}
case EIO_READ:
{
argc = 3;
@ -198,6 +213,63 @@ static Handle<Value> LStat(const Arguments& args) {
}
}
static Handle<Value> Symlink(const Arguments& args) {
HandleScope scope;
if (args.Length() < 2 || !args[0]->IsString() || !args[1]->IsString()) {
return THROW_BAD_ARGS;
}
String::Utf8Value dest(args[0]->ToString());
String::Utf8Value path(args[1]->ToString());
if (args[2]->IsFunction()) {
ASYNC_CALL(symlink, args[2], *dest, *path)
} else {
int ret = symlink(*dest, *path);
if (ret != 0) return ThrowException(errno_exception(errno));
return Undefined();
}
}
static Handle<Value> Link(const Arguments& args) {
HandleScope scope;
if (args.Length() < 2 || !args[0]->IsString() || !args[1]->IsString()) {
return THROW_BAD_ARGS;
}
String::Utf8Value orig_path(args[0]->ToString());
String::Utf8Value new_path(args[1]->ToString());
if (args[2]->IsFunction()) {
ASYNC_CALL(link, args[2], *orig_path, *new_path)
} else {
int ret = link(*orig_path, *new_path);
if (ret != 0) return ThrowException(errno_exception(errno));
return Undefined();
}
}
static Handle<Value> ReadLink(const Arguments& args) {
HandleScope scope;
if (args.Length() < 1 || !args[0]->IsString()) {
return THROW_BAD_ARGS;
}
String::Utf8Value path(args[0]->ToString());
if (args[1]->IsFunction()) {
ASYNC_CALL(readlink, args[1], *path)
} else {
char buf[PATH_MAX];
ssize_t bz = readlink(*path, buf, PATH_MAX);
if (bz == -1) return ThrowException(errno_exception(errno));
return scope.Close(String::New(buf));
}
}
static Handle<Value> Rename(const Arguments& args) {
HandleScope scope;
@ -496,6 +568,9 @@ void File::Initialize(Handle<Object> target) {
NODE_SET_METHOD(target, "readdir", ReadDir);
NODE_SET_METHOD(target, "stat", Stat);
NODE_SET_METHOD(target, "lstat", LStat);
NODE_SET_METHOD(target, "link", Link);
NODE_SET_METHOD(target, "symlink", Symlink);
NODE_SET_METHOD(target, "readlink", ReadLink);
NODE_SET_METHOD(target, "unlink", Unlink);
NODE_SET_METHOD(target, "write", Write);

3
src/node_signal_handler.cc

@ -56,6 +56,9 @@ Handle<Value> SignalHandler::New(const Arguments& args) {
ev_signal_init(&handler->watcher_, SignalHandler::OnSignal, sig);
handler->watcher_.data = handler;
// Give signal handlers very high priority. The only thing that has higher
// priority is the garbage collector check.
ev_set_priority(&handler->watcher_, EV_MAXPRI-1);
ev_signal_start(EV_DEFAULT_UC_ &handler->watcher_);
ev_unref(EV_DEFAULT_UC);

2
test/mjsunit/common.js → test/common.js

@ -2,7 +2,7 @@ var path = require("path");
exports.testDir = path.dirname(__filename);
exports.fixturesDir = path.join(exports.testDir, "fixtures");
exports.libDir = path.join(exports.testDir, "../../lib");
exports.libDir = path.join(exports.testDir, "../lib");
require.paths.unshift(exports.libDir);

0
test/mjsunit/disabled/test-cat.js → test/disabled/test-cat.js

0
test/mjsunit/disabled/test-dns.js → test/disabled/test-dns.js

0
test/mjsunit/disabled/test-eio-race3.js → test/disabled/test-eio-race3.js

0
test/mjsunit/disabled/test-fs-sendfile.js → test/disabled/test-fs-sendfile.js

0
test/mjsunit/disabled/test-http-stress.js → test/disabled/test-http-stress.js

0
test/mjsunit/fixtures/a.js → test/fixtures/a.js

0
test/mjsunit/fixtures/b/c.js → test/fixtures/b/c.js

0
test/mjsunit/fixtures/b/d.js → test/fixtures/b/d.js

0
test/mjsunit/fixtures/b/package/index.js → test/fixtures/b/package/index.js

0
test/mjsunit/fixtures/cycles/folder/foo.js → test/fixtures/cycles/folder/foo.js

0
test/mjsunit/fixtures/cycles/root.js → test/fixtures/cycles/root.js

0
test/mjsunit/fixtures/echo.js → test/fixtures/echo.js

0
test/mjsunit/fixtures/multipart.js → test/fixtures/multipart.js

0
test/mjsunit/fixtures/nested-index/one/hello.js → test/fixtures/nested-index/one/hello.js

0
test/mjsunit/fixtures/nested-index/one/index.js → test/fixtures/nested-index/one/index.js

0
test/mjsunit/fixtures/nested-index/two/hello.js → test/fixtures/nested-index/two/hello.js

0
test/mjsunit/fixtures/nested-index/two/index.js → test/fixtures/nested-index/two/index.js

0
test/mjsunit/fixtures/print-chars.js → test/fixtures/print-chars.js

0
test/fixtures/readdir/are

0
test/fixtures/readdir/dir/empty

0
test/fixtures/readdir/empty

0
test/fixtures/readdir/files

0
test/fixtures/readdir/for

0
test/fixtures/readdir/just

0
test/fixtures/readdir/testing.js

0
test/fixtures/readdir/these

0
test/mjsunit/fixtures/test_ca.pem → test/fixtures/test_ca.pem

0
test/mjsunit/fixtures/test_cert.pem → test/fixtures/test_cert.pem

0
test/mjsunit/fixtures/test_key.pem → test/fixtures/test_key.pem

0
test/mjsunit/fixtures/throws_error.js → test/fixtures/throws_error.js

0
test/mjsunit/fixtures/x.txt → test/fixtures/x.txt

1
test/internet/internet.status

@ -0,0 +1 @@
prefix internet

21
test/mjsunit/testcfg.py → test/internet/testcfg.py

@ -35,10 +35,10 @@ FLAGS_PATTERN = re.compile(r"//\s+Flags:(.*)")
FILES_PATTERN = re.compile(r"//\s+Files:(.*)")
class MjsunitTestCase(test.TestCase):
class SimpleTestCase(test.TestCase):
def __init__(self, path, file, mode, context, config):
super(MjsunitTestCase, self).__init__(context, path)
super(SimpleTestCase, self).__init__(context, path)
self.file = file
self.config = config
self.mode = mode
@ -68,10 +68,10 @@ class MjsunitTestCase(test.TestCase):
return open(self.file).read()
class MjsunitTestConfiguration(test.TestConfiguration):
class SimpleTestConfiguration(test.TestConfiguration):
def __init__(self, context, root):
super(MjsunitTestConfiguration, self).__init__(context, root)
super(SimpleTestConfiguration, self).__init__(context, root)
def Ls(self, path):
def SelectTest(name):
@ -79,27 +79,30 @@ class MjsunitTestConfiguration(test.TestConfiguration):
return [f[:-3] for f in os.listdir(path) if SelectTest(f)]
def ListTests(self, current_path, path, mode):
mjsunit = [current_path + [t] for t in self.Ls(self.root)]
simple = [current_path + [t] for t in self.Ls(self.root)]
#simple = [current_path + ['simple', t] for t in self.Ls(join(self.root, 'simple'))]
#pummel = [current_path + ['pummel', t] for t in self.Ls(join(self.root, 'pummel'))]
#internet = [current_path + ['internet', t] for t in self.Ls(join(self.root, 'internet'))]
#regress = [current_path + ['regress', t] for t in self.Ls(join(self.root, 'regress'))]
#bugs = [current_path + ['bugs', t] for t in self.Ls(join(self.root, 'bugs'))]
#tools = [current_path + ['tools', t] for t in self.Ls(join(self.root, 'tools'))]
all_tests = mjsunit # + regress + bugs + tools
all_tests = simple # + regress + bugs + tools
result = []
for test in all_tests:
if self.Contains(path, test):
file_path = join(self.root, reduce(join, test[1:], "") + ".js")
result.append(MjsunitTestCase(test, file_path, mode, self.context, self))
result.append(SimpleTestCase(test, file_path, mode, self.context, self))
return result
def GetBuildRequirements(self):
return ['sample', 'sample=shell']
def GetTestStatus(self, sections, defs):
status_file = join(self.root, 'mjsunit.status')
status_file = join(self.root, 'simple.status')
if exists(status_file):
test.ReadConfigurationInto(status_file, sections, defs)
def GetConfiguration(context, root):
return MjsunitTestConfiguration(context, root)
return SimpleTestConfiguration(context, root)

40
test/mjsunit/test-readdir.js

@ -1,40 +0,0 @@
process.mixin(require("./common"));
var got_error = false;
var files = ['a.js'
, 'b'
, 'cycles'
, 'echo.js'
, 'multipart.js'
, 'nested-index'
, 'print-chars.js'
, 'test_ca.pem'
, 'test_cert.pem'
, 'test_key.pem'
, 'throws_error.js'
, 'x.txt'
];
puts('readdirSync ' + fixturesDir);
var f = fs.readdirSync(fixturesDir);
p(f);
assert.deepEqual(files, f.sort());
puts("readdir " + fixturesDir);
fs.readdir(fixturesDir, function (err, f) {
if (err) {
puts("error");
got_error = true;
} else {
p(f);
assert.deepEqual(files, f.sort());
}
});
process.addListener("exit", function () {
assert.equal(false, got_error);
puts("exit");
});

5
test/mjsunit/test-sync-fileread.js

@ -1,5 +0,0 @@
process.mixin(require('./common'));
var fixture = path.join(__dirname, "fixtures/x.txt");
assert.equal("xyz\n", fs.readFileSync(fixture));

1
test/pummel/pummel.status

@ -0,0 +1 @@
prefix pummel

2
test/mjsunit/test-http-client-reconnect-bug.js → test/pummel/test-http-client-reconnect-bug.js

@ -1,4 +1,4 @@
process.mixin(require("./common"));
process.mixin(require("../common"));
var tcp = require("tcp"),
sys = require("sys"),

4
test/mjsunit/test-keep-alive.js → test/pummel/test-keep-alive.js

@ -1,12 +1,12 @@
// This test requires the program "ab"
process.mixin(require("./common"));
process.mixin(require("../common"));
http = require("http");
sys = require("sys");
PORT = 8891;
body = "hello world\n";
server = http.createServer(function (req, res) {
res.writeHeader(200, {
res.writeHead(200, {
"Content-Length": body.length,
"Content-Type": "text/plain",
});

8
test/mjsunit/test-multipart.js → test/pummel/test-multipart.js

@ -1,10 +1,10 @@
process.mixin(require("./common"));
process.mixin(require("../common"));
var http = require("http"),
multipart = require("multipart"),
sys = require("sys"),
PORT = 8222,
fixture = require("./fixtures/multipart"),
fixture = require("../fixtures/multipart"),
events = require("events"),
testPart = function (expect, part) {
if (!expect) {
@ -77,12 +77,12 @@ var server = http.createServer(function (req, res) {
}
mp.addListener("error", function (er) {
sys.puts("!! error occurred");
res.writeHeader(400, {});
res.writeHead(400, {});
res.write("bad");
res.close();
});
mp.addListener("complete", function () {
res.writeHeader(200, {});
res.writeHead(200, {});
res.write("ok");
res.close();
});

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save