summaryrefslogtreecommitdiff
path: root/deps/v8/src
diff options
context:
space:
mode:
authorRyan Dahl <ry@tinyclouds.org>2010-02-23 17:52:50 -0800
committerRyan Dahl <ry@tinyclouds.org>2010-02-23 17:52:50 -0800
commitb80bdda14e2213e928d3dc3895b3c680d2ea674a (patch)
tree54f55fe0d2f2cf75cf1026e7dd01ca13d67f4254 /deps/v8/src
parentdf1c1e593f8aac17e6edd8aa1fe278893b2e5a39 (diff)
downloadnode-b80bdda14e2213e928d3dc3895b3c680d2ea674a.tar.gz
Upgrade V8 to 2.1.2
Diffstat (limited to 'deps/v8/src')
-rwxr-xr-xdeps/v8/src/SConscript4
-rw-r--r--deps/v8/src/arm/codegen-arm.cc29
-rw-r--r--deps/v8/src/arm/codegen-arm.h12
-rw-r--r--deps/v8/src/arm/fast-codegen-arm.cc35
-rw-r--r--deps/v8/src/ast.h11
-rw-r--r--deps/v8/src/codegen.cc3
-rw-r--r--deps/v8/src/codegen.h6
-rw-r--r--deps/v8/src/compiler.h53
-rw-r--r--deps/v8/src/debug-delay.js15
-rw-r--r--deps/v8/src/fast-codegen.cc3
-rw-r--r--deps/v8/src/fast-codegen.h9
-rw-r--r--deps/v8/src/frame-element.h5
-rw-r--r--deps/v8/src/heap.cc2
-rw-r--r--deps/v8/src/heap.h4
-rw-r--r--deps/v8/src/ia32/codegen-ia32.cc123
-rw-r--r--deps/v8/src/ia32/codegen-ia32.h17
-rw-r--r--deps/v8/src/ia32/fast-codegen-ia32.cc748
-rw-r--r--deps/v8/src/ia32/fast-codegen-ia32.h155
-rw-r--r--deps/v8/src/ia32/virtual-frame-ia32.cc76
-rw-r--r--deps/v8/src/ia32/virtual-frame-ia32.h12
-rw-r--r--deps/v8/src/jump-target-inl.h2
-rw-r--r--deps/v8/src/jump-target.cc2
-rw-r--r--deps/v8/src/macros.py14
-rw-r--r--deps/v8/src/mips/codegen-mips.cc11
-rw-r--r--deps/v8/src/mips/codegen-mips.h4
-rw-r--r--deps/v8/src/mirror-delay.js33
-rw-r--r--deps/v8/src/objects.h2
-rw-r--r--deps/v8/src/register-allocator.h2
-rw-r--r--deps/v8/src/runtime.cc128
-rw-r--r--deps/v8/src/runtime.js7
-rw-r--r--deps/v8/src/scopeinfo.cc2
-rw-r--r--deps/v8/src/serialize.cc4
-rw-r--r--deps/v8/src/spaces-inl.h2
-rw-r--r--deps/v8/src/string.js120
-rw-r--r--deps/v8/src/stub-cache.cc14
-rw-r--r--deps/v8/src/utils.h6
-rw-r--r--deps/v8/src/version.cc4
-rw-r--r--deps/v8/src/x64/assembler-x64.cc40
-rw-r--r--deps/v8/src/x64/assembler-x64.h94
-rw-r--r--deps/v8/src/x64/codegen-x64.cc26
-rw-r--r--deps/v8/src/x64/codegen-x64.h12
-rw-r--r--deps/v8/src/x64/fast-codegen-x64.cc38
-rw-r--r--deps/v8/src/x64/macro-assembler-x64.h2
43 files changed, 1506 insertions, 385 deletions
diff --git a/deps/v8/src/SConscript b/deps/v8/src/SConscript
index 1a81cc73c..73de193ad 100755
--- a/deps/v8/src/SConscript
+++ b/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
diff --git a/deps/v8/src/arm/codegen-arm.cc b/deps/v8/src/arm/codegen-arm.cc
index 046d7b95b..95c50f262 100644
--- a/deps/v8/src/arm/codegen-arm.cc
+++ b/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')
diff --git a/deps/v8/src/arm/codegen-arm.h b/deps/v8/src/arm/codegen-arm.h
index 10e28f411..1a2e5525a 100644
--- a/deps/v8/src/arm/codegen-arm.h
+++ b/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);
diff --git a/deps/v8/src/arm/fast-codegen-arm.cc b/deps/v8/src/arm/fast-codegen-arm.cc
index a07b0d2dc..aa7128fca 100644
--- a/deps/v8/src/arm/fast-codegen-arm.cc
+++ b/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());
- __ orr(destination(), accumulator1(), Operand(accumulator0()));
- __ BranchOnNotSmi(destination(), bailout());
+ // 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()));
+ 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_);
}
diff --git a/deps/v8/src/ast.h b/deps/v8/src/ast.h
index 8e717a6c8..927a9f503 100644
--- a/deps/v8/src/ast.h
+++ b/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);
}
diff --git a/deps/v8/src/codegen.cc b/deps/v8/src/codegen.cc
index 01ee6d072..dbd1100d9 100644
--- a/deps/v8/src/codegen.cc
+++ b/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"},
diff --git a/deps/v8/src/codegen.h b/deps/v8/src/codegen.h
index 5c10cb62c..8dcde84bb 100644
--- a/deps/v8/src/codegen.h
+++ b/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_);
diff --git a/deps/v8/src/compiler.h b/deps/v8/src/compiler.h
index 6ee2246b2..f01889d0a 100644
--- a/deps/v8/src/compiler.h
+++ b/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);
};
diff --git a/deps/v8/src/debug-delay.js b/deps/v8/src/debug-delay.js
index 754ac5d04..55c25a926 100644
--- a/deps/v8/src/debug-delay.js
+++ b/deps/v8/src/debug-delay.js
@@ -1202,11 +1202,16 @@ DebugCommandProcessor.prototype.processDebugJSONRequest = function(json_request)
throw new Error('Command not specified');
}
- // TODO(yurys): remove request.arguments.compactFormat check once
- // ChromeDevTools are switched to 'inlineRefs'
- if (request.arguments && (request.arguments.inlineRefs ||
- request.arguments.compactFormat)) {
- response.setOption('inlineRefs', true);
+ if (request.arguments) {
+ var args = request.arguments;
+ // TODO(yurys): remove request.arguments.compactFormat check once
+ // ChromeDevTools are switched to 'inlineRefs'
+ if (args.inlineRefs || args.compactFormat) {
+ response.setOption('inlineRefs', true);
+ }
+ if (!IS_UNDEFINED(args.maxStringLength)) {
+ response.setOption('maxStringLength', args.maxStringLength);
+ }
}
if (request.command == 'continue') {
diff --git a/deps/v8/src/fast-codegen.cc b/deps/v8/src/fast-codegen.cc
index ecd26527c..602d6b88c 100644
--- a/deps/v8/src/fast-codegen.cc
+++ b/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();
diff --git a/deps/v8/src/fast-codegen.h b/deps/v8/src/fast-codegen.h
index 96ee5dddb..e96daf65b 100644
--- a/deps/v8/src/fast-codegen.h
+++ b/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_
diff --git a/deps/v8/src/frame-element.h b/deps/v8/src/frame-element.h
index 3ae6d303f..5762814ff 100644
--- a/deps/v8/src/frame-element.h
+++ b/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;
};
diff --git a/deps/v8/src/heap.cc b/deps/v8/src/heap.cc
index fc4e666b9..cfb786ac7 100644
--- a/deps/v8/src/heap.cc
+++ b/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);
}
diff --git a/deps/v8/src/heap.h b/deps/v8/src/heap.h
index 22ab875bb..3f34df72b 100644
--- a/deps/v8/src/heap.h
+++ b/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;
}
diff --git a/deps/v8/src/ia32/codegen-ia32.cc b/deps/v8/src/ia32/codegen-ia32.cc
index 7ec3ff4c5..85d8ed9bc 100644
--- a/deps/v8/src/ia32/codegen-ia32.cc
+++ b/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.
- frame()->Dup();
+ 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()) {
- frame()->Dup();
+ 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.
- Result result = frame()->Pop();
- Result receiver = frame()->Pop();
- frame()->Push(&result);
- frame()->Push(&receiver);
+ 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;
diff --git a/deps/v8/src/ia32/codegen-ia32.h b/deps/v8/src/ia32/codegen-ia32.h
index a6cb3164b..99dc340b6 100644
--- a/deps/v8/src/ia32/codegen-ia32.h
+++ b/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);
diff --git a/deps/v8/src/ia32/fast-codegen-ia32.cc b/deps/v8/src/ia32/fast-codegen-ia32.cc
index 9bab75aa6..f1c250771 100644
--- a/deps/v8/src/ia32/fast-codegen-ia32.cc
+++ b/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.
- __ 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);
+ // 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));
+ 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 __
diff --git a/deps/v8/src/ia32/fast-codegen-ia32.h b/deps/v8/src/ia32/fast-codegen-ia32.h
new file mode 100644
index 000000000..e0851afe0
--- /dev/null
+++ b/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_
diff --git a/deps/v8/src/ia32/virtual-frame-ia32.cc b/deps/v8/src/ia32/virtual-frame-ia32.cc
index d2485392f..7df028e94 100644
--- a/deps/v8/src/ia32/virtual-frame-ia32.cc
+++ b/deps/v8/src/ia32/virtual-frame-ia32.cc
@@ -948,47 +948,38 @@ 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();
- Result receiver = Pop();
- PrepareForCall(0, 0);
+ 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.
- __ xchg(eax, edx);
+ if (value.is_register() && value.reg().is(edx)) {
+ if (receiver.is_register() && receiver.reg().is(eax)) {
+ // Wrong registers.
+ __ xchg(eax, edx);
+ } else {
+ // Register eax is free for value, which frees edx for receiver.
+ value.ToRegister(eax);
+ receiver.ToRegister(edx);
+ }
} else {
- // Register eax is free for value, which frees edx for receiver.
- value.ToRegister(eax);
+ // Register edx is free for receiver, which guarantees eax is free for
+ // value.
receiver.ToRegister(edx);
+ value.ToRegister(eax);
}
- } else {
- // Register edx is free for receiver, which guarantees eax is free for
- // value.
- 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
diff --git a/deps/v8/src/ia32/virtual-frame-ia32.h b/deps/v8/src/ia32/virtual-frame-ia32.h
index b078ba089..7be593cc5 100644
--- a/deps/v8/src/ia32/virtual-frame-ia32.h
+++ b/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).
diff --git a/deps/v8/src/jump-target-inl.h b/deps/v8/src/jump-target-inl.h
index dcd615eef..3cd9a8bde 100644
--- a/deps/v8/src/jump-target-inl.h
+++ b/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);
}
}
diff --git a/deps/v8/src/jump-target.cc b/deps/v8/src/jump-target.cc
index 66764e6a7..bce379a92 100644
--- a/deps/v8/src/jump-target.cc
+++ b/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);
}
diff --git a/deps/v8/src/macros.py b/deps/v8/src/macros.py
index c160b4916..ccc2037f2 100644
--- a/deps/v8/src/macros.py
+++ b/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');
@@ -97,9 +101,11 @@ macro FLOOR(arg) = $floor(arg);
# Inline macros. Use %IS_VAR to make sure arg is evaluated only once.
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_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]);
diff --git a/deps/v8/src/mips/codegen-mips.cc b/deps/v8/src/mips/codegen-mips.cc
index 5a27c2864..2de45f67f 100644
--- a/deps/v8/src/mips/codegen-mips.cc
+++ b/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
-
diff --git a/deps/v8/src/mips/codegen-mips.h b/deps/v8/src/mips/codegen-mips.h
index 05138bc64..147b8724e 100644
--- a/deps/v8/src/mips/codegen-mips.h
+++ b/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_
-
diff --git a/deps/v8/src/mirror-delay.js b/deps/v8/src/mirror-delay.js
index e1bedfdff..7c743ec2c 100644
--- a/deps/v8/src/mirror-delay.js
+++ b/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_;
}
+ 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();
}
diff --git a/deps/v8/src/objects.h b/deps/v8/src/objects.h
index 3ed0a705e..75338920c 100644
--- a/deps/v8/src/objects.h
+++ b/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:
diff --git a/deps/v8/src/register-allocator.h b/deps/v8/src/register-allocator.h
index 4ec0bb4db..747200a05 100644
--- a/deps/v8/src/register-allocator.h
+++ b/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;
diff --git a/deps/v8/src/runtime.cc b/deps/v8/src/runtime.cc
index 38e332b24..6459aa78d 100644
--- a/deps/v8/src/runtime.cc
+++ b/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,39 +2469,115 @@ 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 (!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 (found) return Smi::FromInt(i);
}
- return Smi::FromInt(-1);
+ 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);
}
diff --git a/deps/v8/src/runtime.js b/deps/v8/src/runtime.js
index 231763cbc..e9d984877 100644
--- a/deps/v8/src/runtime.js
+++ b/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) {
diff --git a/deps/v8/src/scopeinfo.cc b/deps/v8/src/scopeinfo.cc
index 8b989d7a3..de1841b02 100644
--- a/deps/v8/src/scopeinfo.cc
+++ b/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);
}
diff --git a/deps/v8/src/serialize.cc b/deps/v8/src/serialize.cc
index bc934fb5a..0819ec224 100644
--- a/deps/v8/src/serialize.cc
+++ b/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
diff --git a/deps/v8/src/spaces-inl.h b/deps/v8/src/spaces-inl.h
index 4fd8a6c8d..72f83050b 100644
--- a/deps/v8/src/spaces-inl.h
+++ b/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);
}
diff --git a/deps/v8/src/string.js b/deps/v8/src/string.js
index ba01ed67e..49f403de7 100644
--- a/deps/v8/src/string.js
+++ b/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,28 +609,18 @@ 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
- // matches at the end of the string.
- if (matchInfo[CAPTURE0] === subject.length) return null;
- return matchInfo;
- }
-
- var separatorIndex = subject.indexOf(separator, start_index);
- if (separatorIndex === -1) return null;
-
- reusableMatchInfo[CAPTURE0] = separatorIndex;
- reusableMatchInfo[CAPTURE1] = separatorIndex + separator.length;
- return reusableMatchInfo;
-};
+ 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
+ // matches at the end of the string.
+ if (matchInfo[CAPTURE0] === subject.length) return null;
+ return matchInfo;
+}
// 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,10 +739,10 @@ function StringFromCharCode(code) {
// Helper function for very basic XSS protection.
function HtmlEscape(str) {
- return ToString(str).replace(/</g, "&lt;")
- .replace(/>/g, "&gt;")
- .replace(/"/g, "&quot;")
- .replace(/'/g, "&#039;");
+ 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;
diff --git a/deps/v8/src/stub-cache.cc b/deps/v8/src/stub-cache.cc
index 3adaa40c1..577c2d773 100644
--- a/deps/v8/src/stub-cache.cc
+++ b/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));
}
diff --git a/deps/v8/src/utils.h b/deps/v8/src/utils.h
index c59ca258a..2fcd241fd 100644
--- a/deps/v8/src/utils.h
+++ b/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);
}
};
diff --git a/deps/v8/src/version.cc b/deps/v8/src/version.cc
index 717bcc3e7..eaa63d541 100644
--- a/deps/v8/src/version.cc
+++ b/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
diff --git a/deps/v8/src/x64/assembler-x64.cc b/deps/v8/src/x64/assembler-x64.cc
index 1f97235ab..a994f45b1 100644
--- a/deps/v8/src/x64/assembler-x64.cc
+++ b/deps/v8/src/x64/assembler-x64.cc
@@ -34,46 +34,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
// The required user mode extensions in X64 are (from AMD64 ABI Table A.1):
diff --git a/deps/v8/src/x64/assembler-x64.h b/deps/v8/src/x64/assembler-x64.h
index 6c6f6a34b..501952550 100644
--- a/deps/v8/src/x64/assembler-x64.h
+++ b/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
diff --git a/deps/v8/src/x64/codegen-x64.cc b/deps/v8/src/x64/codegen-x64.cc
index 6c063f3e7..28a522f34 100644
--- a/deps/v8/src/x64/codegen-x64.cc
+++ b/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')
diff --git a/deps/v8/src/x64/codegen-x64.h b/deps/v8/src/x64/codegen-x64.h
index 345431241..4593a2839 100644
--- a/deps/v8/src/x64/codegen-x64.h
+++ b/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);
diff --git a/deps/v8/src/x64/fast-codegen-x64.cc b/deps/v8/src/x64/fast-codegen-x64.cc
index 1af768554..4dbf26a42 100644
--- a/deps/v8/src/x64/fast-codegen-x64.cc
+++ b/deps/v8/src/x64/fast-codegen-x64.cc
@@ -156,21 +156,28 @@ 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.
- __ movq(scratch0(), accumulator1());
- __ or_(scratch0(), accumulator0());
- __ JumpIfNotSmi(scratch0(), 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());
+ // 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_(destination(), accumulator0());
+ Label* bailout = info()->AddBailout(scratch0(), accumulator0());
+ __ JumpIfNotSmi(destination(), bailout);
+ } else {
+ 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.
set_as_smi(accumulator0());
@@ -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_);
}
diff --git a/deps/v8/src/x64/macro-assembler-x64.h b/deps/v8/src/x64/macro-assembler-x64.h
index 6deeddce7..2673086dc 100644
--- a/deps/v8/src/x64/macro-assembler-x64.h
+++ b/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;