Upgrade V8 to 2.5.3
This commit is contained in:
parent
fd725efa8f
commit
ea78d995e0
9
deps/v8/ChangeLog
vendored
9
deps/v8/ChangeLog
vendored
@ -1,3 +1,12 @@
|
||||
2010-11-01: Version 2.5.3
|
||||
|
||||
Fixed a bug that prevents constants from overwriting function values
|
||||
in object literals (issue 907).
|
||||
|
||||
Fixed a bug with reporting of impossible nested calls of DOM functions
|
||||
(issue http://crbug.com/60753).
|
||||
|
||||
|
||||
2010-10-27: Version 2.5.2
|
||||
|
||||
Improved sampler resolution on Linux.
|
||||
|
44
deps/v8/include/v8.h
vendored
44
deps/v8/include/v8.h
vendored
@ -1790,18 +1790,19 @@ class Arguments {
|
||||
inline bool IsConstructCall() const;
|
||||
inline Local<Value> Data() const;
|
||||
private:
|
||||
static const int kDataIndex = 0;
|
||||
static const int kCalleeIndex = -1;
|
||||
static const int kHolderIndex = -2;
|
||||
|
||||
friend class ImplementationUtilities;
|
||||
inline Arguments(Local<Value> data,
|
||||
Local<Object> holder,
|
||||
Local<Function> callee,
|
||||
bool is_construct_call,
|
||||
void** values, int length);
|
||||
Local<Value> data_;
|
||||
Local<Object> holder_;
|
||||
Local<Function> callee_;
|
||||
bool is_construct_call_;
|
||||
void** values_;
|
||||
inline Arguments(internal::Object** implicit_args,
|
||||
internal::Object** values,
|
||||
int length,
|
||||
bool is_construct_call);
|
||||
internal::Object** implicit_args_;
|
||||
internal::Object** values_;
|
||||
int length_;
|
||||
bool is_construct_call_;
|
||||
};
|
||||
|
||||
|
||||
@ -3470,14 +3471,13 @@ void Persistent<T>::ClearWeak() {
|
||||
}
|
||||
|
||||
|
||||
Arguments::Arguments(v8::Local<v8::Value> data,
|
||||
v8::Local<v8::Object> holder,
|
||||
v8::Local<v8::Function> callee,
|
||||
bool is_construct_call,
|
||||
void** values, int length)
|
||||
: data_(data), holder_(holder), callee_(callee),
|
||||
is_construct_call_(is_construct_call),
|
||||
values_(values), length_(length) { }
|
||||
Arguments::Arguments(internal::Object** implicit_args,
|
||||
internal::Object** values, int length,
|
||||
bool is_construct_call)
|
||||
: implicit_args_(implicit_args),
|
||||
values_(values),
|
||||
length_(length),
|
||||
is_construct_call_(is_construct_call) { }
|
||||
|
||||
|
||||
Local<Value> Arguments::operator[](int i) const {
|
||||
@ -3487,7 +3487,8 @@ Local<Value> Arguments::operator[](int i) const {
|
||||
|
||||
|
||||
Local<Function> Arguments::Callee() const {
|
||||
return callee_;
|
||||
return Local<Function>(reinterpret_cast<Function*>(
|
||||
&implicit_args_[kCalleeIndex]));
|
||||
}
|
||||
|
||||
|
||||
@ -3497,12 +3498,13 @@ Local<Object> Arguments::This() const {
|
||||
|
||||
|
||||
Local<Object> Arguments::Holder() const {
|
||||
return holder_;
|
||||
return Local<Object>(reinterpret_cast<Object*>(
|
||||
&implicit_args_[kHolderIndex]));
|
||||
}
|
||||
|
||||
|
||||
Local<Value> Arguments::Data() const {
|
||||
return data_;
|
||||
return Local<Value>(reinterpret_cast<Value*>(&implicit_args_[kDataIndex]));
|
||||
}
|
||||
|
||||
|
||||
|
4
deps/v8/src/api.cc
vendored
4
deps/v8/src/api.cc
vendored
@ -1155,13 +1155,13 @@ void ObjectTemplate::SetInternalFieldCount(int value) {
|
||||
|
||||
ScriptData* ScriptData::PreCompile(const char* input, int length) {
|
||||
unibrow::Utf8InputBuffer<> buf(input, length);
|
||||
return i::Parser::PreParse(i::Handle<i::String>(), &buf, NULL);
|
||||
return i::ParserApi::PreParse(i::Handle<i::String>(), &buf, NULL);
|
||||
}
|
||||
|
||||
|
||||
ScriptData* ScriptData::PreCompile(v8::Handle<String> source) {
|
||||
i::Handle<i::String> str = Utils::OpenHandle(*source);
|
||||
return i::Parser::PreParse(str, NULL, NULL);
|
||||
return i::ParserApi::PreParse(str, NULL, NULL);
|
||||
}
|
||||
|
||||
|
||||
|
22
deps/v8/src/apiutils.h
vendored
22
deps/v8/src/apiutils.h
vendored
@ -29,7 +29,6 @@
|
||||
#define V8_APIUTILS_H_
|
||||
|
||||
namespace v8 {
|
||||
|
||||
class ImplementationUtilities {
|
||||
public:
|
||||
static v8::Handle<v8::Primitive> Undefined();
|
||||
@ -45,12 +44,21 @@ class ImplementationUtilities {
|
||||
return that->names_;
|
||||
}
|
||||
|
||||
static v8::Arguments NewArguments(Local<Value> data,
|
||||
Local<Object> holder,
|
||||
Local<Function> callee,
|
||||
bool is_construct_call,
|
||||
void** argv, int argc) {
|
||||
return v8::Arguments(data, holder, callee, is_construct_call, argv, argc);
|
||||
// Packs additional parameters for the NewArguments function. |implicit_args|
|
||||
// is a pointer to the last element of 3-elements array controlled by GC.
|
||||
static void PrepareArgumentsData(internal::Object** implicit_args,
|
||||
internal::Object* data,
|
||||
internal::JSFunction* callee,
|
||||
internal::Object* holder) {
|
||||
implicit_args[v8::Arguments::kDataIndex] = data;
|
||||
implicit_args[v8::Arguments::kCalleeIndex] = callee;
|
||||
implicit_args[v8::Arguments::kHolderIndex] = holder;
|
||||
}
|
||||
|
||||
static v8::Arguments NewArguments(internal::Object** implicit_args,
|
||||
internal::Object** argv, int argc,
|
||||
bool is_construct_call) {
|
||||
return v8::Arguments(implicit_args, argv, argc, is_construct_call);
|
||||
}
|
||||
|
||||
// Introduce an alias for the handle scope data to allow non-friends
|
||||
|
9
deps/v8/src/arguments.h
vendored
9
deps/v8/src/arguments.h
vendored
@ -84,6 +84,15 @@ class CustomArguments : public Relocatable {
|
||||
values_[1] = holder;
|
||||
values_[0] = data;
|
||||
}
|
||||
|
||||
inline CustomArguments() {
|
||||
#ifdef DEBUG
|
||||
for (size_t i = 0; i < ARRAY_SIZE(values_); i++) {
|
||||
values_[i] = reinterpret_cast<Object*>(kZapValue);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void IterateInstance(ObjectVisitor* v);
|
||||
Object** end() { return values_ + ARRAY_SIZE(values_) - 1; }
|
||||
private:
|
||||
|
26
deps/v8/src/arm/assembler-arm.cc
vendored
26
deps/v8/src/arm/assembler-arm.cc
vendored
@ -1004,7 +1004,7 @@ void Assembler::blx(int branch_offset) { // v5 and above
|
||||
int h = ((branch_offset & 2) >> 1)*B24;
|
||||
int imm24 = branch_offset >> 2;
|
||||
ASSERT(is_int24(imm24));
|
||||
emit(15 << 28 | B27 | B25 | h | (imm24 & Imm24Mask));
|
||||
emit(nv | B27 | B25 | h | (imm24 & Imm24Mask));
|
||||
}
|
||||
|
||||
|
||||
@ -1634,15 +1634,29 @@ void Assembler::stm(BlockAddrMode am,
|
||||
|
||||
|
||||
// Exception-generating instructions and debugging support.
|
||||
void Assembler::stop(const char* msg) {
|
||||
// Stops with a non-negative code less than kNumOfWatchedStops support
|
||||
// enabling/disabling and a counter feature. See simulator-arm.h .
|
||||
void Assembler::stop(const char* msg, Condition cond, int32_t code) {
|
||||
#ifndef __arm__
|
||||
// The simulator handles these special instructions and stops execution.
|
||||
emit(15 << 28 | ((intptr_t) msg));
|
||||
// See constants-arm.h SoftwareInterruptCodes. Unluckily the Assembler and
|
||||
// Simulator do not share constants declaration.
|
||||
ASSERT(code >= kDefaultStopCode);
|
||||
static const uint32_t kStopInterruptCode = 1 << 23;
|
||||
static const uint32_t kMaxStopCode = kStopInterruptCode - 1;
|
||||
// The Simulator will handle the stop instruction and get the message address.
|
||||
// It expects to find the address just after the svc instruction.
|
||||
BlockConstPoolFor(2);
|
||||
if (code >= 0) {
|
||||
svc(kStopInterruptCode + code, cond);
|
||||
} else {
|
||||
svc(kStopInterruptCode + kMaxStopCode, cond);
|
||||
}
|
||||
emit(reinterpret_cast<Instr>(msg));
|
||||
#else // def __arm__
|
||||
#ifdef CAN_USE_ARMV5_INSTRUCTIONS
|
||||
bkpt(0);
|
||||
#else // ndef CAN_USE_ARMV5_INSTRUCTIONS
|
||||
swi(0x9f0001);
|
||||
svc(0x9f0001);
|
||||
#endif // ndef CAN_USE_ARMV5_INSTRUCTIONS
|
||||
#endif // def __arm__
|
||||
}
|
||||
@ -1654,7 +1668,7 @@ void Assembler::bkpt(uint32_t imm16) { // v5 and above
|
||||
}
|
||||
|
||||
|
||||
void Assembler::swi(uint32_t imm24, Condition cond) {
|
||||
void Assembler::svc(uint32_t imm24, Condition cond) {
|
||||
ASSERT(is_uint24(imm24));
|
||||
emit(cond | 15*B24 | imm24);
|
||||
}
|
||||
|
7
deps/v8/src/arm/assembler-arm.h
vendored
7
deps/v8/src/arm/assembler-arm.h
vendored
@ -904,10 +904,13 @@ class Assembler : public Malloced {
|
||||
void stm(BlockAddrMode am, Register base, RegList src, Condition cond = al);
|
||||
|
||||
// Exception-generating instructions and debugging support
|
||||
void stop(const char* msg);
|
||||
static const int kDefaultStopCode = -1;
|
||||
void stop(const char* msg,
|
||||
Condition cond = al,
|
||||
int32_t code = kDefaultStopCode);
|
||||
|
||||
void bkpt(uint32_t imm16); // v5 and above
|
||||
void swi(uint32_t imm24, Condition cond = al);
|
||||
void svc(uint32_t imm24, Condition cond = al);
|
||||
|
||||
// Coprocessor instructions
|
||||
|
||||
|
26
deps/v8/src/arm/codegen-arm.cc
vendored
26
deps/v8/src/arm/codegen-arm.cc
vendored
@ -3596,6 +3596,12 @@ void CodeGenerator::VisitObjectLiteral(ObjectLiteral* node) {
|
||||
frame_->CallRuntime(Runtime::kCreateObjectLiteralShallow, 4);
|
||||
}
|
||||
frame_->EmitPush(r0); // save the result
|
||||
|
||||
// Mark all computed expressions that are bound to a key that
|
||||
// is shadowed by a later occurrence of the same key. For the
|
||||
// marked expressions, no store code is emitted.
|
||||
node->CalculateEmitStore();
|
||||
|
||||
for (int i = 0; i < node->properties()->length(); i++) {
|
||||
// At the start of each iteration, the top of stack contains
|
||||
// the newly created object literal.
|
||||
@ -3612,11 +3618,15 @@ void CodeGenerator::VisitObjectLiteral(ObjectLiteral* node) {
|
||||
if (key->handle()->IsSymbol()) {
|
||||
Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
|
||||
Load(value);
|
||||
frame_->PopToR0();
|
||||
// Fetch the object literal.
|
||||
frame_->SpillAllButCopyTOSToR1();
|
||||
__ mov(r2, Operand(key->handle()));
|
||||
frame_->CallCodeObject(ic, RelocInfo::CODE_TARGET, 0);
|
||||
if (property->emit_store()) {
|
||||
frame_->PopToR0();
|
||||
// Fetch the object literal.
|
||||
frame_->SpillAllButCopyTOSToR1();
|
||||
__ mov(r2, Operand(key->handle()));
|
||||
frame_->CallCodeObject(ic, RelocInfo::CODE_TARGET, 0);
|
||||
} else {
|
||||
frame_->Drop();
|
||||
}
|
||||
break;
|
||||
}
|
||||
// else fall through
|
||||
@ -3624,7 +3634,11 @@ void CodeGenerator::VisitObjectLiteral(ObjectLiteral* node) {
|
||||
frame_->Dup();
|
||||
Load(key);
|
||||
Load(value);
|
||||
frame_->CallRuntime(Runtime::kSetProperty, 3);
|
||||
if (property->emit_store()) {
|
||||
frame_->CallRuntime(Runtime::kSetProperty, 3);
|
||||
} else {
|
||||
frame_->Drop(3);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ObjectLiteral::Property::SETTER: {
|
||||
|
10
deps/v8/src/arm/constants-arm.h
vendored
10
deps/v8/src/arm/constants-arm.h
vendored
@ -186,12 +186,18 @@ enum Shift {
|
||||
|
||||
// Special Software Interrupt codes when used in the presence of the ARM
|
||||
// simulator.
|
||||
// svc (formerly swi) provides a 24bit immediate value. Use bits 22:0 for
|
||||
// standard SoftwareInterrupCode. Bit 23 is reserved for the stop feature.
|
||||
enum SoftwareInterruptCodes {
|
||||
// transition to C code
|
||||
call_rt_redirected = 0x10,
|
||||
// break point
|
||||
break_point = 0x20
|
||||
break_point = 0x20,
|
||||
// stop
|
||||
stop = 1 << 23
|
||||
};
|
||||
static const int32_t kStopCodeMask = stop - 1;
|
||||
static const uint32_t kMaxStopCode = stop - 1;
|
||||
|
||||
|
||||
// Type of VFP register. Determines register encoding.
|
||||
@ -325,7 +331,7 @@ class Instr {
|
||||
inline int SImmed24Field() const { return ((InstructionBits() << 8) >> 8); }
|
||||
|
||||
// Fields used in Software interrupt instructions
|
||||
inline SoftwareInterruptCodes SwiField() const {
|
||||
inline SoftwareInterruptCodes SvcField() const {
|
||||
return static_cast<SoftwareInterruptCodes>(Bits(23, 0));
|
||||
}
|
||||
|
||||
|
10
deps/v8/src/arm/cpu-arm.cc
vendored
10
deps/v8/src/arm/cpu-arm.cc
vendored
@ -70,7 +70,7 @@ void CPU::FlushICache(void* start, size_t size) {
|
||||
// __arm__ may be defined in thumb mode.
|
||||
register uint32_t scno asm("r7") = __ARM_NR_cacheflush;
|
||||
asm volatile(
|
||||
"swi 0x0"
|
||||
"svc 0x0"
|
||||
: "=r" (beg)
|
||||
: "0" (beg), "r" (end), "r" (flg), "r" (scno));
|
||||
#else
|
||||
@ -83,7 +83,7 @@ void CPU::FlushICache(void* start, size_t size) {
|
||||
".ARM \n"
|
||||
"1: push {r7} \n\t"
|
||||
"mov r7, %4 \n\t"
|
||||
"swi 0x0 \n\t"
|
||||
"svc 0x0 \n\t"
|
||||
"pop {r7} \n\t"
|
||||
"@ Enter THUMB Mode\n\t"
|
||||
"adr r3, 2f+1 \n\t"
|
||||
@ -98,20 +98,20 @@ void CPU::FlushICache(void* start, size_t size) {
|
||||
#if defined (__arm__) && !defined(__thumb__)
|
||||
// __arm__ may be defined in thumb mode.
|
||||
asm volatile(
|
||||
"swi %1"
|
||||
"svc %1"
|
||||
: "=r" (beg)
|
||||
: "i" (__ARM_NR_cacheflush), "0" (beg), "r" (end), "r" (flg));
|
||||
#else
|
||||
// Do not use the value of __ARM_NR_cacheflush in the inline assembly
|
||||
// below, because the thumb mode value would be used, which would be
|
||||
// wrong, since we switch to ARM mode before executing the swi instruction
|
||||
// wrong, since we switch to ARM mode before executing the svc instruction
|
||||
asm volatile(
|
||||
"@ Enter ARM Mode \n\t"
|
||||
"adr r3, 1f \n\t"
|
||||
"bx r3 \n\t"
|
||||
".ALIGN 4 \n\t"
|
||||
".ARM \n"
|
||||
"1: swi 0x9f0002 \n"
|
||||
"1: svc 0x9f0002 \n"
|
||||
"@ Enter THUMB Mode\n\t"
|
||||
"adr r3, 2f+1 \n\t"
|
||||
"bx r3 \n\t"
|
||||
|
113
deps/v8/src/arm/disasm-arm.cc
vendored
113
deps/v8/src/arm/disasm-arm.cc
vendored
@ -108,7 +108,7 @@ class Decoder {
|
||||
void PrintShiftImm(Instr* instr);
|
||||
void PrintShiftSat(Instr* instr);
|
||||
void PrintPU(Instr* instr);
|
||||
void PrintSoftwareInterrupt(SoftwareInterruptCodes swi);
|
||||
void PrintSoftwareInterrupt(SoftwareInterruptCodes svc);
|
||||
|
||||
// Handle formatting of instructions and their options.
|
||||
int FormatRegister(Instr* instr, const char* option);
|
||||
@ -126,8 +126,8 @@ class Decoder {
|
||||
void DecodeType4(Instr* instr);
|
||||
void DecodeType5(Instr* instr);
|
||||
void DecodeType6(Instr* instr);
|
||||
void DecodeType7(Instr* instr);
|
||||
void DecodeUnconditional(Instr* instr);
|
||||
// Type 7 includes special Debugger instructions.
|
||||
int DecodeType7(Instr* instr);
|
||||
// For VFP support.
|
||||
void DecodeTypeVFP(Instr* instr);
|
||||
void DecodeType6CoprocessorIns(Instr* instr);
|
||||
@ -290,8 +290,8 @@ void Decoder::PrintPU(Instr* instr) {
|
||||
|
||||
// Print SoftwareInterrupt codes. Factoring this out reduces the complexity of
|
||||
// the FormatOption method.
|
||||
void Decoder::PrintSoftwareInterrupt(SoftwareInterruptCodes swi) {
|
||||
switch (swi) {
|
||||
void Decoder::PrintSoftwareInterrupt(SoftwareInterruptCodes svc) {
|
||||
switch (svc) {
|
||||
case call_rt_redirected:
|
||||
Print("call_rt_redirected");
|
||||
return;
|
||||
@ -299,9 +299,16 @@ void Decoder::PrintSoftwareInterrupt(SoftwareInterruptCodes swi) {
|
||||
Print("break_point");
|
||||
return;
|
||||
default:
|
||||
out_buffer_pos_ += v8i::OS::SNPrintF(out_buffer_ + out_buffer_pos_,
|
||||
"%d",
|
||||
swi);
|
||||
if (svc >= stop) {
|
||||
out_buffer_pos_ += v8i::OS::SNPrintF(out_buffer_ + out_buffer_pos_,
|
||||
"%d - 0x%x",
|
||||
svc & kStopCodeMask,
|
||||
svc & kStopCodeMask);
|
||||
} else {
|
||||
out_buffer_pos_ += v8i::OS::SNPrintF(out_buffer_ + out_buffer_pos_,
|
||||
"%d",
|
||||
svc);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -553,9 +560,9 @@ int Decoder::FormatOption(Instr* instr, const char* format) {
|
||||
PrintShiftRm(instr);
|
||||
return 8;
|
||||
}
|
||||
} else if (format[1] == 'w') { // 'swi
|
||||
ASSERT(STRING_STARTS_WITH(format, "swi"));
|
||||
PrintSoftwareInterrupt(instr->SwiField());
|
||||
} else if (format[1] == 'v') { // 'svc
|
||||
ASSERT(STRING_STARTS_WITH(format, "svc"));
|
||||
PrintSoftwareInterrupt(instr->SvcField());
|
||||
return 3;
|
||||
} else if (format[1] == 'i') { // 'sign: signed extra loads and stores
|
||||
ASSERT(STRING_STARTS_WITH(format, "sign"));
|
||||
@ -1004,72 +1011,27 @@ void Decoder::DecodeType6(Instr* instr) {
|
||||
}
|
||||
|
||||
|
||||
void Decoder::DecodeType7(Instr* instr) {
|
||||
int Decoder::DecodeType7(Instr* instr) {
|
||||
if (instr->Bit(24) == 1) {
|
||||
Format(instr, "swi'cond 'swi");
|
||||
if (instr->SvcField() >= stop) {
|
||||
Format(instr, "stop'cond 'svc");
|
||||
// Also print the stop message. Its address is encoded
|
||||
// in the following 4 bytes.
|
||||
out_buffer_pos_ +=
|
||||
v8i::OS::SNPrintF(out_buffer_ + out_buffer_pos_,
|
||||
"\n %p %08x stop message: %s",
|
||||
reinterpret_cast<int32_t*>(instr + Instr::kInstrSize),
|
||||
*reinterpret_cast<char**>(instr + Instr::kInstrSize),
|
||||
*reinterpret_cast<char**>(instr + Instr::kInstrSize));
|
||||
// We have decoded 2 * Instr::kInstrSize bytes.
|
||||
return 2 * Instr::kInstrSize;
|
||||
} else {
|
||||
Format(instr, "svc'cond 'svc");
|
||||
}
|
||||
} else {
|
||||
DecodeTypeVFP(instr);
|
||||
}
|
||||
}
|
||||
|
||||
void Decoder::DecodeUnconditional(Instr* instr) {
|
||||
if (instr->Bits(7, 4) == 0xB && instr->Bits(27, 25) == 0 && instr->HasL()) {
|
||||
Format(instr, "'memop'h'pu 'rd, ");
|
||||
bool immediate = instr->HasB();
|
||||
switch (instr->PUField()) {
|
||||
case 0: {
|
||||
// Post index, negative.
|
||||
if (instr->HasW()) {
|
||||
Unknown(instr);
|
||||
break;
|
||||
}
|
||||
if (immediate) {
|
||||
Format(instr, "['rn], #-'imm12");
|
||||
} else {
|
||||
Format(instr, "['rn], -'rm");
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 1: {
|
||||
// Post index, positive.
|
||||
if (instr->HasW()) {
|
||||
Unknown(instr);
|
||||
break;
|
||||
}
|
||||
if (immediate) {
|
||||
Format(instr, "['rn], #+'imm12");
|
||||
} else {
|
||||
Format(instr, "['rn], +'rm");
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 2: {
|
||||
// Pre index or offset, negative.
|
||||
if (immediate) {
|
||||
Format(instr, "['rn, #-'imm12]'w");
|
||||
} else {
|
||||
Format(instr, "['rn, -'rm]'w");
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 3: {
|
||||
// Pre index or offset, positive.
|
||||
if (immediate) {
|
||||
Format(instr, "['rn, #+'imm12]'w");
|
||||
} else {
|
||||
Format(instr, "['rn, +'rm]'w");
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
// The PU field is a 2-bit field.
|
||||
UNREACHABLE();
|
||||
break;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
Format(instr, "break 'msg");
|
||||
return Instr::kInstrSize;
|
||||
}
|
||||
|
||||
|
||||
@ -1332,7 +1294,7 @@ int Decoder::InstructionDecode(byte* instr_ptr) {
|
||||
"%08x ",
|
||||
instr->InstructionBits());
|
||||
if (instr->ConditionField() == special_condition) {
|
||||
DecodeUnconditional(instr);
|
||||
UNIMPLEMENTED();
|
||||
return Instr::kInstrSize;
|
||||
}
|
||||
switch (instr->TypeField()) {
|
||||
@ -1362,8 +1324,7 @@ int Decoder::InstructionDecode(byte* instr_ptr) {
|
||||
break;
|
||||
}
|
||||
case 7: {
|
||||
DecodeType7(instr);
|
||||
break;
|
||||
return DecodeType7(instr);
|
||||
}
|
||||
default: {
|
||||
// The type field is 3-bits in the ARM encoding.
|
||||
|
17
deps/v8/src/arm/full-codegen-arm.cc
vendored
17
deps/v8/src/arm/full-codegen-arm.cc
vendored
@ -1169,6 +1169,11 @@ void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
|
||||
// result_saved is false the result is in r0.
|
||||
bool result_saved = false;
|
||||
|
||||
// Mark all computed expressions that are bound to a key that
|
||||
// is shadowed by a later occurrence of the same key. For the
|
||||
// marked expressions, no store code is emitted.
|
||||
expr->CalculateEmitStore();
|
||||
|
||||
for (int i = 0; i < expr->properties()->length(); i++) {
|
||||
ObjectLiteral::Property* property = expr->properties()->at(i);
|
||||
if (property->IsCompileTimeValue()) continue;
|
||||
@ -1190,8 +1195,10 @@ void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
|
||||
VisitForAccumulatorValue(value);
|
||||
__ mov(r2, Operand(key->handle()));
|
||||
__ ldr(r1, MemOperand(sp));
|
||||
Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
|
||||
EmitCallIC(ic, RelocInfo::CODE_TARGET);
|
||||
if (property->emit_store()) {
|
||||
Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
|
||||
EmitCallIC(ic, RelocInfo::CODE_TARGET);
|
||||
}
|
||||
break;
|
||||
}
|
||||
// Fall through.
|
||||
@ -1201,7 +1208,11 @@ void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
|
||||
__ push(r0);
|
||||
VisitForStackValue(key);
|
||||
VisitForStackValue(value);
|
||||
__ CallRuntime(Runtime::kSetProperty, 3);
|
||||
if (property->emit_store()) {
|
||||
__ CallRuntime(Runtime::kSetProperty, 3);
|
||||
} else {
|
||||
__ Drop(3);
|
||||
}
|
||||
break;
|
||||
case ObjectLiteral::Property::GETTER:
|
||||
case ObjectLiteral::Property::SETTER:
|
||||
|
8
deps/v8/src/arm/ic-arm.cc
vendored
8
deps/v8/src/arm/ic-arm.cc
vendored
@ -544,7 +544,7 @@ static void GenerateMonomorphicCacheProbe(MacroAssembler* masm,
|
||||
// Probe the stub cache.
|
||||
Code::Flags flags =
|
||||
Code::ComputeFlags(kind, NOT_IN_LOOP, MONOMORPHIC, NORMAL, argc);
|
||||
StubCache::GenerateProbe(masm, flags, r1, r2, r3, no_reg);
|
||||
StubCache::GenerateProbe(masm, flags, r1, r2, r3, r4, r5);
|
||||
|
||||
// If the stub cache probing failed, the receiver might be a value.
|
||||
// For value objects, we use the map of the prototype objects for
|
||||
@ -583,7 +583,7 @@ static void GenerateMonomorphicCacheProbe(MacroAssembler* masm,
|
||||
|
||||
// Probe the stub cache for the value object.
|
||||
__ bind(&probe);
|
||||
StubCache::GenerateProbe(masm, flags, r1, r2, r3, no_reg);
|
||||
StubCache::GenerateProbe(masm, flags, r1, r2, r3, r4, r5);
|
||||
|
||||
__ bind(&miss);
|
||||
}
|
||||
@ -858,7 +858,7 @@ void LoadIC::GenerateMegamorphic(MacroAssembler* masm) {
|
||||
Code::Flags flags = Code::ComputeFlags(Code::LOAD_IC,
|
||||
NOT_IN_LOOP,
|
||||
MONOMORPHIC);
|
||||
StubCache::GenerateProbe(masm, flags, r0, r2, r3, no_reg);
|
||||
StubCache::GenerateProbe(masm, flags, r0, r2, r3, r4, r5);
|
||||
|
||||
// Cache miss: Jump to runtime.
|
||||
GenerateMiss(masm);
|
||||
@ -2163,7 +2163,7 @@ void StoreIC::GenerateMegamorphic(MacroAssembler* masm) {
|
||||
Code::Flags flags = Code::ComputeFlags(Code::STORE_IC,
|
||||
NOT_IN_LOOP,
|
||||
MONOMORPHIC);
|
||||
StubCache::GenerateProbe(masm, flags, r1, r2, r3, no_reg);
|
||||
StubCache::GenerateProbe(masm, flags, r1, r2, r3, r4, r5);
|
||||
|
||||
// Cache miss: Jump to runtime.
|
||||
GenerateMiss(masm);
|
||||
|
299
deps/v8/src/arm/simulator-arm.cc
vendored
299
deps/v8/src/arm/simulator-arm.cc
vendored
@ -112,15 +112,29 @@ static void InitializeCoverage() {
|
||||
|
||||
|
||||
void Debugger::Stop(Instr* instr) {
|
||||
char* str = reinterpret_cast<char*>(instr->InstructionBits() & 0x0fffffff);
|
||||
if (strlen(str) > 0) {
|
||||
// Get the stop code.
|
||||
uint32_t code = instr->SvcField() & kStopCodeMask;
|
||||
// Retrieve the encoded address, which comes just after this stop.
|
||||
char** msg_address =
|
||||
reinterpret_cast<char**>(sim_->get_pc() + Instr::kInstrSize);
|
||||
char* msg = *msg_address;
|
||||
ASSERT(msg != NULL);
|
||||
|
||||
// Update this stop description.
|
||||
if (isWatchedStop(code) && !watched_stops[code].desc) {
|
||||
watched_stops[code].desc = msg;
|
||||
}
|
||||
|
||||
if (strlen(msg) > 0) {
|
||||
if (coverage_log != NULL) {
|
||||
fprintf(coverage_log, "%s\n", str);
|
||||
fprintf(coverage_log, "%s\n", msg);
|
||||
fflush(coverage_log);
|
||||
}
|
||||
instr->SetInstructionBits(0xe1a00000); // Overwrite with nop.
|
||||
// Overwrite the instruction and address with nops.
|
||||
instr->SetInstructionBits(kNopInstr);
|
||||
reinterpret_cast<Instr*>(msg_address)->SetInstructionBits(kNopInstr);
|
||||
}
|
||||
sim_->set_pc(sim_->get_pc() + Instr::kInstrSize);
|
||||
sim_->set_pc(sim_->get_pc() + 2 * Instr::kInstrSize);
|
||||
}
|
||||
|
||||
#else // ndef GENERATED_CODE_COVERAGE
|
||||
@ -130,9 +144,16 @@ static void InitializeCoverage() {
|
||||
|
||||
|
||||
void Debugger::Stop(Instr* instr) {
|
||||
const char* str = (const char*)(instr->InstructionBits() & 0x0fffffff);
|
||||
PrintF("Simulator hit %s\n", str);
|
||||
sim_->set_pc(sim_->get_pc() + Instr::kInstrSize);
|
||||
// Get the stop code.
|
||||
uint32_t code = instr->SvcField() & kStopCodeMask;
|
||||
// Retrieve the encoded address, which comes just after this stop.
|
||||
char* msg = *reinterpret_cast<char**>(sim_->get_pc() + Instr::kInstrSize);
|
||||
// Update this stop description.
|
||||
if (sim_->isWatchedStop(code) && !sim_->watched_stops[code].desc) {
|
||||
sim_->watched_stops[code].desc = msg;
|
||||
}
|
||||
PrintF("Simulator hit %s\n", msg);
|
||||
sim_->set_pc(sim_->get_pc() + 2 * Instr::kInstrSize);
|
||||
Debug();
|
||||
}
|
||||
#endif
|
||||
@ -359,6 +380,7 @@ void Debugger::Debug() {
|
||||
// use a reasonably large buffer
|
||||
v8::internal::EmbeddedVector<char, 256> buffer;
|
||||
|
||||
byte* prev = NULL;
|
||||
byte* cur = NULL;
|
||||
byte* end = NULL;
|
||||
|
||||
@ -368,9 +390,9 @@ void Debugger::Debug() {
|
||||
} else if (argc == 2) {
|
||||
int32_t value;
|
||||
if (GetValue(arg1, &value)) {
|
||||
cur = reinterpret_cast<byte*>(value);
|
||||
// no length parameter passed, assume 10 instructions
|
||||
end = cur + (10 * Instr::kInstrSize);
|
||||
cur = reinterpret_cast<byte*>(sim_->get_pc());
|
||||
// Disassemble <arg1> instructions.
|
||||
end = cur + (value * Instr::kInstrSize);
|
||||
}
|
||||
} else {
|
||||
int32_t value1;
|
||||
@ -382,10 +404,10 @@ void Debugger::Debug() {
|
||||
}
|
||||
|
||||
while (cur < end) {
|
||||
dasm.InstructionDecode(buffer, cur);
|
||||
prev = cur;
|
||||
cur += dasm.InstructionDecode(buffer, cur);
|
||||
PrintF(" 0x%08x %s\n",
|
||||
reinterpret_cast<intptr_t>(cur), buffer.start());
|
||||
cur += Instr::kInstrSize;
|
||||
reinterpret_cast<intptr_t>(prev), buffer.start());
|
||||
}
|
||||
} else if (strcmp(cmd, "gdb") == 0) {
|
||||
PrintF("relinquishing control to gdb\n");
|
||||
@ -418,13 +440,58 @@ void Debugger::Debug() {
|
||||
PrintF("OVERFLOW flag: %d; ", sim_->overflow_vfp_flag_);
|
||||
PrintF("UNDERFLOW flag: %d; ", sim_->underflow_vfp_flag_);
|
||||
PrintF("INEXACT flag: %d; ", sim_->inexact_vfp_flag_);
|
||||
} else if (strcmp(cmd, "unstop") == 0) {
|
||||
intptr_t stop_pc = sim_->get_pc() - Instr::kInstrSize;
|
||||
} else if (strcmp(cmd, "stop") == 0) {
|
||||
int32_t value;
|
||||
intptr_t stop_pc = sim_->get_pc() - 2 * Instr::kInstrSize;
|
||||
Instr* stop_instr = reinterpret_cast<Instr*>(stop_pc);
|
||||
if (stop_instr->ConditionField() == special_condition) {
|
||||
stop_instr->SetInstructionBits(kNopInstr);
|
||||
Instr* msg_address =
|
||||
reinterpret_cast<Instr*>(stop_pc + Instr::kInstrSize);
|
||||
if ((argc == 2) && (strcmp(arg1, "unstop") == 0)) {
|
||||
// Remove the current stop.
|
||||
if (sim_->isStopInstruction(stop_instr)) {
|
||||
stop_instr->SetInstructionBits(kNopInstr);
|
||||
msg_address->SetInstructionBits(kNopInstr);
|
||||
} else {
|
||||
PrintF("Not at debugger stop.\n");
|
||||
}
|
||||
} else if (argc == 3) {
|
||||
// Print information about all/the specified breakpoint(s).
|
||||
if (strcmp(arg1, "info") == 0) {
|
||||
if (strcmp(arg2, "all") == 0) {
|
||||
PrintF("Stop information:\n");
|
||||
for (uint32_t i = 0; i < sim_->kNumOfWatchedStops; i++) {
|
||||
sim_->PrintStopInfo(i);
|
||||
}
|
||||
} else if (GetValue(arg2, &value)) {
|
||||
sim_->PrintStopInfo(value);
|
||||
} else {
|
||||
PrintF("Unrecognized argument.\n");
|
||||
}
|
||||
} else if (strcmp(arg1, "enable") == 0) {
|
||||
// Enable all/the specified breakpoint(s).
|
||||
if (strcmp(arg2, "all") == 0) {
|
||||
for (uint32_t i = 0; i < sim_->kNumOfWatchedStops; i++) {
|
||||
sim_->EnableStop(i);
|
||||
}
|
||||
} else if (GetValue(arg2, &value)) {
|
||||
sim_->EnableStop(value);
|
||||
} else {
|
||||
PrintF("Unrecognized argument.\n");
|
||||
}
|
||||
} else if (strcmp(arg1, "disable") == 0) {
|
||||
// Disable all/the specified breakpoint(s).
|
||||
if (strcmp(arg2, "all") == 0) {
|
||||
for (uint32_t i = 0; i < sim_->kNumOfWatchedStops; i++) {
|
||||
sim_->DisableStop(i);
|
||||
}
|
||||
} else if (GetValue(arg2, &value)) {
|
||||
sim_->DisableStop(value);
|
||||
} else {
|
||||
PrintF("Unrecognized argument.\n");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
PrintF("Not at debugger stop.");
|
||||
PrintF("Wrong usage. Use help command for more information.\n");
|
||||
}
|
||||
} else if ((strcmp(cmd, "t") == 0) || strcmp(cmd, "trace") == 0) {
|
||||
::v8::internal::FLAG_trace_sim = !::v8::internal::FLAG_trace_sim;
|
||||
@ -455,11 +522,29 @@ void Debugger::Debug() {
|
||||
PrintF(" set a break point on the address\n");
|
||||
PrintF("del\n");
|
||||
PrintF(" delete the breakpoint\n");
|
||||
PrintF("unstop\n");
|
||||
PrintF(" ignore the stop instruction at the current location");
|
||||
PrintF(" from now on\n");
|
||||
PrintF("trace (alias 't')\n");
|
||||
PrintF(" toogle the tracing of all executed statements\n");
|
||||
PrintF("stop feature:\n");
|
||||
PrintF(" Description:\n");
|
||||
PrintF(" Stops are debug instructions inserted by\n");
|
||||
PrintF(" the Assembler::stop() function.\n");
|
||||
PrintF(" When hitting a stop, the Simulator will\n");
|
||||
PrintF(" stop and and give control to the Debugger.\n");
|
||||
PrintF(" The first %d stop codes are watched:\n",
|
||||
Simulator::kNumOfWatchedStops);
|
||||
PrintF(" - They can be enabled / disabled: the Simulator\n");
|
||||
PrintF(" will / won't stop when hitting them.\n");
|
||||
PrintF(" - The Simulator keeps track of how many times they \n");
|
||||
PrintF(" are met. (See the info command.) Going over a\n");
|
||||
PrintF(" disabled stop still increases its counter. \n");
|
||||
PrintF(" Commands:\n");
|
||||
PrintF(" stop info all/<code> : print infos about number <code>\n");
|
||||
PrintF(" or all stop(s).\n");
|
||||
PrintF(" stop enable/disable all/<code> : enables / disables\n");
|
||||
PrintF(" all or number <code> stop(s)\n");
|
||||
PrintF(" stop unstop\n");
|
||||
PrintF(" ignore the stop instruction at the current location\n");
|
||||
PrintF(" from now on\n");
|
||||
} else {
|
||||
PrintF("Unknown command: %s\n", cmd);
|
||||
}
|
||||
@ -643,9 +728,9 @@ Simulator::Simulator() {
|
||||
// the simulator. The external reference will be a function compiled for the
|
||||
// host architecture. We need to call that function instead of trying to
|
||||
// execute it with the simulator. We do that by redirecting the external
|
||||
// reference to a swi (software-interrupt) instruction that is handled by
|
||||
// reference to a svc (Supervisor Call) instruction that is handled by
|
||||
// the simulator. We write the original destination of the jump just at a known
|
||||
// offset from the swi instruction so the simulator knows what to call.
|
||||
// offset from the svc instruction so the simulator knows what to call.
|
||||
class Redirection {
|
||||
public:
|
||||
Redirection(void* external_function, bool fp_return)
|
||||
@ -1434,8 +1519,8 @@ typedef double (*SimulatorRuntimeFPCall)(int32_t arg0,
|
||||
// Software interrupt instructions are used by the simulator to call into the
|
||||
// C-based V8 runtime.
|
||||
void Simulator::SoftwareInterrupt(Instr* instr) {
|
||||
int swi = instr->SwiField();
|
||||
switch (swi) {
|
||||
int svc = instr->SvcField();
|
||||
switch (svc) {
|
||||
case call_rt_redirected: {
|
||||
// Check if stack is aligned. Error if not aligned is reported below to
|
||||
// include information on the function called.
|
||||
@ -1505,9 +1590,98 @@ void Simulator::SoftwareInterrupt(Instr* instr) {
|
||||
dbg.Debug();
|
||||
break;
|
||||
}
|
||||
// stop uses all codes greater than 1 << 23.
|
||||
default: {
|
||||
UNREACHABLE();
|
||||
break;
|
||||
if (svc >= (1 << 23)) {
|
||||
uint32_t code = svc & kStopCodeMask;
|
||||
if (isWatchedStop(code)) {
|
||||
IncreaseStopCounter(code);
|
||||
}
|
||||
// Stop if it is enabled, otherwise go on jumping over the stop
|
||||
// and the message address.
|
||||
if (isEnabledStop(code)) {
|
||||
Debugger dbg(this);
|
||||
dbg.Stop(instr);
|
||||
} else {
|
||||
set_pc(get_pc() + 2 * Instr::kInstrSize);
|
||||
}
|
||||
} else {
|
||||
// This is not a valid svc code.
|
||||
UNREACHABLE();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Stop helper functions.
|
||||
bool Simulator::isStopInstruction(Instr* instr) {
|
||||
return (instr->Bits(27, 24) == 0xF) && (instr->SvcField() >= stop);
|
||||
}
|
||||
|
||||
|
||||
bool Simulator::isWatchedStop(uint32_t code) {
|
||||
ASSERT(code <= kMaxStopCode);
|
||||
return code < kNumOfWatchedStops;
|
||||
}
|
||||
|
||||
|
||||
bool Simulator::isEnabledStop(uint32_t code) {
|
||||
ASSERT(code <= kMaxStopCode);
|
||||
// Unwatched stops are always enabled.
|
||||
return !isWatchedStop(code) ||
|
||||
!(watched_stops[code].count & kStopDisabledBit);
|
||||
}
|
||||
|
||||
|
||||
void Simulator::EnableStop(uint32_t code) {
|
||||
ASSERT(isWatchedStop(code));
|
||||
if (!isEnabledStop(code)) {
|
||||
watched_stops[code].count &= ~kStopDisabledBit;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Simulator::DisableStop(uint32_t code) {
|
||||
ASSERT(isWatchedStop(code));
|
||||
if (isEnabledStop(code)) {
|
||||
watched_stops[code].count |= kStopDisabledBit;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Simulator::IncreaseStopCounter(uint32_t code) {
|
||||
ASSERT(code <= kMaxStopCode);
|
||||
ASSERT(isWatchedStop(code));
|
||||
if ((watched_stops[code].count & ~(1 << 31)) == 0x7fffffff) {
|
||||
PrintF("Stop counter for code %i has overflowed.\n"
|
||||
"Enabling this code and reseting the counter to 0.\n", code);
|
||||
watched_stops[code].count = 0;
|
||||
EnableStop(code);
|
||||
} else {
|
||||
watched_stops[code].count++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Print a stop status.
|
||||
void Simulator::PrintStopInfo(uint32_t code) {
|
||||
ASSERT(code <= kMaxStopCode);
|
||||
if (!isWatchedStop(code)) {
|
||||
PrintF("Stop not watched.");
|
||||
} else {
|
||||
const char* state = isEnabledStop(code) ? "Enabled" : "Disabled";
|
||||
int32_t count = watched_stops[code].count & ~kStopDisabledBit;
|
||||
// Don't print the state of unused breakpoints.
|
||||
if (count != 0) {
|
||||
if (watched_stops[code].desc) {
|
||||
PrintF("stop %i - 0x%x: \t%s, \tcounter = %i, \t%s\n",
|
||||
code, code, state, count, watched_stops[code].desc);
|
||||
} else {
|
||||
PrintF("stop %i - 0x%x: \t%s, \tcounter = %i\n",
|
||||
code, code, state, count);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2216,73 +2390,6 @@ void Simulator::DecodeType7(Instr* instr) {
|
||||
}
|
||||
|
||||
|
||||
void Simulator::DecodeUnconditional(Instr* instr) {
|
||||
if (instr->Bits(7, 4) == 0x0B && instr->Bits(27, 25) == 0 && instr->HasL()) {
|
||||
// Load halfword instruction, either register or immediate offset.
|
||||
int rd = instr->RdField();
|
||||
int rn = instr->RnField();
|
||||
int32_t rn_val = get_register(rn);
|
||||
int32_t addr = 0;
|
||||
int32_t offset;
|
||||
if (instr->Bit(22) == 0) {
|
||||
// Register offset.
|
||||
int rm = instr->RmField();
|
||||
offset = get_register(rm);
|
||||
} else {
|
||||
// Immediate offset
|
||||
offset = instr->Bits(3, 0) + (instr->Bits(11, 8) << 4);
|
||||
}
|
||||
switch (instr->PUField()) {
|
||||
case 0: {
|
||||
// Post index, negative.
|
||||
ASSERT(!instr->HasW());
|
||||
addr = rn_val;
|
||||
rn_val -= offset;
|
||||
set_register(rn, rn_val);
|
||||
break;
|
||||
}
|
||||
case 1: {
|
||||
// Post index, positive.
|
||||
ASSERT(!instr->HasW());
|
||||
addr = rn_val;
|
||||
rn_val += offset;
|
||||
set_register(rn, rn_val);
|
||||
break;
|
||||
}
|
||||
case 2: {
|
||||
// Pre index or offset, negative.
|
||||
rn_val -= offset;
|
||||
addr = rn_val;
|
||||
if (instr->HasW()) {
|
||||
set_register(rn, rn_val);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 3: {
|
||||
// Pre index or offset, positive.
|
||||
rn_val += offset;
|
||||
addr = rn_val;
|
||||
if (instr->HasW()) {
|
||||
set_register(rn, rn_val);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
// The PU field is a 2-bit field.
|
||||
UNREACHABLE();
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Not sign extending, so load as unsigned.
|
||||
uint16_t halfword = ReadH(addr, instr);
|
||||
set_register(rd, halfword);
|
||||
} else {
|
||||
Debugger dbg(this);
|
||||
dbg.Stop(instr);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// void Simulator::DecodeTypeVFP(Instr* instr)
|
||||
// The Following ARMv7 VFPv instructions are currently supported.
|
||||
// vmov :Sn = Rt
|
||||
@ -2655,7 +2762,7 @@ void Simulator::InstructionDecode(Instr* instr) {
|
||||
PrintF(" 0x%08x %s\n", reinterpret_cast<intptr_t>(instr), buffer.start());
|
||||
}
|
||||
if (instr->ConditionField() == special_condition) {
|
||||
DecodeUnconditional(instr);
|
||||
UNIMPLEMENTED();
|
||||
} else if (ConditionallyExecute(instr)) {
|
||||
switch (instr->TypeField()) {
|
||||
case 0:
|
||||
|
27
deps/v8/src/arm/simulator-arm.h
vendored
27
deps/v8/src/arm/simulator-arm.h
vendored
@ -226,6 +226,15 @@ class Simulator {
|
||||
void HandleRList(Instr* instr, bool load);
|
||||
void SoftwareInterrupt(Instr* instr);
|
||||
|
||||
// Stop helper functions.
|
||||
inline bool isStopInstruction(Instr* instr);
|
||||
inline bool isWatchedStop(uint32_t bkpt_code);
|
||||
inline bool isEnabledStop(uint32_t bkpt_code);
|
||||
inline void EnableStop(uint32_t bkpt_code);
|
||||
inline void DisableStop(uint32_t bkpt_code);
|
||||
inline void IncreaseStopCounter(uint32_t bkpt_code);
|
||||
void PrintStopInfo(uint32_t code);
|
||||
|
||||
// Read and write memory.
|
||||
inline uint8_t ReadBU(int32_t addr);
|
||||
inline int8_t ReadB(int32_t addr);
|
||||
@ -252,7 +261,6 @@ class Simulator {
|
||||
void DecodeType5(Instr* instr);
|
||||
void DecodeType6(Instr* instr);
|
||||
void DecodeType7(Instr* instr);
|
||||
void DecodeUnconditional(Instr* instr);
|
||||
|
||||
// Support for VFP.
|
||||
void DecodeTypeVFP(Instr* instr);
|
||||
@ -317,6 +325,23 @@ class Simulator {
|
||||
// Registered breakpoints.
|
||||
Instr* break_pc_;
|
||||
instr_t break_instr_;
|
||||
|
||||
// A stop is watched if its code is less than kNumOfWatchedStops.
|
||||
// Only watched stops support enabling/disabling and the counter feature.
|
||||
static const uint32_t kNumOfWatchedStops = 256;
|
||||
|
||||
// Breakpoint is disabled if bit 31 is set.
|
||||
static const uint32_t kStopDisabledBit = 1 << 31;
|
||||
|
||||
// A stop is enabled, meaning the simulator will stop when meeting the
|
||||
// instruction, if bit 31 of watched_stops[code].count is unset.
|
||||
// The value watched_stops[code].count & ~(1 << 31) indicates how many times
|
||||
// the breakpoint was hit or gone through.
|
||||
struct StopCoundAndDesc {
|
||||
uint32_t count;
|
||||
char* desc;
|
||||
};
|
||||
StopCoundAndDesc watched_stops[kNumOfWatchedStops];
|
||||
};
|
||||
|
||||
} } // namespace assembler::arm
|
||||
|
59
deps/v8/src/arm/stub-cache-arm.cc
vendored
59
deps/v8/src/arm/stub-cache-arm.cc
vendored
@ -43,43 +43,49 @@ static void ProbeTable(MacroAssembler* masm,
|
||||
Code::Flags flags,
|
||||
StubCache::Table table,
|
||||
Register name,
|
||||
Register offset) {
|
||||
Register offset,
|
||||
Register scratch,
|
||||
Register scratch2) {
|
||||
ExternalReference key_offset(SCTableReference::keyReference(table));
|
||||
ExternalReference value_offset(SCTableReference::valueReference(table));
|
||||
|
||||
Label miss;
|
||||
uint32_t key_off_addr = reinterpret_cast<uint32_t>(key_offset.address());
|
||||
uint32_t value_off_addr = reinterpret_cast<uint32_t>(value_offset.address());
|
||||
|
||||
// Save the offset on the stack.
|
||||
__ push(offset);
|
||||
// Check the relative positions of the address fields.
|
||||
ASSERT(value_off_addr > key_off_addr);
|
||||
ASSERT((value_off_addr - key_off_addr) % 4 == 0);
|
||||
ASSERT((value_off_addr - key_off_addr) < (256 * 4));
|
||||
|
||||
Label miss;
|
||||
Register offsets_base_addr = scratch;
|
||||
|
||||
// Check that the key in the entry matches the name.
|
||||
__ mov(ip, Operand(key_offset));
|
||||
__ ldr(ip, MemOperand(ip, offset, LSL, 1));
|
||||
__ mov(offsets_base_addr, Operand(key_offset));
|
||||
__ ldr(ip, MemOperand(offsets_base_addr, offset, LSL, 1));
|
||||
__ cmp(name, ip);
|
||||
__ b(ne, &miss);
|
||||
|
||||
// Get the code entry from the cache.
|
||||
__ mov(ip, Operand(value_offset));
|
||||
__ ldr(offset, MemOperand(ip, offset, LSL, 1));
|
||||
__ add(offsets_base_addr, offsets_base_addr,
|
||||
Operand(value_off_addr - key_off_addr));
|
||||
__ ldr(scratch2, MemOperand(offsets_base_addr, offset, LSL, 1));
|
||||
|
||||
// Check that the flags match what we're looking for.
|
||||
__ ldr(offset, FieldMemOperand(offset, Code::kFlagsOffset));
|
||||
__ and_(offset, offset, Operand(~Code::kFlagsNotUsedInLookup));
|
||||
__ cmp(offset, Operand(flags));
|
||||
__ ldr(scratch2, FieldMemOperand(scratch2, Code::kFlagsOffset));
|
||||
__ bic(scratch2, scratch2, Operand(Code::kFlagsNotUsedInLookup));
|
||||
__ cmp(scratch2, Operand(flags));
|
||||
__ b(ne, &miss);
|
||||
|
||||
// Restore offset and re-load code entry from cache.
|
||||
__ pop(offset);
|
||||
__ mov(ip, Operand(value_offset));
|
||||
__ ldr(offset, MemOperand(ip, offset, LSL, 1));
|
||||
// Re-load code entry from cache.
|
||||
__ ldr(offset, MemOperand(offsets_base_addr, offset, LSL, 1));
|
||||
|
||||
// Jump to the first instruction in the code stub.
|
||||
__ add(offset, offset, Operand(Code::kHeaderSize - kHeapObjectTag));
|
||||
__ Jump(offset);
|
||||
|
||||
// Miss: Restore offset and fall through.
|
||||
// Miss: fall through.
|
||||
__ bind(&miss);
|
||||
__ pop(offset);
|
||||
}
|
||||
|
||||
|
||||
@ -201,7 +207,8 @@ void StubCache::GenerateProbe(MacroAssembler* masm,
|
||||
Register receiver,
|
||||
Register name,
|
||||
Register scratch,
|
||||
Register extra) {
|
||||
Register extra,
|
||||
Register extra2) {
|
||||
Label miss;
|
||||
|
||||
// Make sure that code is valid. The shifting code relies on the
|
||||
@ -214,6 +221,18 @@ void StubCache::GenerateProbe(MacroAssembler* masm,
|
||||
// Make sure that there are no register conflicts.
|
||||
ASSERT(!scratch.is(receiver));
|
||||
ASSERT(!scratch.is(name));
|
||||
ASSERT(!extra.is(receiver));
|
||||
ASSERT(!extra.is(name));
|
||||
ASSERT(!extra.is(scratch));
|
||||
ASSERT(!extra2.is(receiver));
|
||||
ASSERT(!extra2.is(name));
|
||||
ASSERT(!extra2.is(scratch));
|
||||
ASSERT(!extra2.is(extra));
|
||||
|
||||
// Check scratch, extra and extra2 registers are valid.
|
||||
ASSERT(!scratch.is(no_reg));
|
||||
ASSERT(!extra.is(no_reg));
|
||||
ASSERT(!extra2.is(no_reg));
|
||||
|
||||
// Check that the receiver isn't a smi.
|
||||
__ tst(receiver, Operand(kSmiTagMask));
|
||||
@ -229,7 +248,7 @@ void StubCache::GenerateProbe(MacroAssembler* masm,
|
||||
Operand((kPrimaryTableSize - 1) << kHeapObjectTagSize));
|
||||
|
||||
// Probe the primary table.
|
||||
ProbeTable(masm, flags, kPrimary, name, scratch);
|
||||
ProbeTable(masm, flags, kPrimary, name, scratch, extra, extra2);
|
||||
|
||||
// Primary miss: Compute hash for secondary probe.
|
||||
__ sub(scratch, scratch, Operand(name));
|
||||
@ -239,7 +258,7 @@ void StubCache::GenerateProbe(MacroAssembler* masm,
|
||||
Operand((kSecondaryTableSize - 1) << kHeapObjectTagSize));
|
||||
|
||||
// Probe the secondary table.
|
||||
ProbeTable(masm, flags, kSecondary, name, scratch);
|
||||
ProbeTable(masm, flags, kSecondary, name, scratch, extra, extra2);
|
||||
|
||||
// Cache miss: Fall-through and let caller handle the miss by
|
||||
// entering the runtime system.
|
||||
|
74
deps/v8/src/ast.cc
vendored
74
deps/v8/src/ast.cc
vendored
@ -140,6 +140,7 @@ bool FunctionLiteral::AllowsLazyCompilation() {
|
||||
|
||||
|
||||
ObjectLiteral::Property::Property(Literal* key, Expression* value) {
|
||||
emit_store_ = true;
|
||||
key_ = key;
|
||||
value_ = value;
|
||||
Object* k = *key->handle();
|
||||
@ -156,6 +157,7 @@ ObjectLiteral::Property::Property(Literal* key, Expression* value) {
|
||||
|
||||
|
||||
ObjectLiteral::Property::Property(bool is_getter, FunctionLiteral* value) {
|
||||
emit_store_ = true;
|
||||
key_ = new Literal(value->name());
|
||||
value_ = value;
|
||||
kind_ = is_getter ? GETTER : SETTER;
|
||||
@ -169,6 +171,78 @@ bool ObjectLiteral::Property::IsCompileTimeValue() {
|
||||
}
|
||||
|
||||
|
||||
void ObjectLiteral::Property::set_emit_store(bool emit_store) {
|
||||
emit_store_ = emit_store;
|
||||
}
|
||||
|
||||
|
||||
bool ObjectLiteral::Property::emit_store() {
|
||||
return emit_store_;
|
||||
}
|
||||
|
||||
|
||||
bool IsEqualString(void* first, void* second) {
|
||||
Handle<String> h1(reinterpret_cast<String**>(first));
|
||||
Handle<String> h2(reinterpret_cast<String**>(second));
|
||||
return (*h1)->Equals(*h2);
|
||||
}
|
||||
|
||||
bool IsEqualSmi(void* first, void* second) {
|
||||
Handle<Smi> h1(reinterpret_cast<Smi**>(first));
|
||||
Handle<Smi> h2(reinterpret_cast<Smi**>(second));
|
||||
return (*h1)->value() == (*h2)->value();
|
||||
}
|
||||
|
||||
void ObjectLiteral::CalculateEmitStore() {
|
||||
HashMap properties(&IsEqualString);
|
||||
HashMap elements(&IsEqualSmi);
|
||||
for (int i = this->properties()->length() - 1; i >= 0; i--) {
|
||||
ObjectLiteral::Property* property = this->properties()->at(i);
|
||||
Literal* literal = property->key();
|
||||
Handle<Object> handle = literal->handle();
|
||||
|
||||
if (handle->IsNull()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
uint32_t hash;
|
||||
HashMap* table;
|
||||
void* key;
|
||||
uint32_t index;
|
||||
if (handle->IsSymbol()) {
|
||||
Handle<String> name(String::cast(*handle));
|
||||
ASSERT(!name->AsArrayIndex(&index));
|
||||
key = name.location();
|
||||
hash = name->Hash();
|
||||
table = &properties;
|
||||
} else if (handle->ToArrayIndex(&index)) {
|
||||
key = handle.location();
|
||||
hash = index;
|
||||
table = &elements;
|
||||
} else {
|
||||
ASSERT(handle->IsNumber());
|
||||
double num = handle->Number();
|
||||
char arr[100];
|
||||
Vector<char> buffer(arr, ARRAY_SIZE(arr));
|
||||
const char* str = DoubleToCString(num, buffer);
|
||||
Handle<String> name = Factory::NewStringFromAscii(CStrVector(str));
|
||||
key = name.location();
|
||||
hash = name->Hash();
|
||||
table = &properties;
|
||||
}
|
||||
// If the key of a computed property is in the table, do not emit
|
||||
// a store for the property later.
|
||||
if (property->kind() == ObjectLiteral::Property::COMPUTED) {
|
||||
if (table->Lookup(literal, hash, false) != NULL) {
|
||||
property->set_emit_store(false);
|
||||
}
|
||||
}
|
||||
// Add key to the table.
|
||||
table->Lookup(literal, hash, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void TargetCollector::AddTarget(BreakTarget* target) {
|
||||
// Add the label to the collector, but discard duplicates.
|
||||
int length = targets_->length();
|
||||
|
10
deps/v8/src/ast.h
vendored
10
deps/v8/src/ast.h
vendored
@ -832,10 +832,14 @@ class ObjectLiteral: public MaterializedLiteral {
|
||||
|
||||
bool IsCompileTimeValue();
|
||||
|
||||
void set_emit_store(bool emit_store);
|
||||
bool emit_store();
|
||||
|
||||
private:
|
||||
Literal* key_;
|
||||
Expression* value_;
|
||||
Kind kind_;
|
||||
bool emit_store_;
|
||||
};
|
||||
|
||||
ObjectLiteral(Handle<FixedArray> constant_properties,
|
||||
@ -858,6 +862,12 @@ class ObjectLiteral: public MaterializedLiteral {
|
||||
|
||||
bool fast_elements() const { return fast_elements_; }
|
||||
|
||||
|
||||
// Mark all computed expressions that are bound to a key that
|
||||
// is shadowed by a later occurrence of the same key. For the
|
||||
// marked expressions, no store code is emitted.
|
||||
void CalculateEmitStore();
|
||||
|
||||
private:
|
||||
Handle<FixedArray> constant_properties_;
|
||||
ZoneList<Property*>* properties_;
|
||||
|
72
deps/v8/src/builtins.cc
vendored
72
deps/v8/src/builtins.cc
vendored
@ -1014,20 +1014,18 @@ MUST_USE_RESULT static MaybeObject* HandleApiCallHelper(
|
||||
Object* data_obj = call_data->data();
|
||||
Object* result;
|
||||
|
||||
Handle<Object> data_handle(data_obj);
|
||||
v8::Local<v8::Value> data = v8::Utils::ToLocal(data_handle);
|
||||
ASSERT(raw_holder->IsJSObject());
|
||||
v8::Local<v8::Function> callee = v8::Utils::ToLocal(function);
|
||||
Handle<JSObject> holder_handle(JSObject::cast(raw_holder));
|
||||
v8::Local<v8::Object> holder = v8::Utils::ToLocal(holder_handle);
|
||||
LOG(ApiObjectAccess("call", JSObject::cast(*args.receiver())));
|
||||
ASSERT(raw_holder->IsJSObject());
|
||||
|
||||
CustomArguments custom;
|
||||
v8::ImplementationUtilities::PrepareArgumentsData(custom.end(),
|
||||
data_obj, *function, raw_holder);
|
||||
|
||||
v8::Arguments new_args = v8::ImplementationUtilities::NewArguments(
|
||||
data,
|
||||
holder,
|
||||
callee,
|
||||
is_construct,
|
||||
reinterpret_cast<void**>(&args[0] - 1),
|
||||
args.length() - 1);
|
||||
custom.end(),
|
||||
&args[0] - 1,
|
||||
args.length() - 1,
|
||||
is_construct);
|
||||
|
||||
v8::Handle<v8::Value> value;
|
||||
{
|
||||
@ -1089,26 +1087,22 @@ BUILTIN(FastHandleApiCall) {
|
||||
|
||||
Handle<JSFunction> function = args.at<JSFunction>(args_length);
|
||||
Object* callback_obj = args[args_length + 1];
|
||||
Handle<Object> data_handle = args.at<Object>(args_length + 2);
|
||||
Handle<Object> data = args.at<Object>(args_length + 2);
|
||||
Handle<JSObject> checked_holder = args.at<JSObject>(args_length + 3);
|
||||
|
||||
#ifdef DEBUG
|
||||
VerifyTypeCheck(checked_holder, function);
|
||||
#endif
|
||||
|
||||
v8::Local<v8::Object> holder = v8::Utils::ToLocal(checked_holder);
|
||||
v8::Local<v8::Function> callee = v8::Utils::ToLocal(function);
|
||||
v8::InvocationCallback callback =
|
||||
v8::ToCData<v8::InvocationCallback>(callback_obj);
|
||||
v8::Local<v8::Value> data = v8::Utils::ToLocal(data_handle);
|
||||
CustomArguments custom;
|
||||
v8::ImplementationUtilities::PrepareArgumentsData(custom.end(),
|
||||
*data, *function, *checked_holder);
|
||||
|
||||
v8::Arguments new_args = v8::ImplementationUtilities::NewArguments(
|
||||
data,
|
||||
holder,
|
||||
callee,
|
||||
is_construct,
|
||||
reinterpret_cast<void**>(&args[0] - 1),
|
||||
args_length - 1);
|
||||
custom.end(),
|
||||
&args[0] - 1,
|
||||
args_length - 1,
|
||||
is_construct);
|
||||
|
||||
HandleScope scope;
|
||||
Object* result;
|
||||
@ -1119,6 +1113,9 @@ BUILTIN(FastHandleApiCall) {
|
||||
#ifdef ENABLE_LOGGING_AND_PROFILING
|
||||
state.set_external_callback(v8::ToCData<Address>(callback_obj));
|
||||
#endif
|
||||
v8::InvocationCallback callback =
|
||||
v8::ToCData<v8::InvocationCallback>(callback_obj);
|
||||
|
||||
value = callback(new_args);
|
||||
}
|
||||
if (value.IsEmpty()) {
|
||||
@ -1161,23 +1158,20 @@ MUST_USE_RESULT static MaybeObject* HandleApiCallAsFunctionOrConstructor(
|
||||
v8::ToCData<v8::InvocationCallback>(callback_obj);
|
||||
|
||||
// Get the data for the call and perform the callback.
|
||||
Object* data_obj = call_data->data();
|
||||
Object* result;
|
||||
{ HandleScope scope;
|
||||
v8::Local<v8::Object> self =
|
||||
v8::Utils::ToLocal(Handle<JSObject>::cast(args.receiver()));
|
||||
Handle<Object> data_handle(data_obj);
|
||||
v8::Local<v8::Value> data = v8::Utils::ToLocal(data_handle);
|
||||
Handle<JSFunction> callee_handle(constructor);
|
||||
v8::Local<v8::Function> callee = v8::Utils::ToLocal(callee_handle);
|
||||
LOG(ApiObjectAccess("call non-function", JSObject::cast(*args.receiver())));
|
||||
{
|
||||
HandleScope scope;
|
||||
|
||||
LOG(ApiObjectAccess("call non-function", obj));
|
||||
|
||||
CustomArguments custom;
|
||||
v8::ImplementationUtilities::PrepareArgumentsData(custom.end(),
|
||||
call_data->data(), constructor, obj);
|
||||
v8::Arguments new_args = v8::ImplementationUtilities::NewArguments(
|
||||
data,
|
||||
self,
|
||||
callee,
|
||||
is_construct_call,
|
||||
reinterpret_cast<void**>(&args[0] - 1),
|
||||
args.length() - 1);
|
||||
custom.end(),
|
||||
&args[0] - 1,
|
||||
args.length() - 1,
|
||||
is_construct_call);
|
||||
v8::Handle<v8::Value> value;
|
||||
{
|
||||
// Leaving JavaScript.
|
||||
|
33
deps/v8/src/compiler.cc
vendored
33
deps/v8/src/compiler.cc
vendored
@ -152,10 +152,8 @@ static Handle<SharedFunctionInfo> MakeFunctionInfo(CompilationInfo* info) {
|
||||
script->set_context_data((*i::Top::global_context())->data());
|
||||
|
||||
#ifdef ENABLE_DEBUGGER_SUPPORT
|
||||
if (info->is_eval() || info->is_json()) {
|
||||
Script::CompilationType compilation_type = info->is_json()
|
||||
? Script::COMPILATION_TYPE_JSON
|
||||
: Script::COMPILATION_TYPE_EVAL;
|
||||
if (info->is_eval()) {
|
||||
Script::CompilationType compilation_type = Script::COMPILATION_TYPE_EVAL;
|
||||
script->set_compilation_type(Smi::FromInt(compilation_type));
|
||||
// For eval scripts add information on the function from which eval was
|
||||
// called.
|
||||
@ -178,7 +176,7 @@ static Handle<SharedFunctionInfo> MakeFunctionInfo(CompilationInfo* info) {
|
||||
// Only allow non-global compiles for eval.
|
||||
ASSERT(info->is_eval() || info->is_global());
|
||||
|
||||
if (!Parser::Parse(info)) return Handle<SharedFunctionInfo>::null();
|
||||
if (!ParserApi::Parse(info)) return Handle<SharedFunctionInfo>::null();
|
||||
|
||||
// Measure how long it takes to do the compilation; only take the
|
||||
// rest of the function into account to avoid overlap with the
|
||||
@ -283,7 +281,7 @@ Handle<SharedFunctionInfo> Compiler::Compile(Handle<String> source,
|
||||
if (pre_data == NULL
|
||||
&& FLAG_lazy
|
||||
&& source_length >= FLAG_min_preparse_length) {
|
||||
pre_data = Parser::PartialPreParse(source, NULL, extension);
|
||||
pre_data = ParserApi::PartialPreParse(source, NULL, extension);
|
||||
}
|
||||
|
||||
// Create a script object describing the script to be compiled.
|
||||
@ -323,13 +321,7 @@ Handle<SharedFunctionInfo> Compiler::Compile(Handle<String> source,
|
||||
|
||||
Handle<SharedFunctionInfo> Compiler::CompileEval(Handle<String> source,
|
||||
Handle<Context> context,
|
||||
bool is_global,
|
||||
ValidationState validate) {
|
||||
// Note that if validation is required then no path through this function
|
||||
// is allowed to return a value without validating that the input is legal
|
||||
// json.
|
||||
bool is_json = (validate == VALIDATE_JSON);
|
||||
|
||||
bool is_global) {
|
||||
int source_length = source->length();
|
||||
Counters::total_eval_size.Increment(source_length);
|
||||
Counters::total_compile_size.Increment(source_length);
|
||||
@ -338,13 +330,9 @@ Handle<SharedFunctionInfo> Compiler::CompileEval(Handle<String> source,
|
||||
VMState state(COMPILER);
|
||||
|
||||
// Do a lookup in the compilation cache; if the entry is not there, invoke
|
||||
// the compiler and add the result to the cache. If we're evaluating json
|
||||
// we bypass the cache since we can't be sure a potential value in the
|
||||
// cache has been validated.
|
||||
// the compiler and add the result to the cache.
|
||||
Handle<SharedFunctionInfo> result;
|
||||
if (!is_json) {
|
||||
result = CompilationCache::LookupEval(source, context, is_global);
|
||||
}
|
||||
result = CompilationCache::LookupEval(source, context, is_global);
|
||||
|
||||
if (result.is_null()) {
|
||||
// Create a script object describing the script to be compiled.
|
||||
@ -352,12 +340,9 @@ Handle<SharedFunctionInfo> Compiler::CompileEval(Handle<String> source,
|
||||
CompilationInfo info(script);
|
||||
info.MarkAsEval();
|
||||
if (is_global) info.MarkAsGlobal();
|
||||
if (is_json) info.MarkAsJson();
|
||||
info.SetCallingContext(context);
|
||||
result = MakeFunctionInfo(&info);
|
||||
if (!result.is_null() && !is_json) {
|
||||
// For json it's unlikely that we'll ever see exactly the same string
|
||||
// again so we don't use the compilation cache.
|
||||
if (!result.is_null()) {
|
||||
CompilationCache::PutEval(source, context, is_global, result);
|
||||
}
|
||||
}
|
||||
@ -379,7 +364,7 @@ bool Compiler::CompileLazy(CompilationInfo* info) {
|
||||
Counters::total_compile_size.Increment(compiled_size);
|
||||
|
||||
// Generate the AST for the lazily compiled function.
|
||||
if (Parser::Parse(info)) {
|
||||
if (ParserApi::Parse(info)) {
|
||||
// Measure how long it takes to do the lazy compilation; only take the
|
||||
// rest of the function into account to avoid overlap with the lazy
|
||||
// parsing statistics.
|
||||
|
15
deps/v8/src/compiler.h
vendored
15
deps/v8/src/compiler.h
vendored
@ -49,7 +49,6 @@ class CompilationInfo BASE_EMBEDDED {
|
||||
bool is_lazy() const { return (flags_ & IsLazy::mask()) != 0; }
|
||||
bool is_eval() const { return (flags_ & IsEval::mask()) != 0; }
|
||||
bool is_global() const { return (flags_ & IsGlobal::mask()) != 0; }
|
||||
bool is_json() const { return (flags_ & IsJson::mask()) != 0; }
|
||||
bool is_in_loop() const { return (flags_ & IsInLoop::mask()) != 0; }
|
||||
FunctionLiteral* function() const { return function_; }
|
||||
Scope* scope() const { return scope_; }
|
||||
@ -69,10 +68,6 @@ class CompilationInfo BASE_EMBEDDED {
|
||||
ASSERT(!is_lazy());
|
||||
flags_ |= IsGlobal::encode(true);
|
||||
}
|
||||
void MarkAsJson() {
|
||||
ASSERT(!is_lazy());
|
||||
flags_ |= IsJson::encode(true);
|
||||
}
|
||||
void MarkAsInLoop() {
|
||||
ASSERT(is_lazy());
|
||||
flags_ |= IsInLoop::encode(true);
|
||||
@ -108,16 +103,15 @@ class CompilationInfo BASE_EMBEDDED {
|
||||
// Flags that can be set for eager compilation.
|
||||
class IsEval: public BitField<bool, 1, 1> {};
|
||||
class IsGlobal: public BitField<bool, 2, 1> {};
|
||||
class IsJson: public BitField<bool, 3, 1> {};
|
||||
// Flags that can be set for lazy compilation.
|
||||
class IsInLoop: public BitField<bool, 4, 1> {};
|
||||
class IsInLoop: public BitField<bool, 3, 1> {};
|
||||
|
||||
unsigned flags_;
|
||||
|
||||
// Fields filled in by the compilation pipeline.
|
||||
// AST filled in by the parser.
|
||||
FunctionLiteral* function_;
|
||||
// The scope of the function literal as a convenience. Set to indidicate
|
||||
// The scope of the function literal as a convenience. Set to indicate
|
||||
// that scopes have been analyzed.
|
||||
Scope* scope_;
|
||||
// The compiled code.
|
||||
@ -153,8 +147,6 @@ class CompilationInfo BASE_EMBEDDED {
|
||||
|
||||
class Compiler : public AllStatic {
|
||||
public:
|
||||
enum ValidationState { DONT_VALIDATE_JSON, VALIDATE_JSON };
|
||||
|
||||
// All routines return a JSFunction.
|
||||
// If an error occurs an exception is raised and
|
||||
// the return handle contains NULL.
|
||||
@ -172,8 +164,7 @@ class Compiler : public AllStatic {
|
||||
// Compile a String source within a context for Eval.
|
||||
static Handle<SharedFunctionInfo> CompileEval(Handle<String> source,
|
||||
Handle<Context> context,
|
||||
bool is_global,
|
||||
ValidationState validation);
|
||||
bool is_global);
|
||||
|
||||
// Compile from function info (used for lazy compilation). Returns true on
|
||||
// success and false if the compilation resulted in a stack overflow.
|
||||
|
2
deps/v8/src/debug-debugger.js
vendored
2
deps/v8/src/debug-debugger.js
vendored
@ -1301,7 +1301,7 @@ DebugCommandProcessor.prototype.processDebugJSONRequest = function(json_request)
|
||||
try {
|
||||
try {
|
||||
// Convert the JSON string to an object.
|
||||
request = %CompileString('(' + json_request + ')', false)();
|
||||
request = %CompileString('(' + json_request + ')')();
|
||||
|
||||
// Create an initial response.
|
||||
response = this.createResponse(request);
|
||||
|
6
deps/v8/src/debug.cc
vendored
6
deps/v8/src/debug.cc
vendored
@ -1464,8 +1464,7 @@ bool Debug::IsSourceBreakStub(Code* code) {
|
||||
// location.
|
||||
bool Debug::IsBreakStub(Code* code) {
|
||||
CodeStub::Major major_key = CodeStub::GetMajorKey(code);
|
||||
return major_key == CodeStub::CallFunction ||
|
||||
major_key == CodeStub::StackCheck;
|
||||
return major_key == CodeStub::CallFunction;
|
||||
}
|
||||
|
||||
|
||||
@ -1503,8 +1502,7 @@ Handle<Code> Debug::FindDebugBreak(Handle<Code> code, RelocInfo::Mode mode) {
|
||||
return result;
|
||||
}
|
||||
if (code->kind() == Code::STUB) {
|
||||
ASSERT(code->major_key() == CodeStub::CallFunction ||
|
||||
code->major_key() == CodeStub::StackCheck);
|
||||
ASSERT(code->major_key() == CodeStub::CallFunction);
|
||||
Handle<Code> result =
|
||||
Handle<Code>(Builtins::builtin(Builtins::StubNoRegisters_DebugBreak));
|
||||
return result;
|
||||
|
2
deps/v8/src/execution.cc
vendored
2
deps/v8/src/execution.cc
vendored
@ -797,6 +797,7 @@ v8::Handle<v8::Value> ExternalizeStringExtension::Externalize(
|
||||
if (result && !string->IsSymbol()) {
|
||||
i::ExternalStringTable::AddString(*string);
|
||||
}
|
||||
if (!result) delete resource;
|
||||
} else {
|
||||
uc16* data = new uc16[string->length()];
|
||||
String::WriteToFlat(*string, data, 0, string->length());
|
||||
@ -806,6 +807,7 @@ v8::Handle<v8::Value> ExternalizeStringExtension::Externalize(
|
||||
if (result && !string->IsSymbol()) {
|
||||
i::ExternalStringTable::AddString(*string);
|
||||
}
|
||||
if (!result) delete resource;
|
||||
}
|
||||
if (!result) {
|
||||
return v8::ThrowException(v8::String::New("externalizeString() failed."));
|
||||
|
3
deps/v8/src/flag-definitions.h
vendored
3
deps/v8/src/flag-definitions.h
vendored
@ -140,6 +140,9 @@ DEFINE_bool(stack_trace_on_abort, true,
|
||||
// codegen-ia32.cc / codegen-arm.cc
|
||||
DEFINE_bool(trace, false, "trace function calls")
|
||||
DEFINE_bool(defer_negation, true, "defer negation operation")
|
||||
DEFINE_bool(mask_constants_with_cookie,
|
||||
true,
|
||||
"use random jit cookie to mask large constants")
|
||||
|
||||
// codegen.cc
|
||||
DEFINE_bool(lazy, true, "use lazy compilation")
|
||||
|
21
deps/v8/src/heap.cc
vendored
21
deps/v8/src/heap.cc
vendored
@ -581,25 +581,22 @@ void Heap::EnsureFromSpaceIsCommitted() {
|
||||
}
|
||||
|
||||
|
||||
class ClearThreadJSFunctionResultCachesVisitor: public ThreadVisitor {
|
||||
virtual void VisitThread(ThreadLocalTop* top) {
|
||||
Context* context = top->context_;
|
||||
if (context == NULL) return;
|
||||
void Heap::ClearJSFunctionResultCaches() {
|
||||
if (Bootstrapper::IsActive()) return;
|
||||
|
||||
Object* context = global_contexts_list_;
|
||||
while (!context->IsUndefined()) {
|
||||
// Get the caches for this context:
|
||||
FixedArray* caches =
|
||||
context->global()->global_context()->jsfunction_result_caches();
|
||||
Context::cast(context)->jsfunction_result_caches();
|
||||
// Clear the caches:
|
||||
int length = caches->length();
|
||||
for (int i = 0; i < length; i++) {
|
||||
JSFunctionResultCache::cast(caches->get(i))->Clear();
|
||||
}
|
||||
// Get the next context:
|
||||
context = Context::cast(context)->get(Context::NEXT_CONTEXT_LINK);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
void Heap::ClearJSFunctionResultCaches() {
|
||||
if (Bootstrapper::IsActive()) return;
|
||||
ClearThreadJSFunctionResultCachesVisitor visitor;
|
||||
ThreadManager::IterateArchivedThreads(&visitor);
|
||||
}
|
||||
|
||||
|
||||
|
54
deps/v8/src/ia32/codegen-ia32.cc
vendored
54
deps/v8/src/ia32/codegen-ia32.cc
vendored
@ -153,7 +153,8 @@ CodeGenerator::CodeGenerator(MacroAssembler* masm)
|
||||
in_safe_int32_mode_(false),
|
||||
safe_int32_mode_enabled_(true),
|
||||
function_return_is_shadowed_(false),
|
||||
in_spilled_code_(false) {
|
||||
in_spilled_code_(false),
|
||||
jit_cookie_((FLAG_mask_constants_with_cookie) ? V8::Random() : 0) {
|
||||
}
|
||||
|
||||
|
||||
@ -5363,16 +5364,16 @@ void CodeGenerator::VisitLiteral(Literal* node) {
|
||||
void CodeGenerator::PushUnsafeSmi(Handle<Object> value) {
|
||||
ASSERT(value->IsSmi());
|
||||
int bits = reinterpret_cast<int>(*value);
|
||||
__ push(Immediate(bits & 0x0000FFFF));
|
||||
__ or_(Operand(esp, 0), Immediate(bits & 0xFFFF0000));
|
||||
__ push(Immediate(bits ^ jit_cookie_));
|
||||
__ xor_(Operand(esp, 0), Immediate(jit_cookie_));
|
||||
}
|
||||
|
||||
|
||||
void CodeGenerator::StoreUnsafeSmiToLocal(int offset, Handle<Object> value) {
|
||||
ASSERT(value->IsSmi());
|
||||
int bits = reinterpret_cast<int>(*value);
|
||||
__ mov(Operand(ebp, offset), Immediate(bits & 0x0000FFFF));
|
||||
__ or_(Operand(ebp, offset), Immediate(bits & 0xFFFF0000));
|
||||
__ mov(Operand(ebp, offset), Immediate(bits ^ jit_cookie_));
|
||||
__ xor_(Operand(ebp, offset), Immediate(jit_cookie_));
|
||||
}
|
||||
|
||||
|
||||
@ -5380,8 +5381,8 @@ void CodeGenerator::MoveUnsafeSmi(Register target, Handle<Object> value) {
|
||||
ASSERT(target.is_valid());
|
||||
ASSERT(value->IsSmi());
|
||||
int bits = reinterpret_cast<int>(*value);
|
||||
__ Set(target, Immediate(bits & 0x0000FFFF));
|
||||
__ or_(target, bits & 0xFFFF0000);
|
||||
__ Set(target, Immediate(bits ^ jit_cookie_));
|
||||
__ xor_(target, jit_cookie_);
|
||||
}
|
||||
|
||||
|
||||
@ -5559,6 +5560,11 @@ void CodeGenerator::VisitObjectLiteral(ObjectLiteral* node) {
|
||||
}
|
||||
frame_->Push(&clone);
|
||||
|
||||
// Mark all computed expressions that are bound to a key that
|
||||
// is shadowed by a later occurrence of the same key. For the
|
||||
// marked expressions, no store code is emitted.
|
||||
node->CalculateEmitStore();
|
||||
|
||||
for (int i = 0; i < node->properties()->length(); i++) {
|
||||
ObjectLiteral::Property* property = node->properties()->at(i);
|
||||
switch (property->kind()) {
|
||||
@ -5573,24 +5579,32 @@ void CodeGenerator::VisitObjectLiteral(ObjectLiteral* node) {
|
||||
// Duplicate the object as the IC receiver.
|
||||
frame_->Dup();
|
||||
Load(property->value());
|
||||
Result ignored =
|
||||
frame_->CallStoreIC(Handle<String>::cast(key), false);
|
||||
// A test eax instruction following the store IC call would
|
||||
// indicate the presence of an inlined version of the
|
||||
// store. Add a nop to indicate that there is no such
|
||||
// inlined version.
|
||||
__ nop();
|
||||
if (property->emit_store()) {
|
||||
Result ignored =
|
||||
frame_->CallStoreIC(Handle<String>::cast(key), false);
|
||||
// A test eax instruction following the store IC call would
|
||||
// indicate the presence of an inlined version of the
|
||||
// store. Add a nop to indicate that there is no such
|
||||
// inlined version.
|
||||
__ nop();
|
||||
} else {
|
||||
frame_->Drop(2);
|
||||
}
|
||||
break;
|
||||
}
|
||||
// Fall through
|
||||
}
|
||||
case ObjectLiteral::Property::PROTOTYPE: {
|
||||
// Duplicate the object as an argument to the runtime call.
|
||||
frame_->Dup();
|
||||
Load(property->key());
|
||||
Load(property->value());
|
||||
Result ignored = frame_->CallRuntime(Runtime::kSetProperty, 3);
|
||||
// Ignore the result.
|
||||
// Duplicate the object as an argument to the runtime call.
|
||||
frame_->Dup();
|
||||
Load(property->key());
|
||||
Load(property->value());
|
||||
if (property->emit_store()) {
|
||||
// Ignore the result.
|
||||
Result ignored = frame_->CallRuntime(Runtime::kSetProperty, 3);
|
||||
} else {
|
||||
frame_->Drop(3);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ObjectLiteral::Property::SETTER: {
|
||||
|
5
deps/v8/src/ia32/codegen-ia32.h
vendored
5
deps/v8/src/ia32/codegen-ia32.h
vendored
@ -785,6 +785,11 @@ class CodeGenerator: public AstVisitor {
|
||||
// in a spilled state.
|
||||
bool in_spilled_code_;
|
||||
|
||||
// A cookie that is used for JIT IMM32 Encoding. Initialized to a
|
||||
// random number when the command-line
|
||||
// FLAG_mask_constants_with_cookie is true, zero otherwise.
|
||||
int jit_cookie_;
|
||||
|
||||
friend class VirtualFrame;
|
||||
friend class JumpTarget;
|
||||
friend class Reference;
|
||||
|
17
deps/v8/src/ia32/full-codegen-ia32.cc
vendored
17
deps/v8/src/ia32/full-codegen-ia32.cc
vendored
@ -1202,6 +1202,11 @@ void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
|
||||
// result_saved is false the result is in eax.
|
||||
bool result_saved = false;
|
||||
|
||||
// Mark all computed expressions that are bound to a key that
|
||||
// is shadowed by a later occurrence of the same key. For the
|
||||
// marked expressions, no store code is emitted.
|
||||
expr->CalculateEmitStore();
|
||||
|
||||
for (int i = 0; i < expr->properties()->length(); i++) {
|
||||
ObjectLiteral::Property* property = expr->properties()->at(i);
|
||||
if (property->IsCompileTimeValue()) continue;
|
||||
@ -1221,8 +1226,10 @@ void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
|
||||
VisitForAccumulatorValue(value);
|
||||
__ mov(ecx, Immediate(key->handle()));
|
||||
__ mov(edx, Operand(esp, 0));
|
||||
Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
|
||||
EmitCallIC(ic, RelocInfo::CODE_TARGET);
|
||||
if (property->emit_store()) {
|
||||
Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
|
||||
EmitCallIC(ic, RelocInfo::CODE_TARGET);
|
||||
}
|
||||
break;
|
||||
}
|
||||
// Fall through.
|
||||
@ -1230,7 +1237,11 @@ void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
|
||||
__ push(Operand(esp, 0)); // Duplicate receiver.
|
||||
VisitForStackValue(key);
|
||||
VisitForStackValue(value);
|
||||
__ CallRuntime(Runtime::kSetProperty, 3);
|
||||
if (property->emit_store()) {
|
||||
__ CallRuntime(Runtime::kSetProperty, 3);
|
||||
} else {
|
||||
__ Drop(3);
|
||||
}
|
||||
break;
|
||||
case ObjectLiteral::Property::SETTER:
|
||||
case ObjectLiteral::Property::GETTER:
|
||||
|
8
deps/v8/src/ia32/stub-cache-ia32.cc
vendored
8
deps/v8/src/ia32/stub-cache-ia32.cc
vendored
@ -206,8 +206,10 @@ void StubCache::GenerateProbe(MacroAssembler* masm,
|
||||
Register receiver,
|
||||
Register name,
|
||||
Register scratch,
|
||||
Register extra) {
|
||||
Register extra,
|
||||
Register extra2) {
|
||||
Label miss;
|
||||
USE(extra2); // The register extra2 is not used on the ia32 platform.
|
||||
|
||||
// Make sure that code is valid. The shifting code relies on the
|
||||
// entry size being 8.
|
||||
@ -223,6 +225,10 @@ void StubCache::GenerateProbe(MacroAssembler* masm,
|
||||
ASSERT(!extra.is(name));
|
||||
ASSERT(!extra.is(scratch));
|
||||
|
||||
// Check scratch and extra registers are valid, and extra2 is unused.
|
||||
ASSERT(!scratch.is(no_reg));
|
||||
ASSERT(extra2.is(no_reg));
|
||||
|
||||
// Check that the receiver isn't a smi.
|
||||
__ test(receiver, Immediate(kSmiTagMask));
|
||||
__ j(zero, &miss, not_taken);
|
||||
|
3
deps/v8/src/json.js
vendored
3
deps/v8/src/json.js
vendored
@ -29,8 +29,7 @@ var $JSON = global.JSON;
|
||||
|
||||
function ParseJSONUnfiltered(text) {
|
||||
var s = $String(text);
|
||||
var f = %CompileString(s, true);
|
||||
return f();
|
||||
return %ParseJson(s);
|
||||
}
|
||||
|
||||
function Revive(holder, name, reviver) {
|
||||
|
6
deps/v8/src/jsregexp.cc
vendored
6
deps/v8/src/jsregexp.cc
vendored
@ -125,7 +125,8 @@ Handle<Object> RegExpImpl::Compile(Handle<JSRegExp> re,
|
||||
PostponeInterruptsScope postpone;
|
||||
RegExpCompileData parse_result;
|
||||
FlatStringReader reader(pattern);
|
||||
if (!Parser::ParseRegExp(&reader, flags.is_multiline(), &parse_result)) {
|
||||
if (!RegExpParser::ParseRegExp(&reader, flags.is_multiline(),
|
||||
&parse_result)) {
|
||||
// Throw an exception if we fail to parse the pattern.
|
||||
ThrowRegExpException(re,
|
||||
pattern,
|
||||
@ -267,7 +268,8 @@ bool RegExpImpl::CompileIrregexp(Handle<JSRegExp> re, bool is_ascii) {
|
||||
|
||||
RegExpCompileData compile_data;
|
||||
FlatStringReader reader(pattern);
|
||||
if (!Parser::ParseRegExp(&reader, flags.is_multiline(), &compile_data)) {
|
||||
if (!RegExpParser::ParseRegExp(&reader, flags.is_multiline(),
|
||||
&compile_data)) {
|
||||
// Throw an exception if we fail to parse the pattern.
|
||||
// THIS SHOULD NOT HAPPEN. We already pre-parsed it successfully once.
|
||||
ThrowRegExpException(re,
|
||||
|
2
deps/v8/src/liveedit.cc
vendored
2
deps/v8/src/liveedit.cc
vendored
@ -404,7 +404,7 @@ static void CompileScriptForTracker(Handle<Script> script) {
|
||||
// Build AST.
|
||||
CompilationInfo info(script);
|
||||
info.MarkAsGlobal();
|
||||
if (Parser::Parse(&info)) {
|
||||
if (ParserApi::Parse(&info)) {
|
||||
// Compile the code.
|
||||
LiveEditFunctionTracker tracker(info.function());
|
||||
if (Compiler::MakeCodeForLiveEdit(&info)) {
|
||||
|
5
deps/v8/src/log.cc
vendored
5
deps/v8/src/log.cc
vendored
@ -164,7 +164,10 @@ void StackTracer::Trace(TickSample* sample) {
|
||||
|
||||
int i = 0;
|
||||
const Address callback = VMState::external_callback();
|
||||
if (callback != NULL) {
|
||||
// Surprisingly, PC can point _exactly_ to callback start, with good
|
||||
// probability, and this will result in reporting fake nested
|
||||
// callback call.
|
||||
if (callback != NULL && callback != sample->pc) {
|
||||
sample->stack[i++] = callback;
|
||||
}
|
||||
|
||||
|
3
deps/v8/src/mips/stub-cache-mips.cc
vendored
3
deps/v8/src/mips/stub-cache-mips.cc
vendored
@ -44,7 +44,8 @@ void StubCache::GenerateProbe(MacroAssembler* masm,
|
||||
Register receiver,
|
||||
Register name,
|
||||
Register scratch,
|
||||
Register extra) {
|
||||
Register extra,
|
||||
Register extra2) {
|
||||
UNIMPLEMENTED_MIPS();
|
||||
}
|
||||
|
||||
|
4
deps/v8/src/objects-inl.h
vendored
4
deps/v8/src/objects-inl.h
vendored
@ -1952,7 +1952,9 @@ void JSFunctionResultCache::MakeZeroSize() {
|
||||
void JSFunctionResultCache::Clear() {
|
||||
int cache_size = Smi::cast(get(kCacheSizeIndex))->value();
|
||||
Object** entries_start = RawField(this, OffsetOfElementAt(kEntriesIndex));
|
||||
MemsetPointer(entries_start, Heap::the_hole_value(), cache_size);
|
||||
MemsetPointer(entries_start,
|
||||
Heap::the_hole_value(),
|
||||
cache_size - kEntriesIndex);
|
||||
MakeZeroSize();
|
||||
}
|
||||
|
||||
|
3
deps/v8/src/objects.h
vendored
3
deps/v8/src/objects.h
vendored
@ -3409,8 +3409,7 @@ class Script: public Struct {
|
||||
// Script compilation types.
|
||||
enum CompilationType {
|
||||
COMPILATION_TYPE_HOST = 0,
|
||||
COMPILATION_TYPE_EVAL = 1,
|
||||
COMPILATION_TYPE_JSON = 2
|
||||
COMPILATION_TYPE_EVAL = 1
|
||||
};
|
||||
|
||||
// [source]: the script source.
|
||||
|
614
deps/v8/src/parser.cc
vendored
614
deps/v8/src/parser.cc
vendored
@ -87,112 +87,6 @@ class PositionStack {
|
||||
};
|
||||
|
||||
|
||||
template <typename T, int initial_size>
|
||||
class BufferedZoneList {
|
||||
public:
|
||||
BufferedZoneList() : list_(NULL), last_(NULL) {}
|
||||
|
||||
// Adds element at end of list. This element is buffered and can
|
||||
// be read using last() or removed using RemoveLast until a new Add or until
|
||||
// RemoveLast or GetList has been called.
|
||||
void Add(T* value) {
|
||||
if (last_ != NULL) {
|
||||
if (list_ == NULL) {
|
||||
list_ = new ZoneList<T*>(initial_size);
|
||||
}
|
||||
list_->Add(last_);
|
||||
}
|
||||
last_ = value;
|
||||
}
|
||||
|
||||
T* last() {
|
||||
ASSERT(last_ != NULL);
|
||||
return last_;
|
||||
}
|
||||
|
||||
T* RemoveLast() {
|
||||
ASSERT(last_ != NULL);
|
||||
T* result = last_;
|
||||
if (list_ != NULL && list_->length() > 0)
|
||||
last_ = list_->RemoveLast();
|
||||
else
|
||||
last_ = NULL;
|
||||
return result;
|
||||
}
|
||||
|
||||
T* Get(int i) {
|
||||
ASSERT(0 <= i && i < length());
|
||||
if (list_ == NULL) {
|
||||
ASSERT_EQ(0, i);
|
||||
return last_;
|
||||
} else {
|
||||
if (i == list_->length()) {
|
||||
ASSERT(last_ != NULL);
|
||||
return last_;
|
||||
} else {
|
||||
return list_->at(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Clear() {
|
||||
list_ = NULL;
|
||||
last_ = NULL;
|
||||
}
|
||||
|
||||
int length() {
|
||||
int length = (list_ == NULL) ? 0 : list_->length();
|
||||
return length + ((last_ == NULL) ? 0 : 1);
|
||||
}
|
||||
|
||||
ZoneList<T*>* GetList() {
|
||||
if (list_ == NULL) {
|
||||
list_ = new ZoneList<T*>(initial_size);
|
||||
}
|
||||
if (last_ != NULL) {
|
||||
list_->Add(last_);
|
||||
last_ = NULL;
|
||||
}
|
||||
return list_;
|
||||
}
|
||||
|
||||
private:
|
||||
ZoneList<T*>* list_;
|
||||
T* last_;
|
||||
};
|
||||
|
||||
|
||||
// Accumulates RegExp atoms and assertions into lists of terms and alternatives.
|
||||
class RegExpBuilder: public ZoneObject {
|
||||
public:
|
||||
RegExpBuilder();
|
||||
void AddCharacter(uc16 character);
|
||||
// "Adds" an empty expression. Does nothing except consume a
|
||||
// following quantifier
|
||||
void AddEmpty();
|
||||
void AddAtom(RegExpTree* tree);
|
||||
void AddAssertion(RegExpTree* tree);
|
||||
void NewAlternative(); // '|'
|
||||
void AddQuantifierToAtom(int min, int max, RegExpQuantifier::Type type);
|
||||
RegExpTree* ToRegExp();
|
||||
private:
|
||||
void FlushCharacters();
|
||||
void FlushText();
|
||||
void FlushTerms();
|
||||
bool pending_empty_;
|
||||
ZoneList<uc16>* characters_;
|
||||
BufferedZoneList<RegExpTree, 2> terms_;
|
||||
BufferedZoneList<RegExpTree, 2> text_;
|
||||
BufferedZoneList<RegExpTree, 2> alternatives_;
|
||||
#ifdef DEBUG
|
||||
enum {ADD_NONE, ADD_CHAR, ADD_TERM, ADD_ASSERT, ADD_ATOM} last_added_;
|
||||
#define LAST(x) last_added_ = x;
|
||||
#else
|
||||
#define LAST(x)
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
RegExpBuilder::RegExpBuilder()
|
||||
: pending_empty_(false),
|
||||
characters_(NULL),
|
||||
@ -352,124 +246,13 @@ void RegExpBuilder::AddQuantifierToAtom(int min,
|
||||
}
|
||||
|
||||
|
||||
class RegExpParser {
|
||||
public:
|
||||
RegExpParser(FlatStringReader* in,
|
||||
Handle<String>* error,
|
||||
bool multiline_mode);
|
||||
RegExpTree* ParsePattern();
|
||||
RegExpTree* ParseDisjunction();
|
||||
RegExpTree* ParseGroup();
|
||||
RegExpTree* ParseCharacterClass();
|
||||
|
||||
// Parses a {...,...} quantifier and stores the range in the given
|
||||
// out parameters.
|
||||
bool ParseIntervalQuantifier(int* min_out, int* max_out);
|
||||
|
||||
// Parses and returns a single escaped character. The character
|
||||
// must not be 'b' or 'B' since they are usually handle specially.
|
||||
uc32 ParseClassCharacterEscape();
|
||||
|
||||
// Checks whether the following is a length-digit hexadecimal number,
|
||||
// and sets the value if it is.
|
||||
bool ParseHexEscape(int length, uc32* value);
|
||||
|
||||
uc32 ParseControlLetterEscape();
|
||||
uc32 ParseOctalLiteral();
|
||||
|
||||
// Tries to parse the input as a back reference. If successful it
|
||||
// stores the result in the output parameter and returns true. If
|
||||
// it fails it will push back the characters read so the same characters
|
||||
// can be reparsed.
|
||||
bool ParseBackReferenceIndex(int* index_out);
|
||||
|
||||
CharacterRange ParseClassAtom(uc16* char_class);
|
||||
RegExpTree* ReportError(Vector<const char> message);
|
||||
void Advance();
|
||||
void Advance(int dist);
|
||||
void Reset(int pos);
|
||||
|
||||
// Reports whether the pattern might be used as a literal search string.
|
||||
// Only use if the result of the parse is a single atom node.
|
||||
bool simple();
|
||||
bool contains_anchor() { return contains_anchor_; }
|
||||
void set_contains_anchor() { contains_anchor_ = true; }
|
||||
int captures_started() { return captures_ == NULL ? 0 : captures_->length(); }
|
||||
int position() { return next_pos_ - 1; }
|
||||
bool failed() { return failed_; }
|
||||
|
||||
static const int kMaxCaptures = 1 << 16;
|
||||
static const uc32 kEndMarker = (1 << 21);
|
||||
|
||||
private:
|
||||
enum SubexpressionType {
|
||||
INITIAL,
|
||||
CAPTURE, // All positive values represent captures.
|
||||
POSITIVE_LOOKAHEAD,
|
||||
NEGATIVE_LOOKAHEAD,
|
||||
GROUPING
|
||||
};
|
||||
|
||||
class RegExpParserState : public ZoneObject {
|
||||
public:
|
||||
RegExpParserState(RegExpParserState* previous_state,
|
||||
SubexpressionType group_type,
|
||||
int disjunction_capture_index)
|
||||
: previous_state_(previous_state),
|
||||
builder_(new RegExpBuilder()),
|
||||
group_type_(group_type),
|
||||
disjunction_capture_index_(disjunction_capture_index) {}
|
||||
// Parser state of containing expression, if any.
|
||||
RegExpParserState* previous_state() { return previous_state_; }
|
||||
bool IsSubexpression() { return previous_state_ != NULL; }
|
||||
// RegExpBuilder building this regexp's AST.
|
||||
RegExpBuilder* builder() { return builder_; }
|
||||
// Type of regexp being parsed (parenthesized group or entire regexp).
|
||||
SubexpressionType group_type() { return group_type_; }
|
||||
// Index in captures array of first capture in this sub-expression, if any.
|
||||
// Also the capture index of this sub-expression itself, if group_type
|
||||
// is CAPTURE.
|
||||
int capture_index() { return disjunction_capture_index_; }
|
||||
private:
|
||||
// Linked list implementation of stack of states.
|
||||
RegExpParserState* previous_state_;
|
||||
// Builder for the stored disjunction.
|
||||
RegExpBuilder* builder_;
|
||||
// Stored disjunction type (capture, look-ahead or grouping), if any.
|
||||
SubexpressionType group_type_;
|
||||
// Stored disjunction's capture index (if any).
|
||||
int disjunction_capture_index_;
|
||||
};
|
||||
|
||||
uc32 current() { return current_; }
|
||||
bool has_more() { return has_more_; }
|
||||
bool has_next() { return next_pos_ < in()->length(); }
|
||||
uc32 Next();
|
||||
FlatStringReader* in() { return in_; }
|
||||
void ScanForCaptures();
|
||||
uc32 current_;
|
||||
bool has_more_;
|
||||
bool multiline_;
|
||||
int next_pos_;
|
||||
FlatStringReader* in_;
|
||||
Handle<String>* error_;
|
||||
bool simple_;
|
||||
bool contains_anchor_;
|
||||
ZoneList<RegExpCapture*>* captures_;
|
||||
bool is_scanned_for_captures_;
|
||||
// The capture count is only valid after we have scanned for captures.
|
||||
int capture_count_;
|
||||
bool failed_;
|
||||
};
|
||||
|
||||
|
||||
// A temporary scope stores information during parsing, just like
|
||||
// a plain scope. However, temporary scopes are not kept around
|
||||
// after parsing or referenced by syntax trees so they can be stack-
|
||||
// allocated and hence used by the pre-parser.
|
||||
class TemporaryScope BASE_EMBEDDED {
|
||||
public:
|
||||
explicit TemporaryScope(Parser* parser);
|
||||
explicit TemporaryScope(TemporaryScope** variable);
|
||||
~TemporaryScope();
|
||||
|
||||
int NextMaterializedLiteralIndex() {
|
||||
@ -518,27 +301,25 @@ class TemporaryScope BASE_EMBEDDED {
|
||||
int loop_count_;
|
||||
|
||||
// Bookkeeping
|
||||
Parser* parser_;
|
||||
TemporaryScope** variable_;
|
||||
TemporaryScope* parent_;
|
||||
|
||||
friend class Parser;
|
||||
};
|
||||
|
||||
|
||||
TemporaryScope::TemporaryScope(Parser* parser)
|
||||
TemporaryScope::TemporaryScope(TemporaryScope** variable)
|
||||
: materialized_literal_count_(0),
|
||||
expected_property_count_(0),
|
||||
only_simple_this_property_assignments_(false),
|
||||
this_property_assignments_(Factory::empty_fixed_array()),
|
||||
loop_count_(0),
|
||||
parser_(parser),
|
||||
parent_(parser->temp_scope_) {
|
||||
parser->temp_scope_ = this;
|
||||
variable_(variable),
|
||||
parent_(*variable) {
|
||||
*variable = this;
|
||||
}
|
||||
|
||||
|
||||
TemporaryScope::~TemporaryScope() {
|
||||
parser_->temp_scope_ = parent_;
|
||||
*variable_ = parent_;
|
||||
}
|
||||
|
||||
|
||||
@ -1141,20 +922,20 @@ VariableProxy* PreParser::Declare(Handle<String> name, Variable::Mode mode,
|
||||
|
||||
class Target BASE_EMBEDDED {
|
||||
public:
|
||||
Target(Parser* parser, AstNode* node)
|
||||
: parser_(parser), node_(node), previous_(parser_->target_stack_) {
|
||||
parser_->target_stack_ = this;
|
||||
Target(Target** variable, AstNode* node)
|
||||
: variable_(variable), node_(node), previous_(*variable) {
|
||||
*variable = this;
|
||||
}
|
||||
|
||||
~Target() {
|
||||
parser_->target_stack_ = previous_;
|
||||
*variable_ = previous_;
|
||||
}
|
||||
|
||||
Target* previous() { return previous_; }
|
||||
AstNode* node() { return node_; }
|
||||
|
||||
private:
|
||||
Parser* parser_;
|
||||
Target** variable_;
|
||||
AstNode* node_;
|
||||
Target* previous_;
|
||||
};
|
||||
@ -1162,17 +943,17 @@ class Target BASE_EMBEDDED {
|
||||
|
||||
class TargetScope BASE_EMBEDDED {
|
||||
public:
|
||||
explicit TargetScope(Parser* parser)
|
||||
: parser_(parser), previous_(parser->target_stack_) {
|
||||
parser->target_stack_ = NULL;
|
||||
explicit TargetScope(Target** variable)
|
||||
: variable_(variable), previous_(*variable) {
|
||||
*variable = NULL;
|
||||
}
|
||||
|
||||
~TargetScope() {
|
||||
parser_->target_stack_ = previous_;
|
||||
*variable_ = previous_;
|
||||
}
|
||||
|
||||
private:
|
||||
Parser* parser_;
|
||||
Target** variable_;
|
||||
Target* previous_;
|
||||
};
|
||||
|
||||
@ -1184,22 +965,26 @@ class TargetScope BASE_EMBEDDED {
|
||||
|
||||
class LexicalScope BASE_EMBEDDED {
|
||||
public:
|
||||
LexicalScope(Parser* parser, Scope* scope)
|
||||
: parser_(parser),
|
||||
prev_scope_(parser->top_scope_),
|
||||
prev_level_(parser->with_nesting_level_) {
|
||||
parser_->top_scope_ = scope;
|
||||
parser_->with_nesting_level_ = 0;
|
||||
LexicalScope(Scope** scope_variable,
|
||||
int* with_nesting_level_variable,
|
||||
Scope* scope)
|
||||
: scope_variable_(scope_variable),
|
||||
with_nesting_level_variable_(with_nesting_level_variable),
|
||||
prev_scope_(*scope_variable),
|
||||
prev_level_(*with_nesting_level_variable) {
|
||||
*scope_variable = scope;
|
||||
*with_nesting_level_variable = 0;
|
||||
}
|
||||
|
||||
~LexicalScope() {
|
||||
parser_->top_scope_->Leave();
|
||||
parser_->top_scope_ = prev_scope_;
|
||||
parser_->with_nesting_level_ = prev_level_;
|
||||
(*scope_variable_)->Leave();
|
||||
*scope_variable_ = prev_scope_;
|
||||
*with_nesting_level_variable_ = prev_level_;
|
||||
}
|
||||
|
||||
private:
|
||||
Parser* parser_;
|
||||
Scope** scope_variable_;
|
||||
int* with_nesting_level_variable_;
|
||||
Scope* prev_scope_;
|
||||
int prev_level_;
|
||||
};
|
||||
@ -1262,8 +1047,8 @@ bool Parser::PreParseProgram(Handle<String> source,
|
||||
mode_ = FLAG_lazy ? PARSE_LAZILY : PARSE_EAGERLY;
|
||||
if (allow_natives_syntax_ || extension_ != NULL) mode_ = PARSE_EAGERLY;
|
||||
DummyScope top_scope;
|
||||
LexicalScope scope(this, &top_scope);
|
||||
TemporaryScope temp_scope(this);
|
||||
LexicalScope scope(&this->top_scope_, &this->with_nesting_level_, &top_scope);
|
||||
TemporaryScope temp_scope(&this->temp_scope_);
|
||||
ZoneListWrapper<Statement> processor;
|
||||
bool ok = true;
|
||||
ParseSourceElements(&processor, Token::EOS, &ok);
|
||||
@ -1297,8 +1082,9 @@ FunctionLiteral* Parser::ParseProgram(Handle<String> source,
|
||||
|
||||
FunctionLiteral* result = NULL;
|
||||
{ Scope* scope = factory()->NewScope(top_scope_, type, inside_with());
|
||||
LexicalScope lexical_scope(this, scope);
|
||||
TemporaryScope temp_scope(this);
|
||||
LexicalScope lexical_scope(&this->top_scope_, &this->with_nesting_level_,
|
||||
scope);
|
||||
TemporaryScope temp_scope(&this->temp_scope_);
|
||||
ZoneListWrapper<Statement> body(16);
|
||||
bool ok = true;
|
||||
ParseSourceElements(&body, Token::EOS, &ok);
|
||||
@ -1356,8 +1142,9 @@ FunctionLiteral* Parser::ParseLazy(Handle<SharedFunctionInfo> info) {
|
||||
Handle<String> no_name = factory()->EmptySymbol();
|
||||
Scope* scope =
|
||||
factory()->NewScope(top_scope_, Scope::GLOBAL_SCOPE, inside_with());
|
||||
LexicalScope lexical_scope(this, scope);
|
||||
TemporaryScope temp_scope(this);
|
||||
LexicalScope lexical_scope(&this->top_scope_, &this->with_nesting_level_,
|
||||
scope);
|
||||
TemporaryScope temp_scope(&this->temp_scope_);
|
||||
|
||||
FunctionLiteralType type =
|
||||
info->is_expression() ? EXPRESSION : DECLARATION;
|
||||
@ -1382,56 +1169,6 @@ FunctionLiteral* Parser::ParseLazy(Handle<SharedFunctionInfo> info) {
|
||||
}
|
||||
|
||||
|
||||
FunctionLiteral* Parser::ParseJson(Handle<String> source) {
|
||||
CompilationZoneScope zone_scope(DONT_DELETE_ON_EXIT);
|
||||
|
||||
HistogramTimerScope timer(&Counters::parse);
|
||||
Counters::total_parse_size.Increment(source->length());
|
||||
|
||||
// Initialize parser state.
|
||||
source->TryFlatten(TENURED);
|
||||
scanner_.Initialize(source, JSON);
|
||||
ASSERT(target_stack_ == NULL);
|
||||
|
||||
FunctionLiteral* result = NULL;
|
||||
Handle<String> no_name = factory()->EmptySymbol();
|
||||
|
||||
{
|
||||
Scope* scope = factory()->NewScope(top_scope_, Scope::GLOBAL_SCOPE, false);
|
||||
LexicalScope lexical_scope(this, scope);
|
||||
TemporaryScope temp_scope(this);
|
||||
bool ok = true;
|
||||
Expression* expression = ParseJson(&ok);
|
||||
if (ok) {
|
||||
ZoneListWrapper<Statement> statement = factory()->NewList<Statement>(1);
|
||||
statement.Add(new ExpressionStatement(expression));
|
||||
result = NEW(FunctionLiteral(
|
||||
no_name,
|
||||
top_scope_,
|
||||
statement.elements(),
|
||||
temp_scope.materialized_literal_count(),
|
||||
temp_scope.expected_property_count(),
|
||||
temp_scope.only_simple_this_property_assignments(),
|
||||
temp_scope.this_property_assignments(),
|
||||
0,
|
||||
0,
|
||||
source->length(),
|
||||
false,
|
||||
temp_scope.ContainsLoops()));
|
||||
} else if (scanner().stack_overflow()) {
|
||||
Top::StackOverflow();
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure the target stack is empty.
|
||||
ASSERT(target_stack_ == NULL);
|
||||
|
||||
// If there was a syntax error we have to get rid of the AST
|
||||
// and it is not safe to do so before the scope has been deleted.
|
||||
if (result == NULL) zone_scope.DeleteOnExit();
|
||||
return result;
|
||||
}
|
||||
|
||||
void Parser::ReportMessage(const char* type, Vector<const char*> args) {
|
||||
Scanner::Location source_location = scanner_.location();
|
||||
ReportMessageAt(source_location, type, args);
|
||||
@ -1733,7 +1470,7 @@ void* Parser::ParseSourceElements(ZoneListWrapper<Statement>* processor,
|
||||
// elements. This way, all scripts and functions get their own
|
||||
// target stack thus avoiding illegal breaks and continues across
|
||||
// functions.
|
||||
TargetScope scope(this);
|
||||
TargetScope scope(&this->target_stack_);
|
||||
|
||||
ASSERT(processor != NULL);
|
||||
InitializationBlockFinder block_finder;
|
||||
@ -1857,7 +1594,7 @@ Statement* Parser::ParseStatement(ZoneStringList* labels, bool* ok) {
|
||||
// fall-through. It is much easier just to wrap the entire
|
||||
// try-statement in a statement block and put the labels there
|
||||
Block* result = NEW(Block(labels, 1, false));
|
||||
Target target(this, result);
|
||||
Target target(&this->target_stack_, result);
|
||||
TryStatement* statement = ParseTryStatement(CHECK_OK);
|
||||
if (statement) {
|
||||
statement->set_statement_pos(statement_pos);
|
||||
@ -2073,7 +1810,7 @@ Block* Parser::ParseBlock(ZoneStringList* labels, bool* ok) {
|
||||
//
|
||||
// Construct block expecting 16 statements.
|
||||
Block* result = NEW(Block(labels, 16, false));
|
||||
Target target(this, result);
|
||||
Target target(&this->target_stack_, result);
|
||||
Expect(Token::LBRACE, CHECK_OK);
|
||||
while (peek() != Token::RBRACE) {
|
||||
Statement* stat = ParseStatement(NULL, CHECK_OK);
|
||||
@ -2468,7 +2205,7 @@ Block* Parser::WithHelper(Expression* obj,
|
||||
ZoneList<BreakTarget*>* target_list = NEW(ZoneList<BreakTarget*>(0));
|
||||
TargetCollector collector(target_list);
|
||||
Statement* stat;
|
||||
{ Target target(this, &collector);
|
||||
{ Target target(&this->target_stack_, &collector);
|
||||
with_nesting_level_++;
|
||||
top_scope_->RecordWithStatement();
|
||||
stat = ParseStatement(labels, CHECK_OK);
|
||||
@ -2551,7 +2288,7 @@ SwitchStatement* Parser::ParseSwitchStatement(ZoneStringList* labels,
|
||||
// 'switch' '(' Expression ')' '{' CaseClause* '}'
|
||||
|
||||
SwitchStatement* statement = NEW(SwitchStatement(labels));
|
||||
Target target(this, statement);
|
||||
Target target(&this->target_stack_, statement);
|
||||
|
||||
Expect(Token::SWITCH, CHECK_OK);
|
||||
Expect(Token::LPAREN, CHECK_OK);
|
||||
@ -2608,7 +2345,7 @@ TryStatement* Parser::ParseTryStatement(bool* ok) {
|
||||
TargetCollector collector(target_list);
|
||||
Block* try_block;
|
||||
|
||||
{ Target target(this, &collector);
|
||||
{ Target target(&this->target_stack_, &collector);
|
||||
try_block = ParseBlock(NULL, CHECK_OK);
|
||||
}
|
||||
|
||||
@ -2644,7 +2381,7 @@ TryStatement* Parser::ParseTryStatement(bool* ok) {
|
||||
catch_var = top_scope_->NewTemporary(Factory::catch_var_symbol());
|
||||
Literal* name_literal = NEW(Literal(name));
|
||||
Expression* obj = NEW(CatchExtensionObject(name_literal, catch_var));
|
||||
{ Target target(this, &catch_collector);
|
||||
{ Target target(&this->target_stack_, &catch_collector);
|
||||
catch_block = WithHelper(obj, NULL, true, CHECK_OK);
|
||||
}
|
||||
} else {
|
||||
@ -2703,7 +2440,7 @@ DoWhileStatement* Parser::ParseDoWhileStatement(ZoneStringList* labels,
|
||||
|
||||
temp_scope_->AddLoop();
|
||||
DoWhileStatement* loop = NEW(DoWhileStatement(labels));
|
||||
Target target(this, loop);
|
||||
Target target(&this->target_stack_, loop);
|
||||
|
||||
Expect(Token::DO, CHECK_OK);
|
||||
Statement* body = ParseStatement(NULL, CHECK_OK);
|
||||
@ -2736,7 +2473,7 @@ WhileStatement* Parser::ParseWhileStatement(ZoneStringList* labels, bool* ok) {
|
||||
|
||||
temp_scope_->AddLoop();
|
||||
WhileStatement* loop = NEW(WhileStatement(labels));
|
||||
Target target(this, loop);
|
||||
Target target(&this->target_stack_, loop);
|
||||
|
||||
Expect(Token::WHILE, CHECK_OK);
|
||||
Expect(Token::LPAREN, CHECK_OK);
|
||||
@ -2766,7 +2503,7 @@ Statement* Parser::ParseForStatement(ZoneStringList* labels, bool* ok) {
|
||||
ParseVariableDeclarations(false, &each, CHECK_OK);
|
||||
if (peek() == Token::IN && each != NULL) {
|
||||
ForInStatement* loop = NEW(ForInStatement(labels));
|
||||
Target target(this, loop);
|
||||
Target target(&this->target_stack_, loop);
|
||||
|
||||
Expect(Token::IN, CHECK_OK);
|
||||
Expression* enumerable = ParseExpression(true, CHECK_OK);
|
||||
@ -2800,7 +2537,7 @@ Statement* Parser::ParseForStatement(ZoneStringList* labels, bool* ok) {
|
||||
expression = NewThrowReferenceError(type);
|
||||
}
|
||||
ForInStatement* loop = NEW(ForInStatement(labels));
|
||||
Target target(this, loop);
|
||||
Target target(&this->target_stack_, loop);
|
||||
|
||||
Expect(Token::IN, CHECK_OK);
|
||||
Expression* enumerable = ParseExpression(true, CHECK_OK);
|
||||
@ -2819,7 +2556,7 @@ Statement* Parser::ParseForStatement(ZoneStringList* labels, bool* ok) {
|
||||
|
||||
// Standard 'for' loop
|
||||
ForStatement* loop = NEW(ForStatement(labels));
|
||||
Target target(this, loop);
|
||||
Target target(&this->target_stack_, loop);
|
||||
|
||||
// Parsed initializer at this point.
|
||||
Expect(Token::SEMICOLON, CHECK_OK);
|
||||
@ -3909,8 +3646,9 @@ FunctionLiteral* Parser::ParseFunctionLiteral(Handle<String> var_name,
|
||||
// Parse function body.
|
||||
{ Scope* scope =
|
||||
factory()->NewScope(top_scope_, Scope::FUNCTION_SCOPE, inside_with());
|
||||
LexicalScope lexical_scope(this, scope);
|
||||
TemporaryScope temp_scope(this);
|
||||
LexicalScope lexical_scope(&this->top_scope_, &this->with_nesting_level_,
|
||||
scope);
|
||||
TemporaryScope temp_scope(&this->temp_scope_);
|
||||
top_scope_->SetScopeName(name);
|
||||
|
||||
// FormalParameterList ::
|
||||
@ -4281,145 +4019,165 @@ Expression* Parser::NewThrowError(Handle<String> constructor,
|
||||
// ----------------------------------------------------------------------------
|
||||
// JSON
|
||||
|
||||
Expression* Parser::ParseJson(bool* ok) {
|
||||
Expression* result = ParseJsonValue(CHECK_OK);
|
||||
Expect(Token::EOS, CHECK_OK);
|
||||
Handle<Object> JsonParser::ParseJson(Handle<String> source) {
|
||||
source->TryFlatten();
|
||||
scanner_.Initialize(source, JSON);
|
||||
Handle<Object> result = ParseJsonValue();
|
||||
if (result.is_null() || scanner_.Next() != Token::EOS) {
|
||||
if (scanner_.stack_overflow()) {
|
||||
// Scanner failed.
|
||||
Top::StackOverflow();
|
||||
} else {
|
||||
// Parse failed. Scanner's current token is the unexpected token.
|
||||
Token::Value token = scanner_.current_token();
|
||||
|
||||
const char* message;
|
||||
const char* name_opt = NULL;
|
||||
|
||||
switch (token) {
|
||||
case Token::EOS:
|
||||
message = "unexpected_eos";
|
||||
break;
|
||||
case Token::NUMBER:
|
||||
message = "unexpected_token_number";
|
||||
break;
|
||||
case Token::STRING:
|
||||
message = "unexpected_token_string";
|
||||
break;
|
||||
case Token::IDENTIFIER:
|
||||
message = "unexpected_token_identifier";
|
||||
break;
|
||||
default:
|
||||
message = "unexpected_token";
|
||||
name_opt = Token::String(token);
|
||||
ASSERT(name_opt != NULL);
|
||||
break;
|
||||
}
|
||||
|
||||
Scanner::Location source_location = scanner_.location();
|
||||
MessageLocation location(Factory::NewScript(source),
|
||||
source_location.beg_pos,
|
||||
source_location.end_pos);
|
||||
int argc = (name_opt == NULL) ? 0 : 1;
|
||||
Handle<JSArray> array = Factory::NewJSArray(argc);
|
||||
if (name_opt != NULL) {
|
||||
SetElement(array,
|
||||
0,
|
||||
Factory::NewStringFromUtf8(CStrVector(name_opt)));
|
||||
}
|
||||
Handle<Object> result = Factory::NewSyntaxError(message, array);
|
||||
Top::Throw(*result, &location);
|
||||
return Handle<Object>::null();
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
Handle<String> JsonParser::GetString() {
|
||||
int literal_length = scanner_.literal_length();
|
||||
if (literal_length == 0) {
|
||||
return Factory::empty_string();
|
||||
}
|
||||
const char* literal_string = scanner_.literal_string();
|
||||
Vector<const char> literal(literal_string, literal_length);
|
||||
return Factory::NewStringFromUtf8(literal);
|
||||
}
|
||||
|
||||
|
||||
// Parse any JSON value.
|
||||
Expression* Parser::ParseJsonValue(bool* ok) {
|
||||
Token::Value token = peek();
|
||||
Handle<Object> JsonParser::ParseJsonValue() {
|
||||
Token::Value token = scanner_.Next();
|
||||
switch (token) {
|
||||
case Token::STRING: {
|
||||
Consume(Token::STRING);
|
||||
int literal_length = scanner_.literal_length();
|
||||
const char* literal_string = scanner_.literal_string();
|
||||
if (literal_length == 0) {
|
||||
return NEW(Literal(Factory::empty_string()));
|
||||
}
|
||||
Vector<const char> literal(literal_string, literal_length);
|
||||
return NEW(Literal(Factory::NewStringFromUtf8(literal, TENURED)));
|
||||
return GetString();
|
||||
}
|
||||
case Token::NUMBER: {
|
||||
Consume(Token::NUMBER);
|
||||
ASSERT(scanner_.literal_length() > 0);
|
||||
double value = StringToDouble(scanner_.literal(),
|
||||
NO_FLAGS, // Hex, octal or trailing junk.
|
||||
OS::nan_value());
|
||||
return NewNumberLiteral(value);
|
||||
return Factory::NewNumber(value);
|
||||
}
|
||||
case Token::FALSE_LITERAL:
|
||||
Consume(Token::FALSE_LITERAL);
|
||||
return NEW(Literal(Factory::false_value()));
|
||||
return Factory::false_value();
|
||||
case Token::TRUE_LITERAL:
|
||||
Consume(Token::TRUE_LITERAL);
|
||||
return NEW(Literal(Factory::true_value()));
|
||||
return Factory::true_value();
|
||||
case Token::NULL_LITERAL:
|
||||
Consume(Token::NULL_LITERAL);
|
||||
return NEW(Literal(Factory::null_value()));
|
||||
case Token::LBRACE: {
|
||||
Expression* result = ParseJsonObject(CHECK_OK);
|
||||
return result;
|
||||
}
|
||||
case Token::LBRACK: {
|
||||
Expression* result = ParseJsonArray(CHECK_OK);
|
||||
return result;
|
||||
}
|
||||
return Factory::null_value();
|
||||
case Token::LBRACE:
|
||||
return ParseJsonObject();
|
||||
case Token::LBRACK:
|
||||
return ParseJsonArray();
|
||||
default:
|
||||
*ok = false;
|
||||
ReportUnexpectedToken(token);
|
||||
return NULL;
|
||||
return ReportUnexpectedToken();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Parse a JSON object. Scanner must be right after '{' token.
|
||||
Expression* Parser::ParseJsonObject(bool* ok) {
|
||||
Consume(Token::LBRACE);
|
||||
ZoneListWrapper<ObjectLiteral::Property> properties =
|
||||
factory()->NewList<ObjectLiteral::Property>(4);
|
||||
int boilerplate_properties = 0;
|
||||
if (peek() != Token::RBRACE) {
|
||||
Handle<Object> JsonParser::ParseJsonObject() {
|
||||
Handle<JSFunction> object_constructor(
|
||||
Top::global_context()->object_function());
|
||||
Handle<JSObject> json_object = Factory::NewJSObject(object_constructor);
|
||||
if (scanner_.peek() == Token::RBRACE) {
|
||||
scanner_.Next();
|
||||
} else {
|
||||
do {
|
||||
Expect(Token::STRING, CHECK_OK);
|
||||
Handle<String> key = GetSymbol(CHECK_OK);
|
||||
Expect(Token::COLON, CHECK_OK);
|
||||
Expression* value = ParseJsonValue(CHECK_OK);
|
||||
Literal* key_literal;
|
||||
if (scanner_.Next() != Token::STRING) {
|
||||
return ReportUnexpectedToken();
|
||||
}
|
||||
Handle<String> key = GetString();
|
||||
if (scanner_.Next() != Token::COLON) {
|
||||
return ReportUnexpectedToken();
|
||||
}
|
||||
Handle<Object> value = ParseJsonValue();
|
||||
if (value.is_null()) return Handle<Object>::null();
|
||||
uint32_t index;
|
||||
if (key->AsArrayIndex(&index)) {
|
||||
key_literal = NewNumberLiteral(index);
|
||||
SetElement(json_object, index, value);
|
||||
} else {
|
||||
key_literal = NEW(Literal(key));
|
||||
SetProperty(json_object, key, value, NONE);
|
||||
}
|
||||
ObjectLiteral::Property* property =
|
||||
NEW(ObjectLiteral::Property(key_literal, value));
|
||||
properties.Add(property);
|
||||
|
||||
if (IsBoilerplateProperty(property)) {
|
||||
boilerplate_properties++;
|
||||
}
|
||||
} while (Check(Token::COMMA));
|
||||
} while (scanner_.Next() == Token::COMMA);
|
||||
if (scanner_.current_token() != Token::RBRACE) {
|
||||
return ReportUnexpectedToken();
|
||||
}
|
||||
}
|
||||
Expect(Token::RBRACE, CHECK_OK);
|
||||
|
||||
int literal_index = temp_scope_->NextMaterializedLiteralIndex();
|
||||
if (is_pre_parsing_) return NULL;
|
||||
|
||||
Handle<FixedArray> constant_properties =
|
||||
Factory::NewFixedArray(boilerplate_properties * 2, TENURED);
|
||||
bool is_simple = true;
|
||||
bool fast_elements = true;
|
||||
int depth = 1;
|
||||
BuildObjectLiteralConstantProperties(properties.elements(),
|
||||
constant_properties,
|
||||
&is_simple,
|
||||
&fast_elements,
|
||||
&depth);
|
||||
return new ObjectLiteral(constant_properties,
|
||||
properties.elements(),
|
||||
literal_index,
|
||||
is_simple,
|
||||
fast_elements,
|
||||
depth);
|
||||
return json_object;
|
||||
}
|
||||
|
||||
|
||||
// Parse a JSON array. Scanner must be right after '[' token.
|
||||
Expression* Parser::ParseJsonArray(bool* ok) {
|
||||
Consume(Token::LBRACK);
|
||||
Handle<Object> JsonParser::ParseJsonArray() {
|
||||
ZoneScope zone_scope(DELETE_ON_EXIT);
|
||||
ZoneList<Handle<Object> > elements(4);
|
||||
|
||||
ZoneListWrapper<Expression> values = factory()->NewList<Expression>(4);
|
||||
if (peek() != Token::RBRACK) {
|
||||
Token::Value token = scanner_.peek();
|
||||
if (token == Token::RBRACK) {
|
||||
scanner_.Next();
|
||||
} else {
|
||||
do {
|
||||
Expression* exp = ParseJsonValue(CHECK_OK);
|
||||
values.Add(exp);
|
||||
} while (Check(Token::COMMA));
|
||||
Handle<Object> element = ParseJsonValue();
|
||||
if (element.is_null()) return Handle<Object>::null();
|
||||
elements.Add(element);
|
||||
token = scanner_.Next();
|
||||
} while (token == Token::COMMA);
|
||||
if (token != Token::RBRACK) {
|
||||
return ReportUnexpectedToken();
|
||||
}
|
||||
}
|
||||
Expect(Token::RBRACK, CHECK_OK);
|
||||
|
||||
// Update the scope information before the pre-parsing bailout.
|
||||
int literal_index = temp_scope_->NextMaterializedLiteralIndex();
|
||||
// Allocate a fixed array with all the elements.
|
||||
Handle<FixedArray> fast_elements =
|
||||
Factory::NewFixedArray(elements.length());
|
||||
|
||||
if (is_pre_parsing_) return NULL;
|
||||
for (int i = 0, n = elements.length(); i < n; i++) {
|
||||
fast_elements->set(i, *elements[i]);
|
||||
}
|
||||
|
||||
// Allocate a fixed array with all the literals.
|
||||
Handle<FixedArray> literals =
|
||||
Factory::NewFixedArray(values.length(), TENURED);
|
||||
|
||||
bool is_simple;
|
||||
int depth;
|
||||
BuildArrayLiteralBoilerplateLiterals(values.elements(),
|
||||
literals,
|
||||
&is_simple,
|
||||
&depth);
|
||||
return NEW(ArrayLiteral(literals, values.elements(),
|
||||
literal_index, is_simple, depth));
|
||||
return Factory::NewJSArrayWithElements(fast_elements);
|
||||
}
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Regular expressions
|
||||
|
||||
@ -5247,9 +5005,9 @@ bool ScriptDataImpl::HasError() {
|
||||
|
||||
// Preparse, but only collect data that is immediately useful,
|
||||
// even if the preparser data is only used once.
|
||||
ScriptDataImpl* Parser::PartialPreParse(Handle<String> source,
|
||||
unibrow::CharacterStream* stream,
|
||||
v8::Extension* extension) {
|
||||
ScriptDataImpl* ParserApi::PartialPreParse(Handle<String> source,
|
||||
unibrow::CharacterStream* stream,
|
||||
v8::Extension* extension) {
|
||||
Handle<Script> no_script;
|
||||
bool allow_natives_syntax =
|
||||
FLAG_allow_natives_syntax || Bootstrapper::IsActive();
|
||||
@ -5305,9 +5063,9 @@ int ScriptDataImpl::ReadNumber(byte** source) {
|
||||
}
|
||||
|
||||
|
||||
ScriptDataImpl* Parser::PreParse(Handle<String> source,
|
||||
unibrow::CharacterStream* stream,
|
||||
v8::Extension* extension) {
|
||||
ScriptDataImpl* ParserApi::PreParse(Handle<String> source,
|
||||
unibrow::CharacterStream* stream,
|
||||
v8::Extension* extension) {
|
||||
Handle<Script> no_script;
|
||||
bool allow_natives_syntax =
|
||||
FLAG_allow_natives_syntax || Bootstrapper::IsActive();
|
||||
@ -5320,9 +5078,9 @@ ScriptDataImpl* Parser::PreParse(Handle<String> source,
|
||||
}
|
||||
|
||||
|
||||
bool Parser::ParseRegExp(FlatStringReader* input,
|
||||
bool multiline,
|
||||
RegExpCompileData* result) {
|
||||
bool RegExpParser::ParseRegExp(FlatStringReader* input,
|
||||
bool multiline,
|
||||
RegExpCompileData* result) {
|
||||
ASSERT(result != NULL);
|
||||
RegExpParser parser(input, &result->error, multiline);
|
||||
RegExpTree* tree = parser.ParsePattern();
|
||||
@ -5342,7 +5100,7 @@ bool Parser::ParseRegExp(FlatStringReader* input,
|
||||
}
|
||||
|
||||
|
||||
bool Parser::Parse(CompilationInfo* info) {
|
||||
bool ParserApi::Parse(CompilationInfo* info) {
|
||||
ASSERT(info->function() == NULL);
|
||||
FunctionLiteral* result = NULL;
|
||||
Handle<Script> script = info->script();
|
||||
@ -5368,11 +5126,7 @@ bool Parser::Parse(CompilationInfo* info) {
|
||||
ASSERT(Top::has_pending_exception());
|
||||
} else {
|
||||
Handle<String> source = Handle<String>(String::cast(script->source()));
|
||||
// JSON is always global.
|
||||
ASSERT(!info->is_json() || info->is_global());
|
||||
result = info->is_json()
|
||||
? parser.ParseJson(source)
|
||||
: parser.ParseProgram(source, info->is_global());
|
||||
result = parser.ParseProgram(source, info->is_global());
|
||||
}
|
||||
}
|
||||
|
||||
|
314
deps/v8/src/parser.h
vendored
314
deps/v8/src/parser.h
vendored
@ -177,13 +177,8 @@ class ScriptDataImpl : public ScriptData {
|
||||
};
|
||||
|
||||
|
||||
class Parser {
|
||||
class ParserApi {
|
||||
public:
|
||||
Parser(Handle<Script> script, bool allow_natives_syntax,
|
||||
v8::Extension* extension, ParserMode is_pre_parsing,
|
||||
ParserFactory* factory, ParserLog* log, ScriptDataImpl* pre_data);
|
||||
virtual ~Parser() { }
|
||||
|
||||
// Parses the source code represented by the compilation info and sets its
|
||||
// function literal. Returns false (and deallocates any allocated AST
|
||||
// nodes) if parsing failed.
|
||||
@ -199,11 +194,246 @@ class Parser {
|
||||
static ScriptDataImpl* PartialPreParse(Handle<String> source,
|
||||
unibrow::CharacterStream* stream,
|
||||
v8::Extension* extension);
|
||||
};
|
||||
|
||||
|
||||
// A BuffferedZoneList is an automatically growing list, just like (and backed
|
||||
// by) a ZoneList, that is optimized for the case of adding and removing
|
||||
// a single element. The last element added is stored outside the backing list,
|
||||
// and if no more than one element is ever added, the ZoneList isn't even
|
||||
// allocated.
|
||||
// Elements must not be NULL pointers.
|
||||
template <typename T, int initial_size>
|
||||
class BufferedZoneList {
|
||||
public:
|
||||
BufferedZoneList() : list_(NULL), last_(NULL) {}
|
||||
|
||||
// Adds element at end of list. This element is buffered and can
|
||||
// be read using last() or removed using RemoveLast until a new Add or until
|
||||
// RemoveLast or GetList has been called.
|
||||
void Add(T* value) {
|
||||
if (last_ != NULL) {
|
||||
if (list_ == NULL) {
|
||||
list_ = new ZoneList<T*>(initial_size);
|
||||
}
|
||||
list_->Add(last_);
|
||||
}
|
||||
last_ = value;
|
||||
}
|
||||
|
||||
T* last() {
|
||||
ASSERT(last_ != NULL);
|
||||
return last_;
|
||||
}
|
||||
|
||||
T* RemoveLast() {
|
||||
ASSERT(last_ != NULL);
|
||||
T* result = last_;
|
||||
if ((list_ != NULL) && (list_->length() > 0))
|
||||
last_ = list_->RemoveLast();
|
||||
else
|
||||
last_ = NULL;
|
||||
return result;
|
||||
}
|
||||
|
||||
T* Get(int i) {
|
||||
ASSERT((0 <= i) && (i < length()));
|
||||
if (list_ == NULL) {
|
||||
ASSERT_EQ(0, i);
|
||||
return last_;
|
||||
} else {
|
||||
if (i == list_->length()) {
|
||||
ASSERT(last_ != NULL);
|
||||
return last_;
|
||||
} else {
|
||||
return list_->at(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Clear() {
|
||||
list_ = NULL;
|
||||
last_ = NULL;
|
||||
}
|
||||
|
||||
int length() {
|
||||
int length = (list_ == NULL) ? 0 : list_->length();
|
||||
return length + ((last_ == NULL) ? 0 : 1);
|
||||
}
|
||||
|
||||
ZoneList<T*>* GetList() {
|
||||
if (list_ == NULL) {
|
||||
list_ = new ZoneList<T*>(initial_size);
|
||||
}
|
||||
if (last_ != NULL) {
|
||||
list_->Add(last_);
|
||||
last_ = NULL;
|
||||
}
|
||||
return list_;
|
||||
}
|
||||
|
||||
private:
|
||||
ZoneList<T*>* list_;
|
||||
T* last_;
|
||||
};
|
||||
|
||||
|
||||
// Accumulates RegExp atoms and assertions into lists of terms and alternatives.
|
||||
class RegExpBuilder: public ZoneObject {
|
||||
public:
|
||||
RegExpBuilder();
|
||||
void AddCharacter(uc16 character);
|
||||
// "Adds" an empty expression. Does nothing except consume a
|
||||
// following quantifier
|
||||
void AddEmpty();
|
||||
void AddAtom(RegExpTree* tree);
|
||||
void AddAssertion(RegExpTree* tree);
|
||||
void NewAlternative(); // '|'
|
||||
void AddQuantifierToAtom(int min, int max, RegExpQuantifier::Type type);
|
||||
RegExpTree* ToRegExp();
|
||||
|
||||
private:
|
||||
void FlushCharacters();
|
||||
void FlushText();
|
||||
void FlushTerms();
|
||||
bool pending_empty_;
|
||||
ZoneList<uc16>* characters_;
|
||||
BufferedZoneList<RegExpTree, 2> terms_;
|
||||
BufferedZoneList<RegExpTree, 2> text_;
|
||||
BufferedZoneList<RegExpTree, 2> alternatives_;
|
||||
#ifdef DEBUG
|
||||
enum {ADD_NONE, ADD_CHAR, ADD_TERM, ADD_ASSERT, ADD_ATOM} last_added_;
|
||||
#define LAST(x) last_added_ = x;
|
||||
#else
|
||||
#define LAST(x)
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
class RegExpParser {
|
||||
public:
|
||||
RegExpParser(FlatStringReader* in,
|
||||
Handle<String>* error,
|
||||
bool multiline_mode);
|
||||
|
||||
static bool ParseRegExp(FlatStringReader* input,
|
||||
bool multiline,
|
||||
RegExpCompileData* result);
|
||||
|
||||
RegExpTree* ParsePattern();
|
||||
RegExpTree* ParseDisjunction();
|
||||
RegExpTree* ParseGroup();
|
||||
RegExpTree* ParseCharacterClass();
|
||||
|
||||
// Parses a {...,...} quantifier and stores the range in the given
|
||||
// out parameters.
|
||||
bool ParseIntervalQuantifier(int* min_out, int* max_out);
|
||||
|
||||
// Parses and returns a single escaped character. The character
|
||||
// must not be 'b' or 'B' since they are usually handle specially.
|
||||
uc32 ParseClassCharacterEscape();
|
||||
|
||||
// Checks whether the following is a length-digit hexadecimal number,
|
||||
// and sets the value if it is.
|
||||
bool ParseHexEscape(int length, uc32* value);
|
||||
|
||||
uc32 ParseControlLetterEscape();
|
||||
uc32 ParseOctalLiteral();
|
||||
|
||||
// Tries to parse the input as a back reference. If successful it
|
||||
// stores the result in the output parameter and returns true. If
|
||||
// it fails it will push back the characters read so the same characters
|
||||
// can be reparsed.
|
||||
bool ParseBackReferenceIndex(int* index_out);
|
||||
|
||||
CharacterRange ParseClassAtom(uc16* char_class);
|
||||
RegExpTree* ReportError(Vector<const char> message);
|
||||
void Advance();
|
||||
void Advance(int dist);
|
||||
void Reset(int pos);
|
||||
|
||||
// Reports whether the pattern might be used as a literal search string.
|
||||
// Only use if the result of the parse is a single atom node.
|
||||
bool simple();
|
||||
bool contains_anchor() { return contains_anchor_; }
|
||||
void set_contains_anchor() { contains_anchor_ = true; }
|
||||
int captures_started() { return captures_ == NULL ? 0 : captures_->length(); }
|
||||
int position() { return next_pos_ - 1; }
|
||||
bool failed() { return failed_; }
|
||||
|
||||
static const int kMaxCaptures = 1 << 16;
|
||||
static const uc32 kEndMarker = (1 << 21);
|
||||
|
||||
private:
|
||||
enum SubexpressionType {
|
||||
INITIAL,
|
||||
CAPTURE, // All positive values represent captures.
|
||||
POSITIVE_LOOKAHEAD,
|
||||
NEGATIVE_LOOKAHEAD,
|
||||
GROUPING
|
||||
};
|
||||
|
||||
class RegExpParserState : public ZoneObject {
|
||||
public:
|
||||
RegExpParserState(RegExpParserState* previous_state,
|
||||
SubexpressionType group_type,
|
||||
int disjunction_capture_index)
|
||||
: previous_state_(previous_state),
|
||||
builder_(new RegExpBuilder()),
|
||||
group_type_(group_type),
|
||||
disjunction_capture_index_(disjunction_capture_index) {}
|
||||
// Parser state of containing expression, if any.
|
||||
RegExpParserState* previous_state() { return previous_state_; }
|
||||
bool IsSubexpression() { return previous_state_ != NULL; }
|
||||
// RegExpBuilder building this regexp's AST.
|
||||
RegExpBuilder* builder() { return builder_; }
|
||||
// Type of regexp being parsed (parenthesized group or entire regexp).
|
||||
SubexpressionType group_type() { return group_type_; }
|
||||
// Index in captures array of first capture in this sub-expression, if any.
|
||||
// Also the capture index of this sub-expression itself, if group_type
|
||||
// is CAPTURE.
|
||||
int capture_index() { return disjunction_capture_index_; }
|
||||
|
||||
private:
|
||||
// Linked list implementation of stack of states.
|
||||
RegExpParserState* previous_state_;
|
||||
// Builder for the stored disjunction.
|
||||
RegExpBuilder* builder_;
|
||||
// Stored disjunction type (capture, look-ahead or grouping), if any.
|
||||
SubexpressionType group_type_;
|
||||
// Stored disjunction's capture index (if any).
|
||||
int disjunction_capture_index_;
|
||||
};
|
||||
|
||||
uc32 current() { return current_; }
|
||||
bool has_more() { return has_more_; }
|
||||
bool has_next() { return next_pos_ < in()->length(); }
|
||||
uc32 Next();
|
||||
FlatStringReader* in() { return in_; }
|
||||
void ScanForCaptures();
|
||||
uc32 current_;
|
||||
bool has_more_;
|
||||
bool multiline_;
|
||||
int next_pos_;
|
||||
FlatStringReader* in_;
|
||||
Handle<String>* error_;
|
||||
bool simple_;
|
||||
bool contains_anchor_;
|
||||
ZoneList<RegExpCapture*>* captures_;
|
||||
bool is_scanned_for_captures_;
|
||||
// The capture count is only valid after we have scanned for captures.
|
||||
int capture_count_;
|
||||
bool failed_;
|
||||
};
|
||||
|
||||
|
||||
class Parser {
|
||||
public:
|
||||
Parser(Handle<Script> script, bool allow_natives_syntax,
|
||||
v8::Extension* extension, ParserMode is_pre_parsing,
|
||||
ParserFactory* factory, ParserLog* log, ScriptDataImpl* pre_data);
|
||||
virtual ~Parser() { }
|
||||
|
||||
// Pre-parse the program from the character stream; returns true on
|
||||
// success, false if a stack-overflow happened during parsing.
|
||||
bool PreParseProgram(Handle<String> source, unibrow::CharacterStream* stream);
|
||||
@ -218,7 +448,6 @@ class Parser {
|
||||
FunctionLiteral* ParseProgram(Handle<String> source,
|
||||
bool in_global_context);
|
||||
FunctionLiteral* ParseLazy(Handle<SharedFunctionInfo> info);
|
||||
FunctionLiteral* ParseJson(Handle<String> source);
|
||||
|
||||
// The minimum number of contiguous assignment that will
|
||||
// be treated as an initialization block. Benchmarks show that
|
||||
@ -410,34 +639,6 @@ class Parser {
|
||||
Expression* NewThrowError(Handle<String> constructor,
|
||||
Handle<String> type,
|
||||
Vector< Handle<Object> > arguments);
|
||||
|
||||
// JSON is a subset of JavaScript, as specified in, e.g., the ECMAScript 5
|
||||
// specification section 15.12.1 (and appendix A.8).
|
||||
// The grammar is given section 15.12.1.2 (and appendix A.8.2).
|
||||
|
||||
// Parse JSON input as a single JSON value.
|
||||
Expression* ParseJson(bool* ok);
|
||||
|
||||
// Parse a single JSON value from input (grammar production JSONValue).
|
||||
// A JSON value is either a (double-quoted) string literal, a number literal,
|
||||
// one of "true", "false", or "null", or an object or array literal.
|
||||
Expression* ParseJsonValue(bool* ok);
|
||||
// Parse a JSON object literal (grammar production JSONObject).
|
||||
// An object literal is a squiggly-braced and comma separated sequence
|
||||
// (possibly empty) of key/value pairs, where the key is a JSON string
|
||||
// literal, the value is a JSON value, and the two are spearated by a colon.
|
||||
// A JavaScript object also allows numbers and identifiers as keys.
|
||||
Expression* ParseJsonObject(bool* ok);
|
||||
// Parses a JSON array literal (grammar production JSONArray). An array
|
||||
// literal is a square-bracketed and comma separated sequence (possibly empty)
|
||||
// of JSON values.
|
||||
// A JavaScript array allows leaving out values from the sequence.
|
||||
Expression* ParseJsonArray(bool* ok);
|
||||
|
||||
friend class Target;
|
||||
friend class TargetScope;
|
||||
friend class LexicalScope;
|
||||
friend class TemporaryScope;
|
||||
};
|
||||
|
||||
|
||||
@ -472,6 +673,49 @@ class CompileTimeValue: public AllStatic {
|
||||
};
|
||||
|
||||
|
||||
// JSON is a subset of JavaScript, as specified in, e.g., the ECMAScript 5
|
||||
// specification section 15.12.1 (and appendix A.8).
|
||||
// The grammar is given section 15.12.1.2 (and appendix A.8.2).
|
||||
class JsonParser BASE_EMBEDDED {
|
||||
public:
|
||||
// Parse JSON input as a single JSON value.
|
||||
// Returns null handle and sets exception if parsing failed.
|
||||
static Handle<Object> Parse(Handle<String> source) {
|
||||
return JsonParser().ParseJson(source);
|
||||
}
|
||||
|
||||
private:
|
||||
JsonParser() { }
|
||||
~JsonParser() { }
|
||||
|
||||
// Parse a string containing a single JSON value.
|
||||
Handle<Object> ParseJson(Handle<String>);
|
||||
// Parse a single JSON value from input (grammar production JSONValue).
|
||||
// A JSON value is either a (double-quoted) string literal, a number literal,
|
||||
// one of "true", "false", or "null", or an object or array literal.
|
||||
Handle<Object> ParseJsonValue();
|
||||
// Parse a JSON object literal (grammar production JSONObject).
|
||||
// An object literal is a squiggly-braced and comma separated sequence
|
||||
// (possibly empty) of key/value pairs, where the key is a JSON string
|
||||
// literal, the value is a JSON value, and the two are separated by a colon.
|
||||
// A JSON array dosn't allow numbers and identifiers as keys, like a
|
||||
// JavaScript array.
|
||||
Handle<Object> ParseJsonObject();
|
||||
// Parses a JSON array literal (grammar production JSONArray). An array
|
||||
// literal is a square-bracketed and comma separated sequence (possibly empty)
|
||||
// of JSON values.
|
||||
// A JSON array doesn't allow leaving out values from the sequence, nor does
|
||||
// it allow a terminal comma, like a JavaScript array does.
|
||||
Handle<Object> ParseJsonArray();
|
||||
|
||||
// Mark that a parsing error has happened at the current token, and
|
||||
// return a null handle. Primarily for readability.
|
||||
Handle<Object> ReportUnexpectedToken() { return Handle<Object>::null(); }
|
||||
// Converts the currently parsed literal to a JavaScript String.
|
||||
Handle<String> GetString();
|
||||
|
||||
Scanner scanner_;
|
||||
};
|
||||
} } // namespace v8::internal
|
||||
|
||||
#endif // V8_PARSER_H_
|
||||
|
2
deps/v8/src/platform-linux.cc
vendored
2
deps/v8/src/platform-linux.cc
vendored
@ -856,7 +856,7 @@ void Sampler::Start() {
|
||||
struct sigaction sa;
|
||||
sa.sa_sigaction = ProfilerSignalHandler;
|
||||
sigemptyset(&sa.sa_mask);
|
||||
sa.sa_flags = SA_SIGINFO;
|
||||
sa.sa_flags = SA_RESTART | SA_SIGINFO;
|
||||
if (sigaction(SIGPROF, &sa, &data_->old_signal_handler_) != 0) return;
|
||||
data_->signal_handler_installed_ = true;
|
||||
|
||||
|
32
deps/v8/src/runtime.cc
vendored
32
deps/v8/src/runtime.cc
vendored
@ -7129,20 +7129,31 @@ static MaybeObject* Runtime_GlobalReceiver(Arguments args) {
|
||||
}
|
||||
|
||||
|
||||
static MaybeObject* Runtime_ParseJson(Arguments args) {
|
||||
HandleScope scope;
|
||||
ASSERT_EQ(1, args.length());
|
||||
CONVERT_ARG_CHECKED(String, source, 0);
|
||||
|
||||
Handle<Object> result = JsonParser::Parse(source);
|
||||
if (result.is_null()) {
|
||||
// Syntax error or stack overflow in scanner.
|
||||
ASSERT(Top::has_pending_exception());
|
||||
return Failure::Exception();
|
||||
}
|
||||
return *result;
|
||||
}
|
||||
|
||||
|
||||
static MaybeObject* Runtime_CompileString(Arguments args) {
|
||||
HandleScope scope;
|
||||
ASSERT_EQ(2, args.length());
|
||||
ASSERT_EQ(1, args.length());
|
||||
CONVERT_ARG_CHECKED(String, source, 0);
|
||||
CONVERT_ARG_CHECKED(Oddball, is_json, 1)
|
||||
|
||||
// Compile source string in the global context.
|
||||
Handle<Context> context(Top::context()->global_context());
|
||||
Compiler::ValidationState validate = (is_json->IsTrue())
|
||||
? Compiler::VALIDATE_JSON : Compiler::DONT_VALIDATE_JSON;
|
||||
Handle<SharedFunctionInfo> shared = Compiler::CompileEval(source,
|
||||
context,
|
||||
true,
|
||||
validate);
|
||||
true);
|
||||
if (shared.is_null()) return Failure::Exception();
|
||||
Handle<JSFunction> fun =
|
||||
Factory::NewFunctionFromSharedFunctionInfo(shared, context, NOT_TENURED);
|
||||
@ -7157,8 +7168,7 @@ static ObjectPair CompileGlobalEval(Handle<String> source,
|
||||
Handle<SharedFunctionInfo> shared = Compiler::CompileEval(
|
||||
source,
|
||||
Handle<Context>(Top::context()),
|
||||
Top::context()->IsGlobalContext(),
|
||||
Compiler::DONT_VALIDATE_JSON);
|
||||
Top::context()->IsGlobalContext());
|
||||
if (shared.is_null()) return MakePair(Failure::Exception(), NULL);
|
||||
Handle<JSFunction> compiled = Factory::NewFunctionFromSharedFunctionInfo(
|
||||
shared,
|
||||
@ -9370,8 +9380,7 @@ static MaybeObject* Runtime_DebugEvaluate(Arguments args) {
|
||||
Handle<SharedFunctionInfo> shared =
|
||||
Compiler::CompileEval(function_source,
|
||||
context,
|
||||
context->IsGlobalContext(),
|
||||
Compiler::DONT_VALIDATE_JSON);
|
||||
context->IsGlobalContext());
|
||||
if (shared.is_null()) return Failure::Exception();
|
||||
Handle<JSFunction> compiled_function =
|
||||
Factory::NewFunctionFromSharedFunctionInfo(shared, context);
|
||||
@ -9442,8 +9451,7 @@ static MaybeObject* Runtime_DebugEvaluateGlobal(Arguments args) {
|
||||
Handle<SharedFunctionInfo> shared =
|
||||
Compiler::CompileEval(source,
|
||||
context,
|
||||
true,
|
||||
Compiler::DONT_VALIDATE_JSON);
|
||||
true);
|
||||
if (shared.is_null()) return Failure::Exception();
|
||||
Handle<JSFunction> compiled_function =
|
||||
Handle<JSFunction>(Factory::NewFunctionFromSharedFunctionInfo(shared,
|
||||
|
5
deps/v8/src/runtime.h
vendored
5
deps/v8/src/runtime.h
vendored
@ -164,6 +164,9 @@ namespace internal {
|
||||
F(RegExpConstructResult, 3, 1) \
|
||||
F(RegExpCloneResult, 1, 1) \
|
||||
\
|
||||
/* JSON */ \
|
||||
F(ParseJson, 1, 1) \
|
||||
\
|
||||
/* Strings */ \
|
||||
F(StringCharCodeAt, 2, 1) \
|
||||
F(StringIndexOf, 3, 1) \
|
||||
@ -222,7 +225,7 @@ namespace internal {
|
||||
/* Numbers */ \
|
||||
\
|
||||
/* Globals */ \
|
||||
F(CompileString, 2, 1) \
|
||||
F(CompileString, 1, 1) \
|
||||
F(GlobalPrint, 1, 1) \
|
||||
\
|
||||
/* Eval */ \
|
||||
|
3
deps/v8/src/scanner.h
vendored
3
deps/v8/src/scanner.h
vendored
@ -296,6 +296,9 @@ class Scanner {
|
||||
// Returns the next token.
|
||||
Token::Value Next();
|
||||
|
||||
// Returns the current token again.
|
||||
Token::Value current_token() { return current_.token; }
|
||||
|
||||
// One token look-ahead (past the token returned by Next()).
|
||||
Token::Value peek() const { return next_.token; }
|
||||
|
||||
|
6
deps/v8/src/stub-cache.h
vendored
6
deps/v8/src/stub-cache.h
vendored
@ -241,13 +241,15 @@ class StubCache : public AllStatic {
|
||||
static void Clear();
|
||||
|
||||
// Generate code for probing the stub cache table.
|
||||
// If extra != no_reg it might be used as am extra scratch register.
|
||||
// Arguments extra and extra2 may be used to pass additional scratch
|
||||
// registers. Set to no_reg if not needed.
|
||||
static void GenerateProbe(MacroAssembler* masm,
|
||||
Code::Flags flags,
|
||||
Register receiver,
|
||||
Register name,
|
||||
Register scratch,
|
||||
Register extra);
|
||||
Register extra,
|
||||
Register extra2 = no_reg);
|
||||
|
||||
enum Table {
|
||||
kPrimary,
|
||||
|
4
deps/v8/src/top.h
vendored
4
deps/v8/src/top.h
vendored
@ -105,7 +105,11 @@ class ThreadLocalTop BASE_EMBEDDED {
|
||||
Address handler_; // try-blocks are chained through the stack
|
||||
|
||||
#ifdef USE_SIMULATOR
|
||||
#ifdef V8_TARGET_ARCH_ARM
|
||||
assembler::arm::Simulator* simulator_;
|
||||
#elif V8_TARGET_ARCH_MIPS
|
||||
assembler::mips::Simulator* simulator_;
|
||||
#endif
|
||||
#endif // USE_SIMULATOR
|
||||
|
||||
#ifdef ENABLE_LOGGING_AND_PROFILING
|
||||
|
6
deps/v8/src/v8natives.js
vendored
6
deps/v8/src/v8natives.js
vendored
@ -140,7 +140,7 @@ function GlobalEval(x) {
|
||||
'be the global object from which eval originated');
|
||||
}
|
||||
|
||||
var f = %CompileString(x, false);
|
||||
var f = %CompileString(x);
|
||||
if (!IS_FUNCTION(f)) return f;
|
||||
|
||||
return f.call(this);
|
||||
@ -151,7 +151,7 @@ function GlobalEval(x) {
|
||||
function GlobalExecScript(expr, lang) {
|
||||
// NOTE: We don't care about the character casing.
|
||||
if (!lang || /javascript/i.test(lang)) {
|
||||
var f = %CompileString(ToString(expr), false);
|
||||
var f = %CompileString(ToString(expr));
|
||||
f.call(%GlobalReceiver(global));
|
||||
}
|
||||
return null;
|
||||
@ -1177,7 +1177,7 @@ function NewFunction(arg1) { // length == 1
|
||||
|
||||
// The call to SetNewFunctionAttributes will ensure the prototype
|
||||
// property of the resulting function is enumerable (ECMA262, 15.3.5.2).
|
||||
var f = %CompileString(source, false)();
|
||||
var f = %CompileString(source)();
|
||||
%FunctionSetName(f, "anonymous");
|
||||
return %SetNewFunctionAttributes(f);
|
||||
}
|
||||
|
2
deps/v8/src/version.cc
vendored
2
deps/v8/src/version.cc
vendored
@ -34,7 +34,7 @@
|
||||
// cannot be changed without changing the SCons build script.
|
||||
#define MAJOR_VERSION 2
|
||||
#define MINOR_VERSION 5
|
||||
#define BUILD_NUMBER 2
|
||||
#define BUILD_NUMBER 3
|
||||
#define PATCH_LEVEL 0
|
||||
#define CANDIDATE_VERSION false
|
||||
|
||||
|
31
deps/v8/src/x64/codegen-x64.cc
vendored
31
deps/v8/src/x64/codegen-x64.cc
vendored
@ -4866,6 +4866,11 @@ void CodeGenerator::VisitObjectLiteral(ObjectLiteral* node) {
|
||||
}
|
||||
frame_->Push(&clone);
|
||||
|
||||
// Mark all computed expressions that are bound to a key that
|
||||
// is shadowed by a later occurrence of the same key. For the
|
||||
// marked expressions, no store code is emitted.
|
||||
node->CalculateEmitStore();
|
||||
|
||||
for (int i = 0; i < node->properties()->length(); i++) {
|
||||
ObjectLiteral::Property* property = node->properties()->at(i);
|
||||
switch (property->kind()) {
|
||||
@ -4880,13 +4885,17 @@ void CodeGenerator::VisitObjectLiteral(ObjectLiteral* node) {
|
||||
// Duplicate the object as the IC receiver.
|
||||
frame_->Dup();
|
||||
Load(property->value());
|
||||
Result ignored =
|
||||
frame_->CallStoreIC(Handle<String>::cast(key), false);
|
||||
// A test rax instruction following the store IC call would
|
||||
// indicate the presence of an inlined version of the
|
||||
// store. Add a nop to indicate that there is no such
|
||||
// inlined version.
|
||||
__ nop();
|
||||
if (property->emit_store()) {
|
||||
Result ignored =
|
||||
frame_->CallStoreIC(Handle<String>::cast(key), false);
|
||||
// A test rax instruction following the store IC call would
|
||||
// indicate the presence of an inlined version of the
|
||||
// store. Add a nop to indicate that there is no such
|
||||
// inlined version.
|
||||
__ nop();
|
||||
} else {
|
||||
frame_->Drop(2);
|
||||
}
|
||||
break;
|
||||
}
|
||||
// Fall through
|
||||
@ -4896,8 +4905,12 @@ void CodeGenerator::VisitObjectLiteral(ObjectLiteral* node) {
|
||||
frame_->Dup();
|
||||
Load(property->key());
|
||||
Load(property->value());
|
||||
Result ignored = frame_->CallRuntime(Runtime::kSetProperty, 3);
|
||||
// Ignore the result.
|
||||
if (property->emit_store()) {
|
||||
// Ignore the result.
|
||||
Result ignored = frame_->CallRuntime(Runtime::kSetProperty, 3);
|
||||
} else {
|
||||
frame_->Drop(3);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ObjectLiteral::Property::SETTER: {
|
||||
|
17
deps/v8/src/x64/full-codegen-x64.cc
vendored
17
deps/v8/src/x64/full-codegen-x64.cc
vendored
@ -1158,6 +1158,11 @@ void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
|
||||
// result_saved is false the result is in rax.
|
||||
bool result_saved = false;
|
||||
|
||||
// Mark all computed expressions that are bound to a key that
|
||||
// is shadowed by a later occurrence of the same key. For the
|
||||
// marked expressions, no store code is emitted.
|
||||
expr->CalculateEmitStore();
|
||||
|
||||
for (int i = 0; i < expr->properties()->length(); i++) {
|
||||
ObjectLiteral::Property* property = expr->properties()->at(i);
|
||||
if (property->IsCompileTimeValue()) continue;
|
||||
@ -1179,8 +1184,10 @@ void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
|
||||
VisitForAccumulatorValue(value);
|
||||
__ Move(rcx, key->handle());
|
||||
__ movq(rdx, Operand(rsp, 0));
|
||||
Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
|
||||
EmitCallIC(ic, RelocInfo::CODE_TARGET);
|
||||
if (property->emit_store()) {
|
||||
Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
|
||||
EmitCallIC(ic, RelocInfo::CODE_TARGET);
|
||||
}
|
||||
break;
|
||||
}
|
||||
// Fall through.
|
||||
@ -1188,7 +1195,11 @@ void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
|
||||
__ push(Operand(rsp, 0)); // Duplicate receiver.
|
||||
VisitForStackValue(key);
|
||||
VisitForStackValue(value);
|
||||
__ CallRuntime(Runtime::kSetProperty, 3);
|
||||
if (property->emit_store()) {
|
||||
__ CallRuntime(Runtime::kSetProperty, 3);
|
||||
} else {
|
||||
__ Drop(3);
|
||||
}
|
||||
break;
|
||||
case ObjectLiteral::Property::SETTER:
|
||||
case ObjectLiteral::Property::GETTER:
|
||||
|
10
deps/v8/src/x64/stub-cache-x64.cc
vendored
10
deps/v8/src/x64/stub-cache-x64.cc
vendored
@ -273,9 +273,11 @@ void StubCache::GenerateProbe(MacroAssembler* masm,
|
||||
Register receiver,
|
||||
Register name,
|
||||
Register scratch,
|
||||
Register extra) {
|
||||
Register extra,
|
||||
Register extra2) {
|
||||
Label miss;
|
||||
USE(extra); // The register extra is not used on the X64 platform.
|
||||
USE(extra); // The register extra is not used on the X64 platform.
|
||||
USE(extra2); // The register extra2 is not used on the X64 platform.
|
||||
// Make sure that code is valid. The shifting code relies on the
|
||||
// entry size being 16.
|
||||
ASSERT(sizeof(Entry) == 16);
|
||||
@ -287,6 +289,10 @@ void StubCache::GenerateProbe(MacroAssembler* masm,
|
||||
ASSERT(!scratch.is(receiver));
|
||||
ASSERT(!scratch.is(name));
|
||||
|
||||
// Check scratch register is valid, extra and extra2 are unused.
|
||||
ASSERT(!scratch.is(no_reg));
|
||||
ASSERT(extra2.is(no_reg));
|
||||
|
||||
// Check that the receiver isn't a smi.
|
||||
__ JumpIfSmi(receiver, &miss);
|
||||
|
||||
|
1
deps/v8/test/cctest/test-lock.cc
vendored
1
deps/v8/test/cctest/test-lock.cc
vendored
@ -60,4 +60,5 @@ TEST(SemaphoreTimeout) {
|
||||
sem->Signal();
|
||||
ok = sem->Wait(1000);
|
||||
CHECK(ok);
|
||||
delete sem;
|
||||
}
|
||||
|
13
deps/v8/test/cctest/test-regexp.cc
vendored
13
deps/v8/test/cctest/test-regexp.cc
vendored
@ -64,7 +64,7 @@ static bool CheckParse(const char* input) {
|
||||
ZoneScope zone_scope(DELETE_ON_EXIT);
|
||||
FlatStringReader reader(CStrVector(input));
|
||||
RegExpCompileData result;
|
||||
return v8::internal::Parser::ParseRegExp(&reader, false, &result);
|
||||
return v8::internal::RegExpParser::ParseRegExp(&reader, false, &result);
|
||||
}
|
||||
|
||||
|
||||
@ -74,7 +74,7 @@ static SmartPointer<const char> Parse(const char* input) {
|
||||
ZoneScope zone_scope(DELETE_ON_EXIT);
|
||||
FlatStringReader reader(CStrVector(input));
|
||||
RegExpCompileData result;
|
||||
CHECK(v8::internal::Parser::ParseRegExp(&reader, false, &result));
|
||||
CHECK(v8::internal::RegExpParser::ParseRegExp(&reader, false, &result));
|
||||
CHECK(result.tree != NULL);
|
||||
CHECK(result.error.is_null());
|
||||
SmartPointer<const char> output = result.tree->ToString();
|
||||
@ -88,7 +88,7 @@ static bool CheckSimple(const char* input) {
|
||||
ZoneScope zone_scope(DELETE_ON_EXIT);
|
||||
FlatStringReader reader(CStrVector(input));
|
||||
RegExpCompileData result;
|
||||
CHECK(v8::internal::Parser::ParseRegExp(&reader, false, &result));
|
||||
CHECK(v8::internal::RegExpParser::ParseRegExp(&reader, false, &result));
|
||||
CHECK(result.tree != NULL);
|
||||
CHECK(result.error.is_null());
|
||||
return result.simple;
|
||||
@ -106,7 +106,7 @@ static MinMaxPair CheckMinMaxMatch(const char* input) {
|
||||
ZoneScope zone_scope(DELETE_ON_EXIT);
|
||||
FlatStringReader reader(CStrVector(input));
|
||||
RegExpCompileData result;
|
||||
CHECK(v8::internal::Parser::ParseRegExp(&reader, false, &result));
|
||||
CHECK(v8::internal::RegExpParser::ParseRegExp(&reader, false, &result));
|
||||
CHECK(result.tree != NULL);
|
||||
CHECK(result.error.is_null());
|
||||
int min_match = result.tree->min_match();
|
||||
@ -365,7 +365,7 @@ static void ExpectError(const char* input,
|
||||
ZoneScope zone_scope(DELETE_ON_EXIT);
|
||||
FlatStringReader reader(CStrVector(input));
|
||||
RegExpCompileData result;
|
||||
CHECK_EQ(false, v8::internal::Parser::ParseRegExp(&reader, false, &result));
|
||||
CHECK(!v8::internal::RegExpParser::ParseRegExp(&reader, false, &result));
|
||||
CHECK(result.tree == NULL);
|
||||
CHECK(!result.error.is_null());
|
||||
SmartPointer<char> str = result.error->ToCString(ALLOW_NULLS);
|
||||
@ -473,7 +473,8 @@ static RegExpNode* Compile(const char* input, bool multiline, bool is_ascii) {
|
||||
V8::Initialize(NULL);
|
||||
FlatStringReader reader(CStrVector(input));
|
||||
RegExpCompileData compile_data;
|
||||
if (!v8::internal::Parser::ParseRegExp(&reader, multiline, &compile_data))
|
||||
if (!v8::internal::RegExpParser::ParseRegExp(&reader, multiline,
|
||||
&compile_data))
|
||||
return NULL;
|
||||
Handle<String> pattern = Factory::NewStringFromUtf8(CStrVector(input));
|
||||
RegExpEngine::Compile(&compile_data, false, multiline, pattern, is_ascii);
|
||||
|
6
deps/v8/test/cctest/test-serialize.cc
vendored
6
deps/v8/test/cctest/test-serialize.cc
vendored
@ -216,6 +216,7 @@ void FileByteSink::WriteSpaceUsed(
|
||||
Vector<char> name = Vector<char>::New(file_name_length + 1);
|
||||
OS::SNPrintF(name, "%s.size", file_name_);
|
||||
FILE* fp = OS::FOpen(name.start(), "w");
|
||||
name.Dispose();
|
||||
fprintf(fp, "new %d\n", new_space_used);
|
||||
fprintf(fp, "pointer %d\n", pointer_space_used);
|
||||
fprintf(fp, "data %d\n", data_space_used);
|
||||
@ -381,6 +382,7 @@ TEST(PartialSerialization) {
|
||||
env.Dispose();
|
||||
|
||||
FileByteSink startup_sink(startup_name.start());
|
||||
startup_name.Dispose();
|
||||
StartupSerializer startup_serializer(&startup_sink);
|
||||
startup_serializer.SerializeStrongReferences();
|
||||
|
||||
@ -403,6 +405,7 @@ static void ReserveSpaceForPartialSnapshot(const char* file_name) {
|
||||
Vector<char> name = Vector<char>::New(file_name_length + 1);
|
||||
OS::SNPrintF(name, "%s.size", file_name);
|
||||
FILE* fp = OS::FOpen(name.start(), "r");
|
||||
name.Dispose();
|
||||
int new_size, pointer_size, data_size, code_size, map_size, cell_size;
|
||||
int large_size;
|
||||
#ifdef _MSC_VER
|
||||
@ -438,6 +441,7 @@ DEPENDENT_TEST(PartialDeserialization, PartialSerialization) {
|
||||
OS::SNPrintF(startup_name, "%s.startup", FLAG_testing_serialization_file);
|
||||
|
||||
CHECK(Snapshot::Initialize(startup_name.start()));
|
||||
startup_name.Dispose();
|
||||
|
||||
const char* file_name = FLAG_testing_serialization_file;
|
||||
ReserveSpaceForPartialSnapshot(file_name);
|
||||
@ -495,6 +499,7 @@ TEST(ContextSerialization) {
|
||||
env.Dispose();
|
||||
|
||||
FileByteSink startup_sink(startup_name.start());
|
||||
startup_name.Dispose();
|
||||
StartupSerializer startup_serializer(&startup_sink);
|
||||
startup_serializer.SerializeStrongReferences();
|
||||
|
||||
@ -519,6 +524,7 @@ DEPENDENT_TEST(ContextDeserialization, ContextSerialization) {
|
||||
OS::SNPrintF(startup_name, "%s.startup", FLAG_testing_serialization_file);
|
||||
|
||||
CHECK(Snapshot::Initialize(startup_name.start()));
|
||||
startup_name.Dispose();
|
||||
|
||||
const char* file_name = FLAG_testing_serialization_file;
|
||||
ReserveSpaceForPartialSnapshot(file_name);
|
||||
|
18
deps/v8/test/mjsunit/debug-compile-event.js
vendored
18
deps/v8/test/mjsunit/debug-compile-event.js
vendored
@ -36,7 +36,6 @@ var current_source = ''; // Current source being compiled.
|
||||
var source_count = 0; // Total number of scources compiled.
|
||||
var host_compilations = 0; // Number of scources compiled through the API.
|
||||
var eval_compilations = 0; // Number of scources compiled through eval.
|
||||
var json_compilations = 0; // Number of scources compiled through JSON.parse.
|
||||
|
||||
|
||||
function compileSource(source) {
|
||||
@ -62,9 +61,6 @@ function listener(event, exec_state, event_data, data) {
|
||||
case Debug.ScriptCompilationType.Eval:
|
||||
eval_compilations++;
|
||||
break;
|
||||
case Debug.ScriptCompilationType.JSON:
|
||||
json_compilations++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -74,13 +70,6 @@ function listener(event, exec_state, event_data, data) {
|
||||
// For source with 'eval' there will be compile events with substrings
|
||||
// as well as with with the exact source.
|
||||
assertTrue(current_source.indexOf(event_data.script().source()) >= 0);
|
||||
} else if (current_source.indexOf('JSON.parse') == 0) {
|
||||
// For JSON the JSON source will be in parentheses.
|
||||
var s = event_data.script().source();
|
||||
if (s[0] == '(') {
|
||||
s = s.substring(1, s.length - 2);
|
||||
}
|
||||
assertTrue(current_source.indexOf(s) >= 0);
|
||||
} else {
|
||||
// For source without 'eval' there will be a compile events with the
|
||||
// exact source.
|
||||
@ -113,7 +102,7 @@ source_count++; // Using eval causes additional compilation event.
|
||||
compileSource('eval("eval(\'(function(){return a;})\')")');
|
||||
source_count += 2; // Using eval causes additional compilation event.
|
||||
compileSource('JSON.parse(\'{"a":1,"b":2}\')');
|
||||
source_count++; // Using JSON.parse causes additional compilation event.
|
||||
// Using JSON.parse does not causes additional compilation events.
|
||||
compileSource('x=1; //@ sourceURL=myscript.js');
|
||||
|
||||
// Make sure that the debug event listener was invoked.
|
||||
@ -123,10 +112,9 @@ assertFalse(exception, "exception in listener")
|
||||
assertEquals(before_compile_count, after_compile_count);
|
||||
|
||||
// Check the actual number of events (no compilation through the API as all
|
||||
// source compiled through eval except for one JSON.parse call).
|
||||
// source compiled through eval).
|
||||
assertEquals(source_count, after_compile_count);
|
||||
assertEquals(0, host_compilations);
|
||||
assertEquals(source_count - 1, eval_compilations);
|
||||
assertEquals(1, json_compilations);
|
||||
assertEquals(source_count, eval_compilations);
|
||||
|
||||
Debug.setListener(null);
|
||||
|
4
deps/v8/test/mjsunit/mirror-script.js
vendored
4
deps/v8/test/mjsunit/mirror-script.js
vendored
@ -83,12 +83,10 @@ function testScriptMirror(f, file_name, file_lines, type, compilation_type,
|
||||
|
||||
|
||||
// Test the script mirror for different functions.
|
||||
testScriptMirror(function(){}, 'mirror-script.js', 100, 2, 0);
|
||||
testScriptMirror(function(){}, 'mirror-script.js', 98, 2, 0);
|
||||
testScriptMirror(Math.sin, 'native math.js', -1, 0, 0);
|
||||
testScriptMirror(eval('(function(){})'), null, 1, 2, 1, '(function(){})', 87);
|
||||
testScriptMirror(eval('(function(){\n })'), null, 2, 2, 1, '(function(){\n })', 88);
|
||||
testScriptMirror(%CompileString('{"a":1,"b":2}', true), null, 1, 2, 2, '{"a":1,"b":2}');
|
||||
testScriptMirror(%CompileString('{"a":1,\n "b":2}', true), null, 2, 2, 2, '{"a":1,\n "b":2}');
|
||||
|
||||
// Test taking slices of source.
|
||||
var mirror = debug.MakeMirror(eval('(function(){\n 1;\n})')).script();
|
||||
|
9
deps/v8/test/mjsunit/mjsunit.status
vendored
9
deps/v8/test/mjsunit/mjsunit.status
vendored
@ -45,6 +45,10 @@ unicode-case-overoptimization: PASS, TIMEOUT if ($arch == arm)
|
||||
# Skip long running test in debug and allow it to timeout in release mode.
|
||||
regress/regress-524: (PASS || TIMEOUT), SKIP if $mode == debug
|
||||
|
||||
# Stack manipulations in LiveEdit are buggy - see bug 915
|
||||
debug-liveedit-check-stack: SKIP
|
||||
debug-liveedit-patch-positions-replace: SKIP
|
||||
|
||||
[ $arch == arm ]
|
||||
|
||||
# Slow tests which times out in debug mode.
|
||||
@ -61,14 +65,9 @@ array-splice: PASS || TIMEOUT
|
||||
# Skip long running test in debug mode on ARM.
|
||||
string-indexof-2: PASS, SKIP if $mode == debug
|
||||
|
||||
# Stack manipulations in LiveEdit is implemented for ia32 only.
|
||||
debug-liveedit-check-stack: SKIP
|
||||
|
||||
[ $arch == mips ]
|
||||
|
||||
# Stack manipulations in LiveEdit is implemented for ia32 only.
|
||||
debug-liveedit-check-stack: SKIP
|
||||
|
||||
# Skip all tests on MIPS.
|
||||
*: SKIP
|
||||
|
||||
|
46
deps/v8/test/mjsunit/object-literal-conversions.js
vendored
Normal file
46
deps/v8/test/mjsunit/object-literal-conversions.js
vendored
Normal file
@ -0,0 +1,46 @@
|
||||
// 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.
|
||||
|
||||
// Test that the various conversions between property names are correctly
|
||||
// used when overwriting initializers.
|
||||
|
||||
var test1 = { 13: 6, "13": 7 };
|
||||
var test2 = { 13: 7, "13.0": 6 };
|
||||
var test3 = { "13": 6, 13.0000000000000000: 7 };
|
||||
var test4 = { 13.213000: 6, "13.213": 7 };
|
||||
|
||||
assertEquals(7, test1[13]);
|
||||
assertEquals(7, test2[13]);
|
||||
assertEquals(7, test3[13]);
|
||||
assertEquals(7, test4[13.213]);
|
||||
|
||||
var test5 = { 13: function() {}, "13": 7 };
|
||||
var test6 = { 17.31: function() {}, "17.31": 7 };
|
||||
|
||||
assertEquals(7, test5[13]);
|
||||
assertEquals(7, test6[17.31]);
|
||||
|
118
deps/v8/test/mjsunit/object-literal-overwrite.js
vendored
Normal file
118
deps/v8/test/mjsunit/object-literal-overwrite.js
vendored
Normal file
@ -0,0 +1,118 @@
|
||||
// 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.
|
||||
|
||||
// Check that constants and computed properties are overwriting each other
|
||||
// correctly, i.e., the last initializer for any name is stored in the object.
|
||||
|
||||
|
||||
// Tests for the full code generator (if active).
|
||||
|
||||
var foo1 = {
|
||||
bar: 6,
|
||||
bar: 7
|
||||
};
|
||||
|
||||
var foo2 = {
|
||||
bar: function(a){},
|
||||
bar: 7
|
||||
};
|
||||
|
||||
var foo3 = {
|
||||
bar: function(a){},
|
||||
bar: function(b){},
|
||||
bar: 7
|
||||
};
|
||||
|
||||
var foo4 = {
|
||||
bar: function(b){},
|
||||
bar: 7,
|
||||
bar: function(){return 7},
|
||||
};
|
||||
|
||||
var foo5 = {
|
||||
13: function(a){},
|
||||
13: 7
|
||||
}
|
||||
|
||||
var foo6 = {
|
||||
14.31: function(a){},
|
||||
14.31: 7
|
||||
}
|
||||
|
||||
var foo7 = {
|
||||
15: 6,
|
||||
15: 7
|
||||
}
|
||||
|
||||
assertEquals(7, foo1.bar);
|
||||
assertEquals(7, foo2.bar);
|
||||
assertEquals(7, foo3.bar);
|
||||
assertEquals(7, foo4.bar());
|
||||
assertEquals(7, foo5[13]);
|
||||
assertEquals(7, foo6[14.31]);
|
||||
assertEquals(7, foo7[15]);
|
||||
|
||||
// Test for the classic code generator.
|
||||
|
||||
function fun(x) {
|
||||
var inner = { j: function(x) { return x; }, j: 7 };
|
||||
return inner.j;
|
||||
}
|
||||
|
||||
assertEquals(7, fun(7) );
|
||||
|
||||
// Check that the initializers of computed properties are executed, even if
|
||||
// no store instructions are generated for the literals.
|
||||
|
||||
var glob1 = 0;
|
||||
|
||||
var bar1 = { x: glob1++, x: glob1++, x: glob1++, x: 7};
|
||||
|
||||
assertEquals(3, glob1);
|
||||
|
||||
|
||||
var glob2 = 0;
|
||||
|
||||
function fun2() {
|
||||
var r = { y: glob2++, y: glob2++, y: glob2++, y: 7};
|
||||
return r.y;
|
||||
}
|
||||
|
||||
var y = fun2();
|
||||
assertEquals(7, y);
|
||||
assertEquals(3, glob2);
|
||||
|
||||
var glob3 = 0;
|
||||
|
||||
function fun3() {
|
||||
var r = { 113: glob3++, 113: glob3++, 113: glob3++, 113: 7};
|
||||
return r[113];
|
||||
}
|
||||
|
||||
var y = fun3();
|
||||
assertEquals(7, y);
|
||||
assertEquals(3, glob3);
|
6
deps/v8/test/mjsunit/string-externalize.js
vendored
6
deps/v8/test/mjsunit/string-externalize.js
vendored
@ -25,7 +25,7 @@
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Flags: --expose-externalize-string
|
||||
// Flags: --expose-externalize-string --expose-gc
|
||||
|
||||
var size = 1024;
|
||||
|
||||
@ -93,3 +93,7 @@ function test() {
|
||||
for (var i = 0; i < 10; i++) {
|
||||
test();
|
||||
}
|
||||
|
||||
// Clean up string to make Valgrind happy.
|
||||
gc();
|
||||
gc();
|
||||
|
@ -25,33 +25,45 @@
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Flags: --expose-externalize-string
|
||||
// Flags: --expose-externalize-string --expose-gc
|
||||
|
||||
assertEquals("0123", "aa0bb1cc2dd3".replace(/[a-z]/g, ""));
|
||||
assertEquals("0123", "\u1234a0bb1cc2dd3".replace(/[\u1234a-z]/g, ""));
|
||||
function test() {
|
||||
assertEquals("0123", "aa0bb1cc2dd3".replace(/[a-z]/g, ""));
|
||||
assertEquals("0123", "\u1234a0bb1cc2dd3".replace(/[\u1234a-z]/g, ""));
|
||||
|
||||
var expected = "0123";
|
||||
var cons = "a0b1c2d3";
|
||||
for (var i = 0; i < 5; i++) {
|
||||
expected += expected;
|
||||
cons += cons;
|
||||
}
|
||||
assertEquals(expected, cons.replace(/[a-z]/g, ""));
|
||||
cons = "\u12340b1c2d3";
|
||||
for (var i = 0; i < 5; i++) {
|
||||
cons += cons;
|
||||
}
|
||||
assertEquals(expected, cons.replace(/[\u1234a-z]/g, ""));
|
||||
var expected = "0123";
|
||||
var cons = "a0b1c2d3";
|
||||
for (var i = 0; i < 5; i++) {
|
||||
expected += expected;
|
||||
cons += cons;
|
||||
}
|
||||
assertEquals(expected, cons.replace(/[a-z]/g, ""));
|
||||
cons = "\u12340b1c2d3";
|
||||
for (var i = 0; i < 5; i++) {
|
||||
cons += cons;
|
||||
}
|
||||
assertEquals(expected, cons.replace(/[\u1234a-z]/g, ""));
|
||||
|
||||
cons = "a0b1c2d3";
|
||||
for (var i = 0; i < 5; i++) {
|
||||
cons += cons;
|
||||
cons = "a0b1c2d3";
|
||||
for (var i = 0; i < 5; i++) {
|
||||
cons += cons;
|
||||
}
|
||||
externalizeString(cons, true/* force two-byte */);
|
||||
assertEquals(expected, cons.replace(/[a-z]/g, ""));
|
||||
cons = "\u12340b1c2d3";
|
||||
for (var i = 0; i < 5; i++) {
|
||||
cons += cons;
|
||||
}
|
||||
externalizeString(cons);
|
||||
assertEquals(expected, cons.replace(/[\u1234a-z]/g, ""));
|
||||
}
|
||||
externalizeString(cons, true/* force two-byte */);
|
||||
assertEquals(expected, cons.replace(/[a-z]/g, ""));
|
||||
cons = "\u12340b1c2d3";
|
||||
for (var i = 0; i < 5; i++) {
|
||||
cons += cons;
|
||||
}
|
||||
externalizeString(cons);
|
||||
assertEquals(expected, cons.replace(/[\u1234a-z]/g, ""));
|
||||
|
||||
test();
|
||||
|
||||
// Clear the regexp cache to allow the GC to work.
|
||||
"foo".replace(/foo/g, "");
|
||||
|
||||
// GC in order to free up things on the C side so we don't get
|
||||
// a memory leak. This makes valgrind happy.
|
||||
gc();
|
||||
gc();
|
||||
|
4
deps/v8/tools/ll_prof.py
vendored
4
deps/v8/tools/ll_prof.py
vendored
@ -353,7 +353,7 @@ class CodeLogReader(object):
|
||||
r"code-info,([^,]+),(\d+)")
|
||||
|
||||
_CODE_CREATE_RE = re.compile(
|
||||
r"code-creation,([^,]+),(0x[a-f0-9]+),(\d+),\"([^\"]*)\"(?:,(\d+))?")
|
||||
r"code-creation,([^,]+),(0x[a-f0-9]+),(\d+),\"(.*)\"(?:,(\d+))?")
|
||||
|
||||
_CODE_MOVE_RE = re.compile(
|
||||
r"code-move,(0x[a-f0-9]+),(0x[a-f0-9]+)")
|
||||
@ -910,7 +910,7 @@ if __name__ == "__main__":
|
||||
start = time.time()
|
||||
mmap_info = trace_reader.ReadMmap(header, offset)
|
||||
if mmap_info.filename == V8_GC_FAKE_MMAP:
|
||||
log_reader.ReadUpToGC()
|
||||
log_reader.ReadUpToGC(code_info)
|
||||
else:
|
||||
library_repo.Load(mmap_info, code_map, options)
|
||||
mmap_time += time.time() - start
|
||||
|
Loading…
x
Reference in New Issue
Block a user