Version 3.4.14
Fix the debugger for strict-mode functions. (Chromium issue 89236)
Add GetPropertyAttribute method for Object in the API. (Patch by Peter Varga)
Fix -Wunused-but-set-variable for gcc-4.6 on x64. (Issue 1291)
git-svn-id: http://v8.googlecode.com/svn/trunk@8697 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
diff --git a/src/api.cc b/src/api.cc
index fca7fbf..b0e9775 100644
--- a/src/api.cc
+++ b/src/api.cc
@@ -2794,6 +2794,26 @@
}
+PropertyAttribute v8::Object::GetPropertyAttributes(v8::Handle<Value> key) {
+ i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
+ ON_BAILOUT(isolate, "v8::Object::GetPropertyAttribute()",
+ return static_cast<PropertyAttribute>(NONE));
+ ENTER_V8(isolate);
+ i::HandleScope scope(isolate);
+ i::Handle<i::JSObject> self = Utils::OpenHandle(this);
+ i::Handle<i::Object> key_obj = Utils::OpenHandle(*key);
+ if (!key_obj->IsString()) {
+ EXCEPTION_PREAMBLE(isolate);
+ key_obj = i::Execution::ToString(key_obj, &has_pending_exception);
+ EXCEPTION_BAILOUT_CHECK(isolate, static_cast<PropertyAttribute>(NONE));
+ }
+ i::Handle<i::String> key_string = i::Handle<i::String>::cast(key_obj);
+ PropertyAttributes result = self->GetPropertyAttribute(*key_string);
+ if (result == ABSENT) return static_cast<PropertyAttribute>(NONE);
+ return static_cast<PropertyAttribute>(result);
+}
+
+
Local<Value> v8::Object::GetPrototype() {
i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
ON_BAILOUT(isolate, "v8::Object::GetPrototype()",
diff --git a/src/arm/assembler-arm.cc b/src/arm/assembler-arm.cc
index efa252d..89df079 100644
--- a/src/arm/assembler-arm.cc
+++ b/src/arm/assembler-arm.cc
@@ -326,7 +326,7 @@
no_const_pool_before_ = 0;
first_const_pool_use_ = -1;
last_bound_pos_ = 0;
- ast_id_for_reloc_info_ = kNoASTId;
+ ClearRecordedAstId();
}
@@ -2537,9 +2537,8 @@
}
ASSERT(buffer_space() >= kMaxRelocSize); // too late to grow buffer here
if (rmode == RelocInfo::CODE_TARGET_WITH_ID) {
- ASSERT(ast_id_for_reloc_info_ != kNoASTId);
- RelocInfo reloc_info_with_ast_id(pc_, rmode, ast_id_for_reloc_info_);
- ast_id_for_reloc_info_ = kNoASTId;
+ RelocInfo reloc_info_with_ast_id(pc_, rmode, RecordedAstId());
+ ClearRecordedAstId();
reloc_info_writer.Write(&reloc_info_with_ast_id);
} else {
reloc_info_writer.Write(&rinfo);
diff --git a/src/arm/assembler-arm.h b/src/arm/assembler-arm.h
index fbf610a..97d4226 100644
--- a/src/arm/assembler-arm.h
+++ b/src/arm/assembler-arm.h
@@ -1178,7 +1178,17 @@
// Record the AST id of the CallIC being compiled, so that it can be placed
// in the relocation information.
- void RecordAstId(unsigned ast_id) { ast_id_for_reloc_info_ = ast_id; }
+ void SetRecordedAstId(unsigned ast_id) {
+ ASSERT(recorded_ast_id_ == kNoASTId);
+ recorded_ast_id_ = ast_id;
+ }
+
+ unsigned RecordedAstId() {
+ ASSERT(recorded_ast_id_ != kNoASTId);
+ return recorded_ast_id_;
+ }
+
+ void ClearRecordedAstId() { recorded_ast_id_ = kNoASTId; }
// Record a comment relocation entry that can be used by a disassembler.
// Use --code-comments to enable.
@@ -1244,7 +1254,7 @@
// Relocation for a type-recording IC has the AST id added to it. This
// member variable is a way to pass the information from the call site to
// the relocation info.
- unsigned ast_id_for_reloc_info_;
+ unsigned recorded_ast_id_;
bool emit_debug_code() const { return emit_debug_code_; }
diff --git a/src/arm/code-stubs-arm.cc b/src/arm/code-stubs-arm.cc
index ab7c6f2..eaad9f2 100644
--- a/src/arm/code-stubs-arm.cc
+++ b/src/arm/code-stubs-arm.cc
@@ -4722,6 +4722,7 @@
__ mov(r0, Operand(argc_)); // Setup the number of arguments.
__ mov(r2, Operand(0, RelocInfo::NONE));
__ GetBuiltinEntry(r3, Builtins::CALL_NON_FUNCTION);
+ __ SetCallKind(r5, CALL_AS_METHOD);
__ Jump(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(),
RelocInfo::CODE_TARGET);
}
diff --git a/src/arm/lithium-arm.cc b/src/arm/lithium-arm.cc
index 22e7e41..ea06064 100644
--- a/src/arm/lithium-arm.cc
+++ b/src/arm/lithium-arm.cc
@@ -372,6 +372,15 @@
}
+void LStoreKeyedFastDoubleElement::PrintDataTo(StringStream* stream) {
+ elements()->PrintTo(stream);
+ stream->Add("[");
+ key()->PrintTo(stream);
+ stream->Add("] <- ");
+ value()->PrintTo(stream);
+}
+
+
void LStoreKeyedGeneric::PrintDataTo(StringStream* stream) {
object()->PrintTo(stream);
stream->Add("[");
@@ -1844,6 +1853,18 @@
}
+LInstruction* LChunkBuilder::DoLoadKeyedFastDoubleElement(
+ HLoadKeyedFastDoubleElement* instr) {
+ ASSERT(instr->representation().IsDouble());
+ ASSERT(instr->key()->representation().IsInteger32());
+ LOperand* elements = UseTempRegister(instr->elements());
+ LOperand* key = UseRegisterOrConstantAtStart(instr->key());
+ LLoadKeyedFastDoubleElement* result =
+ new LLoadKeyedFastDoubleElement(elements, key);
+ return AssignEnvironment(DefineAsRegister(result));
+}
+
+
LInstruction* LChunkBuilder::DoLoadKeyedSpecializedArrayElement(
HLoadKeyedSpecializedArrayElement* instr) {
JSObject::ElementsKind elements_kind = instr->elements_kind();
@@ -1897,6 +1918,20 @@
}
+LInstruction* LChunkBuilder::DoStoreKeyedFastDoubleElement(
+ HStoreKeyedFastDoubleElement* instr) {
+ ASSERT(instr->value()->representation().IsDouble());
+ ASSERT(instr->elements()->representation().IsTagged());
+ ASSERT(instr->key()->representation().IsInteger32());
+
+ LOperand* elements = UseRegisterAtStart(instr->elements());
+ LOperand* val = UseTempRegister(instr->value());
+ LOperand* key = UseRegisterOrConstantAtStart(instr->key());
+
+ return new LStoreKeyedFastDoubleElement(elements, key, val);
+}
+
+
LInstruction* LChunkBuilder::DoStoreKeyedSpecializedArrayElement(
HStoreKeyedSpecializedArrayElement* instr) {
Representation representation(instr->value()->representation());
diff --git a/src/arm/lithium-arm.h b/src/arm/lithium-arm.h
index ebeba86..70c348d 100644
--- a/src/arm/lithium-arm.h
+++ b/src/arm/lithium-arm.h
@@ -121,6 +121,7 @@
V(LoadFunctionPrototype) \
V(LoadGlobalCell) \
V(LoadGlobalGeneric) \
+ V(LoadKeyedFastDoubleElement) \
V(LoadKeyedFastElement) \
V(LoadKeyedGeneric) \
V(LoadKeyedSpecializedArrayElement) \
@@ -147,6 +148,7 @@
V(StoreContextSlot) \
V(StoreGlobalCell) \
V(StoreGlobalGeneric) \
+ V(StoreKeyedFastDoubleElement) \
V(StoreKeyedFastElement) \
V(StoreKeyedGeneric) \
V(StoreKeyedSpecializedArrayElement) \
@@ -1137,6 +1139,22 @@
};
+class LLoadKeyedFastDoubleElement: public LTemplateInstruction<1, 2, 0> {
+ public:
+ LLoadKeyedFastDoubleElement(LOperand* elements, LOperand* key) {
+ inputs_[0] = elements;
+ inputs_[1] = key;
+ }
+
+ DECLARE_CONCRETE_INSTRUCTION(LoadKeyedFastDoubleElement,
+ "load-keyed-fast-double-element")
+ DECLARE_HYDROGEN_ACCESSOR(LoadKeyedFastDoubleElement)
+
+ LOperand* elements() { return inputs_[0]; }
+ LOperand* key() { return inputs_[1]; }
+};
+
+
class LLoadKeyedSpecializedArrayElement: public LTemplateInstruction<1, 2, 0> {
public:
LLoadKeyedSpecializedArrayElement(LOperand* external_pointer,
@@ -1597,6 +1615,28 @@
};
+class LStoreKeyedFastDoubleElement: public LTemplateInstruction<0, 3, 0> {
+ public:
+ LStoreKeyedFastDoubleElement(LOperand* elements,
+ LOperand* key,
+ LOperand* val) {
+ inputs_[0] = elements;
+ inputs_[1] = key;
+ inputs_[2] = val;
+ }
+
+ DECLARE_CONCRETE_INSTRUCTION(StoreKeyedFastDoubleElement,
+ "store-keyed-fast-double-element")
+ DECLARE_HYDROGEN_ACCESSOR(StoreKeyedFastDoubleElement)
+
+ virtual void PrintDataTo(StringStream* stream);
+
+ LOperand* elements() { return inputs_[0]; }
+ LOperand* key() { return inputs_[1]; }
+ LOperand* value() { return inputs_[2]; }
+};
+
+
class LStoreKeyedGeneric: public LTemplateInstruction<0, 3, 0> {
public:
LStoreKeyedGeneric(LOperand* obj, LOperand* key, LOperand* val) {
diff --git a/src/arm/lithium-codegen-arm.cc b/src/arm/lithium-codegen-arm.cc
index dc93aea..e4a14af 100644
--- a/src/arm/lithium-codegen-arm.cc
+++ b/src/arm/lithium-codegen-arm.cc
@@ -2433,6 +2433,48 @@
}
+void LCodeGen::DoLoadKeyedFastDoubleElement(
+ LLoadKeyedFastDoubleElement* instr) {
+ Register elements = ToRegister(instr->elements());
+ bool key_is_constant = instr->key()->IsConstantOperand();
+ Register key = no_reg;
+ DwVfpRegister result = ToDoubleRegister(instr->result());
+ Register scratch = scratch0();
+
+ int shift_size =
+ ElementsKindToShiftSize(JSObject::FAST_DOUBLE_ELEMENTS);
+ int constant_key = 0;
+ if (key_is_constant) {
+ constant_key = ToInteger32(LConstantOperand::cast(instr->key()));
+ if (constant_key & 0xF0000000) {
+ Abort("array index constant value too big.");
+ }
+ } else {
+ key = ToRegister(instr->key());
+ }
+
+ Operand operand = key_is_constant
+ ? Operand(constant_key * (1 << shift_size) +
+ FixedDoubleArray::kHeaderSize - kHeapObjectTag)
+ : Operand(key, LSL, shift_size);
+ __ add(elements, elements, operand);
+ if (!key_is_constant) {
+ __ add(elements, elements,
+ Operand(FixedDoubleArray::kHeaderSize - kHeapObjectTag));
+ }
+
+ if (instr->hydrogen()->RequiresHoleCheck()) {
+ // TODO(danno): If no hole check is required, there is no need to allocate
+ // elements into a temporary register, instead scratch can be used.
+ __ ldr(scratch, MemOperand(elements, sizeof(kHoleNanLower32)));
+ __ cmp(scratch, Operand(kHoleNanUpper32));
+ DeoptimizeIf(eq, instr->environment());
+ }
+
+ __ vldr(result, elements, 0);
+}
+
+
void LCodeGen::DoLoadKeyedSpecializedArrayElement(
LLoadKeyedSpecializedArrayElement* instr) {
Register external_pointer = ToRegister(instr->external_pointer());
@@ -2453,9 +2495,10 @@
if (elements_kind == JSObject::EXTERNAL_FLOAT_ELEMENTS ||
elements_kind == JSObject::EXTERNAL_DOUBLE_ELEMENTS) {
CpuFeatures::Scope scope(VFP3);
- DwVfpRegister result(ToDoubleRegister(instr->result()));
- Operand operand(key_is_constant ? Operand(constant_key * (1 << shift_size))
- : Operand(key, LSL, shift_size));
+ DwVfpRegister result = ToDoubleRegister(instr->result());
+ Operand operand = key_is_constant
+ ? Operand(constant_key * (1 << shift_size))
+ : Operand(key, LSL, shift_size);
__ add(scratch0(), external_pointer, operand);
if (elements_kind == JSObject::EXTERNAL_FLOAT_ELEMENTS) {
__ vldr(result.low(), scratch0(), 0);
@@ -2464,7 +2507,7 @@
__ vldr(result, scratch0(), 0);
}
} else {
- Register result(ToRegister(instr->result()));
+ Register result = ToRegister(instr->result());
MemOperand mem_operand(key_is_constant
? MemOperand(external_pointer, constant_key * (1 << shift_size))
: MemOperand(external_pointer, key, LSL, shift_size));
@@ -3243,6 +3286,48 @@
}
+void LCodeGen::DoStoreKeyedFastDoubleElement(
+ LStoreKeyedFastDoubleElement* instr) {
+ DwVfpRegister value = ToDoubleRegister(instr->value());
+ Register elements = ToRegister(instr->elements());
+ Register key = no_reg;
+ Register scratch = scratch0();
+ bool key_is_constant = instr->key()->IsConstantOperand();
+ int constant_key = 0;
+ Label not_nan;
+
+ // Calculate the effective address of the slot in the array to store the
+ // double value.
+ if (key_is_constant) {
+ constant_key = ToInteger32(LConstantOperand::cast(instr->key()));
+ if (constant_key & 0xF0000000) {
+ Abort("array index constant value too big.");
+ }
+ } else {
+ key = ToRegister(instr->key());
+ }
+ int shift_size = ElementsKindToShiftSize(JSObject::FAST_DOUBLE_ELEMENTS);
+ Operand operand = key_is_constant
+ ? Operand(constant_key * (1 << shift_size) +
+ FixedDoubleArray::kHeaderSize - kHeapObjectTag)
+ : Operand(key, LSL, shift_size);
+ __ add(scratch, elements, operand);
+ if (!key_is_constant) {
+ __ add(scratch, scratch,
+ Operand(FixedDoubleArray::kHeaderSize - kHeapObjectTag));
+ }
+
+ // Check for NaN. All NaNs must be canonicalized.
+ __ VFPCompareAndSetFlags(value, value);
+
+ // Only load canonical NaN if the comparison above set the overflow.
+ __ Vmov(value, FixedDoubleArray::canonical_not_the_hole_nan_as_double(), vs);
+
+ __ bind(¬_nan);
+ __ vstr(value, scratch, 0);
+}
+
+
void LCodeGen::DoStoreKeyedSpecializedArrayElement(
LStoreKeyedSpecializedArrayElement* instr) {
diff --git a/src/arm/macro-assembler-arm.cc b/src/arm/macro-assembler-arm.cc
index 1a995e9..c34a579 100644
--- a/src/arm/macro-assembler-arm.cc
+++ b/src/arm/macro-assembler-arm.cc
@@ -192,13 +192,13 @@
bind(&start);
ASSERT(RelocInfo::IsCodeTarget(rmode));
if (rmode == RelocInfo::CODE_TARGET && ast_id != kNoASTId) {
- ASSERT(ast_id_for_reloc_info_ == kNoASTId);
- ast_id_for_reloc_info_ = ast_id;
+ SetRecordedAstId(ast_id);
rmode = RelocInfo::CODE_TARGET_WITH_ID;
}
// 'code' is always generated ARM code, never THUMB code
Call(reinterpret_cast<Address>(code.location()), rmode, cond);
- ASSERT_EQ(CallSize(code, rmode, cond), SizeOfCodeGeneratedSince(&start));
+ ASSERT_EQ(CallSize(code, rmode, ast_id, cond),
+ SizeOfCodeGeneratedSince(&start));
}
@@ -1862,7 +1862,7 @@
void MacroAssembler::CallStub(CodeStub* stub, Condition cond) {
ASSERT(allow_stub_calls()); // Stub calls are not allowed in some stubs.
- Call(stub->GetCode(), RelocInfo::CODE_TARGET, cond);
+ Call(stub->GetCode(), RelocInfo::CODE_TARGET, kNoASTId, cond);
}
@@ -1872,7 +1872,8 @@
{ MaybeObject* maybe_result = stub->TryGetCode();
if (!maybe_result->ToObject(&result)) return maybe_result;
}
- Call(Handle<Code>(Code::cast(result)), RelocInfo::CODE_TARGET, cond);
+ Handle<Code> code(Code::cast(result));
+ Call(code, RelocInfo::CODE_TARGET, kNoASTId, cond);
return result;
}
diff --git a/src/ast-inl.h b/src/ast-inl.h
index c2bd613..c750e6b 100644
--- a/src/ast-inl.h
+++ b/src/ast-inl.h
@@ -37,68 +37,76 @@
namespace internal {
-SwitchStatement::SwitchStatement(ZoneStringList* labels)
- : BreakableStatement(labels, TARGET_FOR_ANONYMOUS),
+SwitchStatement::SwitchStatement(Isolate* isolate,
+ ZoneStringList* labels)
+ : BreakableStatement(isolate, labels, TARGET_FOR_ANONYMOUS),
tag_(NULL), cases_(NULL) {
}
-Block::Block(ZoneStringList* labels, int capacity, bool is_initializer_block)
- : BreakableStatement(labels, TARGET_FOR_NAMED_ONLY),
+Block::Block(Isolate* isolate,
+ ZoneStringList* labels,
+ int capacity,
+ bool is_initializer_block)
+ : BreakableStatement(isolate, labels, TARGET_FOR_NAMED_ONLY),
statements_(capacity),
is_initializer_block_(is_initializer_block) {
}
-BreakableStatement::BreakableStatement(ZoneStringList* labels, Type type)
+BreakableStatement::BreakableStatement(Isolate* isolate,
+ ZoneStringList* labels,
+ Type type)
: labels_(labels),
type_(type),
- entry_id_(GetNextId()),
- exit_id_(GetNextId()) {
+ entry_id_(GetNextId(isolate)),
+ exit_id_(GetNextId(isolate)) {
ASSERT(labels == NULL || labels->length() > 0);
}
-IterationStatement::IterationStatement(ZoneStringList* labels)
- : BreakableStatement(labels, TARGET_FOR_ANONYMOUS),
+IterationStatement::IterationStatement(Isolate* isolate, ZoneStringList* labels)
+ : BreakableStatement(isolate, labels, TARGET_FOR_ANONYMOUS),
body_(NULL),
continue_target_(),
- osr_entry_id_(GetNextId()) {
+ osr_entry_id_(GetNextId(isolate)) {
}
-DoWhileStatement::DoWhileStatement(ZoneStringList* labels)
- : IterationStatement(labels),
+DoWhileStatement::DoWhileStatement(Isolate* isolate, ZoneStringList* labels)
+ : IterationStatement(isolate, labels),
cond_(NULL),
condition_position_(-1),
- continue_id_(GetNextId()),
- back_edge_id_(GetNextId()) {
+ continue_id_(GetNextId(isolate)),
+ back_edge_id_(GetNextId(isolate)) {
}
-WhileStatement::WhileStatement(ZoneStringList* labels)
- : IterationStatement(labels),
+WhileStatement::WhileStatement(Isolate* isolate, ZoneStringList* labels)
+ : IterationStatement(isolate, labels),
cond_(NULL),
may_have_function_literal_(true),
- body_id_(GetNextId()) {
+ body_id_(GetNextId(isolate)) {
}
-ForStatement::ForStatement(ZoneStringList* labels)
- : IterationStatement(labels),
+ForStatement::ForStatement(Isolate* isolate, ZoneStringList* labels)
+ : IterationStatement(isolate, labels),
init_(NULL),
cond_(NULL),
next_(NULL),
may_have_function_literal_(true),
loop_variable_(NULL),
- continue_id_(GetNextId()),
- body_id_(GetNextId()) {
+ continue_id_(GetNextId(isolate)),
+ body_id_(GetNextId(isolate)) {
}
-ForInStatement::ForInStatement(ZoneStringList* labels)
- : IterationStatement(labels), each_(NULL), enumerable_(NULL),
- assignment_id_(GetNextId()) {
+ForInStatement::ForInStatement(Isolate* isolate, ZoneStringList* labels)
+ : IterationStatement(isolate, labels),
+ each_(NULL),
+ enumerable_(NULL),
+ assignment_id_(GetNextId(isolate)) {
}
diff --git a/src/ast.cc b/src/ast.cc
index 9f8a6ee..2df62ee 100644
--- a/src/ast.cc
+++ b/src/ast.cc
@@ -37,11 +37,11 @@
namespace internal {
AstSentinels::AstSentinels()
- : this_proxy_(true),
- identifier_proxy_(false),
- valid_left_hand_side_sentinel_(),
- this_property_(&this_proxy_, NULL, 0),
- call_sentinel_(NULL, NULL, 0) {
+ : this_proxy_(Isolate::Current(), true),
+ identifier_proxy_(Isolate::Current(), false),
+ valid_left_hand_side_sentinel_(Isolate::Current()),
+ this_property_(Isolate::Current(), &this_proxy_, NULL, 0),
+ call_sentinel_(Isolate::Current(), NULL, NULL, 0) {
}
@@ -72,8 +72,9 @@
}
-VariableProxy::VariableProxy(Variable* var)
- : name_(var->name()),
+VariableProxy::VariableProxy(Isolate* isolate, Variable* var)
+ : Expression(isolate),
+ name_(var->name()),
var_(NULL), // Will be set by the call to BindTo.
is_this_(var->is_this()),
inside_with_(false),
@@ -83,26 +84,29 @@
}
-VariableProxy::VariableProxy(Handle<String> name,
+VariableProxy::VariableProxy(Isolate* isolate,
+ Handle<String> name,
bool is_this,
bool inside_with,
int position)
- : name_(name),
- var_(NULL),
- is_this_(is_this),
- inside_with_(inside_with),
- is_trivial_(false),
- position_(position) {
+ : Expression(isolate),
+ name_(name),
+ var_(NULL),
+ is_this_(is_this),
+ inside_with_(inside_with),
+ is_trivial_(false),
+ position_(position) {
// Names must be canonicalized for fast equality checks.
ASSERT(name->IsSymbol());
}
-VariableProxy::VariableProxy(bool is_this)
- : var_(NULL),
- is_this_(is_this),
- inside_with_(false),
- is_trivial_(false) {
+VariableProxy::VariableProxy(Isolate* isolate, bool is_this)
+ : Expression(isolate),
+ var_(NULL),
+ is_this_(is_this),
+ inside_with_(false),
+ is_trivial_(false) {
}
@@ -120,17 +124,19 @@
}
-Assignment::Assignment(Token::Value op,
+Assignment::Assignment(Isolate* isolate,
+ Token::Value op,
Expression* target,
Expression* value,
int pos)
- : op_(op),
+ : Expression(isolate),
+ op_(op),
target_(target),
value_(value),
pos_(pos),
binary_operation_(NULL),
compound_load_id_(kNoNumber),
- assignment_id_(GetNextId()),
+ assignment_id_(GetNextId(isolate)),
block_start_(false),
block_end_(false),
is_monomorphic_(false),
@@ -138,8 +144,12 @@
ASSERT(Token::IsAssignmentOp(op));
if (is_compound()) {
binary_operation_ =
- new(ZONE) BinaryOperation(binary_op(), target, value, pos + 1);
- compound_load_id_ = GetNextId();
+ new(isolate->zone()) BinaryOperation(isolate,
+ binary_op(),
+ target,
+ value,
+ pos + 1);
+ compound_load_id_ = GetNextId(isolate);
}
}
@@ -186,8 +196,9 @@
ObjectLiteral::Property::Property(bool is_getter, FunctionLiteral* value) {
+ Isolate* isolate = Isolate::Current();
emit_store_ = true;
- key_ = new(ZONE) Literal(value->name());
+ key_ = new(isolate->zone()) Literal(isolate, value->name());
value_ = value;
kind_ = is_getter ? GETTER : SETTER;
}
@@ -1190,15 +1201,16 @@
}
-CaseClause::CaseClause(Expression* label,
+CaseClause::CaseClause(Isolate* isolate,
+ Expression* label,
ZoneList<Statement*>* statements,
int pos)
: label_(label),
statements_(statements),
position_(pos),
compare_type_(NONE),
- compare_id_(AstNode::GetNextId()),
- entry_id_(AstNode::GetNextId()) {
+ compare_id_(AstNode::GetNextId(isolate)),
+ entry_id_(AstNode::GetNextId(isolate)) {
}
} } // namespace v8::internal
diff --git a/src/ast.h b/src/ast.h
index b92f2db..23df48b 100644
--- a/src/ast.h
+++ b/src/ast.h
@@ -169,9 +169,11 @@
static void ResetIds() { Isolate::Current()->set_ast_node_id(0); }
protected:
- static unsigned GetNextId() { return ReserveIdRange(1); }
- static unsigned ReserveIdRange(int n) {
- Isolate* isolate = Isolate::Current();
+ static unsigned GetNextId(Isolate* isolate) {
+ return ReserveIdRange(isolate, 1);
+ }
+
+ static unsigned ReserveIdRange(Isolate* isolate, int n) {
unsigned tmp = isolate->ast_node_id();
isolate->set_ast_node_id(tmp + n);
return tmp;
@@ -219,7 +221,9 @@
kTest
};
- Expression() : id_(GetNextId()), test_id_(GetNextId()) {}
+ explicit Expression(Isolate* isolate)
+ : id_(GetNextId(isolate)),
+ test_id_(GetNextId(isolate)) {}
virtual int position() const {
UNREACHABLE();
@@ -286,6 +290,7 @@
*/
class ValidLeftHandSideSentinel: public Expression {
public:
+ explicit ValidLeftHandSideSentinel(Isolate* isolate) : Expression(isolate) {}
virtual bool IsValidLeftHandSide() { return true; }
virtual void Accept(AstVisitor* v) { UNREACHABLE(); }
virtual bool IsInlineable() const;
@@ -317,7 +322,7 @@
int ExitId() const { return exit_id_; }
protected:
- inline BreakableStatement(ZoneStringList* labels, Type type);
+ BreakableStatement(Isolate* isolate, ZoneStringList* labels, Type type);
private:
ZoneStringList* labels_;
@@ -330,7 +335,10 @@
class Block: public BreakableStatement {
public:
- inline Block(ZoneStringList* labels, int capacity, bool is_initializer_block);
+ inline Block(Isolate* isolate,
+ ZoneStringList* labels,
+ int capacity,
+ bool is_initializer_block);
DECLARE_NODE_TYPE(Block)
@@ -398,7 +406,7 @@
Label* continue_target() { return &continue_target_; }
protected:
- explicit inline IterationStatement(ZoneStringList* labels);
+ inline IterationStatement(Isolate* isolate, ZoneStringList* labels);
void Initialize(Statement* body) {
body_ = body;
@@ -413,7 +421,7 @@
class DoWhileStatement: public IterationStatement {
public:
- explicit inline DoWhileStatement(ZoneStringList* labels);
+ inline DoWhileStatement(Isolate* isolate, ZoneStringList* labels);
DECLARE_NODE_TYPE(DoWhileStatement)
@@ -446,7 +454,7 @@
class WhileStatement: public IterationStatement {
public:
- explicit inline WhileStatement(ZoneStringList* labels);
+ inline WhileStatement(Isolate* isolate, ZoneStringList* labels);
DECLARE_NODE_TYPE(WhileStatement)
@@ -479,7 +487,7 @@
class ForStatement: public IterationStatement {
public:
- explicit inline ForStatement(ZoneStringList* labels);
+ inline ForStatement(Isolate* isolate, ZoneStringList* labels);
DECLARE_NODE_TYPE(ForStatement)
@@ -528,7 +536,7 @@
class ForInStatement: public IterationStatement {
public:
- explicit inline ForInStatement(ZoneStringList* labels);
+ inline ForInStatement(Isolate* isolate, ZoneStringList* labels);
DECLARE_NODE_TYPE(ForInStatement)
@@ -645,7 +653,10 @@
class CaseClause: public ZoneObject {
public:
- CaseClause(Expression* label, ZoneList<Statement*>* statements, int pos);
+ CaseClause(Isolate* isolate,
+ Expression* label,
+ ZoneList<Statement*>* statements,
+ int pos);
bool is_default() const { return label_ == NULL; }
Expression* label() const {
@@ -680,7 +691,7 @@
class SwitchStatement: public BreakableStatement {
public:
- explicit inline SwitchStatement(ZoneStringList* labels);
+ inline SwitchStatement(Isolate* isolate, ZoneStringList* labels);
DECLARE_NODE_TYPE(SwitchStatement)
@@ -706,15 +717,16 @@
// given if-statement has a then- or an else-part containing code.
class IfStatement: public Statement {
public:
- IfStatement(Expression* condition,
+ IfStatement(Isolate* isolate,
+ Expression* condition,
Statement* then_statement,
Statement* else_statement)
: condition_(condition),
then_statement_(then_statement),
else_statement_(else_statement),
- if_id_(GetNextId()),
- then_id_(GetNextId()),
- else_id_(GetNextId()) {
+ if_id_(GetNextId(isolate)),
+ then_id_(GetNextId(isolate)),
+ else_id_(GetNextId(isolate)) {
}
DECLARE_NODE_TYPE(IfStatement)
@@ -843,7 +855,8 @@
class Literal: public Expression {
public:
- explicit Literal(Handle<Object> handle) : handle_(handle) { }
+ Literal(Isolate* isolate, Handle<Object> handle)
+ : Expression(isolate), handle_(handle) { }
DECLARE_NODE_TYPE(Literal)
@@ -896,8 +909,14 @@
// Base class for literals that needs space in the corresponding JSFunction.
class MaterializedLiteral: public Expression {
public:
- explicit MaterializedLiteral(int literal_index, bool is_simple, int depth)
- : literal_index_(literal_index), is_simple_(is_simple), depth_(depth) {}
+ MaterializedLiteral(Isolate* isolate,
+ int literal_index,
+ bool is_simple,
+ int depth)
+ : Expression(isolate),
+ literal_index_(literal_index),
+ is_simple_(is_simple),
+ depth_(depth) {}
virtual MaterializedLiteral* AsMaterializedLiteral() { return this; }
@@ -953,14 +972,15 @@
bool emit_store_;
};
- ObjectLiteral(Handle<FixedArray> constant_properties,
+ ObjectLiteral(Isolate* isolate,
+ Handle<FixedArray> constant_properties,
ZoneList<Property*>* properties,
int literal_index,
bool is_simple,
bool fast_elements,
int depth,
bool has_function)
- : MaterializedLiteral(literal_index, is_simple, depth),
+ : MaterializedLiteral(isolate, literal_index, is_simple, depth),
constant_properties_(constant_properties),
properties_(properties),
fast_elements_(fast_elements),
@@ -999,10 +1019,11 @@
// Node for capturing a regexp literal.
class RegExpLiteral: public MaterializedLiteral {
public:
- RegExpLiteral(Handle<String> pattern,
+ RegExpLiteral(Isolate* isolate,
+ Handle<String> pattern,
Handle<String> flags,
int literal_index)
- : MaterializedLiteral(literal_index, false, 1),
+ : MaterializedLiteral(isolate, literal_index, false, 1),
pattern_(pattern),
flags_(flags) {}
@@ -1020,15 +1041,16 @@
// for minimizing the work when constructing it at runtime.
class ArrayLiteral: public MaterializedLiteral {
public:
- ArrayLiteral(Handle<FixedArray> constant_elements,
+ ArrayLiteral(Isolate* isolate,
+ Handle<FixedArray> constant_elements,
ZoneList<Expression*>* values,
int literal_index,
bool is_simple,
int depth)
- : MaterializedLiteral(literal_index, is_simple, depth),
+ : MaterializedLiteral(isolate, literal_index, is_simple, depth),
constant_elements_(constant_elements),
values_(values),
- first_element_id_(ReserveIdRange(values->length())) {}
+ first_element_id_(ReserveIdRange(isolate, values->length())) {}
DECLARE_NODE_TYPE(ArrayLiteral)
@@ -1047,7 +1069,7 @@
class VariableProxy: public Expression {
public:
- explicit VariableProxy(Variable* var);
+ VariableProxy(Isolate* isolate, Variable* var);
DECLARE_NODE_TYPE(VariableProxy)
@@ -1094,11 +1116,12 @@
bool is_trivial_;
int position_;
- VariableProxy(Handle<String> name,
+ VariableProxy(Isolate* isolate,
+ Handle<String> name,
bool is_this,
bool inside_with,
int position = RelocInfo::kNoPosition);
- explicit VariableProxy(bool is_this);
+ VariableProxy(Isolate* isolate, bool is_this);
friend class Scope;
};
@@ -1109,7 +1132,8 @@
virtual bool IsValidLeftHandSide() { return !is_this(); }
private:
- explicit VariableProxySentinel(bool is_this) : VariableProxy(is_this) { }
+ VariableProxySentinel(Isolate* isolate, bool is_this)
+ : VariableProxy(isolate, is_this) { }
friend class AstSentinels;
};
@@ -1139,8 +1163,8 @@
LOOKUP
};
- Slot(Variable* var, Type type, int index)
- : var_(var), type_(type), index_(index) {
+ Slot(Isolate* isolate, Variable* var, Type type, int index)
+ : Expression(isolate), var_(var), type_(type), index_(index) {
ASSERT(var != NULL);
}
@@ -1171,8 +1195,13 @@
// properties should use the global object as receiver, not the base object
// of the resolved Reference.
enum Type { NORMAL, SYNTHETIC };
- Property(Expression* obj, Expression* key, int pos, Type type = NORMAL)
- : obj_(obj),
+ Property(Isolate* isolate,
+ Expression* obj,
+ Expression* key,
+ int pos,
+ Type type = NORMAL)
+ : Expression(isolate),
+ obj_(obj),
key_(key),
pos_(pos),
type_(type),
@@ -1224,14 +1253,18 @@
class Call: public Expression {
public:
- Call(Expression* expression, ZoneList<Expression*>* arguments, int pos)
- : expression_(expression),
+ Call(Isolate* isolate,
+ Expression* expression,
+ ZoneList<Expression*>* arguments,
+ int pos)
+ : Expression(isolate),
+ expression_(expression),
arguments_(arguments),
pos_(pos),
is_monomorphic_(false),
check_type_(RECEIVER_MAP_CHECK),
receiver_types_(NULL),
- return_id_(GetNextId()) {
+ return_id_(GetNextId(isolate)) {
}
DECLARE_NODE_TYPE(Call)
@@ -1310,8 +1343,14 @@
class CallNew: public Expression {
public:
- CallNew(Expression* expression, ZoneList<Expression*>* arguments, int pos)
- : expression_(expression), arguments_(arguments), pos_(pos) { }
+ CallNew(Isolate* isolate,
+ Expression* expression,
+ ZoneList<Expression*>* arguments,
+ int pos)
+ : Expression(isolate),
+ expression_(expression),
+ arguments_(arguments),
+ pos_(pos) { }
DECLARE_NODE_TYPE(CallNew)
@@ -1334,10 +1373,14 @@
// implemented in JavaScript (see "v8natives.js").
class CallRuntime: public Expression {
public:
- CallRuntime(Handle<String> name,
+ CallRuntime(Isolate* isolate,
+ Handle<String> name,
const Runtime::Function* function,
ZoneList<Expression*>* arguments)
- : name_(name), function_(function), arguments_(arguments) { }
+ : Expression(isolate),
+ name_(name),
+ function_(function),
+ arguments_(arguments) { }
DECLARE_NODE_TYPE(CallRuntime)
@@ -1357,8 +1400,11 @@
class UnaryOperation: public Expression {
public:
- UnaryOperation(Token::Value op, Expression* expression, int pos)
- : op_(op), expression_(expression), pos_(pos) {
+ UnaryOperation(Isolate* isolate,
+ Token::Value op,
+ Expression* expression,
+ int pos)
+ : Expression(isolate), op_(op), expression_(expression), pos_(pos) {
ASSERT(Token::IsUnaryOp(op));
}
@@ -1381,14 +1427,15 @@
class BinaryOperation: public Expression {
public:
- BinaryOperation(Token::Value op,
+ BinaryOperation(Isolate* isolate,
+ Token::Value op,
Expression* left,
Expression* right,
int pos)
- : op_(op), left_(left), right_(right), pos_(pos) {
+ : Expression(isolate), op_(op), left_(left), right_(right), pos_(pos) {
ASSERT(Token::IsBinaryOp(op));
right_id_ = (op == Token::AND || op == Token::OR)
- ? static_cast<int>(GetNextId())
+ ? static_cast<int>(GetNextId(isolate))
: AstNode::kNoNumber;
}
@@ -1419,13 +1466,18 @@
class CountOperation: public Expression {
public:
- CountOperation(Token::Value op, bool is_prefix, Expression* expr, int pos)
- : op_(op),
+ CountOperation(Isolate* isolate,
+ Token::Value op,
+ bool is_prefix,
+ Expression* expr,
+ int pos)
+ : Expression(isolate),
+ op_(op),
is_prefix_(is_prefix),
expression_(expr),
pos_(pos),
- assignment_id_(GetNextId()),
- count_id_(GetNextId()),
+ assignment_id_(GetNextId(isolate)),
+ count_id_(GetNextId(isolate)),
receiver_types_(NULL) { }
DECLARE_NODE_TYPE(CountOperation)
@@ -1471,11 +1523,17 @@
class CompareOperation: public Expression {
public:
- CompareOperation(Token::Value op,
+ CompareOperation(Isolate* isolate,
+ Token::Value op,
Expression* left,
Expression* right,
int pos)
- : op_(op), left_(left), right_(right), pos_(pos), compare_type_(NONE) {
+ : Expression(isolate),
+ op_(op),
+ left_(left),
+ right_(right),
+ pos_(pos),
+ compare_type_(NONE) {
ASSERT(Token::IsCompareOp(op));
}
@@ -1510,8 +1568,8 @@
class CompareToNull: public Expression {
public:
- CompareToNull(bool is_strict, Expression* expression)
- : is_strict_(is_strict), expression_(expression) { }
+ CompareToNull(Isolate* isolate, bool is_strict, Expression* expression)
+ : Expression(isolate), is_strict_(is_strict), expression_(expression) { }
DECLARE_NODE_TYPE(CompareToNull)
@@ -1529,18 +1587,20 @@
class Conditional: public Expression {
public:
- Conditional(Expression* condition,
+ Conditional(Isolate* isolate,
+ Expression* condition,
Expression* then_expression,
Expression* else_expression,
int then_expression_position,
int else_expression_position)
- : condition_(condition),
+ : Expression(isolate),
+ condition_(condition),
then_expression_(then_expression),
else_expression_(else_expression),
then_expression_position_(then_expression_position),
else_expression_position_(else_expression_position),
- then_id_(GetNextId()),
- else_id_(GetNextId()) {
+ then_id_(GetNextId(isolate)),
+ else_id_(GetNextId(isolate)) {
}
DECLARE_NODE_TYPE(Conditional)
@@ -1570,7 +1630,11 @@
class Assignment: public Expression {
public:
- Assignment(Token::Value op, Expression* target, Expression* value, int pos);
+ Assignment(Isolate* isolate,
+ Token::Value op,
+ Expression* target,
+ Expression* value,
+ int pos);
DECLARE_NODE_TYPE(Assignment)
@@ -1630,8 +1694,8 @@
class Throw: public Expression {
public:
- Throw(Expression* exception, int pos)
- : exception_(exception), pos_(pos) {}
+ Throw(Isolate* isolate, Expression* exception, int pos)
+ : Expression(isolate), exception_(exception), pos_(pos) {}
DECLARE_NODE_TYPE(Throw)
@@ -1647,7 +1711,8 @@
class FunctionLiteral: public Expression {
public:
- FunctionLiteral(Handle<String> name,
+ FunctionLiteral(Isolate* isolate,
+ Handle<String> name,
Scope* scope,
ZoneList<Statement*>* body,
int materialized_literal_count,
@@ -1659,7 +1724,8 @@
int end_position,
bool is_expression,
bool has_duplicate_parameters)
- : name_(name),
+ : Expression(isolate),
+ name_(name),
scope_(scope),
body_(body),
materialized_literal_count_(materialized_literal_count),
@@ -1738,9 +1804,10 @@
class SharedFunctionInfoLiteral: public Expression {
public:
- explicit SharedFunctionInfoLiteral(
+ SharedFunctionInfoLiteral(
+ Isolate* isolate,
Handle<SharedFunctionInfo> shared_function_info)
- : shared_function_info_(shared_function_info) { }
+ : Expression(isolate), shared_function_info_(shared_function_info) { }
DECLARE_NODE_TYPE(SharedFunctionInfoLiteral)
@@ -1756,6 +1823,7 @@
class ThisFunction: public Expression {
public:
+ explicit ThisFunction(Isolate* isolate) : Expression(isolate) {}
DECLARE_NODE_TYPE(ThisFunction)
virtual bool IsInlineable() const;
};
diff --git a/src/bootstrapper.cc b/src/bootstrapper.cc
index 8e34b9c..8cca561 100644
--- a/src/bootstrapper.cc
+++ b/src/bootstrapper.cc
@@ -1309,6 +1309,7 @@
void Genesis::InstallExperimentalNativeFunctions() {
if (FLAG_harmony_proxies) {
+ INSTALL_NATIVE(JSFunction, "DerivedHasTrap", derived_has_trap);
INSTALL_NATIVE(JSFunction, "DerivedGetTrap", derived_get_trap);
INSTALL_NATIVE(JSFunction, "DerivedSetTrap", derived_set_trap);
}
diff --git a/src/builtins.cc b/src/builtins.cc
index 6a44d8c..d403a95 100644
--- a/src/builtins.cc
+++ b/src/builtins.cc
@@ -1202,10 +1202,10 @@
ASSERT(!CalledAsConstructor(isolate));
Heap* heap = isolate->heap();
- Handle<Object> receiver = args.at<Object>(0);
+ Handle<Object> receiver = args.receiver();
// Get the object called.
- JSObject* obj = JSObject::cast(*args.receiver());
+ JSObject* obj = JSObject::cast(*receiver);
// Get the invocation callback from the function descriptor that was
// used to create the called object.
diff --git a/src/compiler.cc b/src/compiler.cc
index e09b72f..c265b95 100755
--- a/src/compiler.cc
+++ b/src/compiler.cc
@@ -511,7 +511,6 @@
info.SetPreParseData(pre_data);
if (natives == NATIVES_CODE) {
info.MarkAsAllowingNativesSyntax();
- info.MarkAsNative();
}
result = MakeFunctionInfo(&info);
if (extension == NULL && !result.is_null()) {
@@ -679,7 +678,6 @@
info.SetFunction(literal);
info.SetScope(literal->scope());
if (literal->scope()->is_strict_mode()) info.MarkAsStrictMode();
- if (script->type()->value() == Script::TYPE_NATIVE) info.MarkAsNative();
LiveEditFunctionTracker live_edit_tracker(info.isolate(), literal);
// Determine if the function can be lazily compiled. This is necessary to
diff --git a/src/compiler.h b/src/compiler.h
index a77fc8e..8e92cf5 100644
--- a/src/compiler.h
+++ b/src/compiler.h
@@ -173,9 +173,12 @@
void Initialize(Mode mode) {
mode_ = V8::UseCrankshaft() ? mode : NONOPT;
- if (!shared_info_.is_null()) {
- if (shared_info_->strict_mode()) MarkAsStrictMode();
- if (shared_info_->native()) MarkAsNative();
+ ASSERT(!script_.is_null());
+ if (script_->type()->value() == Script::TYPE_NATIVE) {
+ MarkAsNative();
+ }
+ if (!shared_info_.is_null() && shared_info_->strict_mode()) {
+ MarkAsStrictMode();
}
}
diff --git a/src/contexts.h b/src/contexts.h
index 0f3d44c..53b40f1 100644
--- a/src/contexts.h
+++ b/src/contexts.h
@@ -110,6 +110,7 @@
V(MAP_CACHE_INDEX, Object, map_cache) \
V(CONTEXT_DATA_INDEX, Object, data) \
V(ALLOW_CODE_GEN_FROM_STRINGS_INDEX, Object, allow_code_gen_from_strings) \
+ V(DERIVED_HAS_TRAP_INDEX, JSFunction, derived_has_trap) \
V(DERIVED_GET_TRAP_INDEX, JSFunction, derived_get_trap) \
V(DERIVED_SET_TRAP_INDEX, JSFunction, derived_set_trap)
@@ -227,6 +228,7 @@
OUT_OF_MEMORY_INDEX,
CONTEXT_DATA_INDEX,
ALLOW_CODE_GEN_FROM_STRINGS_INDEX,
+ DERIVED_HAS_TRAP_INDEX,
DERIVED_GET_TRAP_INDEX,
DERIVED_SET_TRAP_INDEX,
diff --git a/src/conversions-inl.h b/src/conversions-inl.h
index f1f526f..b828638 100644
--- a/src/conversions-inl.h
+++ b/src/conversions-inl.h
@@ -454,7 +454,6 @@
int significant_digits = 0;
int insignificant_digits = 0;
bool nonzero_digit_dropped = false;
- bool fractional_part = false;
bool negative = false;
@@ -557,10 +556,8 @@
}
}
- // We don't emit a '.', but adjust the exponent instead.
- fractional_part = true;
-
- // There is a fractional part.
+ // There is a fractional part. We don't emit a '.', but adjust the exponent
+ // instead.
while (*current >= '0' && *current <= '9') {
if (significant_digits < kMaxSignificantDigits) {
ASSERT(buffer_pos < kBufferSize);
diff --git a/src/d8.cc b/src/d8.cc
index 64c0d1f..4917f7d 100644
--- a/src/d8.cc
+++ b/src/d8.cc
@@ -187,6 +187,7 @@
Handle<Value> Shell::Print(const Arguments& args) {
Handle<Value> val = Write(args);
printf("\n");
+ fflush(stdout);
return val;
}
diff --git a/src/debug.cc b/src/debug.cc
index c48e514..aecbb46 100644
--- a/src/debug.cc
+++ b/src/debug.cc
@@ -772,9 +772,9 @@
bool caught_exception = false;
Handle<JSFunction> function =
factory->NewFunctionFromSharedFunctionInfo(function_info, context);
- Handle<Object> result =
- Execution::TryCall(function, Handle<Object>(context->global()),
- 0, NULL, &caught_exception);
+
+ Execution::TryCall(function, Handle<Object>(context->global()),
+ 0, NULL, &caught_exception);
// Check for caught exceptions.
if (caught_exception) {
@@ -1886,8 +1886,7 @@
*function_name));
ASSERT(fun->IsJSFunction());
bool caught_exception;
- Handle<Object> js_object = Execution::TryCall(
- Handle<JSFunction>::cast(fun),
+ Execution::TryCall(Handle<JSFunction>::cast(fun),
Handle<JSObject>(Debug::debug_context()->global()),
0, NULL, &caught_exception);
}
@@ -2252,8 +2251,7 @@
bool caught_exception = false;
const int argc = 1;
Object** argv[argc] = { reinterpret_cast<Object**>(wrapper.location()) };
- Handle<Object> result = Execution::TryCall(
- Handle<JSFunction>::cast(update_script_break_points),
+ Execution::TryCall(Handle<JSFunction>::cast(update_script_break_points),
Isolate::Current()->js_builtins_object(), argc, argv,
&caught_exception);
if (caught_exception) {
@@ -2930,7 +2928,7 @@
v8::Handle<v8::Context> context = GetDebugEventContext(isolate);
// Isolate::context() may be NULL when "script collected" event occures.
ASSERT(!context.IsEmpty() || event_ == v8::ScriptCollected);
- return GetDebugEventContext(isolate);
+ return context;
}
diff --git a/src/deoptimizer.cc b/src/deoptimizer.cc
index 175ee6e..3a7b33a 100644
--- a/src/deoptimizer.cc
+++ b/src/deoptimizer.cc
@@ -1462,7 +1462,7 @@
}
void DeoptimizedFrameInfo::Iterate(ObjectVisitor* v) {
- v->VisitPointer(reinterpret_cast<Object**>(&function_));
+ v->VisitPointer(BitCast<Object**>(&function_));
v->VisitPointers(parameters_, parameters_ + parameters_count_);
v->VisitPointers(expression_stack_, expression_stack_ + expression_count_);
}
diff --git a/src/factory.cc b/src/factory.cc
index 9ba48ee..ac96668 100644
--- a/src/factory.cc
+++ b/src/factory.cc
@@ -892,6 +892,13 @@
}
+void Factory::BecomeJSObject(Handle<JSProxy> object) {
+ CALL_HEAP_FUNCTION_VOID(
+ isolate(),
+ isolate()->heap()->ReinitializeJSProxyAsJSObject(*object));
+}
+
+
Handle<SharedFunctionInfo> Factory::NewSharedFunctionInfo(
Handle<String> name,
int number_of_literals,
diff --git a/src/factory.h b/src/factory.h
index 19f09a1..19f3827 100644
--- a/src/factory.h
+++ b/src/factory.h
@@ -253,6 +253,9 @@
Handle<JSProxy> NewJSProxy(Handle<Object> handler, Handle<Object> prototype);
+ // Change the type of the argument into a regular JS object and reinitialize.
+ void BecomeJSObject(Handle<JSProxy> object);
+
Handle<JSFunction> NewFunction(Handle<String> name,
Handle<Object> prototype);
diff --git a/src/frames.cc b/src/frames.cc
index eaf09eb..bebd10a 100644
--- a/src/frames.cc
+++ b/src/frames.cc
@@ -371,7 +371,6 @@
unsigned* stack_slots) {
PcToCodeCache::PcToCodeCacheEntry* entry =
isolate->pc_to_code_cache()->GetCacheEntry(pc);
- SafepointEntry cached_safepoint_entry = entry->safepoint_entry;
if (!entry->safepoint_entry.is_valid()) {
entry->safepoint_entry = entry->code->GetSafepointEntry(pc);
ASSERT(entry->safepoint_entry.is_valid());
diff --git a/src/full-codegen.cc b/src/full-codegen.cc
index 0b91f54..8c2f0d1 100644
--- a/src/full-codegen.cc
+++ b/src/full-codegen.cc
@@ -686,7 +686,6 @@
void FullCodeGenerator::EmitInlineRuntimeCall(CallRuntime* node) {
ZoneList<Expression*>* args = node->arguments();
- Handle<String> name = node->name();
const Runtime::Function* function = node->function();
ASSERT(function != NULL);
ASSERT(function->intrinsic_type == Runtime::INLINE);
diff --git a/src/heap.cc b/src/heap.cc
index 98a2d33..8dbda27 100644
--- a/src/heap.cc
+++ b/src/heap.cc
@@ -3267,14 +3267,13 @@
MaybeObject* maybe_map_obj = AllocateMap(JS_PROXY_TYPE, JSProxy::kSize);
if (!maybe_map_obj->To<Map>(&map)) return maybe_map_obj;
map->set_prototype(prototype);
- map->set_pre_allocated_property_fields(1);
- map->set_inobject_properties(1);
// Allocate the proxy object.
Object* result;
MaybeObject* maybe_result = Allocate(map, NEW_SPACE);
if (!maybe_result->ToObject(&result)) return maybe_result;
JSProxy::cast(result)->set_handler(handler);
+ JSProxy::cast(result)->set_padding(Smi::FromInt(0));
return result;
}
@@ -3414,6 +3413,36 @@
}
+MaybeObject* Heap::ReinitializeJSProxyAsJSObject(JSProxy* object) {
+ // Allocate fresh map.
+ // TODO(rossberg): Once we optimize proxies, cache these maps.
+ Map* map;
+ MaybeObject* maybe_map_obj =
+ AllocateMap(JS_OBJECT_TYPE, JSObject::kHeaderSize);
+ if (!maybe_map_obj->To<Map>(&map)) return maybe_map_obj;
+
+ // Check that the receiver has the same size as a fresh object.
+ ASSERT(map->instance_size() == object->map()->instance_size());
+
+ map->set_prototype(object->map()->prototype());
+
+ // Allocate the backing storage for the properties.
+ int prop_size = map->unused_property_fields() - map->inobject_properties();
+ Object* properties;
+ { MaybeObject* maybe_properties = AllocateFixedArray(prop_size, TENURED);
+ if (!maybe_properties->ToObject(&properties)) return maybe_properties;
+ }
+
+ // Reset the map for the object.
+ object->set_map(map);
+
+ // Reinitialize the object from the constructor map.
+ InitializeJSObjectFromMap(JSObject::cast(object),
+ FixedArray::cast(properties), map);
+ return object;
+}
+
+
MaybeObject* Heap::ReinitializeJSGlobalProxy(JSFunction* constructor,
JSGlobalProxy* object) {
ASSERT(constructor->has_initial_map());
diff --git a/src/heap.h b/src/heap.h
index d90a681..6cd4f84 100644
--- a/src/heap.h
+++ b/src/heap.h
@@ -441,6 +441,11 @@
MUST_USE_RESULT MaybeObject* AllocateJSProxy(Object* handler,
Object* prototype);
+ // Reinitialize a JSProxy into an (empty) JSObject. The receiver
+ // must have the same size as an empty object. The object is reinitialized
+ // and behaves as an object that has been freshly allocated.
+ MUST_USE_RESULT MaybeObject* ReinitializeJSProxyAsJSObject(JSProxy* object);
+
// Reinitialize an JSGlobalProxy based on a constructor. The object
// must have the same size as objects allocated using the
// constructor. The object is reinitialized and behaves as an
diff --git a/src/hydrogen-instructions.cc b/src/hydrogen-instructions.cc
index 50f2f6d..d282f37 100644
--- a/src/hydrogen-instructions.cc
+++ b/src/hydrogen-instructions.cc
@@ -1366,6 +1366,19 @@
}
+void HLoadKeyedFastDoubleElement::PrintDataTo(StringStream* stream) {
+ elements()->PrintNameTo(stream);
+ stream->Add("[");
+ key()->PrintNameTo(stream);
+ stream->Add("]");
+}
+
+
+bool HLoadKeyedFastDoubleElement::RequiresHoleCheck() const {
+ return true;
+}
+
+
void HLoadKeyedGeneric::PrintDataTo(StringStream* stream) {
object()->PrintNameTo(stream);
stream->Add("[");
@@ -1451,6 +1464,15 @@
}
+void HStoreKeyedFastDoubleElement::PrintDataTo(StringStream* stream) {
+ elements()->PrintNameTo(stream);
+ stream->Add("[");
+ key()->PrintNameTo(stream);
+ stream->Add("] = ");
+ value()->PrintNameTo(stream);
+}
+
+
void HStoreKeyedGeneric::PrintDataTo(StringStream* stream) {
object()->PrintNameTo(stream);
stream->Add("[");
diff --git a/src/hydrogen-instructions.h b/src/hydrogen-instructions.h
index 93a7073..15186ff 100644
--- a/src/hydrogen-instructions.h
+++ b/src/hydrogen-instructions.h
@@ -131,6 +131,7 @@
V(LoadFunctionPrototype) \
V(LoadGlobalCell) \
V(LoadGlobalGeneric) \
+ V(LoadKeyedFastDoubleElement) \
V(LoadKeyedFastElement) \
V(LoadKeyedGeneric) \
V(LoadKeyedSpecializedArrayElement) \
@@ -156,6 +157,7 @@
V(StoreContextSlot) \
V(StoreGlobalCell) \
V(StoreGlobalGeneric) \
+ V(StoreKeyedFastDoubleElement) \
V(StoreKeyedFastElement) \
V(StoreKeyedGeneric) \
V(StoreKeyedSpecializedArrayElement) \
@@ -3519,6 +3521,37 @@
};
+class HLoadKeyedFastDoubleElement: public HTemplateInstruction<2> {
+ public:
+ HLoadKeyedFastDoubleElement(HValue* elements, HValue* key) {
+ SetOperandAt(0, elements);
+ SetOperandAt(1, key);
+ set_representation(Representation::Double());
+ SetFlag(kDependsOnArrayElements);
+ SetFlag(kUseGVN);
+ }
+
+ HValue* elements() { return OperandAt(0); }
+ HValue* key() { return OperandAt(1); }
+
+ virtual Representation RequiredInputRepresentation(int index) const {
+ // The key is supposed to be Integer32.
+ return index == 0
+ ? Representation::Tagged()
+ : Representation::Integer32();
+ }
+
+ virtual void PrintDataTo(StringStream* stream);
+
+ bool RequiresHoleCheck() const;
+
+ DECLARE_CONCRETE_INSTRUCTION(LoadKeyedFastDoubleElement)
+
+ protected:
+ virtual bool DataEquals(HValue* other) { return true; }
+};
+
+
class HLoadKeyedSpecializedArrayElement: public HTemplateInstruction<2> {
public:
HLoadKeyedSpecializedArrayElement(HValue* external_elements,
@@ -3704,6 +3737,41 @@
};
+class HStoreKeyedFastDoubleElement: public HTemplateInstruction<3> {
+ public:
+ HStoreKeyedFastDoubleElement(HValue* elements,
+ HValue* key,
+ HValue* val) {
+ SetOperandAt(0, elements);
+ SetOperandAt(1, key);
+ SetOperandAt(2, val);
+ SetFlag(kChangesArrayElements);
+ }
+
+ virtual Representation RequiredInputRepresentation(int index) const {
+ if (index == 1) {
+ return Representation::Integer32();
+ } else if (index == 2) {
+ return Representation::Double();
+ } else {
+ return Representation::Tagged();
+ }
+ }
+
+ HValue* elements() { return OperandAt(0); }
+ HValue* key() { return OperandAt(1); }
+ HValue* value() { return OperandAt(2); }
+
+ bool NeedsWriteBarrier() {
+ return StoringValueNeedsWriteBarrier(value());
+ }
+
+ virtual void PrintDataTo(StringStream* stream);
+
+ DECLARE_CONCRETE_INSTRUCTION(StoreKeyedFastDoubleElement)
+};
+
+
class HStoreKeyedSpecializedArrayElement: public HTemplateInstruction<3> {
public:
HStoreKeyedSpecializedArrayElement(HValue* external_elements,
diff --git a/src/hydrogen.cc b/src/hydrogen.cc
index 57329ba..7e62ec4 100644
--- a/src/hydrogen.cc
+++ b/src/hydrogen.cc
@@ -3901,7 +3901,9 @@
bool is_store) {
ASSERT(expr->IsMonomorphic());
Handle<Map> map = expr->GetMonomorphicReceiverType();
- if (!map->has_fast_elements() && !map->has_external_array_elements()) {
+ if (!map->has_fast_elements() &&
+ !map->has_fast_double_elements() &&
+ !map->has_external_array_elements()) {
return is_store ? BuildStoreKeyedGeneric(object, key, val)
: BuildLoadKeyedGeneric(object, key);
}
@@ -3920,18 +3922,19 @@
return BuildExternalArrayElementAccess(external_elements, checked_key,
val, map->elements_kind(), is_store);
}
- ASSERT(map->has_fast_elements());
+ bool fast_double_elements = map->has_fast_double_elements();
+ ASSERT(map->has_fast_elements() || fast_double_elements);
if (map->instance_type() == JS_ARRAY_TYPE) {
length = AddInstruction(new(zone()) HJSArrayLength(object));
checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length));
AddInstruction(elements);
- if (is_store) {
+ if (is_store && !fast_double_elements) {
AddInstruction(new(zone()) HCheckMap(
elements, isolate()->factory()->fixed_array_map()));
}
} else {
AddInstruction(elements);
- if (is_store) {
+ if (is_store && !fast_double_elements) {
AddInstruction(new(zone()) HCheckMap(
elements, isolate()->factory()->fixed_array_map()));
}
@@ -3939,9 +3942,19 @@
checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length));
}
if (is_store) {
- return new(zone()) HStoreKeyedFastElement(elements, checked_key, val);
+ if (fast_double_elements) {
+ return new(zone()) HStoreKeyedFastDoubleElement(elements,
+ checked_key,
+ val);
+ } else {
+ return new(zone()) HStoreKeyedFastElement(elements, checked_key, val);
+ }
} else {
- return new(zone()) HLoadKeyedFastElement(elements, checked_key);
+ if (fast_double_elements) {
+ return new(zone()) HLoadKeyedFastDoubleElement(elements, checked_key);
+ } else {
+ return new(zone()) HLoadKeyedFastElement(elements, checked_key);
+ }
}
}
@@ -3974,8 +3987,6 @@
todo_external_array = true;
}
}
- // Support for FAST_DOUBLE_ELEMENTS isn't implemented yet, so we deopt.
- type_todo[JSObject::FAST_DOUBLE_ELEMENTS] = false;
HBasicBlock* join = graph()->CreateBasicBlock();
@@ -4024,7 +4035,8 @@
set_current_block(if_true);
HInstruction* access;
- if (elements_kind == JSObject::FAST_ELEMENTS) {
+ if (elements_kind == JSObject::FAST_ELEMENTS ||
+ elements_kind == JSObject::FAST_DOUBLE_ELEMENTS) {
HBasicBlock* if_jsarray = graph()->CreateBasicBlock();
HBasicBlock* if_fastobject = graph()->CreateBasicBlock();
HHasInstanceTypeAndBranch* typecheck =
@@ -4040,14 +4052,28 @@
checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length));
elements = AddInstruction(new(zone()) HLoadElements(object));
elements->ClearFlag(HValue::kUseGVN);
+ bool fast_double_elements =
+ elements_kind == JSObject::FAST_DOUBLE_ELEMENTS;
if (is_store) {
- AddInstruction(new(zone()) HCheckMap(
- elements, isolate()->factory()->fixed_array_map()));
- access = AddInstruction(
- new(zone()) HStoreKeyedFastElement(elements, checked_key, val));
+ if (fast_double_elements) {
+ access = AddInstruction(
+ new(zone()) HStoreKeyedFastDoubleElement(elements,
+ checked_key,
+ val));
+ } else {
+ AddInstruction(new(zone()) HCheckMap(
+ elements, isolate()->factory()->fixed_array_map()));
+ access = AddInstruction(
+ new(zone()) HStoreKeyedFastElement(elements, checked_key, val));
+ }
} else {
- access = AddInstruction(
- new(zone()) HLoadKeyedFastElement(elements, checked_key));
+ if (fast_double_elements) {
+ access = AddInstruction(
+ new(zone()) HLoadKeyedFastDoubleElement(elements, checked_key));
+ } else {
+ access = AddInstruction(
+ new(zone()) HLoadKeyedFastElement(elements, checked_key));
+ }
Push(access);
}
*has_side_effects |= access->HasSideEffects();
@@ -4059,18 +4085,30 @@
set_current_block(if_fastobject);
elements = AddInstruction(new(zone()) HLoadElements(object));
elements->ClearFlag(HValue::kUseGVN);
- if (is_store) {
+ if (is_store && !fast_double_elements) {
AddInstruction(new(zone()) HCheckMap(
elements, isolate()->factory()->fixed_array_map()));
}
length = AddInstruction(new(zone()) HFixedArrayLength(elements));
checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length));
if (is_store) {
- access = AddInstruction(
- new(zone()) HStoreKeyedFastElement(elements, checked_key, val));
+ if (fast_double_elements) {
+ access = AddInstruction(
+ new(zone()) HStoreKeyedFastDoubleElement(elements,
+ checked_key,
+ val));
+ } else {
+ access = AddInstruction(
+ new(zone()) HStoreKeyedFastElement(elements, checked_key, val));
+ }
} else {
- access = AddInstruction(
- new(zone()) HLoadKeyedFastElement(elements, checked_key));
+ if (fast_double_elements) {
+ access = AddInstruction(
+ new(zone()) HLoadKeyedFastDoubleElement(elements, checked_key));
+ } else {
+ access = AddInstruction(
+ new(zone()) HLoadKeyedFastElement(elements, checked_key));
+ }
}
} else if (elements_kind == JSObject::DICTIONARY_ELEMENTS) {
if (is_store) {
diff --git a/src/ia32/code-stubs-ia32.cc b/src/ia32/code-stubs-ia32.cc
index 48bd8b1..71aacf9 100644
--- a/src/ia32/code-stubs-ia32.cc
+++ b/src/ia32/code-stubs-ia32.cc
@@ -4158,6 +4158,7 @@
__ GetBuiltinEntry(edx, Builtins::CALL_NON_FUNCTION);
Handle<Code> adaptor =
masm->isolate()->builtins()->ArgumentsAdaptorTrampoline();
+ __ SetCallKind(ecx, CALL_AS_METHOD);
__ jmp(adaptor, RelocInfo::CODE_TARGET);
}
diff --git a/src/ia32/lithium-codegen-ia32.cc b/src/ia32/lithium-codegen-ia32.cc
index 9532d94..7211ba4 100644
--- a/src/ia32/lithium-codegen-ia32.cc
+++ b/src/ia32/lithium-codegen-ia32.cc
@@ -2230,10 +2230,34 @@
}
-Operand LCodeGen::BuildExternalArrayOperand(
+void LCodeGen::DoLoadKeyedFastDoubleElement(
+ LLoadKeyedFastDoubleElement* instr) {
+ Register elements = ToRegister(instr->elements());
+ XMMRegister result = ToDoubleRegister(instr->result());
+
+ if (instr->hydrogen()->RequiresHoleCheck()) {
+ int offset = FixedDoubleArray::kHeaderSize - kHeapObjectTag +
+ sizeof(kHoleNanLower32);
+ Operand hole_check_operand = BuildFastArrayOperand(
+ instr->elements(), instr->key(),
+ JSObject::FAST_DOUBLE_ELEMENTS,
+ offset);
+ __ cmp(hole_check_operand, Immediate(kHoleNanUpper32));
+ DeoptimizeIf(equal, instr->environment());
+ }
+
+ Operand double_load_operand = BuildFastArrayOperand(
+ instr->elements(), instr->key(), JSObject::FAST_DOUBLE_ELEMENTS,
+ FixedDoubleArray::kHeaderSize - kHeapObjectTag);
+ __ movdbl(result, double_load_operand);
+}
+
+
+Operand LCodeGen::BuildFastArrayOperand(
LOperand* external_pointer,
LOperand* key,
- JSObject::ElementsKind elements_kind) {
+ JSObject::ElementsKind elements_kind,
+ uint32_t offset) {
Register external_pointer_reg = ToRegister(external_pointer);
int shift_size = ElementsKindToShiftSize(elements_kind);
if (key->IsConstantOperand()) {
@@ -2241,10 +2265,11 @@
if (constant_value & 0xF0000000) {
Abort("array index constant value too big");
}
- return Operand(external_pointer_reg, constant_value * (1 << shift_size));
+ return Operand(external_pointer_reg,
+ constant_value * (1 << shift_size) + offset);
} else {
ScaleFactor scale_factor = static_cast<ScaleFactor>(shift_size);
- return Operand(external_pointer_reg, ToRegister(key), scale_factor, 0);
+ return Operand(external_pointer_reg, ToRegister(key), scale_factor, offset);
}
}
@@ -2252,8 +2277,8 @@
void LCodeGen::DoLoadKeyedSpecializedArrayElement(
LLoadKeyedSpecializedArrayElement* instr) {
JSObject::ElementsKind elements_kind = instr->elements_kind();
- Operand operand(BuildExternalArrayOperand(instr->external_pointer(),
- instr->key(), elements_kind));
+ Operand operand(BuildFastArrayOperand(instr->external_pointer(),
+ instr->key(), elements_kind, 0));
if (elements_kind == JSObject::EXTERNAL_FLOAT_ELEMENTS) {
XMMRegister result(ToDoubleRegister(instr->result()));
__ movss(result, operand);
@@ -3001,8 +3026,8 @@
void LCodeGen::DoStoreKeyedSpecializedArrayElement(
LStoreKeyedSpecializedArrayElement* instr) {
JSObject::ElementsKind elements_kind = instr->elements_kind();
- Operand operand(BuildExternalArrayOperand(instr->external_pointer(),
- instr->key(), elements_kind));
+ Operand operand(BuildFastArrayOperand(instr->external_pointer(),
+ instr->key(), elements_kind, 0));
if (elements_kind == JSObject::EXTERNAL_FLOAT_ELEMENTS) {
__ cvtsd2ss(xmm0, ToDoubleRegister(instr->value()));
__ movss(operand, xmm0);
@@ -3069,6 +3094,28 @@
}
+void LCodeGen::DoStoreKeyedFastDoubleElement(
+ LStoreKeyedFastDoubleElement* instr) {
+ XMMRegister value = ToDoubleRegister(instr->value());
+ Register elements = ToRegister(instr->elements());
+ Register key = instr->key()->IsRegister() ? ToRegister(instr->key()) : no_reg;
+ Label have_value;
+
+ __ ucomisd(value, value);
+ __ j(parity_odd, &have_value); // NaN.
+
+ ExternalReference canonical_nan_reference =
+ ExternalReference::address_of_canonical_non_hole_nan();
+ __ movdbl(value, Operand::StaticVariable(canonical_nan_reference));
+ __ bind(&have_value);
+
+ Operand double_store_operand = BuildFastArrayOperand(
+ instr->elements(), instr->key(), JSObject::FAST_DOUBLE_ELEMENTS,
+ FixedDoubleArray::kHeaderSize - kHeapObjectTag);
+ __ movdbl(double_store_operand, value);
+}
+
+
void LCodeGen::DoStoreKeyedGeneric(LStoreKeyedGeneric* instr) {
ASSERT(ToRegister(instr->context()).is(esi));
ASSERT(ToRegister(instr->object()).is(edx));
diff --git a/src/ia32/lithium-codegen-ia32.h b/src/ia32/lithium-codegen-ia32.h
index 7ab446d..c568bef 100644
--- a/src/ia32/lithium-codegen-ia32.h
+++ b/src/ia32/lithium-codegen-ia32.h
@@ -222,9 +222,10 @@
Register ToRegister(int index) const;
XMMRegister ToDoubleRegister(int index) const;
int ToInteger32(LConstantOperand* op) const;
- Operand BuildExternalArrayOperand(LOperand* external_pointer,
- LOperand* key,
- JSObject::ElementsKind elements_kind);
+ Operand BuildFastArrayOperand(LOperand* external_pointer,
+ LOperand* key,
+ JSObject::ElementsKind elements_kind,
+ uint32_t offset);
// Specific math operations - used from DoUnaryMathOperation.
void EmitIntegerMathAbs(LUnaryMathOperation* instr);
diff --git a/src/ia32/lithium-ia32.cc b/src/ia32/lithium-ia32.cc
index 1b9aeb5..9951d25 100644
--- a/src/ia32/lithium-ia32.cc
+++ b/src/ia32/lithium-ia32.cc
@@ -429,6 +429,15 @@
}
+void LStoreKeyedFastDoubleElement::PrintDataTo(StringStream* stream) {
+ elements()->PrintTo(stream);
+ stream->Add("[");
+ key()->PrintTo(stream);
+ stream->Add("] <- ");
+ value()->PrintTo(stream);
+}
+
+
void LStoreKeyedGeneric::PrintDataTo(StringStream* stream) {
object()->PrintTo(stream);
stream->Add("[");
@@ -1878,6 +1887,18 @@
}
+LInstruction* LChunkBuilder::DoLoadKeyedFastDoubleElement(
+ HLoadKeyedFastDoubleElement* instr) {
+ ASSERT(instr->representation().IsDouble());
+ ASSERT(instr->key()->representation().IsInteger32());
+ LOperand* elements = UseRegisterAtStart(instr->elements());
+ LOperand* key = UseRegisterOrConstantAtStart(instr->key());
+ LLoadKeyedFastDoubleElement* result =
+ new LLoadKeyedFastDoubleElement(elements, key);
+ return AssignEnvironment(DefineAsRegister(result));
+}
+
+
LInstruction* LChunkBuilder::DoLoadKeyedSpecializedArrayElement(
HLoadKeyedSpecializedArrayElement* instr) {
JSObject::ElementsKind elements_kind = instr->elements_kind();
@@ -1933,6 +1954,20 @@
}
+LInstruction* LChunkBuilder::DoStoreKeyedFastDoubleElement(
+ HStoreKeyedFastDoubleElement* instr) {
+ ASSERT(instr->value()->representation().IsDouble());
+ ASSERT(instr->elements()->representation().IsTagged());
+ ASSERT(instr->key()->representation().IsInteger32());
+
+ LOperand* elements = UseRegisterAtStart(instr->elements());
+ LOperand* val = UseTempRegister(instr->value());
+ LOperand* key = UseRegisterOrConstantAtStart(instr->key());
+
+ return new LStoreKeyedFastDoubleElement(elements, key, val);
+}
+
+
LInstruction* LChunkBuilder::DoStoreKeyedSpecializedArrayElement(
HStoreKeyedSpecializedArrayElement* instr) {
Representation representation(instr->value()->representation());
diff --git a/src/ia32/lithium-ia32.h b/src/ia32/lithium-ia32.h
index 0daab5f..6b60a6e 100644
--- a/src/ia32/lithium-ia32.h
+++ b/src/ia32/lithium-ia32.h
@@ -116,6 +116,7 @@
V(LoadGlobalCell) \
V(LoadGlobalGeneric) \
V(LoadKeyedFastElement) \
+ V(LoadKeyedFastDoubleElement) \
V(LoadKeyedGeneric) \
V(LoadKeyedSpecializedArrayElement) \
V(LoadNamedField) \
@@ -141,6 +142,7 @@
V(StoreContextSlot) \
V(StoreGlobalCell) \
V(StoreGlobalGeneric) \
+ V(StoreKeyedFastDoubleElement) \
V(StoreKeyedFastElement) \
V(StoreKeyedGeneric) \
V(StoreKeyedSpecializedArrayElement) \
@@ -1161,6 +1163,23 @@
};
+class LLoadKeyedFastDoubleElement: public LTemplateInstruction<1, 2, 0> {
+ public:
+ LLoadKeyedFastDoubleElement(LOperand* elements,
+ LOperand* key) {
+ inputs_[0] = elements;
+ inputs_[1] = key;
+ }
+
+ DECLARE_CONCRETE_INSTRUCTION(LoadKeyedFastDoubleElement,
+ "load-keyed-fast-double-element")
+ DECLARE_HYDROGEN_ACCESSOR(LoadKeyedFastDoubleElement)
+
+ LOperand* elements() { return inputs_[0]; }
+ LOperand* key() { return inputs_[1]; }
+};
+
+
class LLoadKeyedSpecializedArrayElement: public LTemplateInstruction<1, 2, 0> {
public:
LLoadKeyedSpecializedArrayElement(LOperand* external_pointer,
@@ -1651,6 +1670,28 @@
};
+class LStoreKeyedFastDoubleElement: public LTemplateInstruction<0, 3, 0> {
+ public:
+ LStoreKeyedFastDoubleElement(LOperand* elements,
+ LOperand* key,
+ LOperand* val) {
+ inputs_[0] = elements;
+ inputs_[1] = key;
+ inputs_[2] = val;
+ }
+
+ DECLARE_CONCRETE_INSTRUCTION(StoreKeyedFastDoubleElement,
+ "store-keyed-fast-double-element")
+ DECLARE_HYDROGEN_ACCESSOR(StoreKeyedFastDoubleElement)
+
+ virtual void PrintDataTo(StringStream* stream);
+
+ LOperand* elements() { return inputs_[0]; }
+ LOperand* key() { return inputs_[1]; }
+ LOperand* value() { return inputs_[2]; }
+};
+
+
class LStoreKeyedSpecializedArrayElement: public LTemplateInstruction<0, 3, 0> {
public:
LStoreKeyedSpecializedArrayElement(LOperand* external_pointer,
diff --git a/src/jsregexp.cc b/src/jsregexp.cc
index 45a39ff..bc47df8 100644
--- a/src/jsregexp.cc
+++ b/src/jsregexp.cc
@@ -1,4 +1,4 @@
-// Copyright 2006-2009 the V8 project authors. All rights reserved.
+// Copyright 2011 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:
@@ -1958,13 +1958,10 @@
ASSERT(characters_filled_in < details->characters());
int characters = details->characters();
int char_mask;
- int char_shift;
if (compiler->ascii()) {
char_mask = String::kMaxAsciiCharCode;
- char_shift = 8;
} else {
char_mask = String::kMaxUC16CharCode;
- char_shift = 16;
}
for (int k = 0; k < elms_->length(); k++) {
TextElement elm = elms_->at(k);
@@ -4888,7 +4885,6 @@
cp_offset += elm.data.u_atom->data().length();
} else {
cp_offset++;
- Vector<const uc16> quarks = elm.data.u_atom->data();
}
}
}
@@ -5327,8 +5323,6 @@
return CompilationResult(error_message);
}
- NodeInfo info = *node->info();
-
// Create the correct assembler for the architecture.
#ifndef V8_INTERPRETED_REGEXP
// Native regexp implementation.
diff --git a/src/messages.js b/src/messages.js
index b928107..aaa98ed 100644
--- a/src/messages.js
+++ b/src/messages.js
@@ -195,7 +195,8 @@
non_extensible_proto: ["%0", " is not extensible"],
handler_non_object: ["Proxy.", "%0", " called with non-object as handler"],
handler_trap_missing: ["Proxy handler ", "%0", " has no '", "%1", "' trap"],
- handler_failed: ["Proxy handler ", "%0", " returned false for '", "%1", "' trap"],
+ handler_returned_false: ["Proxy handler ", "%0", " returned false for '", "%1", "' trap"],
+ handler_returned_undefined: ["Proxy handler ", "%0", " returned undefined for '", "%1", "' trap"],
proxy_prop_not_configurable: ["Trap ", "%1", " of proxy handler ", "%0", " returned non-configurable descriptor for property ", "%2"],
proxy_non_object_prop_names: ["Trap ", "%1", " returned non-object ", "%0"],
proxy_repeated_prop_name: ["Trap ", "%1", " returned repeated property name ", "%2"],
@@ -1050,13 +1051,15 @@
$Math.__proto__ = global.Object.prototype;
-DefineError(function Error() { });
-DefineError(function TypeError() { });
-DefineError(function RangeError() { });
-DefineError(function SyntaxError() { });
-DefineError(function ReferenceError() { });
-DefineError(function EvalError() { });
-DefineError(function URIError() { });
+// DefineError is a native function. Use explicit receiver. Otherwise
+// the receiver will be 'undefined'.
+this.DefineError(function Error() { });
+this.DefineError(function TypeError() { });
+this.DefineError(function RangeError() { });
+this.DefineError(function SyntaxError() { });
+this.DefineError(function ReferenceError() { });
+this.DefineError(function EvalError() { });
+this.DefineError(function URIError() { });
$Error.captureStackTrace = captureStackTrace;
diff --git a/src/mips/assembler-mips.cc b/src/mips/assembler-mips.cc
index 4ca6a91..51642e0 100644
--- a/src/mips/assembler-mips.cc
+++ b/src/mips/assembler-mips.cc
@@ -285,7 +285,7 @@
unbound_labels_count_ = 0;
block_buffer_growth_ = false;
- ast_id_for_reloc_info_ = kNoASTId;
+ ClearRecordedAstId();
}
@@ -1947,9 +1947,8 @@
}
ASSERT(buffer_space() >= kMaxRelocSize); // Too late to grow buffer here.
if (rmode == RelocInfo::CODE_TARGET_WITH_ID) {
- ASSERT(ast_id_for_reloc_info_ != kNoASTId);
- RelocInfo reloc_info_with_ast_id(pc_, rmode, ast_id_for_reloc_info_);
- ast_id_for_reloc_info_ = kNoASTId;
+ RelocInfo reloc_info_with_ast_id(pc_, rmode, RecordedAstId());
+ ClearRecordedAstId();
reloc_info_writer.Write(&reloc_info_with_ast_id);
} else {
reloc_info_writer.Write(&rinfo);
diff --git a/src/mips/assembler-mips.h b/src/mips/assembler-mips.h
index f3730d6..a16cd80 100644
--- a/src/mips/assembler-mips.h
+++ b/src/mips/assembler-mips.h
@@ -833,7 +833,17 @@
// Record the AST id of the CallIC being compiled, so that it can be placed
// in the relocation information.
- void RecordAstId(unsigned ast_id) { ast_id_for_reloc_info_ = ast_id; }
+ void SetRecordedAstId(unsigned ast_id) {
+ ASSERT(recorded_ast_id_ == kNoASTId);
+ recorded_ast_id_ = ast_id;
+ }
+
+ unsigned RecordedAstId() {
+ ASSERT(recorded_ast_id_ != kNoASTId);
+ return recorded_ast_id_;
+ }
+
+ void ClearRecordedAstId() { recorded_ast_id_ = kNoASTId; }
// Record a comment relocation entry that can be used by a disassembler.
// Use --code-comments to enable.
@@ -926,7 +936,7 @@
// Relocation for a type-recording IC has the AST id added to it. This
// member variable is a way to pass the information from the call site to
// the relocation info.
- unsigned ast_id_for_reloc_info_;
+ unsigned recorded_ast_id_;
bool emit_debug_code() const { return emit_debug_code_; }
diff --git a/src/mips/code-stubs-mips.cc b/src/mips/code-stubs-mips.cc
index d03443f..d89d3e5 100644
--- a/src/mips/code-stubs-mips.cc
+++ b/src/mips/code-stubs-mips.cc
@@ -4913,6 +4913,7 @@
__ li(a0, Operand(argc_)); // Setup the number of arguments.
__ mov(a2, zero_reg);
__ GetBuiltinEntry(a3, Builtins::CALL_NON_FUNCTION);
+ __ SetCallKind(t1, CALL_AS_METHOD);
__ Jump(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(),
RelocInfo::CODE_TARGET);
}
diff --git a/src/mips/macro-assembler-mips.cc b/src/mips/macro-assembler-mips.cc
index 712ceec..5e8d676 100644
--- a/src/mips/macro-assembler-mips.cc
+++ b/src/mips/macro-assembler-mips.cc
@@ -2080,8 +2080,7 @@
bind(&start);
ASSERT(RelocInfo::IsCodeTarget(rmode));
if (rmode == RelocInfo::CODE_TARGET && ast_id != kNoASTId) {
- ASSERT(ast_id_for_reloc_info_ == kNoASTId);
- ast_id_for_reloc_info_ = ast_id;
+ SetRecordedAstId(ast_id);
rmode = RelocInfo::CODE_TARGET_WITH_ID;
}
Call(reinterpret_cast<Address>(code.location()), rmode, cond, rs, rt, bd);
@@ -3701,6 +3700,8 @@
lw(elements, FieldMemOperand(elements, HeapObject::kMapOffset));
LoadRoot(at, Heap::kFixedArrayMapRootIndex);
Branch(&ok, eq, elements, Operand(at));
+ LoadRoot(at, Heap::kFixedDoubleArrayMapRootIndex);
+ Branch(&ok, eq, elements, Operand(at));
LoadRoot(at, Heap::kFixedCOWArrayMapRootIndex);
Branch(&ok, eq, elements, Operand(at));
Abort("JSObject with fast elements map has slow elements");
diff --git a/src/mips/stub-cache-mips.cc b/src/mips/stub-cache-mips.cc
index 6c8e961..f1ffe9b 100644
--- a/src/mips/stub-cache-mips.cc
+++ b/src/mips/stub-cache-mips.cc
@@ -4231,7 +4231,70 @@
void KeyedLoadStubCompiler::GenerateLoadFastDoubleElement(
MacroAssembler* masm) {
- UNIMPLEMENTED();
+ // ----------- S t a t e -------------
+ // -- ra : return address
+ // -- a0 : key
+ // -- a1 : receiver
+ // -----------------------------------
+ Label miss_force_generic, slow_allocate_heapnumber;
+
+ Register key_reg = a0;
+ Register receiver_reg = a1;
+ Register elements_reg = a2;
+ Register heap_number_reg = a2;
+ Register indexed_double_offset = a3;
+ Register scratch = t0;
+ Register scratch2 = t1;
+ Register scratch3 = t2;
+ Register heap_number_map = t3;
+
+ // This stub is meant to be tail-jumped to, the receiver must already
+ // have been verified by the caller to not be a smi.
+
+ // Check that the key is a smi.
+ __ JumpIfNotSmi(key_reg, &miss_force_generic);
+
+ // Get the elements array.
+ __ lw(elements_reg,
+ FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
+
+ // Check that the key is within bounds.
+ __ lw(scratch, FieldMemOperand(elements_reg, FixedArray::kLengthOffset));
+ __ Branch(&miss_force_generic, hs, key_reg, Operand(scratch));
+
+ // Load the upper word of the double in the fixed array and test for NaN.
+ __ sll(scratch2, key_reg, kDoubleSizeLog2 - kSmiTagSize);
+ __ Addu(indexed_double_offset, elements_reg, Operand(scratch2));
+ uint32_t upper_32_offset = FixedArray::kHeaderSize + sizeof(kHoleNanLower32);
+ __ lw(scratch, FieldMemOperand(indexed_double_offset, upper_32_offset));
+ __ Branch(&miss_force_generic, eq, scratch, Operand(kHoleNanUpper32));
+
+ // Non-NaN. Allocate a new heap number and copy the double value into it.
+ __ LoadRoot(heap_number_map, Heap::kHeapNumberMapRootIndex);
+ __ AllocateHeapNumber(heap_number_reg, scratch2, scratch3,
+ heap_number_map, &slow_allocate_heapnumber);
+
+ // Don't need to reload the upper 32 bits of the double, it's already in
+ // scratch.
+ __ sw(scratch, FieldMemOperand(heap_number_reg,
+ HeapNumber::kExponentOffset));
+ __ lw(scratch, FieldMemOperand(indexed_double_offset,
+ FixedArray::kHeaderSize));
+ __ sw(scratch, FieldMemOperand(heap_number_reg,
+ HeapNumber::kMantissaOffset));
+
+ __ mov(v0, heap_number_reg);
+ __ Ret();
+
+ __ bind(&slow_allocate_heapnumber);
+ Handle<Code> slow_ic =
+ masm->isolate()->builtins()->KeyedLoadIC_Slow();
+ __ Jump(slow_ic, RelocInfo::CODE_TARGET);
+
+ __ bind(&miss_force_generic);
+ Handle<Code> miss_ic =
+ masm->isolate()->builtins()->KeyedLoadIC_MissForceGeneric();
+ __ Jump(miss_ic, RelocInfo::CODE_TARGET);
}
@@ -4301,7 +4364,120 @@
void KeyedStoreStubCompiler::GenerateStoreFastDoubleElement(
MacroAssembler* masm,
bool is_js_array) {
- UNIMPLEMENTED();
+ // ----------- S t a t e -------------
+ // -- a0 : value
+ // -- a1 : key
+ // -- a2 : receiver
+ // -- ra : return address
+ // -- a3 : scratch
+ // -- t0 : scratch (elements_reg)
+ // -- t1 : scratch (mantissa_reg)
+ // -- t2 : scratch (exponent_reg)
+ // -- t3 : scratch4
+ // -----------------------------------
+ Label miss_force_generic, smi_value, is_nan, maybe_nan, have_double_value;
+
+ Register value_reg = a0;
+ Register key_reg = a1;
+ Register receiver_reg = a2;
+ Register scratch = a3;
+ Register elements_reg = t0;
+ Register mantissa_reg = t1;
+ Register exponent_reg = t2;
+ Register scratch4 = t3;
+
+ // This stub is meant to be tail-jumped to, the receiver must already
+ // have been verified by the caller to not be a smi.
+ __ JumpIfNotSmi(key_reg, &miss_force_generic);
+
+ __ lw(elements_reg,
+ FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
+
+ // Check that the key is within bounds.
+ if (is_js_array) {
+ __ lw(scratch, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
+ } else {
+ __ lw(scratch,
+ FieldMemOperand(elements_reg, FixedArray::kLengthOffset));
+ }
+ // Compare smis, unsigned compare catches both negative and out-of-bound
+ // indexes.
+ __ Branch(&miss_force_generic, hs, key_reg, Operand(scratch));
+
+ // Handle smi values specially.
+ __ JumpIfSmi(value_reg, &smi_value);
+
+ // Ensure that the object is a heap number
+ __ CheckMap(value_reg,
+ scratch,
+ masm->isolate()->factory()->heap_number_map(),
+ &miss_force_generic,
+ DONT_DO_SMI_CHECK);
+
+ // Check for nan: all NaN values have a value greater (signed) than 0x7ff00000
+ // in the exponent.
+ __ li(scratch, Operand(kNaNOrInfinityLowerBoundUpper32));
+ __ lw(exponent_reg, FieldMemOperand(value_reg, HeapNumber::kExponentOffset));
+ __ Branch(&maybe_nan, ge, exponent_reg, Operand(scratch));
+
+ __ lw(mantissa_reg, FieldMemOperand(value_reg, HeapNumber::kMantissaOffset));
+
+ __ bind(&have_double_value);
+ __ sll(scratch4, key_reg, kDoubleSizeLog2 - kSmiTagSize);
+ __ Addu(scratch, elements_reg, Operand(scratch4));
+ __ sw(mantissa_reg, FieldMemOperand(scratch, FixedDoubleArray::kHeaderSize));
+ uint32_t offset = FixedDoubleArray::kHeaderSize + sizeof(kHoleNanLower32);
+ __ sw(exponent_reg, FieldMemOperand(scratch, offset));
+ __ Ret();
+
+ __ bind(&maybe_nan);
+ // Could be NaN or Infinity. If fraction is not zero, it's NaN, otherwise
+ // it's an Infinity, and the non-NaN code path applies.
+ __ li(scratch, Operand(kNaNOrInfinityLowerBoundUpper32));
+ __ Branch(&is_nan, gt, exponent_reg, Operand(scratch));
+ __ lw(mantissa_reg, FieldMemOperand(value_reg, HeapNumber::kMantissaOffset));
+ __ Branch(&have_double_value, eq, mantissa_reg, Operand(zero_reg));
+
+ __ bind(&is_nan);
+ // Load canonical NaN for storing into the double array.
+ uint64_t nan_int64 = BitCast<uint64_t>(
+ FixedDoubleArray::canonical_not_the_hole_nan_as_double());
+ __ li(mantissa_reg, Operand(static_cast<uint32_t>(nan_int64)));
+ __ li(exponent_reg, Operand(static_cast<uint32_t>(nan_int64 >> 32)));
+ __ jmp(&have_double_value);
+
+ __ bind(&smi_value);
+ __ Addu(scratch, elements_reg,
+ Operand(FixedDoubleArray::kHeaderSize - kHeapObjectTag));
+ __ sll(scratch4, key_reg, kDoubleSizeLog2 - kSmiTagSize);
+ __ Addu(scratch, scratch, scratch4);
+ // scratch is now effective address of the double element
+
+ FloatingPointHelper::Destination destination;
+ if (CpuFeatures::IsSupported(FPU)) {
+ destination = FloatingPointHelper::kFPURegisters;
+ } else {
+ destination = FloatingPointHelper::kCoreRegisters;
+ }
+ __ SmiUntag(value_reg, value_reg);
+ FloatingPointHelper::ConvertIntToDouble(
+ masm, value_reg, destination,
+ f0, mantissa_reg, exponent_reg, // These are: double_dst, dst1, dst2.
+ scratch4, f2); // These are: scratch2, single_scratch.
+ if (destination == FloatingPointHelper::kFPURegisters) {
+ CpuFeatures::Scope scope(FPU);
+ __ sdc1(f0, MemOperand(scratch, 0));
+ } else {
+ __ sw(mantissa_reg, MemOperand(scratch, 0));
+ __ sw(exponent_reg, MemOperand(scratch, Register::kSizeInBytes));
+ }
+ __ Ret();
+
+ // Handle store cache miss, replacing the ic with the generic stub.
+ __ bind(&miss_force_generic);
+ Handle<Code> ic =
+ masm->isolate()->builtins()->KeyedStoreIC_MissForceGeneric();
+ __ Jump(ic, RelocInfo::CODE_TARGET);
}
diff --git a/src/mirror-debugger.js b/src/mirror-debugger.js
index 0a32597..bad0800 100644
--- a/src/mirror-debugger.js
+++ b/src/mirror-debugger.js
@@ -1605,8 +1605,10 @@
// Try to find the function as a property in the receiver. Include the
// prototype chain in the lookup.
var property = GetUndefinedMirror();
- if (!receiver.isUndefined()) {
- for (var r = receiver; !r.isNull() && property.isUndefined(); r = r.protoObject()) {
+ if (receiver.isObject()) {
+ for (var r = receiver;
+ !r.isNull() && property.isUndefined();
+ r = r.protoObject()) {
property = r.lookupProperty(func);
}
}
diff --git a/src/objects-inl.h b/src/objects-inl.h
index fdc5102..5726b37 100644
--- a/src/objects-inl.h
+++ b/src/objects-inl.h
@@ -3761,6 +3761,7 @@
ACCESSORS(JSProxy, handler, Object, kHandlerOffset)
+ACCESSORS(JSProxy, padding, Object, kPaddingOffset)
Address Foreign::address() {
@@ -4006,7 +4007,8 @@
bool JSObject::AllowsSetElementsLength() {
- bool result = elements()->IsFixedArray();
+ bool result = elements()->IsFixedArray() ||
+ elements()->IsFixedDoubleArray();
ASSERT(result == !HasExternalArrayElements());
return result;
}
@@ -4156,6 +4158,22 @@
}
+bool JSReceiver::HasProperty(String* name) {
+ if (IsJSProxy()) {
+ return JSProxy::cast(this)->HasPropertyWithHandler(name);
+ }
+ return GetPropertyAttribute(name) != ABSENT;
+}
+
+
+bool JSReceiver::HasLocalProperty(String* name) {
+ if (IsJSProxy()) {
+ return JSProxy::cast(this)->HasPropertyWithHandler(name);
+ }
+ return GetLocalPropertyAttribute(name) != ABSENT;
+}
+
+
PropertyAttributes JSReceiver::GetPropertyAttribute(String* key) {
return GetPropertyAttributeWithReceiver(this, key);
}
diff --git a/src/objects.cc b/src/objects.cc
index 26ab645..341f929 100644
--- a/src/objects.cc
+++ b/src/objects.cc
@@ -2196,6 +2196,31 @@
}
+bool JSProxy::HasPropertyWithHandler(String* name_raw) {
+ Isolate* isolate = GetIsolate();
+ HandleScope scope(isolate);
+ Handle<Object> receiver(this);
+ Handle<Object> name(name_raw);
+ Handle<Object> handler(this->handler());
+
+ // Extract trap function.
+ Handle<String> trap_name = isolate->factory()->LookupAsciiSymbol("has");
+ Handle<Object> trap(v8::internal::GetProperty(handler, trap_name));
+ if (trap->IsUndefined()) {
+ trap = isolate->derived_has_trap();
+ }
+
+ // Call trap function.
+ Object** args[] = { name.location() };
+ bool has_exception;
+ Handle<Object> result =
+ Execution::Call(trap, handler, ARRAY_SIZE(args), args, &has_exception);
+ if (has_exception) return Failure::Exception();
+
+ return result->ToBoolean()->IsTrue();
+}
+
+
MUST_USE_RESULT MaybeObject* JSProxy::SetPropertyWithHandler(
String* name_raw,
Object* value_raw,
@@ -2220,8 +2245,7 @@
receiver.location(), name.location(), value.location()
};
bool has_exception;
- Handle<Object> result =
- Execution::Call(trap, handler, ARRAY_SIZE(args), args, &has_exception);
+ Execution::Call(trap, handler, ARRAY_SIZE(args), args, &has_exception);
if (has_exception) return Failure::Exception();
return *value;
@@ -2301,6 +2325,18 @@
}
+void JSProxy::Fix() {
+ Isolate* isolate = GetIsolate();
+ HandleScope scope(isolate);
+ Handle<JSProxy> self(this);
+
+ isolate->factory()->BecomeJSObject(self);
+ ASSERT(IsJSObject());
+ // TODO(rossberg): recognize function proxies.
+}
+
+
+
MaybeObject* JSObject::SetPropertyForResult(LookupResult* result,
String* name,
Object* value,
@@ -3170,7 +3206,7 @@
case FAST_DOUBLE_ELEMENTS: {
int length = IsJSArray()
? Smi::cast(JSArray::cast(this)->length())->value()
- : FixedArray::cast(elements())->length();
+ : FixedDoubleArray::cast(elements())->length();
if (index < static_cast<uint32_t>(length)) {
FixedDoubleArray::cast(elements())->set_the_hole(index);
}
@@ -7590,32 +7626,57 @@
if (maybe_smi_length->ToObject(&smi_length) && smi_length->IsSmi()) {
const int value = Smi::cast(smi_length)->value();
if (value < 0) return ArrayLengthRangeError(GetHeap());
- switch (GetElementsKind()) {
- case FAST_ELEMENTS: {
- int old_capacity = FixedArray::cast(elements())->length();
+ JSObject::ElementsKind elements_kind = GetElementsKind();
+ switch (elements_kind) {
+ case FAST_ELEMENTS:
+ case FAST_DOUBLE_ELEMENTS: {
+ int old_capacity = FixedArrayBase::cast(elements())->length();
if (value <= old_capacity) {
if (IsJSArray()) {
Object* obj;
- { MaybeObject* maybe_obj = EnsureWritableFastElements();
+ if (elements_kind == FAST_ELEMENTS) {
+ MaybeObject* maybe_obj = EnsureWritableFastElements();
if (!maybe_obj->ToObject(&obj)) return maybe_obj;
}
- FixedArray* fast_elements = FixedArray::cast(elements());
if (2 * value <= old_capacity) {
// If more than half the elements won't be used, trim the array.
if (value == 0) {
initialize_elements();
} else {
- fast_elements->set_length(value);
- Address filler_start = fast_elements->address() +
- FixedArray::OffsetOfElementAt(value);
- int filler_size = (old_capacity - value) * kPointerSize;
+ Address filler_start;
+ int filler_size;
+ if (GetElementsKind() == FAST_ELEMENTS) {
+ FixedArray* fast_elements = FixedArray::cast(elements());
+ fast_elements->set_length(value);
+ filler_start = fast_elements->address() +
+ FixedArray::OffsetOfElementAt(value);
+ filler_size = (old_capacity - value) * kPointerSize;
+ } else {
+ ASSERT(GetElementsKind() == FAST_DOUBLE_ELEMENTS);
+ FixedDoubleArray* fast_double_elements =
+ FixedDoubleArray::cast(elements());
+ fast_double_elements->set_length(value);
+ filler_start = fast_double_elements->address() +
+ FixedDoubleArray::OffsetOfElementAt(value);
+ filler_size = (old_capacity - value) * kDoubleSize;
+ }
GetHeap()->CreateFillerObjectAt(filler_start, filler_size);
}
} else {
// Otherwise, fill the unused tail with holes.
int old_length = FastD2I(JSArray::cast(this)->length()->Number());
- for (int i = value; i < old_length; i++) {
- fast_elements->set_the_hole(i);
+ if (GetElementsKind() == FAST_ELEMENTS) {
+ FixedArray* fast_elements = FixedArray::cast(elements());
+ for (int i = value; i < old_length; i++) {
+ fast_elements->set_the_hole(i);
+ }
+ } else {
+ ASSERT(GetElementsKind() == FAST_DOUBLE_ELEMENTS);
+ FixedDoubleArray* fast_double_elements =
+ FixedDoubleArray::cast(elements());
+ for (int i = value; i < old_length; i++) {
+ fast_double_elements->set_the_hole(i);
+ }
}
}
JSArray::cast(this)->set_length(Smi::cast(smi_length));
@@ -7626,8 +7687,14 @@
int new_capacity = value > min ? value : min;
if (new_capacity <= kMaxFastElementsLength ||
!ShouldConvertToSlowElements(new_capacity)) {
- MaybeObject* result =
- SetFastElementsCapacityAndLength(new_capacity, value);
+ MaybeObject* result;
+ if (GetElementsKind() == FAST_ELEMENTS) {
+ result = SetFastElementsCapacityAndLength(new_capacity, value);
+ } else {
+ ASSERT(GetElementsKind() == FAST_DOUBLE_ELEMENTS);
+ result = SetFastDoubleElementsCapacityAndLength(new_capacity,
+ value);
+ }
if (result->IsFailure()) return result;
return this;
}
@@ -7663,7 +7730,6 @@
case EXTERNAL_FLOAT_ELEMENTS:
case EXTERNAL_DOUBLE_ELEMENTS:
case EXTERNAL_PIXEL_ELEMENTS:
- case FAST_DOUBLE_ELEMENTS:
UNREACHABLE();
break;
}
@@ -8076,6 +8142,15 @@
!FixedArray::cast(elements())->get(index)->IsTheHole()) return true;
break;
}
+ case FAST_DOUBLE_ELEMENTS: {
+ uint32_t length = IsJSArray() ?
+ static_cast<uint32_t>
+ (Smi::cast(JSArray::cast(this)->length())->value()) :
+ static_cast<uint32_t>(FixedDoubleArray::cast(elements())->length());
+ if ((index < length) &&
+ !FixedDoubleArray::cast(elements())->is_the_hole(index)) return true;
+ break;
+ }
case EXTERNAL_PIXEL_ELEMENTS: {
ExternalPixelArray* pixels = ExternalPixelArray::cast(elements());
if (index < static_cast<uint32_t>(pixels->length())) {
@@ -8097,9 +8172,6 @@
}
break;
}
- case FAST_DOUBLE_ELEMENTS:
- UNREACHABLE();
- break;
case DICTIONARY_ELEMENTS: {
if (element_dictionary()->FindEntry(index)
!= NumberDictionary::kNotFound) {
@@ -9537,6 +9609,21 @@
ASSERT(!storage || storage->length() >= counter);
break;
}
+ case FAST_DOUBLE_ELEMENTS: {
+ int length = IsJSArray() ?
+ Smi::cast(JSArray::cast(this)->length())->value() :
+ FixedDoubleArray::cast(elements())->length();
+ for (int i = 0; i < length; i++) {
+ if (!FixedDoubleArray::cast(elements())->is_the_hole(i)) {
+ if (storage != NULL) {
+ storage->set(counter, Smi::FromInt(i));
+ }
+ counter++;
+ }
+ }
+ ASSERT(!storage || storage->length() >= counter);
+ break;
+ }
case EXTERNAL_PIXEL_ELEMENTS: {
int length = ExternalPixelArray::cast(elements())->length();
while (counter < length) {
@@ -9566,9 +9653,6 @@
ASSERT(!storage || storage->length() >= counter);
break;
}
- case FAST_DOUBLE_ELEMENTS:
- UNREACHABLE();
- break;
case DICTIONARY_ELEMENTS: {
if (storage != NULL) {
element_dictionary()->CopyKeysTo(storage,
diff --git a/src/objects.h b/src/objects.h
index 0eaeb36..9b55ea7 100644
--- a/src/objects.h
+++ b/src/objects.h
@@ -1394,14 +1394,8 @@
PropertyAttributes GetLocalPropertyAttribute(String* name);
// Can cause a GC.
- bool HasProperty(String* name) {
- return GetPropertyAttribute(name) != ABSENT;
- }
-
- // Can cause a GC.
- bool HasLocalProperty(String* name) {
- return GetLocalPropertyAttribute(name) != ABSENT;
- }
+ inline bool HasProperty(String* name);
+ inline bool HasLocalProperty(String* name);
// Return the object's prototype (might be Heap::null_value()).
inline Object* GetPrototype();
@@ -2175,6 +2169,9 @@
return kHeaderSize + length * kDoubleSize;
}
+ // Code Generation support.
+ static int OffsetOfElementAt(int index) { return SizeFor(index); }
+
inline static bool is_the_hole_nan(double value);
inline static double hole_nan_as_double();
inline static double canonical_not_the_hole_nan_as_double();
@@ -6475,9 +6472,14 @@
// [handler]: The handler property.
DECL_ACCESSORS(handler, Object)
+ // [padding]: The padding slot (unused, see below).
+ DECL_ACCESSORS(padding, Object)
+
// Casting.
static inline JSProxy* cast(Object* obj);
+ bool HasPropertyWithHandler(String* name);
+
MUST_USE_RESULT MaybeObject* SetPropertyWithHandler(
String* name,
Object* value,
@@ -6493,6 +6495,9 @@
String* name,
bool* has_exception);
+ // Turn this into an (empty) JSObject.
+ void Fix();
+
// Dispatched behavior.
#ifdef OBJECT_PRINT
inline void JSProxyPrint() {
@@ -6504,9 +6509,14 @@
void JSProxyVerify();
#endif
- // Layout description.
+ // Layout description. We add padding so that a proxy has the same
+ // size as a virgin JSObject. This is essential for becoming a JSObject
+ // upon freeze.
static const int kHandlerOffset = HeapObject::kHeaderSize;
- static const int kSize = kHandlerOffset + kPointerSize;
+ static const int kPaddingOffset = kHandlerOffset + kPointerSize;
+ static const int kSize = kPaddingOffset + kPointerSize;
+
+ STATIC_CHECK(kSize == JSObject::kHeaderSize);
typedef FixedBodyDescriptor<kHandlerOffset,
kHandlerOffset + kPointerSize,
diff --git a/src/parser.cc b/src/parser.cc
index 949ff76..5704cb8 100644
--- a/src/parser.cc
+++ b/src/parser.cc
@@ -648,6 +648,7 @@
}
if (ok) {
result = new(zone()) FunctionLiteral(
+ isolate(),
no_name,
top_scope_,
body,
@@ -718,7 +719,6 @@
{
// Parse the function literal.
- Handle<String> no_name = isolate()->factory()->empty_symbol();
Scope* scope = NewScope(top_scope_, Scope::GLOBAL_SCOPE, inside_with());
if (!info->closure().is_null()) {
scope = Scope::DeserializeScopeChain(info, scope);
@@ -1262,7 +1262,7 @@
// one must take great care not to treat it as a
// 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(zone()) Block(labels, 1, false);
+ Block* result = new(zone()) Block(isolate(), labels, 1, false);
Target target(&this->target_stack_, result);
TryStatement* statement = ParseTryStatement(CHECK_OK);
if (statement) {
@@ -1453,10 +1453,10 @@
// introduced dynamically when we meet their declarations, whereas
// other functions are setup when entering the surrounding scope.
SharedFunctionInfoLiteral* lit =
- new(zone()) SharedFunctionInfoLiteral(shared);
+ new(zone()) SharedFunctionInfoLiteral(isolate(), shared);
VariableProxy* var = Declare(name, Variable::VAR, NULL, true, CHECK_OK);
return new(zone()) ExpressionStatement(new(zone()) Assignment(
- Token::INIT_VAR, var, lit, RelocInfo::kNoPosition));
+ isolate(), Token::INIT_VAR, var, lit, RelocInfo::kNoPosition));
}
@@ -1489,7 +1489,7 @@
// (ECMA-262, 3rd, 12.2)
//
// Construct block expecting 16 statements.
- Block* result = new(zone()) Block(labels, 16, false);
+ Block* result = new(zone()) Block(isolate(), labels, 16, false);
Target target(&this->target_stack_, result);
Expect(Token::LBRACE, CHECK_OK);
InitializationBlockFinder block_finder(top_scope_, target_stack_);
@@ -1564,7 +1564,7 @@
// is inside an initializer block, it is ignored.
//
// Create new block with one expected declaration.
- Block* block = new(zone()) Block(NULL, 1, true);
+ Block* block = new(zone()) Block(isolate(), NULL, 1, true);
int nvars = 0; // the number of variables declared
Handle<String> name;
do {
@@ -1676,7 +1676,7 @@
// Compute the arguments for the runtime call.
ZoneList<Expression*>* arguments = new(zone()) ZoneList<Expression*>(3);
// We have at least 1 parameter.
- arguments->Add(new(zone()) Literal(name));
+ arguments->Add(NewLiteral(name));
CallRuntime* initialize;
if (is_const) {
@@ -1689,9 +1689,10 @@
// the number of arguments (1 or 2).
initialize =
new(zone()) CallRuntime(
- isolate()->factory()->InitializeConstGlobal_symbol(),
- Runtime::FunctionForId(Runtime::kInitializeConstGlobal),
- arguments);
+ isolate(),
+ isolate()->factory()->InitializeConstGlobal_symbol(),
+ Runtime::FunctionForId(Runtime::kInitializeConstGlobal),
+ arguments);
} else {
// Add strict mode.
// We may want to pass singleton to avoid Literal allocations.
@@ -1715,9 +1716,10 @@
// the number of arguments (2 or 3).
initialize =
new(zone()) CallRuntime(
- isolate()->factory()->InitializeVarGlobal_symbol(),
- Runtime::FunctionForId(Runtime::kInitializeVarGlobal),
- arguments);
+ isolate(),
+ isolate()->factory()->InitializeVarGlobal_symbol(),
+ Runtime::FunctionForId(Runtime::kInitializeVarGlobal),
+ arguments);
}
block->AddStatement(new(zone()) ExpressionStatement(initialize));
@@ -1739,7 +1741,7 @@
VariableProxy* proxy =
initialization_scope->NewUnresolved(name, in_with);
Assignment* assignment =
- new(zone()) Assignment(op, proxy, value, position);
+ new(zone()) Assignment(isolate(), op, proxy, value, position);
if (block) {
block->AddStatement(new(zone()) ExpressionStatement(assignment));
}
@@ -1842,7 +1844,8 @@
} else {
else_statement = EmptyStatement();
}
- return new(zone()) IfStatement(condition, then_statement, else_statement);
+ return new(zone()) IfStatement(
+ isolate(), condition, then_statement, else_statement);
}
@@ -1961,17 +1964,17 @@
// Create resulting block with two statements.
// 1: Evaluate the with expression.
// 2: The try-finally block evaluating the body.
- Block* result = new(zone()) Block(NULL, 2, false);
+ Block* result = new(zone()) Block(isolate(), NULL, 2, false);
if (result != NULL) {
result->AddStatement(new(zone()) EnterWithContextStatement(obj));
// Create body block.
- Block* body = new(zone()) Block(NULL, 1, false);
+ Block* body = new(zone()) Block(isolate(), NULL, 1, false);
body->AddStatement(stat);
// Create exit block.
- Block* exit = new(zone()) Block(NULL, 1, false);
+ Block* exit = new(zone()) Block(isolate(), NULL, 1, false);
exit->AddStatement(new(zone()) ExitContextStatement());
// Return a try-finally statement.
@@ -2032,7 +2035,7 @@
statements->Add(stat);
}
- return new(zone()) CaseClause(label, statements, pos);
+ return new(zone()) CaseClause(isolate(), label, statements, pos);
}
@@ -2041,7 +2044,7 @@
// SwitchStatement ::
// 'switch' '(' Expression ')' '{' CaseClause* '}'
- SwitchStatement* statement = new(zone()) SwitchStatement(labels);
+ SwitchStatement* statement = new(zone()) SwitchStatement(isolate(), labels);
Target target(&this->target_stack_, statement);
Expect(Token::SWITCH, CHECK_OK);
@@ -2077,7 +2080,8 @@
Expression* exception = ParseExpression(true, CHECK_OK);
ExpectSemicolon(CHECK_OK);
- return new(zone()) ExpressionStatement(new(zone()) Throw(exception, pos));
+ return new(zone()) ExpressionStatement(
+ new(zone()) Throw(isolate(), exception, pos));
}
@@ -2156,7 +2160,7 @@
}
// Create exit block.
- Block* inner_finally = new(zone()) Block(NULL, 1, false);
+ Block* inner_finally = new(zone()) Block(isolate(), NULL, 1, false);
inner_finally->AddStatement(new(zone()) ExitContextStatement());
// Create a try/finally statement.
@@ -2164,7 +2168,7 @@
new(zone()) TryFinallyStatement(inner_body, inner_finally);
inner_try_finally->set_escaping_targets(inner_collector.targets());
- catch_block = new(zone()) Block(NULL, 1, false);
+ catch_block = new(zone()) Block(isolate(), NULL, 1, false);
catch_block->AddStatement(inner_try_finally);
} else {
Expect(Token::LBRACE, CHECK_OK);
@@ -2193,7 +2197,7 @@
catch_variable,
catch_block);
statement->set_escaping_targets(try_collector.targets());
- try_block = new(zone()) Block(NULL, 1, false);
+ try_block = new(zone()) Block(isolate(), NULL, 1, false);
try_block->AddStatement(statement);
catch_block = NULL; // Clear to indicate it's been handled.
}
@@ -2224,7 +2228,7 @@
// DoStatement ::
// 'do' Statement 'while' '(' Expression ')' ';'
- DoWhileStatement* loop = new(zone()) DoWhileStatement(labels);
+ DoWhileStatement* loop = new(zone()) DoWhileStatement(isolate(), labels);
Target target(&this->target_stack_, loop);
Expect(Token::DO, CHECK_OK);
@@ -2255,7 +2259,7 @@
// WhileStatement ::
// 'while' '(' Expression ')' Statement
- WhileStatement* loop = new(zone()) WhileStatement(labels);
+ WhileStatement* loop = new(zone()) WhileStatement(isolate(), labels);
Target target(&this->target_stack_, loop);
Expect(Token::WHILE, CHECK_OK);
@@ -2285,7 +2289,7 @@
if (peek() == Token::IN && !name.is_null()) {
VariableProxy* each = top_scope_->NewUnresolved(name, inside_with());
- ForInStatement* loop = new(zone()) ForInStatement(labels);
+ ForInStatement* loop = new(zone()) ForInStatement(isolate(), labels);
Target target(&this->target_stack_, loop);
Expect(Token::IN, CHECK_OK);
@@ -2294,7 +2298,7 @@
Statement* body = ParseStatement(NULL, CHECK_OK);
loop->Initialize(each, enumerable, body);
- Block* result = new(zone()) Block(NULL, 2, false);
+ Block* result = new(zone()) Block(isolate(), NULL, 2, false);
result->AddStatement(variable_statement);
result->AddStatement(loop);
// Parsed for-in loop w/ variable/const declaration.
@@ -2315,7 +2319,7 @@
isolate()->factory()->invalid_lhs_in_for_in_symbol();
expression = NewThrowReferenceError(type);
}
- ForInStatement* loop = new(zone()) ForInStatement(labels);
+ ForInStatement* loop = new(zone()) ForInStatement(isolate(), labels);
Target target(&this->target_stack_, loop);
Expect(Token::IN, CHECK_OK);
@@ -2334,7 +2338,7 @@
}
// Standard 'for' loop
- ForStatement* loop = new(zone()) ForStatement(labels);
+ ForStatement* loop = new(zone()) ForStatement(isolate(), labels);
Target target(&this->target_stack_, loop);
// Parsed initializer at this point.
@@ -2370,7 +2374,8 @@
Expect(Token::COMMA, CHECK_OK);
int position = scanner().location().beg_pos;
Expression* right = ParseAssignmentExpression(accept_IN, CHECK_OK);
- result = new(zone()) BinaryOperation(Token::COMMA, result, right, position);
+ result = new(zone()) BinaryOperation(
+ isolate(), Token::COMMA, result, right, position);
}
return result;
}
@@ -2442,7 +2447,7 @@
fni_->Leave();
}
- return new(zone()) Assignment(op, expression, right, pos);
+ return new(zone()) Assignment(isolate(), op, expression, right, pos);
}
@@ -2464,8 +2469,8 @@
Expect(Token::COLON, CHECK_OK);
int right_position = scanner().peek_location().beg_pos;
Expression* right = ParseAssignmentExpression(accept_IN, CHECK_OK);
- return new(zone()) Conditional(expression, left, right,
- left_position, right_position);
+ return new(zone()) Conditional(
+ isolate(), expression, left, right, left_position, right_position);
}
@@ -2552,12 +2557,12 @@
x = NewCompareNode(cmp, x, y, position);
if (cmp != op) {
// The comparison was negated - add a NOT.
- x = new(zone()) UnaryOperation(Token::NOT, x, position);
+ x = new(zone()) UnaryOperation(isolate(), Token::NOT, x, position);
}
} else {
// We have a "normal" binary operation.
- x = new(zone()) BinaryOperation(op, x, y, position);
+ x = new(zone()) BinaryOperation(isolate(), op, x, y, position);
}
}
}
@@ -2574,15 +2579,15 @@
bool is_strict = (op == Token::EQ_STRICT);
Literal* x_literal = x->AsLiteral();
if (x_literal != NULL && x_literal->IsNull()) {
- return new(zone()) CompareToNull(is_strict, y);
+ return new(zone()) CompareToNull(isolate(), is_strict, y);
}
Literal* y_literal = y->AsLiteral();
if (y_literal != NULL && y_literal->IsNull()) {
- return new(zone()) CompareToNull(is_strict, x);
+ return new(zone()) CompareToNull(isolate(), is_strict, x);
}
}
- return new(zone()) CompareOperation(op, x, y, position);
+ return new(zone()) CompareOperation(isolate(), op, x, y, position);
}
@@ -2611,7 +2616,7 @@
// Convert the literal to a boolean condition and negate it.
bool condition = literal->ToBoolean()->IsTrue();
Handle<Object> result(isolate()->heap()->ToBoolean(!condition));
- return new(zone()) Literal(result);
+ return NewLiteral(result);
} else if (literal->IsNumber()) {
// Compute some expressions involving only number literals.
double value = literal->Number();
@@ -2638,7 +2643,7 @@
}
}
- return new(zone()) UnaryOperation(op, expression, position);
+ return new(zone()) UnaryOperation(isolate(), op, expression, position);
} else if (Token::IsCountOp(op)) {
op = Next();
@@ -2659,7 +2664,8 @@
}
int position = scanner().location().beg_pos;
- return new(zone()) CountOperation(op,
+ return new(zone()) CountOperation(isolate(),
+ op,
true /* prefix */,
expression,
position);
@@ -2695,7 +2701,8 @@
Token::Value next = Next();
int position = scanner().location().beg_pos;
expression =
- new(zone()) CountOperation(next,
+ new(zone()) CountOperation(isolate(),
+ next,
false /* postfix */,
expression,
position);
@@ -2721,7 +2728,7 @@
Consume(Token::LBRACK);
int pos = scanner().location().beg_pos;
Expression* index = ParseExpression(true, CHECK_OK);
- result = new(zone()) Property(result, index, pos);
+ result = new(zone()) Property(isolate(), result, index, pos);
Expect(Token::RBRACK, CHECK_OK);
break;
}
@@ -2759,7 +2766,10 @@
Consume(Token::PERIOD);
int pos = scanner().location().beg_pos;
Handle<String> name = ParseIdentifierName(CHECK_OK);
- result = new(zone()) Property(result, new(zone()) Literal(name), pos);
+ result = new(zone()) Property(isolate(),
+ result,
+ NewLiteral(name),
+ pos);
if (fni_ != NULL) fni_->PushLiteralName(name);
break;
}
@@ -2795,7 +2805,8 @@
if (!stack->is_empty()) {
int last = stack->pop();
- result = new(zone()) CallNew(result,
+ result = new(zone()) CallNew(isolate(),
+ result,
new(zone()) ZoneList<Expression*>(0),
last);
}
@@ -2843,7 +2854,7 @@
Consume(Token::LBRACK);
int pos = scanner().location().beg_pos;
Expression* index = ParseExpression(true, CHECK_OK);
- result = new(zone()) Property(result, index, pos);
+ result = new(zone()) Property(isolate(), result, index, pos);
if (fni_ != NULL) {
if (index->IsPropertyName()) {
fni_->PushLiteralName(index->AsLiteral()->AsPropertyName());
@@ -2859,7 +2870,10 @@
Consume(Token::PERIOD);
int pos = scanner().location().beg_pos;
Handle<String> name = ParseIdentifierName(CHECK_OK);
- result = new(zone()) Property(result, new(zone()) Literal(name), pos);
+ result = new(zone()) Property(isolate(),
+ result,
+ NewLiteral(name),
+ pos);
if (fni_ != NULL) fni_->PushLiteralName(name);
break;
}
@@ -2868,7 +2882,7 @@
// Consume one of the new prefixes (already parsed).
ZoneList<Expression*>* args = ParseArguments(CHECK_OK);
int last = stack->pop();
- result = new(zone()) CallNew(result, args, last);
+ result = new(zone()) CallNew(isolate(), result, args, last);
break;
}
default:
@@ -2952,23 +2966,26 @@
switch (peek()) {
case Token::THIS: {
Consume(Token::THIS);
- result = new(zone()) VariableProxy(top_scope_->receiver());
+ result = new(zone()) VariableProxy(isolate(), top_scope_->receiver());
break;
}
case Token::NULL_LITERAL:
Consume(Token::NULL_LITERAL);
- result = new(zone()) Literal(isolate()->factory()->null_value());
+ result = new(zone()) Literal(
+ isolate(), isolate()->factory()->null_value());
break;
case Token::TRUE_LITERAL:
Consume(Token::TRUE_LITERAL);
- result = new(zone()) Literal(isolate()->factory()->true_value());
+ result = new(zone()) Literal(
+ isolate(), isolate()->factory()->true_value());
break;
case Token::FALSE_LITERAL:
Consume(Token::FALSE_LITERAL);
- result = new(zone()) Literal(isolate()->factory()->false_value());
+ result = new(zone()) Literal(
+ isolate(), isolate()->factory()->false_value());
break;
case Token::IDENTIFIER:
@@ -2994,7 +3011,7 @@
case Token::STRING: {
Consume(Token::STRING);
Handle<String> symbol = GetSymbol(CHECK_OK);
- result = new(zone()) Literal(symbol);
+ result = NewLiteral(symbol);
if (fni_ != NULL) fni_->PushLiteralName(symbol);
break;
}
@@ -3121,8 +3138,8 @@
literals->set_map(isolate()->heap()->fixed_cow_array_map());
}
- return new(zone()) ArrayLiteral(literals, values,
- literal_index, is_simple, depth);
+ return new(zone()) ArrayLiteral(
+ isolate(), literals, values, literal_index, is_simple, depth);
}
@@ -3425,7 +3442,6 @@
ObjectLiteralPropertyChecker checker(this, top_scope_->is_strict_mode());
Expect(Token::LBRACE, CHECK_OK);
- Scanner::Location loc = scanner().location();
while (peek() != Token::RBRACE) {
if (fni_ != NULL) fni_->Enter();
@@ -3467,7 +3483,7 @@
}
// Failed to parse as get/set property, so it's just a property
// called "get" or "set".
- key = new(zone()) Literal(id);
+ key = NewLiteral(id);
break;
}
case Token::STRING: {
@@ -3479,7 +3495,7 @@
key = NewNumberLiteral(index);
break;
}
- key = new(zone()) Literal(string);
+ key = NewLiteral(string);
break;
}
case Token::NUMBER: {
@@ -3495,7 +3511,7 @@
if (Token::IsKeyword(next)) {
Consume(next);
Handle<String> string = GetSymbol(CHECK_OK);
- key = new(zone()) Literal(string);
+ key = NewLiteral(string);
} else {
// Unexpected token.
Token::Value next = Next();
@@ -3548,13 +3564,14 @@
&is_simple,
&fast_elements,
&depth);
- return new(zone()) ObjectLiteral(constant_properties,
- properties,
- literal_index,
- is_simple,
- fast_elements,
- depth,
- has_function);
+ return new(zone()) ObjectLiteral(isolate(),
+ constant_properties,
+ properties,
+ literal_index,
+ is_simple,
+ fast_elements,
+ depth,
+ has_function);
}
@@ -3573,7 +3590,8 @@
Handle<String> js_flags = NextLiteralString(TENURED);
Next();
- return new(zone()) RegExpLiteral(js_pattern, js_flags, literal_index);
+ return new(zone()) RegExpLiteral(
+ isolate(), js_pattern, js_flags, literal_index);
}
@@ -3690,9 +3708,11 @@
top_scope_->NewUnresolved(function_name, inside_with());
fproxy->BindTo(fvar);
body->Add(new(zone()) ExpressionStatement(
- new(zone()) Assignment(Token::INIT_CONST, fproxy,
- new(zone()) ThisFunction(),
- RelocInfo::kNoPosition)));
+ new(zone()) Assignment(isolate(),
+ Token::INIT_CONST,
+ fproxy,
+ new(zone()) ThisFunction(isolate()),
+ RelocInfo::kNoPosition)));
}
// Determine if the function will be lazily compiled. The mode can
@@ -3782,7 +3802,8 @@
}
FunctionLiteral* function_literal =
- new(zone()) FunctionLiteral(name,
+ new(zone()) FunctionLiteral(isolate(),
+ name,
scope,
body,
materialized_literal_count,
@@ -3843,7 +3864,7 @@
}
// We have a valid intrinsics call or a call to a builtin.
- return new(zone()) CallRuntime(name, function, args);
+ return new(zone()) CallRuntime(isolate(), name, function, args);
}
@@ -3899,12 +3920,12 @@
Literal* Parser::GetLiteralUndefined() {
- return new(zone()) Literal(isolate()->factory()->undefined_value());
+ return NewLiteral(isolate()->factory()->undefined_value());
}
Literal* Parser::GetLiteralTheHole() {
- return new(zone()) Literal(isolate()->factory()->the_hole_value());
+ return NewLiteral(isolate()->factory()->the_hole_value());
}
@@ -4060,7 +4081,7 @@
Literal* Parser::NewNumberLiteral(double number) {
- return new(zone()) Literal(isolate()->factory()->NewNumber(number, TENURED));
+ return NewLiteral(isolate()->factory()->NewNumber(number, TENURED));
}
@@ -4107,10 +4128,15 @@
TENURED);
ZoneList<Expression*>* args = new(zone()) ZoneList<Expression*>(2);
- args->Add(new(zone()) Literal(type));
- args->Add(new(zone()) Literal(array));
- return new(zone()) Throw(new(zone()) CallRuntime(constructor, NULL, args),
- scanner().location().beg_pos);
+ args->Add(NewLiteral(type));
+ args->Add(NewLiteral(array));
+ CallRuntime* call_constructor = new(zone()) CallRuntime(isolate(),
+ constructor,
+ NULL,
+ args);
+ return new(zone()) Throw(isolate(),
+ call_constructor,
+ scanner().location().beg_pos);
}
// ----------------------------------------------------------------------------
diff --git a/src/parser.h b/src/parser.h
index 71f5d39..13a3603 100644
--- a/src/parser.h
+++ b/src/parser.h
@@ -668,9 +668,12 @@
Expression* NewCall(Expression* expression,
ZoneList<Expression*>* arguments,
int pos) {
- return new(zone()) Call(expression, arguments, pos);
+ return new(zone()) Call(isolate(), expression, arguments, pos);
}
+ inline Literal* NewLiteral(Handle<Object> handle) {
+ return new(zone()) Literal(isolate(), handle);
+ }
// Create a number literal.
Literal* NewNumberLiteral(double value);
diff --git a/src/platform-linux.cc b/src/platform-linux.cc
index ab22a79..bc280ea 100644
--- a/src/platform-linux.cc
+++ b/src/platform-linux.cc
@@ -734,6 +734,7 @@
ASSERT(result == 0);
result = pthread_mutex_init(&mutex_, &attrs);
ASSERT(result == 0);
+ USE(result);
}
virtual ~LinuxMutex() { pthread_mutex_destroy(&mutex_); }
diff --git a/src/platform-nullos.cc b/src/platform-nullos.cc
index 08480ca..8c2a863 100644
--- a/src/platform-nullos.cc
+++ b/src/platform-nullos.cc
@@ -217,6 +217,11 @@
}
+void OS::Guard(void* address, const size_t size) {
+ UNIMPLEMENTED();
+}
+
+
void OS::Sleep(int milliseconds) {
UNIMPLEMENTED();
}
diff --git a/src/platform-posix.cc b/src/platform-posix.cc
index 5be305a..deb4b75 100644
--- a/src/platform-posix.cc
+++ b/src/platform-posix.cc
@@ -33,6 +33,7 @@
#include <errno.h>
#include <time.h>
+#include <sys/mman.h>
#include <sys/socket.h>
#include <sys/resource.h>
#include <sys/time.h>
@@ -43,6 +44,8 @@
#include <netinet/in.h>
#include <netdb.h>
+#undef MAP_TYPE
+
#if defined(ANDROID)
#define LOG_TAG "v8"
#include <utils/Log.h> // LOG_PRI_VA
@@ -67,6 +70,12 @@
}
+// Create guard pages.
+void OS::Guard(void* address, const size_t size) {
+ mprotect(address, size, PROT_NONE);
+}
+
+
// ----------------------------------------------------------------------------
// Math functions
diff --git a/src/platform-win32.cc b/src/platform-win32.cc
index 35b1a8e..b23e25e 100644
--- a/src/platform-win32.cc
+++ b/src/platform-win32.cc
@@ -957,6 +957,12 @@
}
+void OS::Guard(void* address, const size_t size) {
+ DWORD oldprotect;
+ VirtualProtect(address, size, PAGE_READONLY | PAGE_GUARD, &oldprotect);
+}
+
+
void OS::Sleep(int milliseconds) {
::Sleep(milliseconds);
}
diff --git a/src/platform.h b/src/platform.h
index c7fe984..4d7f9cf 100644
--- a/src/platform.h
+++ b/src/platform.h
@@ -206,6 +206,10 @@
size_t* allocated,
bool is_executable);
static void Free(void* address, const size_t size);
+
+ // Assign memory as a guard page so that access will cause an exception.
+ static void Guard(void* address, const size_t size);
+
// Get the Alignment guaranteed by Allocate().
static size_t AllocateAlignment();
diff --git a/src/rewriter.cc b/src/rewriter.cc
index 1ac2bb8..e8ca5b9 100644
--- a/src/rewriter.cc
+++ b/src/rewriter.cc
@@ -67,8 +67,11 @@
Expression* SetResult(Expression* value) {
result_assigned_ = true;
Zone* zone = isolate()->zone();
- VariableProxy* result_proxy = new(zone) VariableProxy(result_);
- return new(zone) Assignment(Token::ASSIGN, result_proxy, value,
+ VariableProxy* result_proxy = new(zone) VariableProxy(isolate(), result_);
+ return new(zone) Assignment(isolate(),
+ Token::ASSIGN,
+ result_proxy,
+ value,
RelocInfo::kNoPosition);
}
@@ -230,8 +233,9 @@
if (processor.HasStackOverflow()) return false;
if (processor.result_assigned()) {
- Zone* zone = info->isolate()->zone();
- VariableProxy* result_proxy = new(zone) VariableProxy(result);
+ Isolate* isolate = info->isolate();
+ Zone* zone = isolate->zone();
+ VariableProxy* result_proxy = new(zone) VariableProxy(isolate, result);
body->Add(new(zone) ReturnStatement(result_proxy));
}
}
diff --git a/src/runtime.cc b/src/runtime.cc
index 0ce5836..b4259c4 100644
--- a/src/runtime.cc
+++ b/src/runtime.cc
@@ -615,6 +615,14 @@
}
+RUNTIME_FUNCTION(MaybeObject*, Runtime_Fix) {
+ ASSERT(args.length() == 1);
+ CONVERT_CHECKED(JSProxy, proxy, args[0]);
+ proxy->Fix();
+ return proxy;
+}
+
+
RUNTIME_FUNCTION(MaybeObject*, Runtime_ClassOf) {
NoHandleAllocation ha;
ASSERT(args.length() == 1);
@@ -4307,11 +4315,11 @@
NoHandleAllocation na;
ASSERT(args.length() == 2);
- // Only JS objects can have properties.
- if (args[0]->IsJSObject()) {
- JSObject* object = JSObject::cast(args[0]);
+ // Only JS receivers can have properties.
+ if (args[0]->IsJSReceiver()) {
+ JSReceiver* receiver = JSReceiver::cast(args[0]);
CONVERT_CHECKED(String, key, args[1]);
- if (object->HasProperty(key)) return isolate->heap()->true_value();
+ if (receiver->HasProperty(key)) return isolate->heap()->true_value();
}
return isolate->heap()->false_value();
}
@@ -10128,7 +10136,8 @@
// Get scope info and read from it for local variable information.
Handle<JSFunction> function(JSFunction::cast(it.frame()->function()));
- Handle<SerializedScopeInfo> scope_info(function->shared()->scope_info());
+ Handle<SharedFunctionInfo> shared(function->shared());
+ Handle<SerializedScopeInfo> scope_info(shared->scope_info());
ASSERT(*scope_info != SerializedScopeInfo::Empty());
ScopeInfo<> info(*scope_info);
@@ -10300,10 +10309,11 @@
// THIS MUST BE DONE LAST SINCE WE MIGHT ADVANCE
// THE FRAME ITERATOR TO WRAP THE RECEIVER.
Handle<Object> receiver(it.frame()->receiver(), isolate);
- if (!receiver->IsJSObject()) {
- // If the receiver is NOT a JSObject we have hit an optimization
- // where a value object is not converted into a wrapped JS objects.
- // To hide this optimization from the debugger, we wrap the receiver
+ if (!receiver->IsJSObject() && !shared->strict_mode() && !shared->native()) {
+ // If the receiver is not a JSObject and the function is not a
+ // builtin or strict-mode we have hit an optimization where a
+ // value object is not converted into a wrapped JS objects. To
+ // hide this optimization from the debugger, we wrap the receiver
// by creating correct wrapper object based on the calling frame's
// global context.
it.Advance();
@@ -12274,8 +12284,9 @@
// call to this function is encountered it is skipped. The seen_caller
// in/out parameter is used to remember if the caller has been seen
// yet.
-static bool ShowFrameInStackTrace(StackFrame* raw_frame, Object* caller,
- bool* seen_caller) {
+static bool ShowFrameInStackTrace(StackFrame* raw_frame,
+ Object* caller,
+ bool* seen_caller) {
// Only display JS frames.
if (!raw_frame->is_java_script())
return false;
@@ -12288,11 +12299,25 @@
*seen_caller = true;
return false;
}
- // Skip all frames until we've seen the caller. Also, skip the most
- // obvious builtin calls. Some builtin calls (such as Number.ADD
- // which is invoked using 'call') are very difficult to recognize
- // so we're leaving them in for now.
- return *seen_caller && !frame->receiver()->IsJSBuiltinsObject();
+ // Skip all frames until we've seen the caller.
+ if (!(*seen_caller)) return false;
+ // Also, skip the most obvious builtin calls. We recognize builtins
+ // as (1) functions called with the builtins object as the receiver and
+ // as (2) functions from native scripts called with undefined as the
+ // receiver (direct calls to helper functions in the builtins
+ // code). Some builtin calls (such as Number.ADD which is invoked
+ // using 'call') are very difficult to recognize so we're leaving
+ // them in for now.
+ if (frame->receiver()->IsJSBuiltinsObject()) {
+ return false;
+ }
+ JSFunction* fun = JSFunction::cast(raw_fun);
+ Object* raw_script = fun->shared()->script();
+ if (frame->receiver()->IsUndefined() && raw_script->IsScript()) {
+ int script_type = Script::cast(raw_script)->type()->value();
+ return script_type != Script::TYPE_NATIVE;
+ }
+ return true;
}
diff --git a/src/runtime.h b/src/runtime.h
index 7bd58c8..ac912d8 100644
--- a/src/runtime.h
+++ b/src/runtime.h
@@ -284,6 +284,7 @@
F(CreateJSProxy, 2, 1) \
F(IsJSProxy, 1, 1) \
F(GetHandler, 1, 1) \
+ F(Fix, 1, 1) \
\
/* Statements */ \
F(NewClosure, 3, 1) \
diff --git a/src/runtime.js b/src/runtime.js
index 77b97ae..4b600df 100644
--- a/src/runtime.js
+++ b/src/runtime.js
@@ -354,7 +354,8 @@
if (!IS_SPEC_OBJECT(x)) {
throw %MakeTypeError('invalid_in_operator_use', [this, x]);
}
- return %_IsNonNegativeSmi(this) ? %HasElement(x, this) : %HasProperty(x, %ToString(this));
+ return %_IsNonNegativeSmi(this) && !%IsJSProxy(x) ?
+ %HasElement(x, this) : %HasProperty(x, %ToString(this));
}
diff --git a/src/scopes.cc b/src/scopes.cc
index f25f5a3..390a0b6 100644
--- a/src/scopes.cc
+++ b/src/scopes.cc
@@ -304,7 +304,7 @@
Variable::VAR,
false,
Variable::THIS);
- var->set_rewrite(new(isolate_->zone()) Slot(var, Slot::PARAMETER, -1));
+ var->set_rewrite(NewSlot(var, Slot::PARAMETER, -1));
receiver_ = var;
}
@@ -350,7 +350,7 @@
Variable* var =
variables_.Declare(this, name, mode, true, Variable::NORMAL);
- var->set_rewrite(new(isolate_->zone()) Slot(var, Slot::CONTEXT, index));
+ var->set_rewrite(NewSlot(var, Slot::CONTEXT, index));
return var;
}
@@ -407,8 +407,8 @@
// the same name because they may be removed selectively via
// RemoveUnresolved().
ASSERT(!already_resolved());
- VariableProxy* proxy =
- new(isolate_->zone()) VariableProxy(name, false, inside_with, position);
+ VariableProxy* proxy = new(isolate_->zone()) VariableProxy(
+ isolate_, name, false, inside_with, position);
unresolved_.Add(proxy);
return proxy;
}
@@ -708,7 +708,7 @@
// Declare a new non-local.
var = map->Declare(NULL, name, mode, true, Variable::NORMAL);
// Allocate it by giving it a dynamic lookup.
- var->set_rewrite(new(isolate_->zone()) Slot(var, Slot::LOOKUP, -1));
+ var->set_rewrite(NewSlot(var, Slot::LOOKUP, -1));
}
return var;
}
@@ -964,14 +964,12 @@
void Scope::AllocateStackSlot(Variable* var) {
- var->set_rewrite(
- new(isolate_->zone()) Slot(var, Slot::LOCAL, num_stack_slots_++));
+ var->set_rewrite(NewSlot(var, Slot::LOCAL, num_stack_slots_++));
}
void Scope::AllocateHeapSlot(Variable* var) {
- var->set_rewrite(
- new(isolate_->zone()) Slot(var, Slot::CONTEXT, num_heap_slots_++));
+ var->set_rewrite(NewSlot(var, Slot::CONTEXT, num_heap_slots_++));
}
@@ -1024,7 +1022,7 @@
} else {
ASSERT(var->rewrite() == NULL || var->IsParameter());
if (var->rewrite() == NULL) {
- var->set_rewrite(new(isolate_->zone()) Slot(var, Slot::PARAMETER, i));
+ var->set_rewrite(NewSlot(var, Slot::PARAMETER, i));
}
}
}
diff --git a/src/scopes.h b/src/scopes.h
index 031ea3d..e76fb50 100644
--- a/src/scopes.h
+++ b/src/scopes.h
@@ -425,6 +425,10 @@
// Construct a catch scope with a binding for the name.
Scope(Scope* inner_scope, Handle<String> catch_variable_name);
+ inline Slot* NewSlot(Variable* var, Slot::Type type, int index) {
+ return new(isolate_->zone()) Slot(isolate_, var, type, index);
+ }
+
void AddInnerScope(Scope* inner_scope) {
if (inner_scope != NULL) {
inner_scopes_.Add(inner_scope);
diff --git a/src/spaces.cc b/src/spaces.cc
index d41ce55..0f80496 100644
--- a/src/spaces.cc
+++ b/src/spaces.cc
@@ -402,7 +402,9 @@
size_t length,
Executability executable) {
#ifdef DEBUG
- ZapBlock(reinterpret_cast<Address>(mem), length);
+ // Do not try to zap the guard page.
+ size_t guard_size = (executable == EXECUTABLE) ? Page::kPageSize : 0;
+ ZapBlock(reinterpret_cast<Address>(mem) + guard_size, length - guard_size);
#endif
if (isolate_->code_range()->contains(static_cast<Address>(mem))) {
isolate_->code_range()->FreeRawMemory(mem, length);
@@ -504,14 +506,28 @@
LOG(isolate_, NewEvent("PagedChunk", chunk, chunk_size));
*allocated_pages = PagesInChunk(static_cast<Address>(chunk), chunk_size);
+
// We may 'lose' a page due to alignment.
ASSERT(*allocated_pages >= kPagesPerChunk - 1);
- if (*allocated_pages == 0) {
- FreeRawMemory(chunk, chunk_size, owner->executable());
+
+ size_t guard_size = (owner->executable() == EXECUTABLE) ? Page::kPageSize : 0;
+
+ // Check that we got at least one page that we can use.
+ if (*allocated_pages <= ((guard_size != 0) ? 1 : 0)) {
+ FreeRawMemory(chunk,
+ chunk_size,
+ owner->executable());
LOG(isolate_, DeleteEvent("PagedChunk", chunk));
return Page::FromAddress(NULL);
}
+ if (guard_size != 0) {
+ OS::Guard(chunk, guard_size);
+ chunk_size -= guard_size;
+ chunk = static_cast<Address>(chunk) + guard_size;
+ --*allocated_pages;
+ }
+
int chunk_id = Pop();
chunks_[chunk_id].init(static_cast<Address>(chunk), chunk_size, owner);
@@ -681,7 +697,8 @@
LOG(isolate_, DeleteEvent("PagedChunk", c.address()));
ObjectSpace space = static_cast<ObjectSpace>(1 << c.owner_identity());
size_t size = c.size();
- FreeRawMemory(c.address(), size, c.executable());
+ size_t guard_size = (c.executable() == EXECUTABLE) ? Page::kPageSize : 0;
+ FreeRawMemory(c.address() - guard_size, size + guard_size, c.executable());
PerformAllocationCallback(space, kAllocationActionFree, size);
}
c.init(NULL, 0, NULL);
@@ -2672,9 +2689,10 @@
Executability executable) {
size_t requested = ChunkSizeFor(size_in_bytes);
size_t size;
+ size_t guard_size = (executable == EXECUTABLE) ? Page::kPageSize : 0;
Isolate* isolate = Isolate::Current();
void* mem = isolate->memory_allocator()->AllocateRawMemory(
- requested, &size, executable);
+ requested + guard_size, &size, executable);
if (mem == NULL) return NULL;
// The start of the chunk may be overlayed with a page so we have to
@@ -2682,13 +2700,19 @@
ASSERT((size & Page::kPageFlagMask) == 0);
LOG(isolate, NewEvent("LargeObjectChunk", mem, size));
- if (size < requested) {
+ if (size < requested + guard_size) {
isolate->memory_allocator()->FreeRawMemory(
mem, size, executable);
LOG(isolate, DeleteEvent("LargeObjectChunk", mem));
return NULL;
}
+ if (guard_size != 0) {
+ OS::Guard(mem, guard_size);
+ size -= guard_size;
+ mem = static_cast<Address>(mem) + guard_size;
+ }
+
ObjectSpace space = (executable == EXECUTABLE)
? kObjectSpaceCodeSpace
: kObjectSpaceLoSpace;
@@ -2742,9 +2766,11 @@
ObjectSpace space = kObjectSpaceLoSpace;
if (executable == EXECUTABLE) space = kObjectSpaceCodeSpace;
size_t size = chunk->size();
- heap()->isolate()->memory_allocator()->FreeRawMemory(chunk->address(),
- size,
- executable);
+ size_t guard_size = (executable == EXECUTABLE) ? Page::kPageSize : 0;
+ heap()->isolate()->memory_allocator()->FreeRawMemory(
+ chunk->address() - guard_size,
+ size + guard_size,
+ executable);
heap()->isolate()->memory_allocator()->PerformAllocationCallback(
space, kAllocationActionFree, size);
}
@@ -2941,10 +2967,15 @@
objects_size_ -= object->Size();
page_count_--;
ObjectSpace space = kObjectSpaceLoSpace;
- if (executable == EXECUTABLE) space = kObjectSpaceCodeSpace;
- heap()->isolate()->memory_allocator()->FreeRawMemory(chunk_address,
- chunk_size,
- executable);
+ size_t guard_size = 0;
+ if (executable == EXECUTABLE) {
+ space = kObjectSpaceCodeSpace;
+ guard_size = Page::kPageSize;
+ }
+ heap()->isolate()->memory_allocator()->FreeRawMemory(
+ chunk_address - guard_size,
+ chunk_size + guard_size,
+ executable);
heap()->isolate()->memory_allocator()->PerformAllocationCallback(
space, kAllocationActionFree, size_);
LOG(heap()->isolate(), DeleteEvent("LargeObjectChunk", chunk_address));
diff --git a/src/spaces.h b/src/spaces.h
index c554a37..ac5d998 100644
--- a/src/spaces.h
+++ b/src/spaces.h
@@ -647,13 +647,11 @@
#ifdef V8_TARGET_ARCH_X64
static const int kPagesPerChunk = 32;
// On 64 bit the chunk table consists of 4 levels of 4096-entry tables.
- static const int kPagesPerChunkLog2 = 5;
static const int kChunkTableLevels = 4;
static const int kChunkTableBitsPerLevel = 12;
#else
static const int kPagesPerChunk = 16;
// On 32 bit the chunk table consists of 2 levels of 256-entry tables.
- static const int kPagesPerChunkLog2 = 4;
static const int kChunkTableLevels = 2;
static const int kChunkTableBitsPerLevel = 8;
#endif
@@ -662,7 +660,6 @@
MemoryAllocator();
static const int kChunkSize = kPagesPerChunk * Page::kPageSize;
- static const int kChunkSizeLog2 = kPagesPerChunkLog2 + kPageSizeBits;
// Maximum space size in bytes.
intptr_t capacity_;
diff --git a/src/v8natives.js b/src/v8natives.js
index 53a0317..9843635 100644
--- a/src/v8natives.js
+++ b/src/v8natives.js
@@ -663,7 +663,8 @@
var result = %_CallFunction(handler, p, attributes, defineProperty);
if (!ToBoolean(result)) {
if (should_throw) {
- throw MakeTypeError("handler_failed", [handler, "defineProperty"]);
+ throw MakeTypeError("handler_returned_false",
+ [handler, "defineProperty"]);
} else {
return false;
}
@@ -1020,11 +1021,30 @@
}
+// Harmony proxies.
+function ProxyFix(obj) {
+ var handler = %GetHandler(obj);
+ var fix = handler.fix;
+ if (IS_UNDEFINED(fix)) {
+ throw MakeTypeError("handler_trap_missing", [handler, "fix"]);
+ }
+ var props = %_CallFunction(handler, fix);
+ if (IS_UNDEFINED(props)) {
+ throw MakeTypeError("handler_returned_undefined", [handler, "fix"]);
+ }
+ %Fix(obj);
+ ObjectDefineProperties(obj, props);
+}
+
+
// ES5 section 15.2.3.8.
function ObjectSeal(obj) {
if (!IS_SPEC_OBJECT(obj)) {
throw MakeTypeError("obj_ctor_property_non_object", ["seal"]);
}
+ if (%IsJSProxy(obj)) {
+ ProxyFix(obj);
+ }
var names = ObjectGetOwnPropertyNames(obj);
for (var i = 0; i < names.length; i++) {
var name = names[i];
@@ -1034,7 +1054,8 @@
DefineOwnProperty(obj, name, desc, true);
}
}
- return ObjectPreventExtension(obj);
+ %PreventExtensions(obj);
+ return obj;
}
@@ -1043,6 +1064,9 @@
if (!IS_SPEC_OBJECT(obj)) {
throw MakeTypeError("obj_ctor_property_non_object", ["freeze"]);
}
+ if (%IsJSProxy(obj)) {
+ ProxyFix(obj);
+ }
var names = ObjectGetOwnPropertyNames(obj);
for (var i = 0; i < names.length; i++) {
var name = names[i];
@@ -1053,7 +1077,8 @@
DefineOwnProperty(obj, name, desc, true);
}
}
- return ObjectPreventExtension(obj);
+ %PreventExtensions(obj);
+ return obj;
}
@@ -1062,6 +1087,9 @@
if (!IS_SPEC_OBJECT(obj)) {
throw MakeTypeError("obj_ctor_property_non_object", ["preventExtension"]);
}
+ if (%IsJSProxy(obj)) {
+ ProxyFix(obj);
+ }
%PreventExtensions(obj);
return obj;
}
@@ -1072,6 +1100,9 @@
if (!IS_SPEC_OBJECT(obj)) {
throw MakeTypeError("obj_ctor_property_non_object", ["isSealed"]);
}
+ if (%IsJSProxy(obj)) {
+ return false;
+ }
var names = ObjectGetOwnPropertyNames(obj);
for (var i = 0; i < names.length; i++) {
var name = names[i];
@@ -1090,6 +1121,9 @@
if (!IS_SPEC_OBJECT(obj)) {
throw MakeTypeError("obj_ctor_property_non_object", ["isFrozen"]);
}
+ if (%IsJSProxy(obj)) {
+ return false;
+ }
var names = ObjectGetOwnPropertyNames(obj);
for (var i = 0; i < names.length; i++) {
var name = names[i];
@@ -1109,6 +1143,9 @@
if (!IS_SPEC_OBJECT(obj)) {
throw MakeTypeError("obj_ctor_property_non_object", ["isExtensible"]);
}
+ if (%IsJSProxy(obj)) {
+ return true;
+ }
return %IsExtensible(obj);
}
diff --git a/src/version.cc b/src/version.cc
index b0a346d..b8ae218 100644
--- a/src/version.cc
+++ b/src/version.cc
@@ -34,7 +34,7 @@
// cannot be changed without changing the SCons build script.
#define MAJOR_VERSION 3
#define MINOR_VERSION 4
-#define BUILD_NUMBER 13
+#define BUILD_NUMBER 14
#define PATCH_LEVEL 0
// Use 1 for candidates and 0 otherwise.
// (Boolean macro values are not supported by all preprocessors.)
diff --git a/src/x64/code-stubs-x64.cc b/src/x64/code-stubs-x64.cc
index 3cf7840..1a6efcb 100644
--- a/src/x64/code-stubs-x64.cc
+++ b/src/x64/code-stubs-x64.cc
@@ -2529,6 +2529,7 @@
#else
// Already there in AMD64 calling convention.
ASSERT(arg1.is(rdi));
+ USE(arg1);
#endif
// Locate the code entry and call it.
@@ -3198,6 +3199,7 @@
__ GetBuiltinEntry(rdx, Builtins::CALL_NON_FUNCTION);
Handle<Code> adaptor =
Isolate::Current()->builtins()->ArgumentsAdaptorTrampoline();
+ __ SetCallKind(rcx, CALL_AS_METHOD);
__ Jump(adaptor, RelocInfo::CODE_TARGET);
}
diff --git a/src/x64/deoptimizer-x64.cc b/src/x64/deoptimizer-x64.cc
index 6f48320..2a31f28 100644
--- a/src/x64/deoptimizer-x64.cc
+++ b/src/x64/deoptimizer-x64.cc
@@ -128,7 +128,9 @@
Address instruction_start = function->code()->instruction_start();
Address jump_table_address =
instruction_start + function->code()->safepoint_table_offset();
+#ifdef DEBUG
Address previous_pc = instruction_start;
+#endif
SafepointTableDeoptimiztionEntryIterator deoptimizations(function->code());
Address entry_pc = NULL;
@@ -157,12 +159,16 @@
CodePatcher patcher(call_address, Assembler::kCallInstructionLength);
patcher.masm()->Call(GetDeoptimizationEntry(deoptimization_index, LAZY),
RelocInfo::NONE);
+#ifdef DEBUG
previous_pc = call_end_address;
+#endif
} else {
// Not room enough for a long Call instruction. Write a short call
// instruction to a long jump placed elsewhere in the code.
+#ifdef DEBUG
Address short_call_end_address =
call_address + MacroAssembler::kShortCallInstructionLength;
+#endif
ASSERT(next_pc >= short_call_end_address);
// Write jump in jump-table.
@@ -177,7 +183,9 @@
CodePatcher call_patcher(call_address,
MacroAssembler::kShortCallInstructionLength);
call_patcher.masm()->call(jump_table_address);
+#ifdef DEBUG
previous_pc = short_call_end_address;
+#endif
}
// Continue with next deoptimization entry.
diff --git a/src/x64/full-codegen-x64.cc b/src/x64/full-codegen-x64.cc
index a54bff5..0f7e5b3 100644
--- a/src/x64/full-codegen-x64.cc
+++ b/src/x64/full-codegen-x64.cc
@@ -4060,10 +4060,8 @@
default: {
VisitForAccumulatorValue(expr->right());
Condition cc = no_condition;
- bool strict = false;
switch (op) {
case Token::EQ_STRICT:
- strict = true;
// Fall through.
case Token::EQ:
cc = equal;
diff --git a/src/x64/lithium-codegen-x64.cc b/src/x64/lithium-codegen-x64.cc
index 98667ce..49361e4 100644
--- a/src/x64/lithium-codegen-x64.cc
+++ b/src/x64/lithium-codegen-x64.cc
@@ -1883,7 +1883,6 @@
__ push(ToRegister(instr->InputAt(0)));
__ Push(instr->function());
- Register temp = ToRegister(instr->TempAt(0));
static const int kAdditionalDelta = 10;
int delta =
masm_->SizeOfCodeGeneratedSince(map_check) + kAdditionalDelta;
@@ -2245,10 +2244,35 @@
}
-Operand LCodeGen::BuildExternalArrayOperand(
+void LCodeGen::DoLoadKeyedFastDoubleElement(
+ LLoadKeyedFastDoubleElement* instr) {
+ Register elements = ToRegister(instr->elements());
+ XMMRegister result(ToDoubleRegister(instr->result()));
+
+ if (instr->hydrogen()->RequiresHoleCheck()) {
+ int offset = FixedDoubleArray::kHeaderSize - kHeapObjectTag +
+ sizeof(kHoleNanLower32);
+ Operand hole_check_operand = BuildFastArrayOperand(
+ instr->elements(),
+ instr->key(),
+ JSObject::FAST_DOUBLE_ELEMENTS,
+ offset);
+ __ cmpl(hole_check_operand, Immediate(kHoleNanUpper32));
+ DeoptimizeIf(equal, instr->environment());
+ }
+
+ Operand double_load_operand = BuildFastArrayOperand(
+ instr->elements(), instr->key(), JSObject::FAST_DOUBLE_ELEMENTS,
+ FixedDoubleArray::kHeaderSize - kHeapObjectTag);
+ __ movsd(result, double_load_operand);
+}
+
+
+Operand LCodeGen::BuildFastArrayOperand(
LOperand* external_pointer,
LOperand* key,
- JSObject::ElementsKind elements_kind) {
+ JSObject::ElementsKind elements_kind,
+ uint32_t offset) {
Register external_pointer_reg = ToRegister(external_pointer);
int shift_size = ElementsKindToShiftSize(elements_kind);
if (key->IsConstantOperand()) {
@@ -2256,10 +2280,12 @@
if (constant_value & 0xF0000000) {
Abort("array index constant value too big");
}
- return Operand(external_pointer_reg, constant_value * (1 << shift_size));
+ return Operand(external_pointer_reg,
+ constant_value * (1 << shift_size) + offset);
} else {
ScaleFactor scale_factor = static_cast<ScaleFactor>(shift_size);
- return Operand(external_pointer_reg, ToRegister(key), scale_factor, 0);
+ return Operand(external_pointer_reg, ToRegister(key),
+ scale_factor, offset);
}
}
@@ -2267,8 +2293,8 @@
void LCodeGen::DoLoadKeyedSpecializedArrayElement(
LLoadKeyedSpecializedArrayElement* instr) {
JSObject::ElementsKind elements_kind = instr->elements_kind();
- Operand operand(BuildExternalArrayOperand(instr->external_pointer(),
- instr->key(), elements_kind));
+ Operand operand(BuildFastArrayOperand(instr->external_pointer(),
+ instr->key(), elements_kind, 0));
if (elements_kind == JSObject::EXTERNAL_FLOAT_ELEMENTS) {
XMMRegister result(ToDoubleRegister(instr->result()));
__ movss(result, operand);
@@ -2994,8 +3020,8 @@
void LCodeGen::DoStoreKeyedSpecializedArrayElement(
LStoreKeyedSpecializedArrayElement* instr) {
JSObject::ElementsKind elements_kind = instr->elements_kind();
- Operand operand(BuildExternalArrayOperand(instr->external_pointer(),
- instr->key(), elements_kind));
+ Operand operand(BuildFastArrayOperand(instr->external_pointer(),
+ instr->key(), elements_kind, 0));
if (elements_kind == JSObject::EXTERNAL_FLOAT_ELEMENTS) {
XMMRegister value(ToDoubleRegister(instr->value()));
__ cvtsd2ss(value, value);
@@ -3072,6 +3098,28 @@
}
+void LCodeGen::DoStoreKeyedFastDoubleElement(
+ LStoreKeyedFastDoubleElement* instr) {
+ XMMRegister value = ToDoubleRegister(instr->value());
+ Register elements = ToRegister(instr->elements());
+ Label have_value;
+
+ __ ucomisd(value, value);
+ __ j(parity_odd, &have_value); // NaN.
+
+ ExternalReference canonical_nan_reference =
+ ExternalReference::address_of_canonical_non_hole_nan();
+ __ Set(kScratchRegister, BitCast<uint64_t>(
+ FixedDoubleArray::canonical_not_the_hole_nan_as_double()));
+ __ movq(value, kScratchRegister);
+
+ __ bind(&have_value);
+ Operand double_store_operand = BuildFastArrayOperand(
+ instr->elements(), instr->key(), JSObject::FAST_DOUBLE_ELEMENTS,
+ FixedDoubleArray::kHeaderSize - kHeapObjectTag);
+ __ movsd(double_store_operand, value);
+}
+
void LCodeGen::DoStoreKeyedGeneric(LStoreKeyedGeneric* instr) {
ASSERT(ToRegister(instr->object()).is(rdx));
ASSERT(ToRegister(instr->key()).is(rcx));
diff --git a/src/x64/lithium-codegen-x64.h b/src/x64/lithium-codegen-x64.h
index feacc2c..d7c72b5 100644
--- a/src/x64/lithium-codegen-x64.h
+++ b/src/x64/lithium-codegen-x64.h
@@ -215,10 +215,11 @@
Register ToRegister(int index) const;
XMMRegister ToDoubleRegister(int index) const;
- Operand BuildExternalArrayOperand(
+ Operand BuildFastArrayOperand(
LOperand* external_pointer,
LOperand* key,
- JSObject::ElementsKind elements_kind);
+ JSObject::ElementsKind elements_kind,
+ uint32_t offset);
// Specific math operations - used from DoUnaryMathOperation.
void EmitIntegerMathAbs(LUnaryMathOperation* instr);
diff --git a/src/x64/lithium-x64.cc b/src/x64/lithium-x64.cc
index b2994cd..5b502a8 100644
--- a/src/x64/lithium-x64.cc
+++ b/src/x64/lithium-x64.cc
@@ -428,6 +428,15 @@
}
+void LStoreKeyedFastDoubleElement::PrintDataTo(StringStream* stream) {
+ elements()->PrintTo(stream);
+ stream->Add("[");
+ key()->PrintTo(stream);
+ stream->Add("] <- ");
+ value()->PrintTo(stream);
+}
+
+
void LStoreKeyedGeneric::PrintDataTo(StringStream* stream) {
object()->PrintTo(stream);
stream->Add("[");
@@ -1822,6 +1831,18 @@
}
+LInstruction* LChunkBuilder::DoLoadKeyedFastDoubleElement(
+ HLoadKeyedFastDoubleElement* instr) {
+ ASSERT(instr->representation().IsDouble());
+ ASSERT(instr->key()->representation().IsInteger32());
+ LOperand* elements = UseRegisterAtStart(instr->elements());
+ LOperand* key = UseRegisterOrConstantAtStart(instr->key());
+ LLoadKeyedFastDoubleElement* result =
+ new LLoadKeyedFastDoubleElement(elements, key);
+ return AssignEnvironment(DefineAsRegister(result));
+}
+
+
LInstruction* LChunkBuilder::DoLoadKeyedSpecializedArrayElement(
HLoadKeyedSpecializedArrayElement* instr) {
JSObject::ElementsKind elements_kind = instr->elements_kind();
@@ -1874,6 +1895,20 @@
}
+LInstruction* LChunkBuilder::DoStoreKeyedFastDoubleElement(
+ HStoreKeyedFastDoubleElement* instr) {
+ ASSERT(instr->value()->representation().IsDouble());
+ ASSERT(instr->elements()->representation().IsTagged());
+ ASSERT(instr->key()->representation().IsInteger32());
+
+ LOperand* elements = UseRegisterAtStart(instr->elements());
+ LOperand* val = UseTempRegister(instr->value());
+ LOperand* key = UseRegisterOrConstantAtStart(instr->key());
+
+ return new LStoreKeyedFastDoubleElement(elements, key, val);
+}
+
+
LInstruction* LChunkBuilder::DoStoreKeyedSpecializedArrayElement(
HStoreKeyedSpecializedArrayElement* instr) {
Representation representation(instr->value()->representation());
diff --git a/src/x64/lithium-x64.h b/src/x64/lithium-x64.h
index af0b299..12bdfb2 100644
--- a/src/x64/lithium-x64.h
+++ b/src/x64/lithium-x64.h
@@ -121,6 +121,7 @@
V(LoadFunctionPrototype) \
V(LoadGlobalCell) \
V(LoadGlobalGeneric) \
+ V(LoadKeyedFastDoubleElement) \
V(LoadKeyedFastElement) \
V(LoadKeyedGeneric) \
V(LoadKeyedSpecializedArrayElement) \
@@ -147,6 +148,7 @@
V(StoreContextSlot) \
V(StoreGlobalCell) \
V(StoreGlobalGeneric) \
+ V(StoreKeyedFastDoubleElement) \
V(StoreKeyedFastElement) \
V(StoreKeyedGeneric) \
V(StoreKeyedSpecializedArrayElement) \
@@ -1134,6 +1136,22 @@
};
+class LLoadKeyedFastDoubleElement: public LTemplateInstruction<1, 2, 0> {
+ public:
+ LLoadKeyedFastDoubleElement(LOperand* elements, LOperand* key) {
+ inputs_[0] = elements;
+ inputs_[1] = key;
+ }
+
+ DECLARE_CONCRETE_INSTRUCTION(LoadKeyedFastDoubleElement,
+ "load-keyed-fast-double-element")
+ DECLARE_HYDROGEN_ACCESSOR(LoadKeyedFastDoubleElement)
+
+ LOperand* elements() { return inputs_[0]; }
+ LOperand* key() { return inputs_[1]; }
+};
+
+
class LLoadKeyedSpecializedArrayElement: public LTemplateInstruction<1, 2, 0> {
public:
LLoadKeyedSpecializedArrayElement(LOperand* external_pointer,
@@ -1585,6 +1603,28 @@
};
+class LStoreKeyedFastDoubleElement: public LTemplateInstruction<0, 3, 0> {
+ public:
+ LStoreKeyedFastDoubleElement(LOperand* elements,
+ LOperand* key,
+ LOperand* val) {
+ inputs_[0] = elements;
+ inputs_[1] = key;
+ inputs_[2] = val;
+ }
+
+ DECLARE_CONCRETE_INSTRUCTION(StoreKeyedFastDoubleElement,
+ "store-keyed-fast-double-element")
+ DECLARE_HYDROGEN_ACCESSOR(StoreKeyedFastDoubleElement)
+
+ virtual void PrintDataTo(StringStream* stream);
+
+ LOperand* elements() { return inputs_[0]; }
+ LOperand* key() { return inputs_[1]; }
+ LOperand* value() { return inputs_[2]; }
+};
+
+
class LStoreKeyedSpecializedArrayElement: public LTemplateInstruction<0, 3, 0> {
public:
LStoreKeyedSpecializedArrayElement(LOperand* external_pointer,
diff --git a/src/x64/regexp-macro-assembler-x64.cc b/src/x64/regexp-macro-assembler-x64.cc
index 2ea17f0..395466e 100644
--- a/src/x64/regexp-macro-assembler-x64.cc
+++ b/src/x64/regexp-macro-assembler-x64.cc
@@ -661,7 +661,6 @@
}
__ movq(rbx, ExternalReference::re_word_character_map());
ASSERT_EQ(0, word_character_map[0]); // Character '\0' is not a word char.
- ExternalReference word_map = ExternalReference::re_word_character_map();
__ testb(Operand(rbx, current_character(), times_1, 0),
current_character());
BranchOrBacktrack(zero, on_no_match);
@@ -676,7 +675,6 @@
}
__ movq(rbx, ExternalReference::re_word_character_map());
ASSERT_EQ(0, word_character_map[0]); // Character '\0' is not a word char.
- ExternalReference word_map = ExternalReference::re_word_character_map();
__ testb(Operand(rbx, current_character(), times_1, 0),
current_character());
BranchOrBacktrack(not_zero, on_no_match);
diff --git a/src/x64/stub-cache-x64.cc b/src/x64/stub-cache-x64.cc
index d4f9d7c..b8e5f22 100644
--- a/src/x64/stub-cache-x64.cc
+++ b/src/x64/stub-cache-x64.cc
@@ -1089,9 +1089,8 @@
__ JumpIfSmi(receiver, miss);
// Check that the maps haven't changed.
- Register reg =
- CheckPrototypes(object, receiver, holder,
- scratch1, scratch2, scratch3, name, miss);
+ CheckPrototypes(object, receiver, holder,
+ scratch1, scratch2, scratch3, name, miss);
// Return the constant value.
__ Move(rax, Handle<Object>(value));
@@ -3746,8 +3745,6 @@
__ bind(&is_nan);
// Convert all NaNs to the same canonical NaN value when they are stored in
// the double array.
- ExternalReference canonical_nan_reference =
- ExternalReference::address_of_canonical_non_hole_nan();
__ Set(kScratchRegister, BitCast<uint64_t>(
FixedDoubleArray::canonical_not_the_hole_nan_as_double()));
__ movq(xmm0, kScratchRegister);