Upgrade V8 to 2.1.2
This commit is contained in:
parent
df1c1e593f
commit
b80bdda14e
8
deps/v8/ChangeLog
vendored
8
deps/v8/ChangeLog
vendored
@ -1,3 +1,11 @@
|
||||
2010-02-23: Version 2.1.2
|
||||
|
||||
Fix a crash bug caused by wrong assert.
|
||||
|
||||
Fix a bug with register names on 64-bit V8 (issue 615).
|
||||
|
||||
Performance improvements on all platforms.
|
||||
|
||||
2010-02-19: Version 2.1.1
|
||||
|
||||
[ES5] Implemented Object.defineProperty.
|
||||
|
1
deps/v8/SConstruct
vendored
1
deps/v8/SConstruct
vendored
@ -267,6 +267,7 @@ V8_EXTRA_FLAGS = {
|
||||
'gcc': {
|
||||
'all': {
|
||||
'WARNINGFLAGS': ['-Wall',
|
||||
'-Werror',
|
||||
'-W',
|
||||
'-Wno-unused-parameter',
|
||||
'-Wnon-virtual-dtor']
|
||||
|
4
deps/v8/src/SConscript
vendored
4
deps/v8/src/SConscript
vendored
@ -57,7 +57,6 @@ SOURCES = {
|
||||
disassembler.cc
|
||||
execution.cc
|
||||
factory.cc
|
||||
fast-codegen.cc
|
||||
flags.cc
|
||||
frame-element.cc
|
||||
frames.cc
|
||||
@ -109,6 +108,7 @@ SOURCES = {
|
||||
zone.cc
|
||||
"""),
|
||||
'arch:arm': Split("""
|
||||
fast-codegen.cc
|
||||
arm/builtins-arm.cc
|
||||
arm/codegen-arm.cc
|
||||
arm/constants-arm.cc
|
||||
@ -133,6 +133,7 @@ SOURCES = {
|
||||
arm/assembler-thumb2.cc
|
||||
"""),
|
||||
'arch:mips': Split("""
|
||||
fast-codegen.cc
|
||||
mips/assembler-mips.cc
|
||||
mips/builtins-mips.cc
|
||||
mips/codegen-mips.cc
|
||||
@ -169,6 +170,7 @@ SOURCES = {
|
||||
ia32/virtual-frame-ia32.cc
|
||||
"""),
|
||||
'arch:x64': Split("""
|
||||
fast-codegen.cc
|
||||
x64/assembler-x64.cc
|
||||
x64/builtins-x64.cc
|
||||
x64/codegen-x64.cc
|
||||
|
29
deps/v8/src/arm/codegen-arm.cc
vendored
29
deps/v8/src/arm/codegen-arm.cc
vendored
@ -142,7 +142,7 @@ Scope* CodeGenerator::scope() { return info_->function()->scope(); }
|
||||
// r1: called JS function
|
||||
// cp: callee's context
|
||||
|
||||
void CodeGenerator::Generate(CompilationInfo* info, Mode mode) {
|
||||
void CodeGenerator::Generate(CompilationInfo* info) {
|
||||
// Record the position for debugging purposes.
|
||||
CodeForFunctionPosition(info->function());
|
||||
|
||||
@ -174,7 +174,7 @@ void CodeGenerator::Generate(CompilationInfo* info, Mode mode) {
|
||||
}
|
||||
#endif
|
||||
|
||||
if (mode == PRIMARY) {
|
||||
if (info->mode() == CompilationInfo::PRIMARY) {
|
||||
frame_->Enter();
|
||||
// tos: code slot
|
||||
|
||||
@ -277,6 +277,12 @@ void CodeGenerator::Generate(CompilationInfo* info, Mode mode) {
|
||||
frame_->Adjust(4);
|
||||
allocator_->Unuse(r1);
|
||||
allocator_->Unuse(lr);
|
||||
|
||||
// Bind all the bailout labels to the beginning of the function.
|
||||
List<CompilationInfo::Bailout*>* bailouts = info->bailouts();
|
||||
for (int i = 0; i < bailouts->length(); i++) {
|
||||
__ bind(bailouts->at(i)->label());
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize the function return target after the locals are set
|
||||
@ -3420,6 +3426,25 @@ void CodeGenerator::GenerateIsArray(ZoneList<Expression*>* args) {
|
||||
}
|
||||
|
||||
|
||||
void CodeGenerator::GenerateIsRegExp(ZoneList<Expression*>* args) {
|
||||
VirtualFrame::SpilledScope spilled_scope;
|
||||
ASSERT(args->length() == 1);
|
||||
LoadAndSpill(args->at(0));
|
||||
JumpTarget answer;
|
||||
// We need the CC bits to come out as not_equal in the case where the
|
||||
// object is a smi. This can't be done with the usual test opcode so
|
||||
// we use XOR to get the right CC bits.
|
||||
frame_->EmitPop(r0);
|
||||
__ and_(r1, r0, Operand(kSmiTagMask));
|
||||
__ eor(r1, r1, Operand(kSmiTagMask), SetCC);
|
||||
answer.Branch(ne);
|
||||
// It is a heap object - get the map. Check if the object is a regexp.
|
||||
__ CompareObjectType(r0, r1, r1, JS_REGEXP_TYPE);
|
||||
answer.Bind();
|
||||
cc_reg_ = eq;
|
||||
}
|
||||
|
||||
|
||||
void CodeGenerator::GenerateIsObject(ZoneList<Expression*>* args) {
|
||||
// This generates a fast version of:
|
||||
// (typeof(arg) === 'object' || %_ClassOf(arg) == 'RegExp')
|
||||
|
12
deps/v8/src/arm/codegen-arm.h
vendored
12
deps/v8/src/arm/codegen-arm.h
vendored
@ -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);
|
||||
|
35
deps/v8/src/arm/fast-codegen-arm.cc
vendored
35
deps/v8/src/arm/fast-codegen-arm.cc
vendored
@ -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_);
|
||||
}
|
||||
|
||||
|
||||
|
11
deps/v8/src/ast.h
vendored
11
deps/v8/src/ast.h
vendored
@ -1,4 +1,4 @@
|
||||
// Copyright 2006-2008 the V8 project authors. All rights reserved.
|
||||
// Copyright 2010 the V8 project authors. All rights reserved.
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
@ -199,6 +199,10 @@ class Expression: public AstNode {
|
||||
// evaluated.
|
||||
virtual bool IsLeaf() { return false; }
|
||||
|
||||
// True if the expression has no side effects and is safe to
|
||||
// evaluate out of order.
|
||||
virtual bool IsTrivial() { return false; }
|
||||
|
||||
// Mark the expression as being compiled as an expression
|
||||
// statement. This is used to transform postfix increments to
|
||||
// (faster) prefix increments.
|
||||
@ -738,6 +742,7 @@ class Literal: public Expression {
|
||||
}
|
||||
|
||||
virtual bool IsLeaf() { return true; }
|
||||
virtual bool IsTrivial() { return true; }
|
||||
|
||||
// Identity testers.
|
||||
bool IsNull() const { return handle_.is_identical_to(Factory::null_value()); }
|
||||
@ -926,6 +931,10 @@ class VariableProxy: public Expression {
|
||||
return var()->is_global() || var()->rewrite()->IsLeaf();
|
||||
}
|
||||
|
||||
// Reading from a mutable variable is a side effect, but 'this' is
|
||||
// immutable.
|
||||
virtual bool IsTrivial() { return is_this(); }
|
||||
|
||||
bool IsVariable(Handle<String> n) {
|
||||
return !is_this() && name().is_identical_to(n);
|
||||
}
|
||||
|
3
deps/v8/src/codegen.cc
vendored
3
deps/v8/src/codegen.cc
vendored
@ -248,7 +248,7 @@ Handle<Code> CodeGenerator::MakeCode(CompilationInfo* info) {
|
||||
CodeGenerator cgen(&masm);
|
||||
CodeGeneratorScope scope(&cgen);
|
||||
live_edit_tracker.RecordFunctionScope(info->function()->scope());
|
||||
cgen.Generate(info, PRIMARY);
|
||||
cgen.Generate(info);
|
||||
if (cgen.HasStackOverflow()) {
|
||||
ASSERT(!Top::has_pending_exception());
|
||||
return Handle<Code>::null();
|
||||
@ -360,6 +360,7 @@ CodeGenerator::InlineRuntimeLUT CodeGenerator::kInlineRuntimeLUT[] = {
|
||||
{&CodeGenerator::GenerateIsSmi, "_IsSmi"},
|
||||
{&CodeGenerator::GenerateIsNonNegativeSmi, "_IsNonNegativeSmi"},
|
||||
{&CodeGenerator::GenerateIsArray, "_IsArray"},
|
||||
{&CodeGenerator::GenerateIsRegExp, "_IsRegExp"},
|
||||
{&CodeGenerator::GenerateIsConstructCall, "_IsConstructCall"},
|
||||
{&CodeGenerator::GenerateArgumentsLength, "_ArgumentsLength"},
|
||||
{&CodeGenerator::GenerateArgumentsAccess, "_Arguments"},
|
||||
|
6
deps/v8/src/codegen.h
vendored
6
deps/v8/src/codegen.h
vendored
@ -518,14 +518,14 @@ class CallFunctionStub: public CodeStub {
|
||||
}
|
||||
#endif
|
||||
|
||||
// Minor key encoding in 31 bits AAAAAAAAAAAAAAAAAAAAAFI A(rgs)F(lag)I(nloop).
|
||||
// Minor key encoding in 32 bits with Bitfield <Type, shift, size>.
|
||||
class InLoopBits: public BitField<InLoopFlag, 0, 1> {};
|
||||
class FlagBits: public BitField<CallFunctionFlags, 1, 1> {};
|
||||
class ArgcBits: public BitField<int, 2, 29> {};
|
||||
class ArgcBits: public BitField<int, 2, 32 - 2> {};
|
||||
|
||||
Major MajorKey() { return CallFunction; }
|
||||
int MinorKey() {
|
||||
// Encode the parameters in a unique 31 bit value.
|
||||
// Encode the parameters in a unique 32 bit value.
|
||||
return InLoopBits::encode(in_loop_)
|
||||
| FlagBits::encode(flags_)
|
||||
| ArgcBits::encode(argc_);
|
||||
|
53
deps/v8/src/compiler.h
vendored
53
deps/v8/src/compiler.h
vendored
@ -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);
|
||||
};
|
||||
|
||||
|
15
deps/v8/src/debug-delay.js
vendored
15
deps/v8/src/debug-delay.js
vendored
@ -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') {
|
||||
|
3
deps/v8/src/fast-codegen.cc
vendored
3
deps/v8/src/fast-codegen.cc
vendored
@ -456,7 +456,8 @@ Handle<Code> FastCodeGenerator::MakeCode(CompilationInfo* info) {
|
||||
// macro assembler.
|
||||
CodeGenerator cgen(&masm);
|
||||
CodeGeneratorScope scope(&cgen);
|
||||
cgen.Generate(info, CodeGenerator::SECONDARY);
|
||||
info->set_mode(CompilationInfo::SECONDARY);
|
||||
cgen.Generate(info);
|
||||
if (cgen.HasStackOverflow()) {
|
||||
ASSERT(!Top::has_pending_exception());
|
||||
return Handle<Code>::null();
|
||||
|
9
deps/v8/src/fast-codegen.h
vendored
9
deps/v8/src/fast-codegen.h
vendored
@ -28,10 +28,15 @@
|
||||
#ifndef V8_FAST_CODEGEN_H_
|
||||
#define V8_FAST_CODEGEN_H_
|
||||
|
||||
#if V8_TARGET_ARCH_IA32
|
||||
#include "ia32/fast-codegen-ia32.h"
|
||||
#else
|
||||
|
||||
#include "v8.h"
|
||||
|
||||
#include "ast.h"
|
||||
#include "compiler.h"
|
||||
#include "list.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
@ -76,7 +81,6 @@ class FastCodeGenerator: public AstVisitor {
|
||||
private:
|
||||
MacroAssembler* masm() { return masm_; }
|
||||
CompilationInfo* info() { return info_; }
|
||||
Label* bailout() { return &bailout_; }
|
||||
|
||||
Register destination() { return destination_; }
|
||||
void set_destination(Register reg) { destination_ = reg; }
|
||||
@ -142,7 +146,6 @@ class FastCodeGenerator: public AstVisitor {
|
||||
|
||||
MacroAssembler* masm_;
|
||||
CompilationInfo* info_;
|
||||
Label bailout_;
|
||||
Register destination_;
|
||||
uint32_t smi_bits_;
|
||||
|
||||
@ -152,4 +155,6 @@ class FastCodeGenerator: public AstVisitor {
|
||||
|
||||
} } // namespace v8::internal
|
||||
|
||||
#endif // V8_TARGET_ARCH_IA32
|
||||
|
||||
#endif // V8_FAST_CODEGEN_H_
|
||||
|
5
deps/v8/src/frame-element.h
vendored
5
deps/v8/src/frame-element.h
vendored
@ -65,6 +65,9 @@ class FrameElement BASE_EMBEDDED {
|
||||
}
|
||||
|
||||
inline void set_number_info(NumberInfo::Type info) {
|
||||
// Copied elements do not have number info. Instead
|
||||
// we have to inspect their backing element in the frame.
|
||||
ASSERT(!is_copy());
|
||||
value_ = value_ & ~NumberInfoField::mask();
|
||||
value_ = value_ | NumberInfoField::encode(info);
|
||||
}
|
||||
@ -250,7 +253,7 @@ class FrameElement BASE_EMBEDDED {
|
||||
class CopiedField: public BitField<bool, 3, 1> {};
|
||||
class SyncedField: public BitField<bool, 4, 1> {};
|
||||
class NumberInfoField: public BitField<NumberInfo::Type, 5, 3> {};
|
||||
class DataField: public BitField<uint32_t, 8, 32 - 9> {};
|
||||
class DataField: public BitField<uint32_t, 8, 32 - 8> {};
|
||||
|
||||
friend class VirtualFrame;
|
||||
};
|
||||
|
2
deps/v8/src/heap.cc
vendored
2
deps/v8/src/heap.cc
vendored
@ -4111,7 +4111,7 @@ int KeyedLookupCache::Hash(Map* map, String* name) {
|
||||
// Uses only lower 32 bits if pointers are larger.
|
||||
uintptr_t addr_hash =
|
||||
static_cast<uint32_t>(reinterpret_cast<uintptr_t>(map)) >> kMapHashShift;
|
||||
return (addr_hash ^ name->Hash()) & kCapacityMask;
|
||||
return static_cast<uint32_t>((addr_hash ^ name->Hash()) & kCapacityMask);
|
||||
}
|
||||
|
||||
|
||||
|
4
deps/v8/src/heap.h
vendored
4
deps/v8/src/heap.h
vendored
@ -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;
|
||||
}
|
||||
|
123
deps/v8/src/ia32/codegen-ia32.cc
vendored
123
deps/v8/src/ia32/codegen-ia32.cc
vendored
@ -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;
|
||||
|
17
deps/v8/src/ia32/codegen-ia32.h
vendored
17
deps/v8/src/ia32/codegen-ia32.h
vendored
@ -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);
|
||||
|
750
deps/v8/src/ia32/fast-codegen-ia32.cc
vendored
750
deps/v8/src/ia32/fast-codegen-ia32.cc
vendored
@ -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);
|
||||
|
||||
__ bind(&bailout_);
|
||||
}
|
||||
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
|
||||
void FastCodeGenerator::VisitFunctionBoilerplateLiteral(
|
||||
FunctionBoilerplateLiteral* expr) {
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
|
||||
void FastCodeGenerator::VisitConditional(Conditional* expr) {
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
|
||||
void FastCodeGenerator::VisitSlot(Slot* expr) {
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
|
||||
void FastCodeGenerator::VisitVariableProxy(VariableProxy* expr) {
|
||||
ASSERT(expr->var()->is_global() && !expr->var()->is_this());
|
||||
// Check if we can compile a global variable load directly from the cell.
|
||||
ASSERT(info()->has_global_object());
|
||||
LookupResult lookup;
|
||||
info()->global_object()->Lookup(*expr->name(), &lookup);
|
||||
// We only support normal (non-accessor/interceptor) DontDelete properties
|
||||
// for now.
|
||||
ASSERT(lookup.IsProperty());
|
||||
ASSERT_EQ(NORMAL, lookup.type());
|
||||
ASSERT(lookup.IsDontDelete());
|
||||
Handle<Object> cell(info()->global_object()->GetPropertyCell(&lookup));
|
||||
|
||||
// Global variable lookups do not have side effects, so we do not need to
|
||||
// emit code if we are in an effect context.
|
||||
if (!destination().is(no_reg)) {
|
||||
Comment cmnt(masm(), ";; Global");
|
||||
if (FLAG_print_ir) {
|
||||
SmartPointer<char> name = expr->name()->ToCString();
|
||||
PrintF("%d: t%d = Global(%s) // last_use = %d\n", expr->num(),
|
||||
expr->num(), *name, expr->var_def()->last_use()->num());
|
||||
}
|
||||
EmitGlobalVariableLoad(cell);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void FastCodeGenerator::VisitLiteral(Literal* expr) {
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
|
||||
void FastCodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) {
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
|
||||
void FastCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
|
||||
void FastCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
|
||||
void FastCodeGenerator::VisitCatchExtensionObject(CatchExtensionObject* expr) {
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
|
||||
void FastCodeGenerator::VisitAssignment(Assignment* expr) {
|
||||
// Known to be a simple this property assignment. Effectively a unary
|
||||
// operation.
|
||||
{ Register my_destination = destination();
|
||||
set_destination(accumulator0());
|
||||
Visit(expr->value());
|
||||
set_destination(my_destination);
|
||||
}
|
||||
|
||||
Property* prop = expr->target()->AsProperty();
|
||||
ASSERT_NOT_NULL(prop);
|
||||
ASSERT_NOT_NULL(prop->obj()->AsVariableProxy());
|
||||
ASSERT(prop->obj()->AsVariableProxy()->var()->is_this());
|
||||
ASSERT(prop->key()->IsPropertyName());
|
||||
Handle<String> name =
|
||||
Handle<String>::cast(prop->key()->AsLiteral()->handle());
|
||||
|
||||
Comment cmnt(masm(), ";; Store to this");
|
||||
if (FLAG_print_ir) {
|
||||
SmartPointer<char> name_string = name->ToCString();
|
||||
PrintF("%d: ", expr->num());
|
||||
if (!destination().is(no_reg)) PrintF("t%d = ", expr->num());
|
||||
PrintF("Store(this, \"%s\", t%d) // last_use(this) = %d\n", *name_string,
|
||||
expr->value()->num(),
|
||||
expr->var_def()->last_use()->num());
|
||||
}
|
||||
|
||||
EmitThisPropertyStore(name);
|
||||
}
|
||||
|
||||
|
||||
void FastCodeGenerator::VisitThrow(Throw* expr) {
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
|
||||
void FastCodeGenerator::VisitProperty(Property* expr) {
|
||||
ASSERT_NOT_NULL(expr->obj()->AsVariableProxy());
|
||||
ASSERT(expr->obj()->AsVariableProxy()->var()->is_this());
|
||||
ASSERT(expr->key()->IsPropertyName());
|
||||
if (!destination().is(no_reg)) {
|
||||
Handle<String> name =
|
||||
Handle<String>::cast(expr->key()->AsLiteral()->handle());
|
||||
|
||||
Comment cmnt(masm(), ";; Load from this");
|
||||
if (FLAG_print_ir) {
|
||||
SmartPointer<char> name_string = name->ToCString();
|
||||
PrintF("%d: t%d = Load(this, \"%s\") // last_use(this) = %d\n",
|
||||
expr->num(), expr->num(), *name_string,
|
||||
expr->var_def()->last_use()->num());
|
||||
}
|
||||
EmitThisPropertyLoad(name);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void FastCodeGenerator::VisitCall(Call* expr) {
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
|
||||
void FastCodeGenerator::VisitCallNew(CallNew* expr) {
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
|
||||
void FastCodeGenerator::VisitCallRuntime(CallRuntime* expr) {
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
|
||||
void FastCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
|
||||
void FastCodeGenerator::VisitCountOperation(CountOperation* expr) {
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
|
||||
void FastCodeGenerator::VisitBinaryOperation(BinaryOperation* expr) {
|
||||
// We support limited binary operations: bitwise OR only allowed to be
|
||||
// nested on the left.
|
||||
ASSERT(expr->op() == Token::BIT_OR);
|
||||
ASSERT(expr->right()->IsLeaf());
|
||||
|
||||
{ Register my_destination = destination();
|
||||
set_destination(accumulator1());
|
||||
Visit(expr->left());
|
||||
set_destination(accumulator0());
|
||||
Visit(expr->right());
|
||||
set_destination(my_destination);
|
||||
}
|
||||
|
||||
Comment cmnt(masm(), ";; BIT_OR");
|
||||
if (FLAG_print_ir) {
|
||||
PrintF("%d: ", expr->num());
|
||||
if (!destination().is(no_reg)) PrintF("t%d = ", expr->num());
|
||||
PrintF("BIT_OR(t%d, t%d)\n", expr->left()->num(), expr->right()->num());
|
||||
}
|
||||
EmitBitOr();
|
||||
}
|
||||
|
||||
|
||||
void FastCodeGenerator::VisitCompareOperation(CompareOperation* expr) {
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
|
||||
void FastCodeGenerator::VisitThisFunction(ThisFunction* expr) {
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
#undef __
|
||||
|
||||
|
||||
|
155
deps/v8/src/ia32/fast-codegen-ia32.h
vendored
Normal file
155
deps/v8/src/ia32/fast-codegen-ia32.h
vendored
Normal file
@ -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_
|
82
deps/v8/src/ia32/virtual-frame-ia32.cc
vendored
82
deps/v8/src/ia32/virtual-frame-ia32.cc
vendored
@ -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);
|
||||
|
||||
// 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);
|
||||
} else {
|
||||
// Register eax is free for value, which frees edx for receiver.
|
||||
value.ToRegister(eax);
|
||||
receiver.ToRegister(edx);
|
||||
}
|
||||
} else {
|
||||
// Register edx is free for receiver, which guarantees eax is free for
|
||||
// value.
|
||||
receiver.ToRegister(edx);
|
||||
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);
|
||||
|
||||
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 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
|
||||
|
12
deps/v8/src/ia32/virtual-frame-ia32.h
vendored
12
deps/v8/src/ia32/virtual-frame-ia32.h
vendored
@ -339,12 +339,12 @@ class VirtualFrame: public ZoneObject {
|
||||
Result CallLoadIC(RelocInfo::Mode mode);
|
||||
|
||||
// Call keyed load IC. Key and receiver are found on top of the
|
||||
// frame. They are not dropped.
|
||||
// frame. Both are dropped.
|
||||
Result CallKeyedLoadIC(RelocInfo::Mode mode);
|
||||
|
||||
// Call store IC. Name, value, and receiver are found on top of the
|
||||
// frame. Receiver is not dropped.
|
||||
Result CallStoreIC();
|
||||
// Call store IC. If the load is contextual, value is found on top of the
|
||||
// frame. If not, value and receiver are on the frame. Both are dropped.
|
||||
Result CallStoreIC(Handle<String> name, bool is_contextual);
|
||||
|
||||
// Call keyed store IC. Value, key, and receiver are found on top
|
||||
// of the frame. Key and receiver are not dropped.
|
||||
@ -415,6 +415,10 @@ class VirtualFrame: public ZoneObject {
|
||||
result->Unuse();
|
||||
}
|
||||
|
||||
// Pushing an expression expects that the expression is trivial (according
|
||||
// to Expression::IsTrivial).
|
||||
void Push(Expression* expr);
|
||||
|
||||
// Nip removes zero or more elements from immediately below the top
|
||||
// of the frame, leaving the previous top-of-frame value on top of
|
||||
// the frame. Nip(k) is equivalent to x = Pop(), Drop(k), Push(x).
|
||||
|
2
deps/v8/src/jump-target-inl.h
vendored
2
deps/v8/src/jump-target-inl.h
vendored
@ -42,7 +42,7 @@ void JumpTarget::InitializeEntryElement(int index, FrameElement* target) {
|
||||
} else if (target->is_copy()) {
|
||||
entry_frame_->elements_[target->index()].set_copied();
|
||||
}
|
||||
if (direction_ == BIDIRECTIONAL) {
|
||||
if (direction_ == BIDIRECTIONAL && !target->is_copy()) {
|
||||
entry_frame_->elements_[index].set_number_info(NumberInfo::kUnknown);
|
||||
}
|
||||
}
|
||||
|
2
deps/v8/src/jump-target.cc
vendored
2
deps/v8/src/jump-target.cc
vendored
@ -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);
|
||||
}
|
||||
|
14
deps/v8/src/macros.py
vendored
14
deps/v8/src/macros.py
vendored
@ -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]);
|
||||
|
11
deps/v8/src/mips/codegen-mips.cc
vendored
11
deps/v8/src/mips/codegen-mips.cc
vendored
@ -305,6 +305,11 @@ void CodeGenerator::GenerateIsArray(ZoneList<Expression*>* args) {
|
||||
}
|
||||
|
||||
|
||||
void CodeGenerator::GenerateIsRegExp(ZoneList<Expression*>* args) {
|
||||
UNIMPLEMENTED_MIPS();
|
||||
}
|
||||
|
||||
|
||||
void CodeGenerator::GenerateIsConstructCall(ZoneList<Expression*>* args) {
|
||||
UNIMPLEMENTED_MIPS();
|
||||
}
|
||||
@ -365,6 +370,11 @@ void CodeGenerator::GenerateRegExpExec(ZoneList<Expression*>* args) {
|
||||
}
|
||||
|
||||
|
||||
void CodeGenerator::GenerateNumberToString(ZoneList<Expression*>* args) {
|
||||
UNIMPLEMENTED_MIPS();
|
||||
}
|
||||
|
||||
|
||||
void CodeGenerator::VisitCallRuntime(CallRuntime* node) {
|
||||
UNIMPLEMENTED_MIPS();
|
||||
}
|
||||
@ -498,4 +508,3 @@ int CompareStub::MinorKey() {
|
||||
#undef __
|
||||
|
||||
} } // namespace v8::internal
|
||||
|
||||
|
4
deps/v8/src/mips/codegen-mips.h
vendored
4
deps/v8/src/mips/codegen-mips.h
vendored
@ -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_
|
||||
|
||||
|
33
deps/v8/src/mirror-delay.js
vendored
33
deps/v8/src/mirror-delay.js
vendored
@ -553,14 +553,16 @@ StringMirror.prototype.length = function() {
|
||||
return this.value_.length;
|
||||
};
|
||||
|
||||
StringMirror.prototype.getTruncatedValue = function(maxLength) {
|
||||
if (maxLength != -1 && this.length() > maxLength) {
|
||||
return this.value_.substring(0, maxLength) +
|
||||
'... (length: ' + this.length() + ')';
|
||||
}
|
||||
return this.value_;
|
||||
}
|
||||
|
||||
StringMirror.prototype.toText = function() {
|
||||
if (this.length() > kMaxProtocolStringLength) {
|
||||
return this.value_.substring(0, kMaxProtocolStringLength) +
|
||||
'... (length: ' + this.length() + ')';
|
||||
} else {
|
||||
return this.value_;
|
||||
}
|
||||
return this.getTruncatedValue(kMaxProtocolStringLength);
|
||||
}
|
||||
|
||||
|
||||
@ -1955,6 +1957,15 @@ JSONProtocolSerializer.prototype.inlineRefs_ = function() {
|
||||
}
|
||||
|
||||
|
||||
JSONProtocolSerializer.prototype.maxStringLength_ = function() {
|
||||
if (IS_UNDEFINED(this.options_) ||
|
||||
IS_UNDEFINED(this.options_.maxStringLength)) {
|
||||
return kMaxProtocolStringLength;
|
||||
}
|
||||
return this.options_.maxStringLength;
|
||||
}
|
||||
|
||||
|
||||
JSONProtocolSerializer.prototype.add_ = function(mirror) {
|
||||
// If this mirror is already in the list just return.
|
||||
for (var i = 0; i < this.mirrors_.length; i++) {
|
||||
@ -1987,8 +1998,7 @@ JSONProtocolSerializer.prototype.serializeReferenceWithDisplayData_ =
|
||||
o.value = mirror.value();
|
||||
break;
|
||||
case STRING_TYPE:
|
||||
// Limit string length.
|
||||
o.value = mirror.toText();
|
||||
o.value = mirror.getTruncatedValue(this.maxStringLength_());
|
||||
break;
|
||||
case FUNCTION_TYPE:
|
||||
o.name = mirror.name();
|
||||
@ -2052,11 +2062,12 @@ JSONProtocolSerializer.prototype.serialize_ = function(mirror, reference,
|
||||
|
||||
case STRING_TYPE:
|
||||
// String values might have their value cropped to keep down size.
|
||||
if (mirror.length() > kMaxProtocolStringLength) {
|
||||
var str = mirror.value().substring(0, kMaxProtocolStringLength);
|
||||
if (this.maxStringLength_() != -1 &&
|
||||
mirror.length() > this.maxStringLength_()) {
|
||||
var str = mirror.getTruncatedValue(this.maxStringLength_());
|
||||
content.value = str;
|
||||
content.fromIndex = 0;
|
||||
content.toIndex = kMaxProtocolStringLength;
|
||||
content.toIndex = this.maxStringLength_();
|
||||
} else {
|
||||
content.value = mirror.value();
|
||||
}
|
||||
|
2
deps/v8/src/objects.h
vendored
2
deps/v8/src/objects.h
vendored
@ -179,7 +179,7 @@ class PropertyDetails BASE_EMBEDDED {
|
||||
class TypeField: public BitField<PropertyType, 0, 3> {};
|
||||
class AttributesField: public BitField<PropertyAttributes, 3, 3> {};
|
||||
class DeletedField: public BitField<uint32_t, 6, 1> {};
|
||||
class IndexField: public BitField<uint32_t, 7, 31-7> {};
|
||||
class IndexField: public BitField<uint32_t, 7, 32-7> {};
|
||||
|
||||
static const int kInitialIndex = 1;
|
||||
private:
|
||||
|
2
deps/v8/src/register-allocator.h
vendored
2
deps/v8/src/register-allocator.h
vendored
@ -141,7 +141,7 @@ class Result BASE_EMBEDDED {
|
||||
|
||||
class TypeField: public BitField<Type, 0, 2> {};
|
||||
class NumberInfoField : public BitField<NumberInfo::Type, 2, 3> {};
|
||||
class DataField: public BitField<uint32_t, 5, 32 - 6> {};
|
||||
class DataField: public BitField<uint32_t, 5, 32 - 5> {};
|
||||
|
||||
inline void CopyTo(Result* destination) const;
|
||||
|
||||
|
128
deps/v8/src/runtime.cc
vendored
128
deps/v8/src/runtime.cc
vendored
@ -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]);
|
||||
CONVERT_ARG_CHECKED(String, sub, 0);
|
||||
CONVERT_ARG_CHECKED(String, pat, 1);
|
||||
|
||||
Object* index = args[2];
|
||||
|
||||
sub->TryFlattenIfNotFlat();
|
||||
pat->TryFlattenIfNotFlat();
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
|
7
deps/v8/src/runtime.js
vendored
7
deps/v8/src/runtime.js
vendored
@ -529,6 +529,13 @@ function ToString(x) {
|
||||
return (IS_NULL(x)) ? 'null' : %ToString(%DefaultString(x));
|
||||
}
|
||||
|
||||
function NonStringToString(x) {
|
||||
if (IS_NUMBER(x)) return %NumberToString(x);
|
||||
if (IS_BOOLEAN(x)) return x ? 'true' : 'false';
|
||||
if (IS_UNDEFINED(x)) return 'undefined';
|
||||
return (IS_NULL(x)) ? 'null' : %ToString(%DefaultString(x));
|
||||
}
|
||||
|
||||
|
||||
// ECMA-262, section 9.9, page 36.
|
||||
function ToObject(x) {
|
||||
|
2
deps/v8/src/scopeinfo.cc
vendored
2
deps/v8/src/scopeinfo.cc
vendored
@ -536,7 +536,7 @@ int ContextSlotCache::Hash(Code* code, String* name) {
|
||||
// Uses only lower 32 bits if pointers are larger.
|
||||
uintptr_t addr_hash =
|
||||
static_cast<uint32_t>(reinterpret_cast<uintptr_t>(code)) >> 2;
|
||||
return (addr_hash ^ name->Hash()) % kLength;
|
||||
return static_cast<int>((addr_hash ^ name->Hash()) % kLength);
|
||||
}
|
||||
|
||||
|
||||
|
4
deps/v8/src/serialize.cc
vendored
4
deps/v8/src/serialize.cc
vendored
@ -852,10 +852,10 @@ void SnapshotByteSink::PutInt(uintptr_t integer, const char* description) {
|
||||
const int max_shift = ((kPointerSize * kBitsPerByte) / 7) * 7;
|
||||
for (int shift = max_shift; shift > 0; shift -= 7) {
|
||||
if (integer >= static_cast<uintptr_t>(1u) << shift) {
|
||||
Put(((integer >> shift) & 0x7f) | 0x80, "IntPart");
|
||||
Put((static_cast<int>((integer >> shift)) & 0x7f) | 0x80, "IntPart");
|
||||
}
|
||||
}
|
||||
PutSection(integer & 0x7f, "IntLastPart");
|
||||
PutSection(static_cast<int>(integer & 0x7f), "IntLastPart");
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
|
2
deps/v8/src/spaces-inl.h
vendored
2
deps/v8/src/spaces-inl.h
vendored
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
120
deps/v8/src/string.js
vendored
120
deps/v8/src/string.js
vendored
@ -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, "<")
|
||||
.replace(/>/g, ">")
|
||||
.replace(/"/g, """)
|
||||
.replace(/'/g, "'");
|
||||
return TO_STRING_INLINE(str).replace(/</g, "<")
|
||||
.replace(/>/g, ">")
|
||||
.replace(/"/g, """)
|
||||
.replace(/'/g, "'");
|
||||
};
|
||||
|
||||
|
||||
@ -813,7 +821,7 @@ function ReplaceResultBuilder(str) {
|
||||
|
||||
|
||||
ReplaceResultBuilder.prototype.add = function(str) {
|
||||
if (!IS_STRING(str)) str = ToString(str);
|
||||
str = TO_STRING_INLINE(str);
|
||||
if (str.length > 0) {
|
||||
var elements = this.elements;
|
||||
elements[elements.length] = str;
|
||||
|
14
deps/v8/src/stub-cache.cc
vendored
14
deps/v8/src/stub-cache.cc
vendored
@ -105,7 +105,7 @@ Object* StubCache::ComputeLoadField(String* name,
|
||||
if (code->IsFailure()) return code;
|
||||
LOG(CodeCreateEvent(Logger::LOAD_IC_TAG, Code::cast(code), name));
|
||||
Object* result = receiver->map()->UpdateCodeCache(name, Code::cast(code));
|
||||
if (result->IsFailure()) return code;
|
||||
if (result->IsFailure()) return result;
|
||||
}
|
||||
return Set(name, receiver->map(), Code::cast(code));
|
||||
}
|
||||
@ -124,7 +124,7 @@ Object* StubCache::ComputeLoadCallback(String* name,
|
||||
if (code->IsFailure()) return code;
|
||||
LOG(CodeCreateEvent(Logger::LOAD_IC_TAG, Code::cast(code), name));
|
||||
Object* result = receiver->map()->UpdateCodeCache(name, Code::cast(code));
|
||||
if (result->IsFailure()) return code;
|
||||
if (result->IsFailure()) return result;
|
||||
}
|
||||
return Set(name, receiver->map(), Code::cast(code));
|
||||
}
|
||||
@ -143,7 +143,7 @@ Object* StubCache::ComputeLoadConstant(String* name,
|
||||
if (code->IsFailure()) return code;
|
||||
LOG(CodeCreateEvent(Logger::LOAD_IC_TAG, Code::cast(code), name));
|
||||
Object* result = receiver->map()->UpdateCodeCache(name, Code::cast(code));
|
||||
if (result->IsFailure()) return code;
|
||||
if (result->IsFailure()) return result;
|
||||
}
|
||||
return Set(name, receiver->map(), Code::cast(code));
|
||||
}
|
||||
@ -160,7 +160,7 @@ Object* StubCache::ComputeLoadInterceptor(String* name,
|
||||
if (code->IsFailure()) return code;
|
||||
LOG(CodeCreateEvent(Logger::LOAD_IC_TAG, Code::cast(code), name));
|
||||
Object* result = receiver->map()->UpdateCodeCache(name, Code::cast(code));
|
||||
if (result->IsFailure()) return code;
|
||||
if (result->IsFailure()) return result;
|
||||
}
|
||||
return Set(name, receiver->map(), Code::cast(code));
|
||||
}
|
||||
@ -189,7 +189,7 @@ Object* StubCache::ComputeLoadGlobal(String* name,
|
||||
if (code->IsFailure()) return code;
|
||||
LOG(CodeCreateEvent(Logger::LOAD_IC_TAG, Code::cast(code), name));
|
||||
Object* result = receiver->map()->UpdateCodeCache(name, Code::cast(code));
|
||||
if (result->IsFailure()) return code;
|
||||
if (result->IsFailure()) return result;
|
||||
}
|
||||
return Set(name, receiver->map(), Code::cast(code));
|
||||
}
|
||||
@ -351,7 +351,7 @@ Object* StubCache::ComputeStoreGlobal(String* name,
|
||||
if (code->IsFailure()) return code;
|
||||
LOG(CodeCreateEvent(Logger::LOAD_IC_TAG, Code::cast(code), name));
|
||||
Object* result = receiver->map()->UpdateCodeCache(name, Code::cast(code));
|
||||
if (result->IsFailure()) return code;
|
||||
if (result->IsFailure()) return result;
|
||||
}
|
||||
return Set(name, receiver->map(), Code::cast(code));
|
||||
}
|
||||
@ -566,7 +566,7 @@ Object* StubCache::ComputeCallGlobal(int argc,
|
||||
ASSERT_EQ(flags, Code::cast(code)->flags());
|
||||
LOG(CodeCreateEvent(Logger::CALL_IC_TAG, Code::cast(code), name));
|
||||
Object* result = receiver->map()->UpdateCodeCache(name, Code::cast(code));
|
||||
if (result->IsFailure()) return code;
|
||||
if (result->IsFailure()) return result;
|
||||
}
|
||||
return Set(name, receiver->map(), Code::cast(code));
|
||||
}
|
||||
|
6
deps/v8/src/utils.h
vendored
6
deps/v8/src/utils.h
vendored
@ -157,7 +157,9 @@ class BitField {
|
||||
|
||||
// Returns a uint32_t mask of bit field.
|
||||
static uint32_t mask() {
|
||||
return (1U << (size + shift)) - (1U << shift);
|
||||
// To use all bits of a uint32 in a bitfield without compiler warnings we
|
||||
// have to compute 2^32 without using a shift count of 32.
|
||||
return ((1U << shift) << size) - (1U << shift);
|
||||
}
|
||||
|
||||
// Returns a uint32_t with the bit field value encoded.
|
||||
@ -168,7 +170,7 @@ class BitField {
|
||||
|
||||
// Extracts the bit field from the value.
|
||||
static T decode(uint32_t value) {
|
||||
return static_cast<T>((value >> shift) & ((1U << (size)) - 1));
|
||||
return static_cast<T>((value & mask()) >> shift);
|
||||
}
|
||||
};
|
||||
|
||||
|
4
deps/v8/src/version.cc
vendored
4
deps/v8/src/version.cc
vendored
@ -34,8 +34,8 @@
|
||||
// cannot be changed without changing the SCons build script.
|
||||
#define MAJOR_VERSION 2
|
||||
#define MINOR_VERSION 1
|
||||
#define BUILD_NUMBER 1
|
||||
#define PATCH_LEVEL 1
|
||||
#define BUILD_NUMBER 2
|
||||
#define PATCH_LEVEL 0
|
||||
#define CANDIDATE_VERSION false
|
||||
|
||||
// Define SONAME to have the SCons build the put a specific SONAME into the
|
||||
|
40
deps/v8/src/x64/assembler-x64.cc
vendored
40
deps/v8/src/x64/assembler-x64.cc
vendored
@ -33,46 +33,6 @@
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Implementation of Register
|
||||
|
||||
Register rax = { 0 };
|
||||
Register rcx = { 1 };
|
||||
Register rdx = { 2 };
|
||||
Register rbx = { 3 };
|
||||
Register rsp = { 4 };
|
||||
Register rbp = { 5 };
|
||||
Register rsi = { 6 };
|
||||
Register rdi = { 7 };
|
||||
Register r8 = { 8 };
|
||||
Register r9 = { 9 };
|
||||
Register r10 = { 10 };
|
||||
Register r11 = { 11 };
|
||||
Register r12 = { 12 };
|
||||
Register r13 = { 13 };
|
||||
Register r14 = { 14 };
|
||||
Register r15 = { 15 };
|
||||
|
||||
Register no_reg = { -1 };
|
||||
|
||||
XMMRegister xmm0 = { 0 };
|
||||
XMMRegister xmm1 = { 1 };
|
||||
XMMRegister xmm2 = { 2 };
|
||||
XMMRegister xmm3 = { 3 };
|
||||
XMMRegister xmm4 = { 4 };
|
||||
XMMRegister xmm5 = { 5 };
|
||||
XMMRegister xmm6 = { 6 };
|
||||
XMMRegister xmm7 = { 7 };
|
||||
XMMRegister xmm8 = { 8 };
|
||||
XMMRegister xmm9 = { 9 };
|
||||
XMMRegister xmm10 = { 10 };
|
||||
XMMRegister xmm11 = { 11 };
|
||||
XMMRegister xmm12 = { 12 };
|
||||
XMMRegister xmm13 = { 13 };
|
||||
XMMRegister xmm14 = { 14 };
|
||||
XMMRegister xmm15 = { 15 };
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Implementation of CpuFeatures
|
||||
|
||||
|
94
deps/v8/src/x64/assembler-x64.h
vendored
94
deps/v8/src/x64/assembler-x64.h
vendored
@ -118,51 +118,23 @@ struct Register {
|
||||
int code_;
|
||||
};
|
||||
|
||||
extern Register rax;
|
||||
extern Register rcx;
|
||||
extern Register rdx;
|
||||
extern Register rbx;
|
||||
extern Register rsp;
|
||||
extern Register rbp;
|
||||
extern Register rsi;
|
||||
extern Register rdi;
|
||||
extern Register r8;
|
||||
extern Register r9;
|
||||
extern Register r10;
|
||||
extern Register r11;
|
||||
extern Register r12;
|
||||
extern Register r13;
|
||||
extern Register r14;
|
||||
extern Register r15;
|
||||
extern Register no_reg;
|
||||
|
||||
|
||||
struct MMXRegister {
|
||||
bool is_valid() const { return 0 <= code_ && code_ < 2; }
|
||||
int code() const {
|
||||
ASSERT(is_valid());
|
||||
return code_;
|
||||
}
|
||||
|
||||
int code_;
|
||||
};
|
||||
|
||||
extern MMXRegister mm0;
|
||||
extern MMXRegister mm1;
|
||||
extern MMXRegister mm2;
|
||||
extern MMXRegister mm3;
|
||||
extern MMXRegister mm4;
|
||||
extern MMXRegister mm5;
|
||||
extern MMXRegister mm6;
|
||||
extern MMXRegister mm7;
|
||||
extern MMXRegister mm8;
|
||||
extern MMXRegister mm9;
|
||||
extern MMXRegister mm10;
|
||||
extern MMXRegister mm11;
|
||||
extern MMXRegister mm12;
|
||||
extern MMXRegister mm13;
|
||||
extern MMXRegister mm14;
|
||||
extern MMXRegister mm15;
|
||||
const Register rax = { 0 };
|
||||
const Register rcx = { 1 };
|
||||
const Register rdx = { 2 };
|
||||
const Register rbx = { 3 };
|
||||
const Register rsp = { 4 };
|
||||
const Register rbp = { 5 };
|
||||
const Register rsi = { 6 };
|
||||
const Register rdi = { 7 };
|
||||
const Register r8 = { 8 };
|
||||
const Register r9 = { 9 };
|
||||
const Register r10 = { 10 };
|
||||
const Register r11 = { 11 };
|
||||
const Register r12 = { 12 };
|
||||
const Register r13 = { 13 };
|
||||
const Register r14 = { 14 };
|
||||
const Register r15 = { 15 };
|
||||
const Register no_reg = { -1 };
|
||||
|
||||
|
||||
struct XMMRegister {
|
||||
@ -186,22 +158,22 @@ struct XMMRegister {
|
||||
int code_;
|
||||
};
|
||||
|
||||
extern XMMRegister xmm0;
|
||||
extern XMMRegister xmm1;
|
||||
extern XMMRegister xmm2;
|
||||
extern XMMRegister xmm3;
|
||||
extern XMMRegister xmm4;
|
||||
extern XMMRegister xmm5;
|
||||
extern XMMRegister xmm6;
|
||||
extern XMMRegister xmm7;
|
||||
extern XMMRegister xmm8;
|
||||
extern XMMRegister xmm9;
|
||||
extern XMMRegister xmm10;
|
||||
extern XMMRegister xmm11;
|
||||
extern XMMRegister xmm12;
|
||||
extern XMMRegister xmm13;
|
||||
extern XMMRegister xmm14;
|
||||
extern XMMRegister xmm15;
|
||||
const XMMRegister xmm0 = { 0 };
|
||||
const XMMRegister xmm1 = { 1 };
|
||||
const XMMRegister xmm2 = { 2 };
|
||||
const XMMRegister xmm3 = { 3 };
|
||||
const XMMRegister xmm4 = { 4 };
|
||||
const XMMRegister xmm5 = { 5 };
|
||||
const XMMRegister xmm6 = { 6 };
|
||||
const XMMRegister xmm7 = { 7 };
|
||||
const XMMRegister xmm8 = { 8 };
|
||||
const XMMRegister xmm9 = { 9 };
|
||||
const XMMRegister xmm10 = { 10 };
|
||||
const XMMRegister xmm11 = { 11 };
|
||||
const XMMRegister xmm12 = { 12 };
|
||||
const XMMRegister xmm13 = { 13 };
|
||||
const XMMRegister xmm14 = { 14 };
|
||||
const XMMRegister xmm15 = { 15 };
|
||||
|
||||
enum Condition {
|
||||
// any value < 0 is considered no_condition
|
||||
|
26
deps/v8/src/x64/codegen-x64.cc
vendored
26
deps/v8/src/x64/codegen-x64.cc
vendored
@ -277,7 +277,7 @@ void CodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) {
|
||||
}
|
||||
|
||||
|
||||
void CodeGenerator::Generate(CompilationInfo* info, Mode mode) {
|
||||
void CodeGenerator::Generate(CompilationInfo* info) {
|
||||
// Record the position for debugging purposes.
|
||||
CodeForFunctionPosition(info->function());
|
||||
|
||||
@ -316,7 +316,7 @@ void CodeGenerator::Generate(CompilationInfo* info, Mode mode) {
|
||||
// rsi: callee's context
|
||||
allocator_->Initialize();
|
||||
|
||||
if (mode == PRIMARY) {
|
||||
if (info->mode() == CompilationInfo::PRIMARY) {
|
||||
frame_->Enter();
|
||||
|
||||
// Allocate space for locals and initialize them.
|
||||
@ -407,6 +407,12 @@ void CodeGenerator::Generate(CompilationInfo* info, Mode mode) {
|
||||
// frame to match this state.
|
||||
frame_->Adjust(3);
|
||||
allocator_->Unuse(rdi);
|
||||
|
||||
// Bind all the bailout labels to the beginning of the function.
|
||||
List<CompilationInfo::Bailout*>* bailouts = info->bailouts();
|
||||
for (int i = 0; i < bailouts->length(); i++) {
|
||||
__ bind(bailouts->at(i)->label());
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize the function return target after the locals are set
|
||||
@ -3627,6 +3633,22 @@ void CodeGenerator::GenerateIsArray(ZoneList<Expression*>* args) {
|
||||
}
|
||||
|
||||
|
||||
void CodeGenerator::GenerateIsRegExp(ZoneList<Expression*>* args) {
|
||||
ASSERT(args->length() == 1);
|
||||
Load(args->at(0));
|
||||
Result value = frame_->Pop();
|
||||
value.ToRegister();
|
||||
ASSERT(value.is_valid());
|
||||
Condition is_smi = masm_->CheckSmi(value.reg());
|
||||
destination()->false_target()->Branch(is_smi);
|
||||
// It is a heap object - get map.
|
||||
// Check if the object is a regexp.
|
||||
__ CmpObjectType(value.reg(), JS_REGEXP_TYPE, kScratchRegister);
|
||||
value.Unuse();
|
||||
destination()->Split(equal);
|
||||
}
|
||||
|
||||
|
||||
void CodeGenerator::GenerateIsObject(ZoneList<Expression*>* args) {
|
||||
// This generates a fast version of:
|
||||
// (typeof(arg) === 'object' || %_ClassOf(arg) == 'RegExp')
|
||||
|
12
deps/v8/src/x64/codegen-x64.h
vendored
12
deps/v8/src/x64/codegen-x64.h
vendored
@ -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);
|
||||
|
38
deps/v8/src/x64/fast-codegen-x64.cc
vendored
38
deps/v8/src/x64/fast-codegen-x64.cc
vendored
@ -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_);
|
||||
}
|
||||
|
||||
|
||||
|
2
deps/v8/src/x64/macro-assembler-x64.h
vendored
2
deps/v8/src/x64/macro-assembler-x64.h
vendored
@ -36,7 +36,7 @@ namespace internal {
|
||||
// Default scratch register used by MacroAssembler (and other code that needs
|
||||
// a spare register). The register isn't callee save, and not used by the
|
||||
// function calling convention.
|
||||
static const Register kScratchRegister = r10;
|
||||
static const Register kScratchRegister = { 10 }; // r10.
|
||||
|
||||
// Convenience for platform-independent signatures.
|
||||
typedef Operand MemOperand;
|
||||
|
62
deps/v8/test/mjsunit/bugs/bug-619.js
vendored
Normal file
62
deps/v8/test/mjsunit/bugs/bug-619.js
vendored
Normal file
@ -0,0 +1,62 @@
|
||||
// Copyright 2010 the V8 project authors. All rights reserved.
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following
|
||||
// disclaimer in the documentation and/or other materials provided
|
||||
// with the distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived
|
||||
// from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// When this bug is corrected move to object-define-property and add
|
||||
// additional tests for configurable in the same manner as existing tests
|
||||
// there.
|
||||
|
||||
var obj = {};
|
||||
obj[1] = 42;
|
||||
assertEquals(42, obj[1]);
|
||||
Object.defineProperty(obj, '1', {value:10, writable:false});
|
||||
assertEquals(10, obj[1]);
|
||||
|
||||
// We should not be able to override obj[1].
|
||||
obj[1] = 5;
|
||||
assertEquals(10, obj[1]);
|
||||
|
||||
// Try on a range of numbers.
|
||||
for(var i = 0; i < 1024; i++) {
|
||||
obj[i] = 42;
|
||||
}
|
||||
|
||||
for(var i = 0; i < 1024; i++) {
|
||||
Object.defineProperty(obj, i, {value: i, writable:false});
|
||||
}
|
||||
|
||||
for(var i = 0; i < 1024; i++) {
|
||||
assertEquals(i, obj[i]);
|
||||
}
|
||||
|
||||
for(var i = 0; i < 1024; i++) {
|
||||
obj[1] = 5;
|
||||
}
|
||||
|
||||
for(var i = 0; i < 1024; i++) {
|
||||
assertEquals(i, obj[i]);
|
||||
}
|
||||
|
37
deps/v8/test/mjsunit/debug-evaluate.js
vendored
37
deps/v8/test/mjsunit/debug-evaluate.js
vendored
@ -87,6 +87,37 @@ function listener(event, exec_state, event_data, data) {
|
||||
testRequest(dcp, '{"expression":"a","global":true}', true, 1);
|
||||
testRequest(dcp, '{"expression":"this.a","global":true}', true, 1);
|
||||
|
||||
// Test that the whole string text is returned if maxStringLength
|
||||
// parameter is passed.
|
||||
testRequest(
|
||||
dcp,
|
||||
'{"expression":"this.longString","global":true,maxStringLength:-1}',
|
||||
true,
|
||||
longString);
|
||||
testRequest(
|
||||
dcp,
|
||||
'{"expression":"this.longString","global":true,maxStringLength:' +
|
||||
longString.length + '}',
|
||||
true,
|
||||
longString);
|
||||
var truncatedStringSuffix = '... (length: ' + longString.length + ')';
|
||||
testRequest(
|
||||
dcp,
|
||||
'{"expression":"this.longString","global":true,maxStringLength:0}',
|
||||
true,
|
||||
truncatedStringSuffix);
|
||||
testRequest(
|
||||
dcp,
|
||||
'{"expression":"this.longString","global":true,maxStringLength:1}',
|
||||
true,
|
||||
longString.charAt(0) + truncatedStringSuffix);
|
||||
// Test that by default string is truncated to first 80 chars.
|
||||
testRequest(
|
||||
dcp,
|
||||
'{"expression":"this.longString","global":true}',
|
||||
true,
|
||||
longString.substring(0, 80) + truncatedStringSuffix);
|
||||
|
||||
// Indicate that all was processed.
|
||||
listenerComplete = true;
|
||||
}
|
||||
@ -109,6 +140,12 @@ function g() {
|
||||
|
||||
a = 1;
|
||||
|
||||
// String which is longer than 80 chars.
|
||||
var longString = "1234567890_";
|
||||
for (var i = 0; i < 4; i++) {
|
||||
longString += longString;
|
||||
}
|
||||
|
||||
// Set a break point at return in f and invoke g to hit the breakpoint.
|
||||
Debug.setBreakPoint(f, 2, 0);
|
||||
g();
|
||||
|
4
deps/v8/tools/gyp/v8.gyp
vendored
4
deps/v8/tools/gyp/v8.gyp
vendored
@ -269,7 +269,6 @@
|
||||
'../../src/execution.h',
|
||||
'../../src/factory.cc',
|
||||
'../../src/factory.h',
|
||||
'../../src/fast-codegen.cc',
|
||||
'../../src/fast-codegen.h',
|
||||
'../../src/flag-definitions.h',
|
||||
'../../src/flags.cc',
|
||||
@ -404,6 +403,7 @@
|
||||
'../../src/arm',
|
||||
],
|
||||
'sources': [
|
||||
'../../src/fast-codegen.cc',
|
||||
'../../src/arm/assembler-arm-inl.h',
|
||||
'../../src/arm/assembler-arm.cc',
|
||||
'../../src/arm/assembler-arm.h',
|
||||
@ -455,6 +455,7 @@
|
||||
'../../src/ia32/debug-ia32.cc',
|
||||
'../../src/ia32/disasm-ia32.cc',
|
||||
'../../src/ia32/fast-codegen-ia32.cc',
|
||||
'../../src/ia32/fast-codegen-ia32.h',
|
||||
'../../src/ia32/frames-ia32.cc',
|
||||
'../../src/ia32/frames-ia32.h',
|
||||
'../../src/ia32/full-codegen-ia32.cc',
|
||||
@ -475,6 +476,7 @@
|
||||
'../../src/x64',
|
||||
],
|
||||
'sources': [
|
||||
'../../src/fast-codegen.cc',
|
||||
'../../src/x64/assembler-x64-inl.h',
|
||||
'../../src/x64/assembler-x64.cc',
|
||||
'../../src/x64/assembler-x64.h',
|
||||
|
2
deps/v8/tools/visual_studio/v8_base.vcproj
vendored
2
deps/v8/tools/visual_studio/v8_base.vcproj
vendored
@ -401,7 +401,7 @@
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\fast-codegen.cc"
|
||||
RelativePath="..\..\src\ia32\fast-codegen-ia32.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
|
Loading…
x
Reference in New Issue
Block a user