Version 3.5.4
Added preliminary implementation of ES Harmony weak maps. Weak maps can be enabled by the flag --harmony_weakmaps.
Introduced a toplevel Makefile to support GYP-based building. GYP can be found at http://gyp.googlecode.com.
Fixed a bug in the length property of functions created by Function.prototype.bind.
Reduced malloc heap allocation on process startup.
Several important code generation bug fixes.
Performance improvements on all platforms.
git-svn-id: http://v8.googlecode.com/svn/trunk@8874 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
diff --git a/src/SConscript b/src/SConscript
index b45a567..453a7c6 100755
--- a/src/SConscript
+++ b/src/SConscript
@@ -32,6 +32,7 @@
import js2c
Import('context')
Import('tools')
+Import('d8_env')
SOURCES = {
@@ -65,6 +66,7 @@
disassembler.cc
diy-fp.cc
dtoa.cc
+ elements.cc
execution.cc
factory.cc
flags.cc
@@ -307,6 +309,7 @@
EXPERIMENTAL_LIBRARY_FILES = '''
proxy.js
+weakmap.js
'''.split()
@@ -338,7 +341,7 @@
else:
d8_files = context.GetRelevantSources(D8_FULL_FILES)
d8_objs = [d8_js_obj]
- d8_objs.append(context.ConfigureObject(env, [d8_files]))
+ d8_objs.append(context.ConfigureObject(d8_env, [d8_files]))
# Combine the JavaScript library files into a single C++ file and
# compile it.
diff --git a/src/api.cc b/src/api.cc
index fa2c88c..7355cd6 100644
--- a/src/api.cc
+++ b/src/api.cc
@@ -84,7 +84,7 @@
if (has_pending_exception) { \
if (handle_scope_implementer->CallDepthIsZero() && \
(isolate)->is_out_of_memory()) { \
- if (!handle_scope_implementer->ignore_out_of_memory()) \
+ if (!(isolate)->ignore_out_of_memory()) \
i::V8::FatalProcessOutOfMemory(NULL); \
} \
bool call_depth_is_zero = handle_scope_implementer->CallDepthIsZero(); \
@@ -4259,8 +4259,8 @@
Local<Value> v8::External::Wrap(void* data) {
i::Isolate* isolate = i::Isolate::Current();
STATIC_ASSERT(sizeof(data) == sizeof(i::Address));
- LOG_API(isolate, "External::Wrap");
EnsureInitializedForIsolate(isolate, "v8::External::Wrap()");
+ LOG_API(isolate, "External::Wrap");
ENTER_V8(isolate);
v8::Local<v8::Value> result = CanBeEncodedAsSmi(data)
@@ -4304,8 +4304,8 @@
Local<External> v8::External::New(void* data) {
STATIC_ASSERT(sizeof(data) == sizeof(i::Address));
i::Isolate* isolate = i::Isolate::Current();
- LOG_API(isolate, "External::New");
EnsureInitializedForIsolate(isolate, "v8::External::New()");
+ LOG_API(isolate, "External::New");
ENTER_V8(isolate);
return ExternalNewImpl(data);
}
@@ -4797,8 +4797,7 @@
void V8::IgnoreOutOfMemoryException() {
- EnterIsolateIfNeeded()->handle_scope_implementer()->set_ignore_out_of_memory(
- true);
+ EnterIsolateIfNeeded()->set_ignore_out_of_memory(true);
}
diff --git a/src/api.h b/src/api.h
index 8d2e778..ce39d63 100644
--- a/src/api.h
+++ b/src/api.h
@@ -404,7 +404,6 @@
entered_contexts_(0),
saved_contexts_(0),
spare_(NULL),
- ignore_out_of_memory_(false),
call_depth_(0) { }
// Threading support for handle data.
@@ -437,10 +436,6 @@
inline bool HasSavedContexts();
inline List<internal::Object**>* blocks() { return &blocks_; }
- inline bool ignore_out_of_memory() { return ignore_out_of_memory_; }
- inline void set_ignore_out_of_memory(bool value) {
- ignore_out_of_memory_ = value;
- }
private:
void ResetAfterArchive() {
@@ -448,7 +443,6 @@
entered_contexts_.Initialize(0);
saved_contexts_.Initialize(0);
spare_ = NULL;
- ignore_out_of_memory_ = false;
call_depth_ = 0;
}
@@ -473,7 +467,6 @@
// Used as a stack to keep track of saved contexts.
List<Context*> saved_contexts_;
Object** spare_;
- bool ignore_out_of_memory_;
int call_depth_;
// This is only used for threading support.
v8::ImplementationUtilities::HandleScopeData handle_scope_data_;
diff --git a/src/arm/code-stubs-arm.cc b/src/arm/code-stubs-arm.cc
index eaad9f2..161421e 100644
--- a/src/arm/code-stubs-arm.cc
+++ b/src/arm/code-stubs-arm.cc
@@ -1603,83 +1603,139 @@
}
-// The stub returns zero for false, and a non-zero value for true.
+// The stub expects its argument in the tos_ register and returns its result in
+// it, too: zero for false, and a non-zero value for true.
void ToBooleanStub::Generate(MacroAssembler* masm) {
// This stub uses VFP3 instructions.
CpuFeatures::Scope scope(VFP3);
- Label false_result, true_result, not_string;
+ Label patch;
const Register map = r9.is(tos_) ? r7 : r9;
- // undefined -> false
- __ LoadRoot(ip, Heap::kUndefinedValueRootIndex);
- __ cmp(tos_, ip);
- __ b(eq, &false_result);
+ // undefined -> false.
+ CheckOddball(masm, UNDEFINED, Heap::kUndefinedValueRootIndex, false, &patch);
- // Boolean -> its value
- __ LoadRoot(ip, Heap::kFalseValueRootIndex);
- __ cmp(tos_, ip);
- __ b(eq, &false_result);
- __ LoadRoot(ip, Heap::kTrueValueRootIndex);
- __ cmp(tos_, ip);
- // "tos_" is a register and contains a non-zero value. Hence we implicitly
- // return true if the equal condition is satisfied.
- __ Ret(eq);
+ // Boolean -> its value.
+ CheckOddball(masm, BOOLEAN, Heap::kFalseValueRootIndex, false, &patch);
+ CheckOddball(masm, BOOLEAN, Heap::kTrueValueRootIndex, true, &patch);
- // Smis: 0 -> false, all other -> true
- __ tst(tos_, tos_);
- __ b(eq, &false_result);
- __ tst(tos_, Operand(kSmiTagMask));
- // "tos_" is a register and contains a non-zero value. Hence we implicitly
- // return true if the not equal condition is satisfied.
- __ Ret(eq);
+ // 'null' -> false.
+ CheckOddball(masm, NULL_TYPE, Heap::kNullValueRootIndex, false, &patch);
- // 'null' -> false
- __ LoadRoot(ip, Heap::kNullValueRootIndex);
- __ cmp(tos_, ip);
- __ b(eq, &false_result);
+ if (types_.Contains(SMI)) {
+ // Smis: 0 -> false, all other -> true
+ __ tst(tos_, Operand(kSmiTagMask));
+ // tos_ contains the correct return value already
+ __ Ret(eq);
+ } else if (types_.NeedsMap()) {
+ // If we need a map later and have a Smi -> patch.
+ __ JumpIfSmi(tos_, &patch);
+ }
- // Get the map of the heap object.
- __ ldr(map, FieldMemOperand(tos_, HeapObject::kMapOffset));
+ if (types_.NeedsMap()) {
+ __ ldr(map, FieldMemOperand(tos_, HeapObject::kMapOffset));
- // Undetectable -> false.
- __ ldrb(ip, FieldMemOperand(map, Map::kBitFieldOffset));
- __ tst(ip, Operand(1 << Map::kIsUndetectable));
- __ b(&false_result, ne);
+ // Everything with a map could be undetectable, so check this now.
+ __ ldrb(ip, FieldMemOperand(map, Map::kBitFieldOffset));
+ __ tst(ip, Operand(1 << Map::kIsUndetectable));
+ // Undetectable -> false.
+ __ mov(tos_, Operand(0, RelocInfo::NONE), LeaveCC, ne);
+ __ Ret(ne);
+ }
- // JavaScript object -> true.
- __ CompareInstanceType(map, ip, FIRST_SPEC_OBJECT_TYPE);
- // "tos_" is a register and contains a non-zero value. Hence we implicitly
- // return true if the greater than condition is satisfied.
- __ Ret(ge);
+ if (types_.Contains(SPEC_OBJECT)) {
+ // Spec object -> true.
+ __ CompareInstanceType(map, ip, FIRST_SPEC_OBJECT_TYPE);
+ // tos_ contains the correct non-zero return value already.
+ __ Ret(ge);
+ } else if (types_.Contains(INTERNAL_OBJECT)) {
+ // We've seen a spec object for the first time -> patch.
+ __ CompareInstanceType(map, ip, FIRST_SPEC_OBJECT_TYPE);
+ __ b(ge, &patch);
+ }
- // String value -> false iff empty.
+ if (types_.Contains(STRING)) {
+ // String value -> false iff empty.
__ CompareInstanceType(map, ip, FIRST_NONSTRING_TYPE);
- __ b(¬_string, ge);
- __ ldr(tos_, FieldMemOperand(tos_, String::kLengthOffset));
- // Return string length as boolean value, i.e. return false iff length is 0.
- __ Ret();
+ __ ldr(tos_, FieldMemOperand(tos_, String::kLengthOffset), lt);
+ __ Ret(lt); // the string length is OK as the return value
+ } else if (types_.Contains(INTERNAL_OBJECT)) {
+ // We've seen a string for the first time -> patch
+ __ CompareInstanceType(map, ip, FIRST_NONSTRING_TYPE);
+ __ b(lt, &patch);
+ }
- __ bind(¬_string);
- // HeapNumber -> false iff +0, -0, or NaN.
- __ CompareRoot(map, Heap::kHeapNumberMapRootIndex);
- __ b(&true_result, ne);
- __ vldr(d1, FieldMemOperand(tos_, HeapNumber::kValueOffset));
- __ VFPCompareAndSetFlags(d1, 0.0);
- // "tos_" is a register, and contains a non zero value by default.
- // Hence we only need to overwrite "tos_" with zero to return false for
- // FP_ZERO or FP_NAN cases. Otherwise, by default it returns true.
- __ mov(tos_, Operand(0, RelocInfo::NONE), LeaveCC, eq); // for FP_ZERO
- __ mov(tos_, Operand(0, RelocInfo::NONE), LeaveCC, vs); // for FP_NAN
- __ Ret();
+ if (types_.Contains(HEAP_NUMBER)) {
+ // Heap number -> false iff +0, -0, or NaN.
+ Label not_heap_number;
+ __ CompareRoot(map, Heap::kHeapNumberMapRootIndex);
+ __ b(ne, ¬_heap_number);
+ __ vldr(d1, FieldMemOperand(tos_, HeapNumber::kValueOffset));
+ __ VFPCompareAndSetFlags(d1, 0.0);
+ // "tos_" is a register, and contains a non zero value by default.
+ // Hence we only need to overwrite "tos_" with zero to return false for
+ // FP_ZERO or FP_NAN cases. Otherwise, by default it returns true.
+ __ mov(tos_, Operand(0, RelocInfo::NONE), LeaveCC, eq); // for FP_ZERO
+ __ mov(tos_, Operand(0, RelocInfo::NONE), LeaveCC, vs); // for FP_NAN
+ __ Ret();
+ __ bind(¬_heap_number);
+ } else if (types_.Contains(INTERNAL_OBJECT)) {
+ // We've seen a heap number for the first time -> patch
+ __ CompareRoot(map, Heap::kHeapNumberMapRootIndex);
+ __ b(eq, &patch);
+ }
- // Return 1/0 for true/false in tos_.
- __ bind(&true_result);
- __ mov(tos_, Operand(1, RelocInfo::NONE));
- __ Ret();
- __ bind(&false_result);
- __ mov(tos_, Operand(0, RelocInfo::NONE));
- __ Ret();
+ if (types_.Contains(INTERNAL_OBJECT)) {
+ // Internal objects -> true.
+ __ mov(tos_, Operand(1, RelocInfo::NONE));
+ __ Ret();
+ }
+
+ if (!types_.IsAll()) {
+ __ bind(&patch);
+ GenerateTypeTransition(masm);
+ }
+}
+
+
+void ToBooleanStub::CheckOddball(MacroAssembler* masm,
+ Type type,
+ Heap::RootListIndex value,
+ bool result,
+ Label* patch) {
+ if (types_.Contains(type)) {
+ // If we see an expected oddball, return its ToBoolean value tos_.
+ __ LoadRoot(ip, value);
+ __ cmp(tos_, ip);
+ // The value of a root is never NULL, so we can avoid loading a non-null
+ // value into tos_ when we want to return 'true'.
+ if (!result) {
+ __ mov(tos_, Operand(0, RelocInfo::NONE), LeaveCC, eq);
+ }
+ __ Ret(eq);
+ } else if (types_.Contains(INTERNAL_OBJECT)) {
+ // If we see an unexpected oddball and handle internal objects, we must
+ // patch because the code for internal objects doesn't handle it explictly.
+ __ LoadRoot(ip, value);
+ __ cmp(tos_, ip);
+ __ b(eq, patch);
+ }
+}
+
+
+void ToBooleanStub::GenerateTypeTransition(MacroAssembler* masm) {
+ if (!tos_.is(r3)) {
+ __ mov(r3, Operand(tos_));
+ }
+ __ mov(r2, Operand(Smi::FromInt(tos_.code())));
+ __ mov(r1, Operand(Smi::FromInt(types_.ToByte())));
+ __ Push(r3, r2, r1);
+ // Patch the caller to an appropriate specialized stub and return the
+ // operation result to the caller of the stub.
+ __ TailCallExternalReference(
+ ExternalReference(IC_Utility(IC::kToBoolean_Patch), masm->isolate()),
+ 3,
+ 1);
}
diff --git a/src/arm/deoptimizer-arm.cc b/src/arm/deoptimizer-arm.cc
index cd70e6d..9d9c045 100644
--- a/src/arm/deoptimizer-arm.cc
+++ b/src/arm/deoptimizer-arm.cc
@@ -35,7 +35,7 @@
namespace v8 {
namespace internal {
-int Deoptimizer::table_entry_size_ = 16;
+const int Deoptimizer::table_entry_size_ = 16;
int Deoptimizer::patch_size() {
@@ -65,8 +65,6 @@
// For each return after a safepoint insert an absolute call to the
// corresponding deoptimization entry.
- ASSERT(patch_size() % Assembler::kInstrSize == 0);
- int call_size_in_words = patch_size() / Assembler::kInstrSize;
unsigned last_pc_offset = 0;
SafepointTable table(function->code());
for (unsigned i = 0; i < table.length(); i++) {
@@ -87,13 +85,18 @@
#endif
last_pc_offset = pc_offset;
if (deoptimization_index != Safepoint::kNoDeoptimizationIndex) {
- last_pc_offset += gap_code_size;
- CodePatcher patcher(code->instruction_start() + last_pc_offset,
- call_size_in_words);
Address deoptimization_entry = Deoptimizer::GetDeoptimizationEntry(
deoptimization_index, Deoptimizer::LAZY);
+ last_pc_offset += gap_code_size;
+ int call_size_in_bytes = MacroAssembler::CallSize(deoptimization_entry,
+ RelocInfo::NONE);
+ int call_size_in_words = call_size_in_bytes / Assembler::kInstrSize;
+ ASSERT(call_size_in_bytes % Assembler::kInstrSize == 0);
+ ASSERT(call_size_in_bytes <= patch_size());
+ CodePatcher patcher(code->instruction_start() + last_pc_offset,
+ call_size_in_words);
patcher.masm()->Call(deoptimization_entry, RelocInfo::NONE);
- last_pc_offset += patch_size();
+ last_pc_offset += call_size_in_bytes;
}
}
@@ -530,8 +533,6 @@
output_frame->SetContinuation(
reinterpret_cast<uint32_t>(continuation->entry()));
}
-
- if (output_count_ - 1 == frame_index) iterator->Done();
}
diff --git a/src/arm/disasm-arm.cc b/src/arm/disasm-arm.cc
index d4bd81c..603b3cf 100644
--- a/src/arm/disasm-arm.cc
+++ b/src/arm/disasm-arm.cc
@@ -200,7 +200,7 @@
// These shift names are defined in a way to match the native disassembler
// formatting. See for example the command "objdump -d <binary file>".
-static const char* shift_names[kNumberOfShifts] = {
+static const char* const shift_names[kNumberOfShifts] = {
"lsl", "lsr", "asr", "ror"
};
diff --git a/src/arm/lithium-arm.cc b/src/arm/lithium-arm.cc
index ea06064..1eb4aff 100644
--- a/src/arm/lithium-arm.cc
+++ b/src/arm/lithium-arm.cc
@@ -1039,7 +1039,13 @@
: instr->SecondSuccessor();
return new LGoto(successor->block_id());
}
- return new LBranch(UseRegisterAtStart(v));
+ LInstruction* branch = new LBranch(UseRegister(v));
+ // When we handle all cases, we never deopt, so we don't need to assign the
+ // environment then. Note that we map the "empty" case to the "all" case in
+ // the code generator.
+ ToBooleanStub::Types types = instr->expected_input_types();
+ bool all_cases_handled = types.IsAll() || types.IsEmpty();
+ return all_cases_handled ? branch : AssignEnvironment(branch);
}
diff --git a/src/arm/lithium-codegen-arm.cc b/src/arm/lithium-codegen-arm.cc
index ee2bb84..3f3f31a 100644
--- a/src/arm/lithium-codegen-arm.cc
+++ b/src/arm/lithium-codegen-arm.cc
@@ -1564,52 +1564,138 @@
} else {
ASSERT(r.IsTagged());
Register reg = ToRegister(instr->InputAt(0));
- if (instr->hydrogen()->value()->type().IsBoolean()) {
- __ LoadRoot(ip, Heap::kTrueValueRootIndex);
- __ cmp(reg, ip);
+ HType type = instr->hydrogen()->value()->type();
+ if (type.IsBoolean()) {
+ __ CompareRoot(reg, Heap::kTrueValueRootIndex);
EmitBranch(true_block, false_block, eq);
+ } else if (type.IsSmi()) {
+ __ cmp(reg, Operand(0));
+ EmitBranch(true_block, false_block, ne);
} else {
Label* true_label = chunk_->GetAssemblyLabel(true_block);
Label* false_label = chunk_->GetAssemblyLabel(false_block);
- __ LoadRoot(ip, Heap::kUndefinedValueRootIndex);
- __ cmp(reg, ip);
- __ b(eq, false_label);
- __ LoadRoot(ip, Heap::kTrueValueRootIndex);
- __ cmp(reg, ip);
- __ b(eq, true_label);
- __ LoadRoot(ip, Heap::kFalseValueRootIndex);
- __ cmp(reg, ip);
- __ b(eq, false_label);
- __ cmp(reg, Operand(0));
- __ b(eq, false_label);
- __ JumpIfSmi(reg, true_label);
+ ToBooleanStub::Types expected = instr->hydrogen()->expected_input_types();
+ // Avoid deopts in the case where we've never executed this path before.
+ if (expected.IsEmpty()) expected = ToBooleanStub::all_types();
- // Test double values. Zero and NaN are false.
- Label call_stub;
- DoubleRegister dbl_scratch = double_scratch0();
- Register scratch = scratch0();
- __ ldr(scratch, FieldMemOperand(reg, HeapObject::kMapOffset));
- __ LoadRoot(ip, Heap::kHeapNumberMapRootIndex);
- __ cmp(scratch, Operand(ip));
- __ b(ne, &call_stub);
- __ sub(ip, reg, Operand(kHeapObjectTag));
- __ vldr(dbl_scratch, ip, HeapNumber::kValueOffset);
- __ VFPCompareAndLoadFlags(dbl_scratch, 0.0, scratch);
- __ tst(scratch, Operand(kVFPZConditionFlagBit | kVFPVConditionFlagBit));
- __ b(ne, false_label);
- __ b(true_label);
+ if (expected.Contains(ToBooleanStub::UNDEFINED)) {
+ // undefined -> false.
+ __ CompareRoot(reg, Heap::kUndefinedValueRootIndex);
+ __ b(eq, false_label);
+ } else if (expected.Contains(ToBooleanStub::INTERNAL_OBJECT)) {
+ // We've seen undefined for the first time -> deopt.
+ __ LoadRoot(ip, Heap::kUndefinedValueRootIndex);
+ DeoptimizeIf(eq, instr->environment());
+ }
- // The conversion stub doesn't cause garbage collections so it's
- // safe to not record a safepoint after the call.
- __ bind(&call_stub);
- ToBooleanStub stub(reg);
- RegList saved_regs = kJSCallerSaved | kCalleeSaved;
- __ stm(db_w, sp, saved_regs);
- __ CallStub(&stub);
- __ cmp(reg, Operand(0));
- __ ldm(ia_w, sp, saved_regs);
- EmitBranch(true_block, false_block, ne);
+ if (expected.Contains(ToBooleanStub::BOOLEAN)) {
+ // Boolean -> its value.
+ __ CompareRoot(reg, Heap::kTrueValueRootIndex);
+ __ b(eq, true_label);
+ __ CompareRoot(reg, Heap::kFalseValueRootIndex);
+ __ b(eq, false_label);
+ } else if (expected.Contains(ToBooleanStub::INTERNAL_OBJECT)) {
+ // We've seen a boolean for the first time -> deopt.
+ __ CompareRoot(reg, Heap::kTrueValueRootIndex);
+ DeoptimizeIf(eq, instr->environment());
+ __ CompareRoot(reg, Heap::kFalseValueRootIndex);
+ DeoptimizeIf(eq, instr->environment());
+ }
+
+#if 0
+ if (expected.Contains(ToBooleanStub::BOOLEAN)) {
+ // false -> false.
+ __ CompareRoot(reg, Heap::kFalseValueRootIndex);
+ __ b(eq, false_label);
+ } else if (expected.Contains(ToBooleanStub::INTERNAL_OBJECT)) {
+ // We've seen a boolean for the first time -> deopt.
+ __ CompareRoot(reg, Heap::kFalseValueRootIndex);
+ DeoptimizeIf(eq, instr->environment());
+ }
+#endif
+
+ if (expected.Contains(ToBooleanStub::NULL_TYPE)) {
+ // 'null' -> false.
+ __ CompareRoot(reg, Heap::kNullValueRootIndex);
+ __ b(eq, false_label);
+ } else if (expected.Contains(ToBooleanStub::INTERNAL_OBJECT)) {
+ // We've seen null for the first time -> deopt.
+ __ CompareRoot(reg, Heap::kNullValueRootIndex);
+ DeoptimizeIf(eq, instr->environment());
+ }
+
+ if (expected.Contains(ToBooleanStub::SMI)) {
+ // Smis: 0 -> false, all other -> true.
+ __ cmp(reg, Operand(0));
+ __ b(eq, false_label);
+ __ JumpIfSmi(reg, true_label);
+ } else if (expected.NeedsMap()) {
+ // If we need a map later and have a Smi -> deopt.
+ __ tst(reg, Operand(kSmiTagMask));
+ DeoptimizeIf(eq, instr->environment());
+ }
+
+ const Register map = scratch0();
+ if (expected.NeedsMap()) {
+ __ ldr(map, FieldMemOperand(reg, HeapObject::kMapOffset));
+ // Everything with a map could be undetectable, so check this now.
+ __ ldrb(ip, FieldMemOperand(map, Map::kBitFieldOffset));
+ __ tst(ip, Operand(1 << Map::kIsUndetectable));
+ __ b(ne, false_label);
+ }
+
+ if (expected.Contains(ToBooleanStub::SPEC_OBJECT)) {
+ // spec object -> true.
+ __ CompareInstanceType(map, ip, FIRST_SPEC_OBJECT_TYPE);
+ __ b(ge, true_label);
+ } else if (expected.Contains(ToBooleanStub::INTERNAL_OBJECT)) {
+ // We've seen a spec object for the first time -> deopt.
+ __ CompareInstanceType(map, ip, FIRST_SPEC_OBJECT_TYPE);
+ DeoptimizeIf(ge, instr->environment());
+ }
+
+ if (expected.Contains(ToBooleanStub::STRING)) {
+ // String value -> false iff empty.
+ Label not_string;
+ __ CompareInstanceType(map, ip, FIRST_NONSTRING_TYPE);
+ __ b(ge, ¬_string);
+ __ ldr(ip, FieldMemOperand(reg, String::kLengthOffset));
+ __ cmp(ip, Operand(0));
+ __ b(ne, true_label);
+ __ b(false_label);
+ __ bind(¬_string);
+ } else if (expected.Contains(ToBooleanStub::INTERNAL_OBJECT)) {
+ // We've seen a string for the first time -> deopt
+ __ CompareInstanceType(map, ip, FIRST_NONSTRING_TYPE);
+ DeoptimizeIf(lt, instr->environment());
+ }
+
+ if (expected.Contains(ToBooleanStub::HEAP_NUMBER)) {
+ // heap number -> false iff +0, -0, or NaN.
+ DoubleRegister dbl_scratch = double_scratch0();
+ Label not_heap_number;
+ __ CompareRoot(map, Heap::kHeapNumberMapRootIndex);
+ __ b(ne, ¬_heap_number);
+ __ vldr(dbl_scratch, FieldMemOperand(reg, HeapNumber::kValueOffset));
+ __ VFPCompareAndSetFlags(dbl_scratch, 0.0);
+ __ b(vs, false_label); // NaN -> false.
+ __ b(eq, false_label); // +0, -0 -> false.
+ __ b(true_label);
+ __ bind(¬_heap_number);
+ } else if (expected.Contains(ToBooleanStub::INTERNAL_OBJECT)) {
+ // We've seen a heap number for the first time -> deopt.
+ __ CompareRoot(map, Heap::kHeapNumberMapRootIndex);
+ DeoptimizeIf(eq, instr->environment());
+ }
+
+ if (expected.Contains(ToBooleanStub::INTERNAL_OBJECT)) {
+ // internal objects -> true
+ __ b(true_label);
+ } else {
+ // We've seen something for the first time -> deopt.
+ DeoptimizeIf(al, instr->environment());
+ }
}
}
}
diff --git a/src/arm/macro-assembler-arm.h b/src/arm/macro-assembler-arm.h
index 07281a7..9c653ad 100644
--- a/src/arm/macro-assembler-arm.h
+++ b/src/arm/macro-assembler-arm.h
@@ -92,14 +92,16 @@
void Jump(Register target, Condition cond = al);
void Jump(Address target, RelocInfo::Mode rmode, Condition cond = al);
void Jump(Handle<Code> code, RelocInfo::Mode rmode, Condition cond = al);
- int CallSize(Register target, Condition cond = al);
+ static int CallSize(Register target, Condition cond = al);
void Call(Register target, Condition cond = al);
- int CallSize(Address target, RelocInfo::Mode rmode, Condition cond = al);
+ static int CallSize(Address target,
+ RelocInfo::Mode rmode,
+ Condition cond = al);
void Call(Address target, RelocInfo::Mode rmode, Condition cond = al);
- int CallSize(Handle<Code> code,
- RelocInfo::Mode rmode = RelocInfo::CODE_TARGET,
- unsigned ast_id = kNoASTId,
- Condition cond = al);
+ static int CallSize(Handle<Code> code,
+ RelocInfo::Mode rmode = RelocInfo::CODE_TARGET,
+ unsigned ast_id = kNoASTId,
+ Condition cond = al);
void Call(Handle<Code> code,
RelocInfo::Mode rmode = RelocInfo::CODE_TARGET,
unsigned ast_id = kNoASTId,
diff --git a/src/assembler.cc b/src/assembler.cc
index fbd8089..ad5f350 100644
--- a/src/assembler.cc
+++ b/src/assembler.cc
@@ -74,7 +74,7 @@
const double DoubleConstant::canonical_non_hole_nan = OS::nan_value();
const double DoubleConstant::the_hole_nan = BitCast<double>(kHoleNanInt64);
const double DoubleConstant::negative_infinity = -V8_INFINITY;
-const char* RelocInfo::kFillerCommentString = "DEOPTIMIZATION PADDING";
+const char* const RelocInfo::kFillerCommentString = "DEOPTIMIZATION PADDING";
// -----------------------------------------------------------------------------
// Implementation of AssemblerBase
diff --git a/src/assembler.h b/src/assembler.h
index 2d14f06..d58034d 100644
--- a/src/assembler.h
+++ b/src/assembler.h
@@ -171,7 +171,7 @@
// where we are not sure to have enough space for patching in during
// lazy deoptimization. This is the case if we have indirect calls for which
// we do not normally record relocation info.
- static const char* kFillerCommentString;
+ static const char* const kFillerCommentString;
// The minimum size of a comment is equal to three bytes for the extra tagged
// pc + the tag for the data, and kPointerSize for the actual pointer to the
diff --git a/src/ast.h b/src/ast.h
index 23df48b..b4705f6 100644
--- a/src/ast.h
+++ b/src/ast.h
@@ -1711,6 +1711,12 @@
class FunctionLiteral: public Expression {
public:
+ enum Type {
+ ANONYMOUS_EXPRESSION,
+ NAMED_EXPRESSION,
+ DECLARATION
+ };
+
FunctionLiteral(Isolate* isolate,
Handle<String> name,
Scope* scope,
@@ -1722,7 +1728,7 @@
int num_parameters,
int start_position,
int end_position,
- bool is_expression,
+ Type type,
bool has_duplicate_parameters)
: Expression(isolate),
name_(name),
@@ -1738,7 +1744,8 @@
end_position_(end_position),
function_token_position_(RelocInfo::kNoPosition),
inferred_name_(HEAP->empty_string()),
- is_expression_(is_expression),
+ is_expression_(type != DECLARATION),
+ is_anonymous_(type == ANONYMOUS_EXPRESSION),
pretenure_(false),
has_duplicate_parameters_(has_duplicate_parameters) {
}
@@ -1753,6 +1760,7 @@
int start_position() const { return start_position_; }
int end_position() const { return end_position_; }
bool is_expression() const { return is_expression_; }
+ bool is_anonymous() const { return is_anonymous_; }
bool strict_mode() const;
int materialized_literal_count() { return materialized_literal_count_; }
@@ -1797,6 +1805,7 @@
int function_token_position_;
Handle<String> inferred_name_;
bool is_expression_;
+ bool is_anonymous_;
bool pretenure_;
bool has_duplicate_parameters_;
};
diff --git a/src/bootstrapper.cc b/src/bootstrapper.cc
index 8cca561..a5cb555 100644
--- a/src/bootstrapper.cc
+++ b/src/bootstrapper.cc
@@ -199,6 +199,7 @@
// New context initialization. Used for creating a context from scratch.
void InitializeGlobal(Handle<GlobalObject> inner_global,
Handle<JSFunction> empty_function);
+ void InitializeExperimentalGlobal();
// Installs the contents of the native .js files on the global objects.
// Used for creating a context from scratch.
void InstallNativeFunctions();
@@ -1190,6 +1191,21 @@
}
+void Genesis::InitializeExperimentalGlobal() {
+ Isolate* isolate = this->isolate();
+ Handle<JSObject> global = Handle<JSObject>(global_context()->global());
+
+ // TODO(mstarzinger): Move this into Genesis::InitializeGlobal once we no
+ // longer need to live behind a flag, so WeakMap gets added to the snapshot.
+ if (FLAG_harmony_weakmaps) { // -- W e a k M a p
+ Handle<JSFunction> weakmap_fun =
+ InstallFunction(global, "WeakMap", JS_WEAK_MAP_TYPE, JSWeakMap::kSize,
+ isolate->initial_object_prototype(),
+ Builtins::kIllegal, true);
+ }
+}
+
+
bool Genesis::CompileBuiltin(Isolate* isolate, int index) {
Vector<const char> name = Natives::GetScriptName(index);
Handle<String> source_code =
@@ -1680,6 +1696,11 @@
"native proxy.js") == 0) {
if (!CompileExperimentalBuiltin(isolate(), i)) return false;
}
+ if (FLAG_harmony_weakmaps &&
+ strcmp(ExperimentalNatives::GetScriptName(i).start(),
+ "native weakmap.js") == 0) {
+ if (!CompileExperimentalBuiltin(isolate(), i)) return false;
+ }
}
InstallExperimentalNativeFunctions();
@@ -2169,7 +2190,8 @@
isolate->counters()->contexts_created_from_scratch()->Increment();
}
- // Install experimental natives.
+ // Initialize experimental globals and install experimental natives.
+ InitializeExperimentalGlobal();
if (!InstallExperimentalNatives()) return;
result_ = global_context_;
diff --git a/src/codegen.cc b/src/codegen.cc
index fb723a3..cdc9ba1 100644
--- a/src/codegen.cc
+++ b/src/codegen.cc
@@ -169,7 +169,6 @@
#endif // ENABLE_DISASSEMBLER
}
-static Vector<const char> kRegexp = CStrVector("regexp");
bool CodeGenerator::ShouldGenerateLog(Expression* type) {
ASSERT(type != NULL);
@@ -179,7 +178,7 @@
}
Handle<String> name = Handle<String>::cast(type->AsLiteral()->handle());
if (FLAG_log_regexp) {
- if (name->IsEqualTo(kRegexp))
+ if (name->IsEqualTo(CStrVector("regexp")))
return true;
}
return false;
diff --git a/src/compiler.cc b/src/compiler.cc
index c265b95..a87eecc 100755
--- a/src/compiler.cc
+++ b/src/compiler.cc
@@ -736,6 +736,7 @@
function_info->set_start_position(lit->start_position());
function_info->set_end_position(lit->end_position());
function_info->set_is_expression(lit->is_expression());
+ function_info->set_is_anonymous(lit->is_anonymous());
function_info->set_is_toplevel(is_toplevel);
function_info->set_inferred_name(*lit->inferred_name());
function_info->SetThisPropertyAssignmentsInfo(
diff --git a/src/d8.cc b/src/d8.cc
index f4ace87..3b9c183 100644
--- a/src/d8.cc
+++ b/src/d8.cc
@@ -26,8 +26,8 @@
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-#ifdef V8_SHARED
-#define USING_V8_SHARED
+#ifdef USING_V8_SHARED // Defined when linking against shared lib on Windows.
+#define V8_SHARED
#endif
#ifdef COMPRESS_STARTUP_DATA_BZ2
@@ -37,15 +37,16 @@
#include <errno.h>
#include <stdlib.h>
#include <string.h>
+#include <sys/stat.h>
-#ifdef USING_V8_SHARED
+#ifdef V8_SHARED
#include <assert.h>
#include "../include/v8-testing.h"
-#endif // USING_V8_SHARED
+#endif // V8_SHARED
#include "d8.h"
-#ifndef USING_V8_SHARED
+#ifndef V8_SHARED
#include "api.h"
#include "checks.h"
#include "d8-debug.h"
@@ -53,20 +54,20 @@
#include "natives.h"
#include "platform.h"
#include "v8.h"
-#endif // USING_V8_SHARED
+#endif // V8_SHARED
#if !defined(_WIN32) && !defined(_WIN64)
#include <unistd.h> // NOLINT
#endif
-#ifdef USING_V8_SHARED
+#ifndef ASSERT
#define ASSERT(condition) assert(condition)
-#endif // USING_V8_SHARED
+#endif
namespace v8 {
-#ifndef USING_V8_SHARED
+#ifndef V8_SHARED
LineEditor *LineEditor::first_ = NULL;
const char* Shell::kHistoryFileName = ".d8_history";
@@ -116,20 +117,20 @@
CounterCollection* Shell::counters_ = &local_counters_;
i::Mutex* Shell::context_mutex_(i::OS::CreateMutex());
Persistent<Context> Shell::utility_context_;
-#endif // USING_V8_SHARED
+#endif // V8_SHARED
Persistent<Context> Shell::evaluation_context_;
ShellOptions Shell::options;
const char* Shell::kPrompt = "d8> ";
-#ifndef USING_V8_SHARED
+#ifndef V8_SHARED
bool CounterMap::Match(void* key1, void* key2) {
const char* name1 = reinterpret_cast<const char*>(key1);
const char* name2 = reinterpret_cast<const char*>(key2);
return strcmp(name1, name2) == 0;
}
-#endif // USING_V8_SHARED
+#endif // V8_SHARED
// Converts a V8 value to a C string.
@@ -143,11 +144,11 @@
Handle<Value> name,
bool print_result,
bool report_exceptions) {
-#ifndef USING_V8_SHARED
+#ifndef V8_SHARED
bool FLAG_debugger = i::FLAG_debugger;
#else
bool FLAG_debugger = false;
-#endif // USING_V8_SHARED
+#endif // V8_SHARED
HandleScope handle_scope;
TryCatch try_catch;
options.script_executed = true;
@@ -276,9 +277,9 @@
String::New("Array constructor needs one parameter."));
}
static const int kMaxLength = 0x3fffffff;
-#ifndef USING_V8_SHARED
+#ifndef V8_SHARED
ASSERT(kMaxLength == i::ExternalArray::kMaxLength);
-#endif // USING_V8_SHARED
+#endif // V8_SHARED
size_t length = 0;
if (args[0]->IsUint32()) {
length = args[0]->Uint32Value();
@@ -378,9 +379,9 @@
Handle<Value> Shell::Quit(const Arguments& args) {
int exit_code = args[0]->Int32Value();
-#ifndef USING_V8_SHARED
+#ifndef V8_SHARED
OnExit();
-#endif // USING_V8_SHARED
+#endif // V8_SHARED
exit(exit_code);
return Undefined();
}
@@ -429,7 +430,7 @@
}
-#ifndef USING_V8_SHARED
+#ifndef V8_SHARED
Handle<Array> Shell::GetCompletions(Handle<String> text, Handle<String> full) {
HandleScope handle_scope;
Context::Scope context_scope(utility_context_);
@@ -464,10 +465,10 @@
return val;
}
#endif // ENABLE_DEBUGGER_SUPPORT
-#endif // USING_V8_SHARED
+#endif // V8_SHARED
-#ifndef USING_V8_SHARED
+#ifndef V8_SHARED
int32_t* Counter::Bind(const char* name, bool is_histogram) {
int i;
for (i = 0; i < kMaxNameSize - 1 && name[i]; i++)
@@ -615,7 +616,7 @@
}
#endif // ENABLE_DEBUGGER_SUPPORT
}
-#endif // USING_V8_SHARED
+#endif // V8_SHARED
#ifdef COMPRESS_STARTUP_DATA_BZ2
@@ -682,11 +683,11 @@
global_template->Set(String::New("lol_is_enabled"), Boolean::New(false));
#endif
-#ifndef USING_V8_SHARED
+#ifndef V8_SHARED
Handle<ObjectTemplate> os_templ = ObjectTemplate::New();
AddOSMethods(os_templ);
global_template->Set(String::New("os"), os_templ);
-#endif // USING_V8_SHARED
+#endif // V8_SHARED
return global_template;
}
@@ -702,7 +703,7 @@
}
#endif
-#ifndef USING_V8_SHARED
+#ifndef V8_SHARED
Shell::counter_map_ = new CounterMap();
// Set up counters
if (i::StrLength(i::FLAG_map_counters) != 0)
@@ -712,10 +713,10 @@
V8::SetCreateHistogramFunction(CreateHistogram);
V8::SetAddHistogramSampleFunction(AddHistogramSample);
}
-#endif // USING_V8_SHARED
+#endif // V8_SHARED
if (options.test_shell) return;
-#ifndef USING_V8_SHARED
+#ifndef V8_SHARED
Locker lock;
HandleScope scope;
Handle<ObjectTemplate> global_template = CreateGlobalTemplate();
@@ -727,21 +728,21 @@
v8::Debug::EnableAgent("d8 shell", i::FLAG_debugger_port, true);
}
#endif // ENABLE_DEBUGGER_SUPPORT
-#endif // USING_V8_SHARED
+#endif // V8_SHARED
}
Persistent<Context> Shell::CreateEvaluationContext() {
-#ifndef USING_V8_SHARED
+#ifndef V8_SHARED
// This needs to be a critical section since this is not thread-safe
i::ScopedLock lock(context_mutex_);
-#endif // USING_V8_SHARED
+#endif // V8_SHARED
// Initialize the global objects
Handle<ObjectTemplate> global_template = CreateGlobalTemplate();
Persistent<Context> context = Context::New(NULL, global_template);
Context::Scope scope(context);
-#ifndef USING_V8_SHARED
+#ifndef V8_SHARED
i::JSArguments js_args = i::FLAG_js_arguments;
i::Handle<i::FixedArray> arguments_array =
FACTORY->NewFixedArray(js_args.argc());
@@ -754,12 +755,12 @@
FACTORY->NewJSArrayWithElements(arguments_array);
context->Global()->Set(String::New("arguments"),
Utils::ToLocal(arguments_jsarray));
-#endif // USING_V8_SHARED
+#endif // V8_SHARED
return context;
}
-#ifndef USING_V8_SHARED
+#ifndef V8_SHARED
void Shell::OnExit() {
if (i::FLAG_dump_counters) {
printf("+----------------------------------------+-------------+\n");
@@ -779,18 +780,34 @@
if (counters_file_ != NULL)
delete counters_file_;
}
-#endif // USING_V8_SHARED
+#endif // V8_SHARED
+
+
+static FILE* FOpen(const char* path, const char* mode) {
+#if (defined(_WIN32) || defined(_WIN64))
+ FILE* result;
+ if (fopen_s(&result, path, mode) == 0) {
+ return result;
+ } else {
+ return NULL;
+ }
+#else
+ FILE* file = fopen(path, mode);
+ if (file == NULL) return NULL;
+ struct stat file_stat;
+ if (fstat(fileno(file), &file_stat) != 0) return NULL;
+ bool is_regular_file = ((file_stat.st_mode & S_IFREG) != 0);
+ if (is_regular_file) return file;
+ fclose(file);
+ return NULL;
+#endif
+}
static char* ReadChars(const char* name, int* size_out) {
// Release the V8 lock while reading files.
v8::Unlocker unlocker(Isolate::GetCurrent());
-#ifndef USING_V8_SHARED
- FILE* file = i::OS::FOpen(name, "rb");
-#else
- // TODO(yangguo@chromium.org): reading from a directory hangs!
- FILE* file = fopen(name, "rb");
-#endif // USING_V8_SHARED
+ FILE* file = FOpen(name, "rb");
if (file == NULL) return NULL;
fseek(file, 0, SEEK_END);
@@ -809,7 +826,7 @@
}
-#ifndef USING_V8_SHARED
+#ifndef V8_SHARED
static char* ReadToken(char* data, char token) {
char* next = i::OS::StrChr(data, token);
if (next != NULL) {
@@ -829,7 +846,7 @@
static char* ReadWord(char* data) {
return ReadToken(data, ' ');
}
-#endif // USING_V8_SHARED
+#endif // V8_SHARED
// Reads a file into a v8 string.
@@ -848,7 +865,7 @@
Context::Scope context_scope(evaluation_context_);
HandleScope handle_scope;
Handle<String> name = String::New("(d8)");
-#ifndef USING_V8_SHARED
+#ifndef V8_SHARED
LineEditor* editor = LineEditor::Get();
printf("V8 version %s [console: %s]\n", V8::GetVersion(), editor->name());
if (i::FLAG_debugger) {
@@ -871,12 +888,12 @@
if (fgets(buffer, kBufferSize, stdin) == NULL) break;
ExecuteString(String::New(buffer), name, true, true);
}
-#endif // USING_V8_SHARED
+#endif // V8_SHARED
printf("\n");
}
-#ifndef USING_V8_SHARED
+#ifndef V8_SHARED
class ShellThread : public i::Thread {
public:
ShellThread(int no, i::Vector<const char> files)
@@ -929,7 +946,7 @@
ptr = next_line;
}
}
-#endif // USING_V8_SHARED
+#endif // V8_SHARED
void SourceGroup::ExitShell(int exit_code) {
@@ -976,32 +993,16 @@
Handle<String> SourceGroup::ReadFile(const char* name) {
-#ifndef USING_V8_SHARED
- FILE* file = i::OS::FOpen(name, "rb");
-#else
- // TODO(yangguo@chromium.org): reading from a directory hangs!
- FILE* file = fopen(name, "rb");
-#endif // USING_V8_SHARED
- if (file == NULL) return Handle<String>();
-
- fseek(file, 0, SEEK_END);
- int size = ftell(file);
- rewind(file);
-
- char* chars = new char[size + 1];
- chars[size] = '\0';
- for (int i = 0; i < size;) {
- int read = static_cast<int>(fread(&chars[i], 1, size - i, file));
- i += read;
- }
- fclose(file);
+ int size;
+ const char* chars = ReadChars(name, &size);
+ if (chars == NULL) return Handle<String>();
Handle<String> result = String::New(chars, size);
delete[] chars;
return result;
}
-#ifndef USING_V8_SHARED
+#ifndef V8_SHARED
i::Thread::Options SourceGroup::GetThreadOptions() {
i::Thread::Options options;
options.name = "IsolateThread";
@@ -1053,7 +1054,7 @@
done_semaphore_->Wait();
}
}
-#endif // USING_V8_SHARED
+#endif // V8_SHARED
bool Shell::SetOptions(int argc, char* argv[]) {
@@ -1075,23 +1076,23 @@
options.test_shell = true;
argv[i] = NULL;
} else if (strcmp(argv[i], "--preemption") == 0) {
-#ifdef USING_V8_SHARED
+#ifdef V8_SHARED
printf("D8 with shared library does not support multi-threading\n");
return false;
#else
options.use_preemption = true;
argv[i] = NULL;
-#endif // USING_V8_SHARED
+#endif // V8_SHARED
} else if (strcmp(argv[i], "--no-preemption") == 0) {
-#ifdef USING_V8_SHARED
+#ifdef V8_SHARED
printf("D8 with shared library does not support multi-threading\n");
return false;
#else
options.use_preemption = false;
argv[i] = NULL;
-#endif // USING_V8_SHARED
+#endif // V8_SHARED
} else if (strcmp(argv[i], "--preemption-interval") == 0) {
-#ifdef USING_V8_SHARED
+#ifdef V8_SHARED
printf("D8 with shared library does not support multi-threading\n");
return false;
#else
@@ -1110,19 +1111,19 @@
printf("Missing value for --preemption-interval\n");
return false;
}
-#endif // USING_V8_SHARED
+#endif // V8_SHARED
} else if (strcmp(argv[i], "-f") == 0) {
// Ignore any -f flags for compatibility with other stand-alone
// JavaScript engines.
continue;
} else if (strcmp(argv[i], "--isolate") == 0) {
-#ifdef USING_V8_SHARED
+#ifdef V8_SHARED
printf("D8 with shared library does not support multi-threading\n");
return false;
-#endif // USING_V8_SHARED
+#endif // V8_SHARED
options.num_isolates++;
}
-#ifdef USING_V8_SHARED
+#ifdef V8_SHARED
else if (strcmp(argv[i], "--dump-counters") == 0) {
printf("D8 with shared library does not include counters\n");
return false;
@@ -1133,10 +1134,10 @@
printf("Javascript debugger not included\n");
return false;
}
-#endif // USING_V8_SHARED
+#endif // V8_SHARED
}
-#ifndef USING_V8_SHARED
+#ifndef V8_SHARED
// Run parallel threads if we are not using --isolate
for (int i = 1; i < argc; i++) {
if (argv[i] == NULL) continue;
@@ -1157,9 +1158,10 @@
}
argv[i] = NULL;
options.parallel_files->Add(i::Vector<const char>(files, size));
+ delete[] files;
}
}
-#endif // USING_V8_SHARED
+#endif // V8_SHARED
v8::V8::SetFlagsFromCommandLine(&argc, argv, true);
@@ -1184,7 +1186,7 @@
int Shell::RunMain(int argc, char* argv[]) {
-#ifndef USING_V8_SHARED
+#ifndef V8_SHARED
i::List<i::Thread*> threads(1);
if (options.parallel_files != NULL)
for (int i = 0; i < options.parallel_files->length(); i++) {
@@ -1197,7 +1199,7 @@
for (int i = 1; i < options.num_isolates; ++i) {
options.isolate_sources[i].StartExecuteInThread();
}
-#endif // USING_V8_SHARED
+#endif // V8_SHARED
{ // NOLINT
Locker lock;
HandleScope scope;
@@ -1213,17 +1215,17 @@
context.Dispose();
}
-#ifndef USING_V8_SHARED
+#ifndef V8_SHARED
// Start preemption if threads have been created and preemption is enabled.
if (options.parallel_files != NULL
&& threads.length() > 0
&& options.use_preemption) {
Locker::StartPreemption(options.preemption_interval);
}
-#endif // USING_V8_SHARED
+#endif // V8_SHARED
}
-#ifndef USING_V8_SHARED
+#ifndef V8_SHARED
for (int i = 1; i < options.num_isolates; ++i) {
options.isolate_sources[i].WaitForThread();
}
@@ -1236,7 +1238,7 @@
}
OnExit();
-#endif // USING_V8_SHARED
+#endif // V8_SHARED
return 0;
}
@@ -1264,14 +1266,14 @@
}
-#if !defined(USING_V8_SHARED) && defined(ENABLE_DEBUGGER_SUPPORT)
+#if !defined(V8_SHARED) && defined(ENABLE_DEBUGGER_SUPPORT)
// Run remote debugger if requested, but never on --test
if (i::FLAG_remote_debugger && !options.test_shell) {
InstallUtilityScript();
RunRemoteDebugger(i::FLAG_debugger_port);
return 0;
}
-#endif // !USING_V8_SHARED && ENABLE_DEBUGGER_SUPPORT
+#endif // !V8_SHARED && ENABLE_DEBUGGER_SUPPORT
// Run interactive shell if explicitly requested or if no script has been
// executed, but never on --test
@@ -1279,9 +1281,9 @@
if (( options.interactive_shell
|| !options.script_executed )
&& !options.test_shell ) {
-#ifndef USING_V8_SHARED
+#ifndef V8_SHARED
InstallUtilityScript();
-#endif // USING_V8_SHARED
+#endif // V8_SHARED
RunShell();
}
diff --git a/src/d8.gyp b/src/d8.gyp
index d2b4254..2d9af78 100644
--- a/src/d8.gyp
+++ b/src/d8.gyp
@@ -47,9 +47,17 @@
],
'conditions': [
[ 'component!="shared_library"', {
- 'dependencies': [ 'd8_js2c#host', ],
'sources': [ 'd8-debug.cc', '<(SHARED_INTERMEDIATE_DIR)/d8-js.cc', ],
'conditions': [
+ [ 'want_separate_host_toolset==1', {
+ 'dependencies': [
+ 'd8_js2c#host',
+ ],
+ }, {
+ 'dependencies': [
+ 'd8_js2c',
+ ],
+ }],
[ 'console=="readline"', {
'libraries': [ '-lreadline', ],
'sources': [ 'd8-readline.cc' ],
@@ -68,13 +76,19 @@
{
'target_name': 'd8_js2c',
'type': 'none',
- 'toolsets': ['host'],
'variables': {
'js_files': [
'd8.js',
'macros.py',
],
},
+ 'conditions': [
+ [ 'want_separate_host_toolset==1', {
+ 'toolsets': ['host'],
+ }, {
+ 'toolsets': ['target'],
+ }]
+ ],
'actions': [
{
'action_name': 'd8_js2c',
@@ -90,6 +104,7 @@
'../tools/js2c.py',
'<@(_outputs)',
'D8',
+ 'off', # compress startup data
'<@(js_files)'
],
},
diff --git a/src/d8.h b/src/d8.h
index 840ca1e..40cc83b 100644
--- a/src/d8.h
+++ b/src/d8.h
@@ -29,22 +29,22 @@
#define V8_D8_H_
-#ifndef USING_V8_SHARED
+#ifndef V8_SHARED
#include "v8.h"
#include "allocation.h"
#include "hashmap.h"
#else
#include "../include/v8.h"
-#endif // USING_V8_SHARED
+#endif // V8_SHARED
namespace v8 {
-#ifndef USING_V8_SHARED
+#ifndef V8_SHARED
namespace i = v8::internal;
-#endif // USING_V8_SHARED
+#endif // V8_SHARED
-#ifndef USING_V8_SHARED
+#ifndef V8_SHARED
// A single counter in a counter collection.
class Counter {
public:
@@ -117,17 +117,17 @@
static bool Match(void* key1, void* key2);
i::HashMap hash_map_;
};
-#endif // USING_V8_SHARED
+#endif // V8_SHARED
class SourceGroup {
public:
SourceGroup() :
-#ifndef USING_V8_SHARED
+#ifndef V8_SHARED
next_semaphore_(v8::internal::OS::CreateSemaphore(0)),
done_semaphore_(v8::internal::OS::CreateSemaphore(0)),
thread_(NULL),
-#endif // USING_V8_SHARED
+#endif // V8_SHARED
argv_(NULL),
begin_offset_(0),
end_offset_(0) { }
@@ -141,7 +141,7 @@
void Execute();
-#ifndef USING_V8_SHARED
+#ifndef V8_SHARED
void StartExecuteInThread();
void WaitForThread();
@@ -165,7 +165,7 @@
i::Semaphore* next_semaphore_;
i::Semaphore* done_semaphore_;
i::Thread* thread_;
-#endif // USING_V8_SHARED
+#endif // V8_SHARED
void ExitShell(int exit_code);
Handle<String> ReadFile(const char* name);
@@ -179,11 +179,11 @@
class ShellOptions {
public:
ShellOptions() :
-#ifndef USING_V8_SHARED
+#ifndef V8_SHARED
use_preemption(true),
preemption_interval(10),
parallel_files(NULL),
-#endif // USING_V8_SHARED
+#endif // V8_SHARED
script_executed(false),
last_run(true),
stress_opt(false),
@@ -193,11 +193,11 @@
num_isolates(1),
isolate_sources(NULL) { }
-#ifndef USING_V8_SHARED
+#ifndef V8_SHARED
bool use_preemption;
int preemption_interval;
i::List< i::Vector<const char> >* parallel_files;
-#endif // USING_V8_SHARED
+#endif // V8_SHARED
bool script_executed;
bool last_run;
bool stress_opt;
@@ -208,11 +208,11 @@
SourceGroup* isolate_sources;
};
-#ifdef USING_V8_SHARED
+#ifdef V8_SHARED
class Shell {
#else
class Shell : public i::AllStatic {
-#endif // USING_V8_SHARED
+#endif // V8_SHARED
public:
static bool ExecuteString(Handle<String> source,
Handle<Value> name,
@@ -225,7 +225,7 @@
static int RunMain(int argc, char* argv[]);
static int Main(int argc, char* argv[]);
-#ifndef USING_V8_SHARED
+#ifndef V8_SHARED
static Handle<Array> GetCompletions(Handle<String> text,
Handle<String> full);
static void OnExit();
@@ -236,7 +236,7 @@
size_t buckets);
static void AddHistogramSample(void* histogram, int sample);
static void MapCounters(const char* name);
-#endif // USING_V8_SHARED
+#endif // V8_SHARED
#ifdef ENABLE_DEBUGGER_SUPPORT
static Handle<Object> DebugMessageDetails(Handle<String> message);
@@ -300,15 +300,15 @@
static Handle<Value> RemoveDirectory(const Arguments& args);
static void AddOSMethods(Handle<ObjectTemplate> os_template);
-#ifndef USING_V8_SHARED
+#ifndef V8_SHARED
static const char* kHistoryFileName;
-#endif // USING_V8_SHARED
+#endif // V8_SHARED
static const char* kPrompt;
static ShellOptions options;
private:
static Persistent<Context> evaluation_context_;
-#ifndef USING_V8_SHARED
+#ifndef V8_SHARED
static Persistent<Context> utility_context_;
static CounterMap* counter_map_;
// We statically allocate a set of local counters to be used if we
@@ -320,7 +320,7 @@
static Counter* GetCounter(const char* name, bool is_histogram);
static void InstallUtilityScript();
-#endif // USING_V8_SHARED
+#endif // V8_SHARED
static void Initialize();
static void RunShell();
static bool SetOptions(int argc, char* argv[]);
@@ -332,7 +332,7 @@
};
-#ifndef USING_V8_SHARED
+#ifndef V8_SHARED
class LineEditor {
public:
enum Type { DUMB = 0, READLINE = 1 };
@@ -352,7 +352,7 @@
LineEditor* next_;
static LineEditor* first_;
};
-#endif // USING_V8_SHARED
+#endif // V8_SHARED
} // namespace v8
diff --git a/src/debug.cc b/src/debug.cc
index 5024bce..2d58ce1 100644
--- a/src/debug.cc
+++ b/src/debug.cc
@@ -1965,7 +1965,7 @@
Debugger::Debugger(Isolate* isolate)
- : debugger_access_(OS::CreateMutex()),
+ : debugger_access_(isolate->debugger_access()),
event_listener_(Handle<Object>()),
event_listener_data_(Handle<Object>()),
compiling_natives_(false),
@@ -1987,8 +1987,6 @@
Debugger::~Debugger() {
- delete debugger_access_;
- debugger_access_ = 0;
delete dispatch_handler_access_;
dispatch_handler_access_ = 0;
delete command_received_;
diff --git a/src/deoptimizer.cc b/src/deoptimizer.cc
index 3a7b33a..5feb73d 100644
--- a/src/deoptimizer.cc
+++ b/src/deoptimizer.cc
@@ -1183,11 +1183,11 @@
int32_t TranslationIterator::Next() {
- ASSERT(HasNext());
// Run through the bytes until we reach one with a least significant
// bit of zero (marks the end).
uint32_t bits = 0;
for (int i = 0; true; i += 7) {
+ ASSERT(HasNext());
uint8_t next = buffer_->get(index_++);
bits |= (next >> 1) << i;
if ((next & 1) == 0) break;
@@ -1438,6 +1438,7 @@
UNREACHABLE();
}
+#ifdef ENABLE_DEBUGGER_SUPPORT
DeoptimizedFrameInfo::DeoptimizedFrameInfo(
Deoptimizer* deoptimizer, int frame_index) {
@@ -1467,5 +1468,6 @@
v->VisitPointers(expression_stack_, expression_stack_ + expression_count_);
}
+#endif // ENABLE_DEBUGGER_SUPPORT
} } // namespace v8::internal
diff --git a/src/deoptimizer.h b/src/deoptimizer.h
index 9265905..033d924 100644
--- a/src/deoptimizer.h
+++ b/src/deoptimizer.h
@@ -317,7 +317,7 @@
List<HeapNumberMaterializationDescriptor> deferred_heap_numbers_;
- static int table_entry_size_;
+ static const int table_entry_size_;
friend class FrameDescription;
friend class DeoptimizingCodeListNode;
@@ -497,9 +497,7 @@
int32_t Next();
- bool HasNext() const { return index_ >= 0; }
-
- void Done() { index_ = -1; }
+ bool HasNext() const { return index_ < buffer_->length(); }
void Skip(int n) {
for (int i = 0; i < n; i++) Next();
diff --git a/src/elements.cc b/src/elements.cc
new file mode 100644
index 0000000..9cfccee
--- /dev/null
+++ b/src/elements.cc
@@ -0,0 +1,536 @@
+// 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:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "v8.h"
+
+#include "objects.h"
+#include "elements.h"
+
+namespace v8 {
+namespace internal {
+
+
+ElementsAccessor** ElementsAccessor::elements_accessors_;
+
+
+bool HasKey(FixedArray* array, Object* key) {
+ int len0 = array->length();
+ for (int i = 0; i < len0; i++) {
+ Object* element = array->get(i);
+ if (element->IsSmi() && element == key) return true;
+ if (element->IsString() &&
+ key->IsString() && String::cast(element)->Equals(String::cast(key))) {
+ return true;
+ }
+ }
+ return false;
+}
+
+
+// Base class for element handler implementations. Contains the
+// the common logic for objects with different ElementsKinds.
+// Subclasses must specialize method for which the element
+// implementation differs from the base class implementation.
+//
+// This class is intended to be used in the following way:
+//
+// class SomeElementsAccessor :
+// public ElementsAccessorBase<SomeElementsAccessor,
+// BackingStoreClass> {
+// ...
+// }
+//
+// This is an example of the Curiously Recurring Template Pattern (see
+// http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern). We use
+// CRTP to guarantee aggressive compile time optimizations (i.e. inlining and
+// specialization of SomeElementsAccessor methods).
+template <typename ElementsAccessorSubclass, typename BackingStoreClass>
+class ElementsAccessorBase : public ElementsAccessor {
+ public:
+ ElementsAccessorBase() { }
+ virtual MaybeObject* GetWithReceiver(JSObject* obj,
+ Object* receiver,
+ uint32_t index) {
+ if (index < ElementsAccessorSubclass::GetLength(obj)) {
+ BackingStoreClass* backing_store =
+ ElementsAccessorSubclass::GetBackingStore(obj);
+ return backing_store->get(index);
+ }
+ return obj->GetHeap()->the_hole_value();
+ }
+
+ virtual MaybeObject* Delete(JSObject* obj,
+ uint32_t index,
+ JSReceiver::DeleteMode mode) = 0;
+
+ virtual MaybeObject* AddJSArrayKeysToFixedArray(JSArray* other,
+ FixedArray* keys) {
+ int len0 = keys->length();
+#ifdef DEBUG
+ if (FLAG_enable_slow_asserts) {
+ for (int i = 0; i < len0; i++) {
+ ASSERT(keys->get(i)->IsString() || keys->get(i)->IsNumber());
+ }
+ }
+#endif
+ int len1 = ElementsAccessorSubclass::GetCapacity(other);
+
+ // Optimize if 'other' is empty.
+ // We cannot optimize if 'this' is empty, as other may have holes
+ // or non keys.
+ if (len1 == 0) return keys;
+
+ // Compute how many elements are not in other.
+ int extra = 0;
+ for (int y = 0; y < len1; y++) {
+ Object* value;
+ MaybeObject* maybe_value =
+ ElementsAccessorSubclass::GetElementAtCapacityIndex(other, y);
+ if (!maybe_value->ToObject(&value)) return maybe_value;
+ if (!value->IsTheHole() && !HasKey(keys, value)) extra++;
+ }
+
+ if (extra == 0) return keys;
+
+ // Allocate the result
+ FixedArray* result;
+ MaybeObject* maybe_obj =
+ other->GetHeap()->AllocateFixedArray(len0 + extra);
+ if (!maybe_obj->To<FixedArray>(&result)) return maybe_obj;
+
+ // Fill in the content
+ {
+ AssertNoAllocation no_gc;
+ WriteBarrierMode mode = result->GetWriteBarrierMode(no_gc);
+ for (int i = 0; i < len0; i++) {
+ Object* e = keys->get(i);
+ ASSERT(e->IsString() || e->IsNumber());
+ result->set(i, e, mode);
+ }
+ }
+ // Fill in the extra keys.
+ int index = 0;
+ for (int y = 0; y < len1; y++) {
+ MaybeObject* maybe_value =
+ ElementsAccessorSubclass::GetElementAtCapacityIndex(other, y);
+ Object* value;
+ if (!maybe_value->ToObject(&value)) return maybe_value;
+ if (!value->IsTheHole() && !HasKey(keys, value)) {
+ ASSERT(value->IsString() || value->IsNumber());
+ result->set(len0 + index, value);
+ index++;
+ }
+ }
+ ASSERT(extra == index);
+ return result;
+ }
+
+ static uint32_t GetCapacity(JSObject* obj) {
+ return ElementsAccessorSubclass::GetBackingStore(obj)->length();
+ }
+
+ static MaybeObject* GetElementAtCapacityIndex(JSObject* obj, int index) {
+ BackingStoreClass* backing_store =
+ ElementsAccessorSubclass::GetBackingStore(obj);
+ return backing_store->get(index);
+ }
+
+ protected:
+ static BackingStoreClass* GetBackingStore(JSObject* obj) {
+ return BackingStoreClass::cast(obj->elements());
+ }
+
+ static uint32_t GetLength(JSObject* obj) {
+ return ElementsAccessorSubclass::GetBackingStore(obj)->length();
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ElementsAccessorBase);
+};
+
+
+class FastElementsAccessor
+ : public ElementsAccessorBase<FastElementsAccessor, FixedArray> {
+ public:
+ static MaybeObject* DeleteCommon(JSObject* obj,
+ uint32_t index) {
+ ASSERT(obj->HasFastElements() || obj->HasFastArgumentsElements());
+ Heap* heap = obj->GetHeap();
+ FixedArray* backing_store = FixedArray::cast(obj->elements());
+ if (backing_store->map() == heap->non_strict_arguments_elements_map()) {
+ backing_store = FixedArray::cast(backing_store->get(1));
+ } else {
+ Object* writable;
+ MaybeObject* maybe = obj->EnsureWritableFastElements();
+ if (!maybe->ToObject(&writable)) return maybe;
+ backing_store = FixedArray::cast(writable);
+ }
+ uint32_t length = static_cast<uint32_t>(
+ obj->IsJSArray()
+ ? Smi::cast(JSArray::cast(obj)->length())->value()
+ : backing_store->length());
+ if (index < length) {
+ backing_store->set_the_hole(index);
+ // If an old space backing store is larger than a certain size and
+ // has too few used values, normalize it.
+ // To avoid doing the check on every delete we require at least
+ // one adjacent hole to the value being deleted.
+ Object* hole = heap->the_hole_value();
+ const int kMinLengthForSparsenessCheck = 64;
+ if (backing_store->length() >= kMinLengthForSparsenessCheck &&
+ !heap->InNewSpace(backing_store) &&
+ ((index > 0 && backing_store->get(index - 1) == hole) ||
+ (index + 1 < length && backing_store->get(index + 1) == hole))) {
+ int num_used = 0;
+ for (int i = 0; i < backing_store->length(); ++i) {
+ if (backing_store->get(i) != hole) ++num_used;
+ // Bail out early if more than 1/4 is used.
+ if (4 * num_used > backing_store->length()) break;
+ }
+ if (4 * num_used <= backing_store->length()) {
+ MaybeObject* result = obj->NormalizeElements();
+ if (result->IsFailure()) return result;
+ }
+ }
+ }
+ return heap->true_value();
+ }
+
+ virtual MaybeObject* Delete(JSObject* obj,
+ uint32_t index,
+ JSReceiver::DeleteMode mode) {
+ return DeleteCommon(obj, index);
+ }
+};
+
+
+class FastDoubleElementsAccessor
+ : public ElementsAccessorBase<FastDoubleElementsAccessor,
+ FixedDoubleArray> {
+ virtual MaybeObject* Delete(JSObject* obj,
+ uint32_t index,
+ JSReceiver::DeleteMode mode) {
+ int length = obj->IsJSArray()
+ ? Smi::cast(JSArray::cast(obj)->length())->value()
+ : FixedDoubleArray::cast(obj->elements())->length();
+ if (index < static_cast<uint32_t>(length)) {
+ FixedDoubleArray::cast(obj->elements())->set_the_hole(index);
+ }
+ return obj->GetHeap()->true_value();
+ }
+};
+
+
+// Super class for all external element arrays.
+template<typename ExternalElementsAccessorSubclass,
+ typename ExternalArray>
+class ExternalElementsAccessor
+ : public ElementsAccessorBase<ExternalElementsAccessorSubclass,
+ ExternalArray> {
+ public:
+ virtual MaybeObject* GetWithReceiver(JSObject* obj,
+ Object* receiver,
+ uint32_t index) {
+ if (index < ExternalElementsAccessorSubclass::GetLength(obj)) {
+ ExternalArray* backing_store =
+ ExternalElementsAccessorSubclass::GetBackingStore(obj);
+ return backing_store->get(index);
+ } else {
+ return obj->GetHeap()->undefined_value();
+ }
+ }
+
+ virtual MaybeObject* Delete(JSObject* obj,
+ uint32_t index,
+ JSReceiver::DeleteMode mode) {
+ // External arrays always ignore deletes.
+ return obj->GetHeap()->true_value();
+ }
+};
+
+
+class ExternalByteElementsAccessor
+ : public ExternalElementsAccessor<ExternalByteElementsAccessor,
+ ExternalByteArray> {
+};
+
+
+class ExternalUnsignedByteElementsAccessor
+ : public ExternalElementsAccessor<ExternalUnsignedByteElementsAccessor,
+ ExternalUnsignedByteArray> {
+};
+
+
+class ExternalShortElementsAccessor
+ : public ExternalElementsAccessor<ExternalShortElementsAccessor,
+ ExternalShortArray> {
+};
+
+
+class ExternalUnsignedShortElementsAccessor
+ : public ExternalElementsAccessor<ExternalUnsignedShortElementsAccessor,
+ ExternalUnsignedShortArray> {
+};
+
+
+class ExternalIntElementsAccessor
+ : public ExternalElementsAccessor<ExternalIntElementsAccessor,
+ ExternalIntArray> {
+};
+
+
+class ExternalUnsignedIntElementsAccessor
+ : public ExternalElementsAccessor<ExternalUnsignedIntElementsAccessor,
+ ExternalUnsignedIntArray> {
+};
+
+
+class ExternalFloatElementsAccessor
+ : public ExternalElementsAccessor<ExternalFloatElementsAccessor,
+ ExternalFloatArray> {
+};
+
+
+class ExternalDoubleElementsAccessor
+ : public ExternalElementsAccessor<ExternalDoubleElementsAccessor,
+ ExternalDoubleArray> {
+};
+
+
+class PixelElementsAccessor
+ : public ExternalElementsAccessor<PixelElementsAccessor,
+ ExternalPixelArray> {
+};
+
+
+class DictionaryElementsAccessor
+ : public ElementsAccessorBase<DictionaryElementsAccessor,
+ NumberDictionary> {
+ public:
+ static MaybeObject* GetNumberDictionaryElement(
+ JSObject* obj,
+ Object* receiver,
+ NumberDictionary* backing_store,
+ uint32_t index) {
+ int entry = backing_store->FindEntry(index);
+ if (entry != NumberDictionary::kNotFound) {
+ Object* element = backing_store->ValueAt(entry);
+ PropertyDetails details = backing_store->DetailsAt(entry);
+ if (details.type() == CALLBACKS) {
+ return obj->GetElementWithCallback(receiver,
+ element,
+ index,
+ obj);
+ } else {
+ return element;
+ }
+ }
+ return obj->GetHeap()->the_hole_value();
+ }
+
+
+ static MaybeObject* DeleteCommon(JSObject* obj,
+ uint32_t index,
+ JSReceiver::DeleteMode mode) {
+ Isolate* isolate = obj->GetIsolate();
+ Heap* heap = isolate->heap();
+ FixedArray* backing_store = FixedArray::cast(obj->elements());
+ bool is_arguments =
+ (obj->GetElementsKind() == JSObject::NON_STRICT_ARGUMENTS_ELEMENTS);
+ if (is_arguments) {
+ backing_store = FixedArray::cast(backing_store->get(1));
+ }
+ NumberDictionary* dictionary = NumberDictionary::cast(backing_store);
+ int entry = dictionary->FindEntry(index);
+ if (entry != NumberDictionary::kNotFound) {
+ Object* result = dictionary->DeleteProperty(entry, mode);
+ if (result == heap->true_value()) {
+ MaybeObject* maybe_elements = dictionary->Shrink(index);
+ FixedArray* new_elements = NULL;
+ if (!maybe_elements->To(&new_elements)) {
+ return maybe_elements;
+ }
+ if (is_arguments) {
+ FixedArray::cast(obj->elements())->set(1, new_elements);
+ } else {
+ obj->set_elements(new_elements);
+ }
+ }
+ if (mode == JSObject::STRICT_DELETION &&
+ result == heap->false_value()) {
+ // In strict mode, attempting to delete a non-configurable property
+ // throws an exception.
+ HandleScope scope(isolate);
+ Handle<Object> holder(obj);
+ Handle<Object> name = isolate->factory()->NewNumberFromUint(index);
+ Handle<Object> args[2] = { name, holder };
+ Handle<Object> error =
+ isolate->factory()->NewTypeError("strict_delete_property",
+ HandleVector(args, 2));
+ return isolate->Throw(*error);
+ }
+ }
+ return heap->true_value();
+ }
+
+ virtual MaybeObject* Delete(JSObject* obj,
+ uint32_t index,
+ JSReceiver::DeleteMode mode) {
+ return DeleteCommon(obj, index, mode);
+ }
+
+ virtual MaybeObject* GetWithReceiver(JSObject* obj,
+ Object* receiver,
+ uint32_t index) {
+ return GetNumberDictionaryElement(obj,
+ receiver,
+ obj->element_dictionary(),
+ index);
+ }
+
+ static uint32_t GetCapacity(JSObject* obj) {
+ return obj->element_dictionary()->Capacity();
+ }
+
+ static MaybeObject* GetElementAtCapacityIndex(JSObject* obj, int index) {
+ NumberDictionary* dict = obj->element_dictionary();
+ if (dict->IsKey(dict->KeyAt(index))) {
+ return dict->ValueAt(index);
+ } else {
+ return obj->GetHeap()->the_hole_value();
+ }
+ }
+};
+
+
+class NonStrictArgumentsElementsAccessor
+ : public ElementsAccessorBase<NonStrictArgumentsElementsAccessor,
+ FixedArray> {
+ public:
+ virtual MaybeObject* GetWithReceiver(JSObject* obj,
+ Object* receiver,
+ uint32_t index) {
+ FixedArray* parameter_map = GetBackingStore(obj);
+ uint32_t length = parameter_map->length();
+ Object* probe =
+ (index < length - 2) ? parameter_map->get(index + 2) : NULL;
+ if (probe != NULL && !probe->IsTheHole()) {
+ Context* context = Context::cast(parameter_map->get(0));
+ int context_index = Smi::cast(probe)->value();
+ ASSERT(!context->get(context_index)->IsTheHole());
+ return context->get(context_index);
+ } else {
+ // Object is not mapped, defer to the arguments.
+ FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
+ if (arguments->IsDictionary()) {
+ return DictionaryElementsAccessor::GetNumberDictionaryElement(
+ obj,
+ receiver,
+ NumberDictionary::cast(arguments),
+ index);
+ } else if (index < static_cast<uint32_t>(arguments->length())) {
+ return arguments->get(index);
+ }
+ }
+ return obj->GetHeap()->the_hole_value();
+ }
+
+ virtual MaybeObject* Delete(JSObject* obj,
+ uint32_t index,
+ JSReceiver::DeleteMode mode) {
+ FixedArray* parameter_map = FixedArray::cast(obj->elements());
+ uint32_t length = parameter_map->length();
+ Object* probe =
+ index < (length - 2) ? parameter_map->get(index + 2) : NULL;
+ if (probe != NULL && !probe->IsTheHole()) {
+ // TODO(kmillikin): We could check if this was the last aliased
+ // parameter, and revert to normal elements in that case. That
+ // would enable GC of the context.
+ parameter_map->set_the_hole(index + 2);
+ } else {
+ FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
+ if (arguments->IsDictionary()) {
+ return DictionaryElementsAccessor::DeleteCommon(obj, index, mode);
+ } else {
+ return FastElementsAccessor::DeleteCommon(obj, index);
+ }
+ }
+ return obj->GetHeap()->true_value();
+ }
+
+ static uint32_t GetCapacity(JSObject* obj) {
+ // TODO(danno): Return max of parameter map length or backing store
+ // capacity.
+ return 0;
+ }
+
+ static MaybeObject* GetElementAtCapacityIndex(JSObject* obj, int index) {
+ // TODO(danno): Return either value from parameter map of backing
+ // store value at index.
+ return obj->GetHeap()->the_hole_value();
+ }
+};
+
+
+void ElementsAccessor::InitializeOncePerProcess() {
+ static struct ConcreteElementsAccessors {
+ FastElementsAccessor fast_elements_handler;
+ FastDoubleElementsAccessor fast_double_elements_handler;
+ DictionaryElementsAccessor dictionary_elements_handler;
+ NonStrictArgumentsElementsAccessor non_strict_arguments_elements_handler;
+ ExternalByteElementsAccessor byte_elements_handler;
+ ExternalUnsignedByteElementsAccessor unsigned_byte_elements_handler;
+ ExternalShortElementsAccessor short_elements_handler;
+ ExternalUnsignedShortElementsAccessor unsigned_short_elements_handler;
+ ExternalIntElementsAccessor int_elements_handler;
+ ExternalUnsignedIntElementsAccessor unsigned_int_elements_handler;
+ ExternalFloatElementsAccessor float_elements_handler;
+ ExternalDoubleElementsAccessor double_elements_handler;
+ PixelElementsAccessor pixel_elements_handler;
+ } element_accessors;
+
+ static ElementsAccessor* accessor_array[] = {
+ &element_accessors.fast_elements_handler,
+ &element_accessors.fast_double_elements_handler,
+ &element_accessors.dictionary_elements_handler,
+ &element_accessors.non_strict_arguments_elements_handler,
+ &element_accessors.byte_elements_handler,
+ &element_accessors.unsigned_byte_elements_handler,
+ &element_accessors.short_elements_handler,
+ &element_accessors.unsigned_short_elements_handler,
+ &element_accessors.int_elements_handler,
+ &element_accessors.unsigned_int_elements_handler,
+ &element_accessors.float_elements_handler,
+ &element_accessors.double_elements_handler,
+ &element_accessors.pixel_elements_handler
+ };
+
+ elements_accessors_ = accessor_array;
+}
+
+
+} } // namespace v8::internal
diff --git a/src/elements.h b/src/elements.h
new file mode 100644
index 0000000..f64244e
--- /dev/null
+++ b/src/elements.h
@@ -0,0 +1,69 @@
+// 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:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef V8_ELEMENTS_H_
+#define V8_ELEMENTS_H_
+
+#include "objects.h"
+
+namespace v8 {
+namespace internal {
+
+// Abstract base class for handles that can operate on objects with differing
+// ElementsKinds.
+class ElementsAccessor {
+ public:
+ ElementsAccessor() { }
+ virtual ~ElementsAccessor() { }
+ virtual MaybeObject* GetWithReceiver(JSObject* obj,
+ Object* receiver,
+ uint32_t index) = 0;
+
+ virtual MaybeObject* Delete(JSObject* obj,
+ uint32_t index,
+ JSReceiver::DeleteMode mode) = 0;
+
+ virtual MaybeObject* AddJSArrayKeysToFixedArray(JSArray* other,
+ FixedArray* keys) = 0;
+
+ // Returns a shared ElementsAccessor for the specified ElementsKind.
+ static ElementsAccessor* ForKind(JSObject::ElementsKind elements_kind) {
+ ASSERT(elements_kind < JSObject::kElementsKindCount);
+ return elements_accessors_[elements_kind];
+ }
+
+ static void InitializeOncePerProcess();
+
+ private:
+ static ElementsAccessor** elements_accessors_;
+
+ DISALLOW_COPY_AND_ASSIGN(ElementsAccessor);
+};
+
+} } // namespace v8::internal
+
+#endif // V8_ELEMENTS_H_
diff --git a/src/execution.cc b/src/execution.cc
index 6ab73e7..bdbdca8 100644
--- a/src/execution.cc
+++ b/src/execution.cc
@@ -132,7 +132,7 @@
if (*has_pending_exception) {
isolate->ReportPendingMessages();
if (isolate->pending_exception() == Failure::OutOfMemoryException()) {
- if (!isolate->handle_scope_implementer()->ignore_out_of_memory()) {
+ if (!isolate->ignore_out_of_memory()) {
V8::FatalProcessOutOfMemory("JS", true);
}
}
diff --git a/src/flag-definitions.h b/src/flag-definitions.h
index 6900a9e..2ea9651 100644
--- a/src/flag-definitions.h
+++ b/src/flag-definitions.h
@@ -98,6 +98,7 @@
// Flags for experimental language features.
DEFINE_bool(harmony_proxies, false, "enable harmony proxies")
+DEFINE_bool(harmony_weakmaps, false, "enable harmony weak maps")
// Flags for experimental implementation features.
DEFINE_bool(unbox_double_arrays, true, "automatically unbox arrays of doubles")
diff --git a/src/heap.cc b/src/heap.cc
index efdb549..dbf3b95 100644
--- a/src/heap.cc
+++ b/src/heap.cc
@@ -438,7 +438,9 @@
#if defined(DEBUG)
ReportStatisticsAfterGC();
#endif // DEBUG
+#ifdef ENABLE_DEBUGGER_SUPPORT
isolate_->debug()->AfterGarbageCollection();
+#endif // ENABLE_DEBUGGER_SUPPORT
}
@@ -1292,6 +1294,10 @@
&ObjectEvacuationStrategy<POINTER_OBJECT>::
template VisitSpecialized<SharedFunctionInfo::kSize>);
+ table_.Register(kVisitJSWeakMap,
+ &ObjectEvacuationStrategy<POINTER_OBJECT>::
+ Visit);
+
table_.Register(kVisitJSRegExp,
&ObjectEvacuationStrategy<POINTER_OBJECT>::
Visit);
@@ -2393,40 +2399,41 @@
MaybeObject* Heap::AllocateSharedFunctionInfo(Object* name) {
- Object* result;
- { MaybeObject* maybe_result =
- Allocate(shared_function_info_map(), OLD_POINTER_SPACE);
- if (!maybe_result->ToObject(&result)) return maybe_result;
- }
+ SharedFunctionInfo* share;
+ MaybeObject* maybe = Allocate(shared_function_info_map(), OLD_POINTER_SPACE);
+ if (!maybe->To<SharedFunctionInfo>(&share)) return maybe;
- SharedFunctionInfo* share = SharedFunctionInfo::cast(result);
+ // Set pointer fields.
share->set_name(name);
Code* illegal = isolate_->builtins()->builtin(Builtins::kIllegal);
share->set_code(illegal);
share->set_scope_info(SerializedScopeInfo::Empty());
- Code* construct_stub = isolate_->builtins()->builtin(
- Builtins::kJSConstructStubGeneric);
+ Code* construct_stub =
+ isolate_->builtins()->builtin(Builtins::kJSConstructStubGeneric);
share->set_construct_stub(construct_stub);
- share->set_expected_nof_properties(0);
- share->set_length(0);
- share->set_formal_parameter_count(0);
share->set_instance_class_name(Object_symbol());
share->set_function_data(undefined_value());
share->set_script(undefined_value());
- share->set_start_position_and_type(0);
share->set_debug_info(undefined_value());
share->set_inferred_name(empty_string());
- share->set_compiler_hints(0);
- share->set_deopt_counter(Smi::FromInt(FLAG_deopt_every_n_times));
share->set_initial_map(undefined_value());
- share->set_this_property_assignments_count(0);
share->set_this_property_assignments(undefined_value());
- share->set_opt_count(0);
+ share->set_deopt_counter(Smi::FromInt(FLAG_deopt_every_n_times));
+
+ // Set integer fields (smi or int, depending on the architecture).
+ share->set_length(0);
+ share->set_formal_parameter_count(0);
+ share->set_expected_nof_properties(0);
share->set_num_literals(0);
+ share->set_start_position_and_type(0);
share->set_end_position(0);
share->set_function_token_position(0);
- share->set_native(false);
- return result;
+ // All compiler hints default to false or 0.
+ share->set_compiler_hints(0);
+ share->set_this_property_assignments_count(0);
+ share->set_opt_count(0);
+
+ return share;
}
diff --git a/src/heap.h b/src/heap.h
index a7a24b0..4f4ef14 100644
--- a/src/heap.h
+++ b/src/heap.h
@@ -1646,6 +1646,7 @@
friend class Page;
friend class Isolate;
friend class MarkCompactCollector;
+ friend class StaticMarkingVisitor;
friend class MapCompact;
DISALLOW_COPY_AND_ASSIGN(Heap);
diff --git a/src/hydrogen-instructions.cc b/src/hydrogen-instructions.cc
index 5bea55a..2be2a03 100644
--- a/src/hydrogen-instructions.cc
+++ b/src/hydrogen-instructions.cc
@@ -862,10 +862,19 @@
Range* HValue::InferRange() {
- // Untagged integer32 cannot be -0, all other representations can.
- Range* result = new Range();
- result->set_can_be_minus_zero(!representation().IsInteger32());
- return result;
+ if (representation().IsTagged()) {
+ // Tagged values are always in int32 range when converted to integer,
+ // but they can contain -0.
+ Range* result = new Range();
+ result->set_can_be_minus_zero(true);
+ return result;
+ } else if (representation().IsNone()) {
+ return NULL;
+ } else {
+ // Untagged integer32 cannot be -0 and we don't compute ranges for
+ // untagged doubles.
+ return new Range();
+ }
}
diff --git a/src/ia32/deoptimizer-ia32.cc b/src/ia32/deoptimizer-ia32.cc
index 4ff1bfc..e23f3e9 100644
--- a/src/ia32/deoptimizer-ia32.cc
+++ b/src/ia32/deoptimizer-ia32.cc
@@ -37,7 +37,7 @@
namespace v8 {
namespace internal {
-int Deoptimizer::table_entry_size_ = 10;
+const int Deoptimizer::table_entry_size_ = 10;
int Deoptimizer::patch_size() {
@@ -601,8 +601,6 @@
output_frame->SetContinuation(
reinterpret_cast<uint32_t>(continuation->entry()));
}
-
- if (output_count_ - 1 == frame_index) iterator->Done();
}
diff --git a/src/ia32/disasm-ia32.cc b/src/ia32/disasm-ia32.cc
index 7a59a4f..900668f 100644
--- a/src/ia32/disasm-ia32.cc
+++ b/src/ia32/disasm-ia32.cc
@@ -54,7 +54,7 @@
};
-static ByteMnemonic two_operands_instr[] = {
+static const ByteMnemonic two_operands_instr[] = {
{0x03, "add", REG_OPER_OP_ORDER},
{0x09, "or", OPER_REG_OP_ORDER},
{0x0B, "or", REG_OPER_OP_ORDER},
@@ -79,7 +79,7 @@
};
-static ByteMnemonic zero_operands_instr[] = {
+static const ByteMnemonic zero_operands_instr[] = {
{0xC3, "ret", UNSET_OP_ORDER},
{0xC9, "leave", UNSET_OP_ORDER},
{0x90, "nop", UNSET_OP_ORDER},
@@ -98,14 +98,14 @@
};
-static ByteMnemonic call_jump_instr[] = {
+static const ByteMnemonic call_jump_instr[] = {
{0xE8, "call", UNSET_OP_ORDER},
{0xE9, "jmp", UNSET_OP_ORDER},
{-1, "", UNSET_OP_ORDER}
};
-static ByteMnemonic short_immediate_instr[] = {
+static const ByteMnemonic short_immediate_instr[] = {
{0x05, "add", UNSET_OP_ORDER},
{0x0D, "or", UNSET_OP_ORDER},
{0x15, "adc", UNSET_OP_ORDER},
@@ -117,7 +117,7 @@
};
-static const char* jump_conditional_mnem[] = {
+static const char* const jump_conditional_mnem[] = {
/*0*/ "jo", "jno", "jc", "jnc",
/*4*/ "jz", "jnz", "jna", "ja",
/*8*/ "js", "jns", "jpe", "jpo",
@@ -125,7 +125,7 @@
};
-static const char* set_conditional_mnem[] = {
+static const char* const set_conditional_mnem[] = {
/*0*/ "seto", "setno", "setc", "setnc",
/*4*/ "setz", "setnz", "setna", "seta",
/*8*/ "sets", "setns", "setpe", "setpo",
@@ -133,7 +133,7 @@
};
-static const char* conditional_move_mnem[] = {
+static const char* const conditional_move_mnem[] = {
/*0*/ "cmovo", "cmovno", "cmovc", "cmovnc",
/*4*/ "cmovz", "cmovnz", "cmovna", "cmova",
/*8*/ "cmovs", "cmovns", "cmovpe", "cmovpo",
@@ -169,7 +169,7 @@
InstructionDesc instructions_[256];
void Clear();
void Init();
- void CopyTable(ByteMnemonic bm[], InstructionType type);
+ void CopyTable(const ByteMnemonic bm[], InstructionType type);
void SetTableRange(InstructionType type,
byte start,
byte end,
@@ -208,7 +208,8 @@
}
-void InstructionTable::CopyTable(ByteMnemonic bm[], InstructionType type) {
+void InstructionTable::CopyTable(const ByteMnemonic bm[],
+ InstructionType type) {
for (int i = 0; bm[i].b >= 0; i++) {
InstructionDesc* id = &instructions_[bm[i].b];
id->mnem = bm[i].mnem;
diff --git a/src/isolate.cc b/src/isolate.cc
index 8a30e79..9ca6117 100644
--- a/src/isolate.cc
+++ b/src/isolate.cc
@@ -76,6 +76,10 @@
ThreadLocalTop::ThreadLocalTop() {
InitializeInternal();
+ // This flag may be set using v8::V8::IgnoreOutOfMemoryException()
+ // before an isolate is initialized. The initialize methods below do
+ // not touch it to preserve its value.
+ ignore_out_of_memory_ = false;
}
@@ -382,7 +386,6 @@
if (Thread::GetThreadLocal(isolate_key_) == NULL) {
Thread::SetThreadLocal(isolate_key_, default_isolate_);
}
- CHECK(default_isolate_->PreInit());
}
@@ -654,6 +657,7 @@
incomplete_message_ = &accumulator;
PrintStack(&accumulator);
accumulator.OutputToStdOut();
+ InitializeLoggingAndCounters();
accumulator.Log();
incomplete_message_ = NULL;
stack_trace_nesting_level_ = 0;
@@ -1375,11 +1379,15 @@
bootstrapper_(NULL),
runtime_profiler_(NULL),
compilation_cache_(NULL),
- counters_(new Counters()),
+ counters_(NULL),
code_range_(NULL),
+ // Must be initialized early to allow v8::SetResourceConstraints calls.
break_access_(OS::CreateMutex()),
- logger_(new Logger()),
- stats_table_(new StatsTable()),
+ debugger_initialized_(false),
+ // Must be initialized early to allow v8::Debug calls.
+ debugger_access_(OS::CreateMutex()),
+ logger_(NULL),
+ stats_table_(NULL),
stub_cache_(NULL),
deoptimizer_data_(NULL),
capture_stack_trace_for_uncaught_exceptions_(false),
@@ -1510,7 +1518,7 @@
logger_->TearDown();
// The default isolate is re-initializable due to legacy API.
- state_ = PREINITIALIZED;
+ state_ = UNINITIALIZED;
}
}
@@ -1592,58 +1600,6 @@
}
-bool Isolate::PreInit() {
- if (state_ != UNINITIALIZED) return true;
-
- TRACE_ISOLATE(preinit);
-
- ASSERT(Isolate::Current() == this);
-#ifdef ENABLE_DEBUGGER_SUPPORT
- debug_ = new Debug(this);
- debugger_ = new Debugger(this);
-#endif
-
- memory_allocator_ = new MemoryAllocator();
- memory_allocator_->isolate_ = this;
- code_range_ = new CodeRange();
- code_range_->isolate_ = this;
-
- // Safe after setting Heap::isolate_, initializing StackGuard and
- // ensuring that Isolate::Current() == this.
- heap_.SetStackLimits();
-
-#ifdef DEBUG
- DisallowAllocationFailure disallow_allocation_failure;
-#endif
-
-#define C(name) isolate_addresses_[Isolate::k_##name] = \
- reinterpret_cast<Address>(name());
- ISOLATE_ADDRESS_LIST(C)
-#undef C
-
- string_tracker_ = new StringTracker();
- string_tracker_->isolate_ = this;
- compilation_cache_ = new CompilationCache(this);
- transcendental_cache_ = new TranscendentalCache();
- keyed_lookup_cache_ = new KeyedLookupCache();
- context_slot_cache_ = new ContextSlotCache();
- descriptor_lookup_cache_ = new DescriptorLookupCache();
- unicode_cache_ = new UnicodeCache();
- pc_to_code_cache_ = new PcToCodeCache(this);
- write_input_buffer_ = new StringInputBuffer();
- global_handles_ = new GlobalHandles(this);
- bootstrapper_ = new Bootstrapper();
- handle_scope_implementer_ = new HandleScopeImplementer(this);
- stub_cache_ = new StubCache(this);
- ast_sentinels_ = new AstSentinels();
- regexp_stack_ = new RegExpStack();
- regexp_stack_->isolate_ = this;
-
- state_ = PREINITIALIZED;
- return true;
-}
-
-
void Isolate::InitializeThreadLocal() {
thread_local_top_.isolate_ = this;
thread_local_top_.Initialize();
@@ -1680,19 +1636,71 @@
}
+void Isolate::InitializeLoggingAndCounters() {
+ if (logger_ == NULL) {
+ logger_ = new Logger;
+ }
+ if (counters_ == NULL) {
+ counters_ = new Counters;
+ }
+}
+
+
+void Isolate::InitializeDebugger() {
+#ifdef ENABLE_DEBUGGER_SUPPORT
+ ScopedLock lock(debugger_access_);
+ if (NoBarrier_Load(&debugger_initialized_)) return;
+ InitializeLoggingAndCounters();
+ debug_ = new Debug(this);
+ debugger_ = new Debugger(this);
+ Release_Store(&debugger_initialized_, true);
+#endif
+}
+
+
bool Isolate::Init(Deserializer* des) {
ASSERT(state_ != INITIALIZED);
-
+ ASSERT(Isolate::Current() == this);
TRACE_ISOLATE(init);
- bool create_heap_objects = des == NULL;
-
#ifdef DEBUG
// The initialization process does not handle memory exhaustion.
DisallowAllocationFailure disallow_allocation_failure;
#endif
- if (state_ == UNINITIALIZED && !PreInit()) return false;
+ InitializeLoggingAndCounters();
+
+ InitializeDebugger();
+
+ memory_allocator_ = new MemoryAllocator(this);
+ code_range_ = new CodeRange(this);
+
+ // Safe after setting Heap::isolate_, initializing StackGuard and
+ // ensuring that Isolate::Current() == this.
+ heap_.SetStackLimits();
+
+#define C(name) isolate_addresses_[Isolate::k_##name] = \
+ reinterpret_cast<Address>(name());
+ ISOLATE_ADDRESS_LIST(C)
+#undef C
+
+ string_tracker_ = new StringTracker();
+ string_tracker_->isolate_ = this;
+ compilation_cache_ = new CompilationCache(this);
+ transcendental_cache_ = new TranscendentalCache();
+ keyed_lookup_cache_ = new KeyedLookupCache();
+ context_slot_cache_ = new ContextSlotCache();
+ descriptor_lookup_cache_ = new DescriptorLookupCache();
+ unicode_cache_ = new UnicodeCache();
+ pc_to_code_cache_ = new PcToCodeCache(this);
+ write_input_buffer_ = new StringInputBuffer();
+ global_handles_ = new GlobalHandles(this);
+ bootstrapper_ = new Bootstrapper();
+ handle_scope_implementer_ = new HandleScopeImplementer(this);
+ stub_cache_ = new StubCache(this);
+ ast_sentinels_ = new AstSentinels();
+ regexp_stack_ = new RegExpStack();
+ regexp_stack_->isolate_ = this;
// Enable logging before setting up the heap
logger_->Setup();
@@ -1715,7 +1723,8 @@
stack_guard_.InitThread(lock);
}
- // Setup the object heap
+ // Setup the object heap.
+ const bool create_heap_objects = (des == NULL);
ASSERT(!heap_.HasBeenSetup());
if (!heap_.Setup(create_heap_objects)) {
V8::SetFatalError();
@@ -1775,6 +1784,16 @@
}
+// Initialized lazily to allow early
+// v8::V8::SetAddHistogramSampleFunction calls.
+StatsTable* Isolate::stats_table() {
+ if (stats_table_ == NULL) {
+ stats_table_ = new StatsTable;
+ }
+ return stats_table_;
+}
+
+
void Isolate::Enter() {
Isolate* current_isolate = NULL;
PerIsolateThreadData* current_data = CurrentPerIsolateThreadData();
@@ -1814,8 +1833,6 @@
SetIsolateThreadLocals(this, data);
- CHECK(PreInit());
-
// In case it's the first time some thread enters the isolate.
set_thread_id(data->thread_id());
}
diff --git a/src/isolate.h b/src/isolate.h
index f2281aa..5bb504d 100644
--- a/src/isolate.h
+++ b/src/isolate.h
@@ -256,6 +256,9 @@
// Call back function to report unsafe JS accesses.
v8::FailedAccessCheckCallback failed_access_check_callback_;
+ // Whether out of memory exceptions should be ignored.
+ bool ignore_out_of_memory_;
+
private:
void InitializeInternal();
@@ -446,6 +449,13 @@
return reinterpret_cast<Isolate*>(Thread::GetThreadLocal(isolate_key_));
}
+ // Usually called by Init(), but can be called early e.g. to allow
+ // testing components that require logging but not the whole
+ // isolate.
+ //
+ // Safe to call more than once.
+ void InitializeLoggingAndCounters();
+
bool Init(Deserializer* des);
bool IsInitialized() { return state_ == INITIALIZED; }
@@ -498,10 +508,12 @@
// switched to non-legacy behavior).
static void EnterDefaultIsolate();
- // Debug.
// Mutex for serializing access to break control structures.
Mutex* break_access() { return break_access_; }
+ // Mutex for serializing access to debugger.
+ Mutex* debugger_access() { return debugger_access_; }
+
Address get_address_from_id(AddressId id);
// Access to top context (where the current function object was created).
@@ -661,6 +673,12 @@
// Tells whether the current context has experienced an out of memory
// exception.
bool is_out_of_memory();
+ bool ignore_out_of_memory() {
+ return thread_local_top_.ignore_out_of_memory_;
+ }
+ void set_ignore_out_of_memory(bool value) {
+ thread_local_top_.ignore_out_of_memory_ = value;
+ }
void PrintCurrentStackTrace(FILE* out);
void PrintStackTrace(FILE* out, char* thread_data);
@@ -769,14 +787,24 @@
#undef GLOBAL_CONTEXT_FIELD_ACCESSOR
Bootstrapper* bootstrapper() { return bootstrapper_; }
- Counters* counters() { return counters_; }
+ Counters* counters() {
+ // Call InitializeLoggingAndCounters() if logging is needed before
+ // the isolate is fully initialized.
+ ASSERT(counters_ != NULL);
+ return counters_;
+ }
CodeRange* code_range() { return code_range_; }
RuntimeProfiler* runtime_profiler() { return runtime_profiler_; }
CompilationCache* compilation_cache() { return compilation_cache_; }
- Logger* logger() { return logger_; }
+ Logger* logger() {
+ // Call InitializeLoggingAndCounters() if logging is needed before
+ // the isolate is fully initialized.
+ ASSERT(logger_ != NULL);
+ return logger_;
+ }
StackGuard* stack_guard() { return &stack_guard_; }
Heap* heap() { return &heap_; }
- StatsTable* stats_table() { return stats_table_; }
+ StatsTable* stats_table();
StubCache* stub_cache() { return stub_cache_; }
DeoptimizerData* deoptimizer_data() { return deoptimizer_data_; }
ThreadLocalTop* thread_local_top() { return &thread_local_top_; }
@@ -877,8 +905,14 @@
void PreallocatedStorageInit(size_t size);
#ifdef ENABLE_DEBUGGER_SUPPORT
- Debugger* debugger() { return debugger_; }
- Debug* debug() { return debug_; }
+ Debugger* debugger() {
+ if (!NoBarrier_Load(&debugger_initialized_)) InitializeDebugger();
+ return debugger_;
+ }
+ Debug* debug() {
+ if (!NoBarrier_Load(&debugger_initialized_)) InitializeDebugger();
+ return debug_;
+ }
#endif
inline bool DebuggerHasBreakPoints();
@@ -1010,8 +1044,6 @@
static Isolate* default_isolate_;
static ThreadDataTable* thread_data_table_;
- bool PreInit();
-
void Deinit();
static void SetIsolateThreadLocals(Isolate* isolate,
@@ -1019,7 +1051,6 @@
enum State {
UNINITIALIZED, // Some components may not have been allocated.
- PREINITIALIZED, // Components have been allocated but not initialized.
INITIALIZED // All components are fully initialized.
};
@@ -1063,6 +1094,8 @@
void PropagatePendingExceptionToExternalTryCatch();
+ void InitializeDebugger();
+
int stack_trace_nesting_level_;
StringStream* incomplete_message_;
// The preallocated memory thread singleton.
@@ -1076,6 +1109,8 @@
Counters* counters_;
CodeRange* code_range_;
Mutex* break_access_;
+ Atomic32 debugger_initialized_;
+ Mutex* debugger_access_;
Heap heap_;
Logger* logger_;
StackGuard stack_guard_;
@@ -1165,6 +1200,7 @@
friend class Simulator;
friend class StackGuard;
friend class ThreadId;
+ friend class TestMemoryAllocatorScope;
friend class v8::Isolate;
friend class v8::Locker;
friend class v8::Unlocker;
diff --git a/src/json-parser.h b/src/json-parser.h
index f93b04d..68eab65 100644
--- a/src/json-parser.h
+++ b/src/json-parser.h
@@ -458,12 +458,12 @@
String::WriteToFlat(*prefix, dest, start, end);
while (c0_ != '"') {
+ // Check for control character (0x00-0x1f) or unterminated string (<0).
+ if (c0_ < 0x20) return Handle<String>::null();
if (count >= length) {
// We need to create a longer sequential string for the result.
return SlowScanJsonString<StringType, SinkChar>(seq_str, 0, count);
}
- // Check for control character (0x00-0x1f) or unterminated string (<0).
- if (c0_ < 0x20) return Handle<String>::null();
if (c0_ != '\\') {
// If the sink can contain UC16 characters, or source_ contains only
// ASCII characters, there's no need to test whether we can store the
diff --git a/src/jsregexp.cc b/src/jsregexp.cc
index bc47df8..af64437 100644
--- a/src/jsregexp.cc
+++ b/src/jsregexp.cc
@@ -267,7 +267,7 @@
seq_sub->ToUC16Vector(),
needle->ToUC16Vector(),
index)));
- if (index == -1) return FACTORY->null_value();
+ if (index == -1) return isolate->factory()->null_value();
}
ASSERT(last_match_info->HasFastElements());
diff --git a/src/log-utils.cc b/src/log-utils.cc
index 6112e34..27e654d 100644
--- a/src/log-utils.cc
+++ b/src/log-utils.cc
@@ -34,7 +34,7 @@
namespace internal {
-const char* Log::kLogToTemporaryFile = "&";
+const char* const Log::kLogToTemporaryFile = "&";
Log::Log(Logger* logger)
diff --git a/src/log-utils.h b/src/log-utils.h
index d336d71..2b20a01 100644
--- a/src/log-utils.h
+++ b/src/log-utils.h
@@ -59,7 +59,7 @@
// This mode is only used in tests, as temporary files are automatically
// deleted on close and thus can't be accessed afterwards.
- static const char* kLogToTemporaryFile;
+ static const char* const kLogToTemporaryFile;
private:
explicit Log(Logger* logger);
diff --git a/src/mark-compact.cc b/src/mark-compact.cc
index 0bf8286..0961350 100644
--- a/src/mark-compact.cc
+++ b/src/mark-compact.cc
@@ -64,13 +64,15 @@
live_bytes_(0),
#endif
heap_(NULL),
- code_flusher_(NULL) { }
+ code_flusher_(NULL),
+ encountered_weak_maps_(NULL) { }
void MarkCompactCollector::CollectGarbage() {
// Make sure that Prepare() has been called. The individual steps below will
// update the state as they proceed.
ASSERT(state_ == PREPARE_GC);
+ ASSERT(encountered_weak_maps_ == Smi::FromInt(0));
// Prepare has selected whether to compact the old generation or not.
// Tell the tracer.
@@ -80,6 +82,8 @@
if (FLAG_collect_maps) ClearNonLiveTransitions();
+ ClearWeakMaps();
+
SweepLargeObjectSpace();
if (IsCompacting()) {
@@ -407,6 +411,8 @@
table_.Register(kVisitSeqAsciiString, &DataObjectVisitor::Visit);
table_.Register(kVisitSeqTwoByteString, &DataObjectVisitor::Visit);
+ table_.Register(kVisitJSWeakMap, &VisitJSWeakMap);
+
table_.Register(kVisitOddball,
&FixedBodyVisitor<StaticMarkingVisitor,
Oddball::BodyDescriptor,
@@ -556,6 +562,34 @@
StructBodyDescriptor,
void> StructObjectVisitor;
+ static void VisitJSWeakMap(Map* map, HeapObject* object) {
+ MarkCompactCollector* collector = map->heap()->mark_compact_collector();
+ JSWeakMap* weak_map = reinterpret_cast<JSWeakMap*>(object);
+
+ // Enqueue weak map in linked list of encountered weak maps.
+ ASSERT(weak_map->next() == Smi::FromInt(0));
+ weak_map->set_next(collector->encountered_weak_maps());
+ collector->set_encountered_weak_maps(weak_map);
+
+ // Skip visiting the backing hash table containing the mappings.
+ int object_size = JSWeakMap::BodyDescriptor::SizeOf(map, object);
+ BodyVisitorBase<StaticMarkingVisitor>::IteratePointers(
+ map->heap(),
+ object,
+ JSWeakMap::BodyDescriptor::kStartOffset,
+ JSWeakMap::kTableOffset);
+ BodyVisitorBase<StaticMarkingVisitor>::IteratePointers(
+ map->heap(),
+ object,
+ JSWeakMap::kTableOffset + kPointerSize,
+ object_size);
+
+ // Mark the backing hash table without pushing it on the marking stack.
+ ASSERT(!weak_map->unchecked_table()->IsMarked());
+ ASSERT(weak_map->unchecked_table()->map()->IsMarked());
+ collector->SetMark(weak_map->unchecked_table());
+ }
+
static void VisitCode(Map* map, HeapObject* object) {
reinterpret_cast<Code*>(object)->CodeIterateBody<StaticMarkingVisitor>(
map->heap());
@@ -1369,20 +1403,26 @@
// marking stack have been marked, or are overflowed in the heap.
void MarkCompactCollector::EmptyMarkingStack() {
while (!marking_stack_.is_empty()) {
- HeapObject* object = marking_stack_.Pop();
- ASSERT(object->IsHeapObject());
- ASSERT(heap()->Contains(object));
- ASSERT(object->IsMarked());
- ASSERT(!object->IsOverflowed());
+ while (!marking_stack_.is_empty()) {
+ HeapObject* object = marking_stack_.Pop();
+ ASSERT(object->IsHeapObject());
+ ASSERT(heap()->Contains(object));
+ ASSERT(object->IsMarked());
+ ASSERT(!object->IsOverflowed());
- // Because the object is marked, we have to recover the original map
- // pointer and use it to mark the object's body.
- MapWord map_word = object->map_word();
- map_word.ClearMark();
- Map* map = map_word.ToMap();
- MarkObject(map);
+ // Because the object is marked, we have to recover the original map
+ // pointer and use it to mark the object's body.
+ MapWord map_word = object->map_word();
+ map_word.ClearMark();
+ Map* map = map_word.ToMap();
+ MarkObject(map);
- StaticMarkingVisitor::IterateBody(map, object);
+ StaticMarkingVisitor::IterateBody(map, object);
+ }
+
+ // Process encountered weak maps, mark objects only reachable by those
+ // weak maps and repeat until fix-point is reached.
+ ProcessWeakMaps();
}
}
@@ -1735,6 +1775,45 @@
}
}
+
+void MarkCompactCollector::ProcessWeakMaps() {
+ Object* weak_map_obj = encountered_weak_maps();
+ while (weak_map_obj != Smi::FromInt(0)) {
+ ASSERT(HeapObject::cast(weak_map_obj)->IsMarked());
+ JSWeakMap* weak_map = reinterpret_cast<JSWeakMap*>(weak_map_obj);
+ ObjectHashTable* table = weak_map->unchecked_table();
+ for (int i = 0; i < table->Capacity(); i++) {
+ if (HeapObject::cast(table->KeyAt(i))->IsMarked()) {
+ Object* value = table->get(table->EntryToValueIndex(i));
+ StaticMarkingVisitor::MarkObjectByPointer(heap(), &value);
+ table->set_unchecked(heap(),
+ table->EntryToValueIndex(i),
+ value,
+ UPDATE_WRITE_BARRIER);
+ }
+ }
+ weak_map_obj = weak_map->next();
+ }
+}
+
+
+void MarkCompactCollector::ClearWeakMaps() {
+ Object* weak_map_obj = encountered_weak_maps();
+ while (weak_map_obj != Smi::FromInt(0)) {
+ ASSERT(HeapObject::cast(weak_map_obj)->IsMarked());
+ JSWeakMap* weak_map = reinterpret_cast<JSWeakMap*>(weak_map_obj);
+ ObjectHashTable* table = weak_map->unchecked_table();
+ for (int i = 0; i < table->Capacity(); i++) {
+ if (!HeapObject::cast(table->KeyAt(i))->IsMarked()) {
+ table->RemoveEntry(i, heap());
+ }
+ }
+ weak_map_obj = weak_map->next();
+ weak_map->set_next(Smi::FromInt(0));
+ }
+ set_encountered_weak_maps(Smi::FromInt(0));
+}
+
// -------------------------------------------------------------------------
// Phase 2: Encode forwarding addresses.
// When compacting, forwarding addresses for objects in old space and map
diff --git a/src/mark-compact.h b/src/mark-compact.h
index 179edba..9b67c8a 100644
--- a/src/mark-compact.h
+++ b/src/mark-compact.h
@@ -193,6 +193,11 @@
inline bool is_code_flushing_enabled() const { return code_flusher_ != NULL; }
void EnableCodeFlushing(bool enable);
+ inline Object* encountered_weak_maps() { return encountered_weak_maps_; }
+ inline void set_encountered_weak_maps(Object* weak_map) {
+ encountered_weak_maps_ = weak_map;
+ }
+
private:
MarkCompactCollector();
~MarkCompactCollector();
@@ -329,6 +334,16 @@
// We replace them with a null descriptor, with the same key.
void ClearNonLiveTransitions();
+ // Mark all values associated with reachable keys in weak maps encountered
+ // so far. This might push new object or even new weak maps onto the
+ // marking stack.
+ void ProcessWeakMaps();
+
+ // After all reachable objects have been marked those weak map entries
+ // with an unreachable key are removed from all encountered weak maps.
+ // The linked list of all encountered weak maps is destroyed.
+ void ClearWeakMaps();
+
// -----------------------------------------------------------------------
// Phase 2: Sweeping to clear mark bits and free non-live objects for
// a non-compacting collection, or else computing and encoding
@@ -499,6 +514,7 @@
Heap* heap_;
MarkingStack marking_stack_;
CodeFlusher* code_flusher_;
+ Object* encountered_weak_maps_;
friend class Heap;
friend class OverflowedObjectsScanner;
diff --git a/src/messages.js b/src/messages.js
index c1618e5..6603185 100644
--- a/src/messages.js
+++ b/src/messages.js
@@ -201,6 +201,7 @@
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"],
+ invalid_weakmap_key: ["Invalid value used as weak map key"],
// RangeError
invalid_array_length: ["Invalid array length"],
stack_overflow: ["Maximum call stack size exceeded"],
diff --git a/src/mips/deoptimizer-mips.cc b/src/mips/deoptimizer-mips.cc
index 9a19aba..18b6231 100644
--- a/src/mips/deoptimizer-mips.cc
+++ b/src/mips/deoptimizer-mips.cc
@@ -39,7 +39,7 @@
namespace internal {
-int Deoptimizer::table_entry_size_ = 10;
+const int Deoptimizer::table_entry_size_ = 10;
int Deoptimizer::patch_size() {
diff --git a/src/objects-debug.cc b/src/objects-debug.cc
index 2963231..8c0330d 100644
--- a/src/objects-debug.cc
+++ b/src/objects-debug.cc
@@ -153,6 +153,9 @@
case JS_ARRAY_TYPE:
JSArray::cast(this)->JSArrayVerify();
break;
+ case JS_WEAK_MAP_TYPE:
+ JSWeakMap::cast(this)->JSWeakMapVerify();
+ break;
case JS_REGEXP_TYPE:
JSRegExp::cast(this)->JSRegExpVerify();
break;
@@ -313,7 +316,7 @@
void FixedDoubleArray::FixedDoubleArrayVerify() {
for (int i = 0; i < length(); i++) {
if (!is_the_hole(i)) {
- double value = get(i);
+ double value = get_scalar(i);
ASSERT(!isnan(value) ||
(BitCast<uint64_t>(value) ==
BitCast<uint64_t>(canonical_not_the_hole_nan_as_double())));
@@ -453,6 +456,14 @@
}
+void JSWeakMap::JSWeakMapVerify() {
+ CHECK(IsJSWeakMap());
+ JSObjectVerify();
+ VerifyHeapPointer(table());
+ ASSERT(table()->IsHashTable());
+}
+
+
void JSRegExp::JSRegExpVerify() {
JSObjectVerify();
ASSERT(data()->IsUndefined() || data()->IsFixedArray());
diff --git a/src/objects-inl.h b/src/objects-inl.h
index 6870ce0..70ed47b 100644
--- a/src/objects-inl.h
+++ b/src/objects-inl.h
@@ -35,6 +35,7 @@
#ifndef V8_OBJECTS_INL_H_
#define V8_OBJECTS_INL_H_
+#include "elements.h"
#include "objects.h"
#include "contexts.h"
#include "conversions-inl.h"
@@ -480,6 +481,12 @@
}
+bool Object::IsJSWeakMap() {
+ return Object::IsJSObject() &&
+ HeapObject::cast(this)->map()->instance_type() == JS_WEAK_MAP_TYPE;
+}
+
+
bool Object::IsJSContextExtensionObject() {
return IsHeapObject()
&& (HeapObject::cast(this)->map()->instance_type() ==
@@ -1416,6 +1423,8 @@
return JSValue::kSize;
case JS_ARRAY_TYPE:
return JSValue::kSize;
+ case JS_WEAK_MAP_TYPE:
+ return JSWeakMap::kSize;
case JS_REGEXP_TYPE:
return JSValue::kSize;
case JS_CONTEXT_EXTENSION_OBJECT_TYPE:
@@ -1603,6 +1612,7 @@
void FixedArray::set(int index, Smi* value) {
ASSERT(map() != HEAP->fixed_cow_array_map());
+ ASSERT(index >= 0 && index < this->length());
ASSERT(reinterpret_cast<Object*>(value)->IsSmi());
int offset = kHeaderSize + index * kPointerSize;
WRITE_FIELD(this, offset, value);
@@ -1635,7 +1645,7 @@
}
-double FixedDoubleArray::get(int index) {
+double FixedDoubleArray::get_scalar(int index) {
ASSERT(map() != HEAP->fixed_cow_array_map() &&
map() != HEAP->fixed_array_map());
ASSERT(index >= 0 && index < this->length());
@@ -1645,6 +1655,15 @@
}
+MaybeObject* FixedDoubleArray::get(int index) {
+ if (is_the_hole(index)) {
+ return GetHeap()->the_hole_value();
+ } else {
+ return GetHeap()->NumberFromDouble(get_scalar(index));
+ }
+}
+
+
void FixedDoubleArray::set(int index, double value) {
ASSERT(map() != HEAP->fixed_cow_array_map() &&
map() != HEAP->fixed_array_map());
@@ -2066,6 +2085,7 @@
CAST_ACCESSOR(JSRegExp)
CAST_ACCESSOR(JSProxy)
CAST_ACCESSOR(JSFunctionProxy)
+CAST_ACCESSOR(JSWeakMap)
CAST_ACCESSOR(Foreign)
CAST_ACCESSOR(ByteArray)
CAST_ACCESSOR(ExternalArray)
@@ -2369,13 +2389,18 @@
}
-uint8_t ExternalPixelArray::get(int index) {
+uint8_t ExternalPixelArray::get_scalar(int index) {
ASSERT((index >= 0) && (index < this->length()));
uint8_t* ptr = external_pixel_pointer();
return ptr[index];
}
+MaybeObject* ExternalPixelArray::get(int index) {
+ return Smi::FromInt(static_cast<int>(get_scalar(index)));
+}
+
+
void ExternalPixelArray::set(int index, uint8_t value) {
ASSERT((index >= 0) && (index < this->length()));
uint8_t* ptr = external_pixel_pointer();
@@ -2395,13 +2420,18 @@
}
-int8_t ExternalByteArray::get(int index) {
+int8_t ExternalByteArray::get_scalar(int index) {
ASSERT((index >= 0) && (index < this->length()));
int8_t* ptr = static_cast<int8_t*>(external_pointer());
return ptr[index];
}
+MaybeObject* ExternalByteArray::get(int index) {
+ return Smi::FromInt(static_cast<int>(get_scalar(index)));
+}
+
+
void ExternalByteArray::set(int index, int8_t value) {
ASSERT((index >= 0) && (index < this->length()));
int8_t* ptr = static_cast<int8_t*>(external_pointer());
@@ -2409,13 +2439,18 @@
}
-uint8_t ExternalUnsignedByteArray::get(int index) {
+uint8_t ExternalUnsignedByteArray::get_scalar(int index) {
ASSERT((index >= 0) && (index < this->length()));
uint8_t* ptr = static_cast<uint8_t*>(external_pointer());
return ptr[index];
}
+MaybeObject* ExternalUnsignedByteArray::get(int index) {
+ return Smi::FromInt(static_cast<int>(get_scalar(index)));
+}
+
+
void ExternalUnsignedByteArray::set(int index, uint8_t value) {
ASSERT((index >= 0) && (index < this->length()));
uint8_t* ptr = static_cast<uint8_t*>(external_pointer());
@@ -2423,13 +2458,18 @@
}
-int16_t ExternalShortArray::get(int index) {
+int16_t ExternalShortArray::get_scalar(int index) {
ASSERT((index >= 0) && (index < this->length()));
int16_t* ptr = static_cast<int16_t*>(external_pointer());
return ptr[index];
}
+MaybeObject* ExternalShortArray::get(int index) {
+ return Smi::FromInt(static_cast<int>(get_scalar(index)));
+}
+
+
void ExternalShortArray::set(int index, int16_t value) {
ASSERT((index >= 0) && (index < this->length()));
int16_t* ptr = static_cast<int16_t*>(external_pointer());
@@ -2437,13 +2477,18 @@
}
-uint16_t ExternalUnsignedShortArray::get(int index) {
+uint16_t ExternalUnsignedShortArray::get_scalar(int index) {
ASSERT((index >= 0) && (index < this->length()));
uint16_t* ptr = static_cast<uint16_t*>(external_pointer());
return ptr[index];
}
+MaybeObject* ExternalUnsignedShortArray::get(int index) {
+ return Smi::FromInt(static_cast<int>(get_scalar(index)));
+}
+
+
void ExternalUnsignedShortArray::set(int index, uint16_t value) {
ASSERT((index >= 0) && (index < this->length()));
uint16_t* ptr = static_cast<uint16_t*>(external_pointer());
@@ -2451,13 +2496,18 @@
}
-int32_t ExternalIntArray::get(int index) {
+int32_t ExternalIntArray::get_scalar(int index) {
ASSERT((index >= 0) && (index < this->length()));
int32_t* ptr = static_cast<int32_t*>(external_pointer());
return ptr[index];
}
+MaybeObject* ExternalIntArray::get(int index) {
+ return GetHeap()->NumberFromInt32(get_scalar(index));
+}
+
+
void ExternalIntArray::set(int index, int32_t value) {
ASSERT((index >= 0) && (index < this->length()));
int32_t* ptr = static_cast<int32_t*>(external_pointer());
@@ -2465,13 +2515,18 @@
}
-uint32_t ExternalUnsignedIntArray::get(int index) {
+uint32_t ExternalUnsignedIntArray::get_scalar(int index) {
ASSERT((index >= 0) && (index < this->length()));
uint32_t* ptr = static_cast<uint32_t*>(external_pointer());
return ptr[index];
}
+MaybeObject* ExternalUnsignedIntArray::get(int index) {
+ return GetHeap()->NumberFromUint32(get_scalar(index));
+}
+
+
void ExternalUnsignedIntArray::set(int index, uint32_t value) {
ASSERT((index >= 0) && (index < this->length()));
uint32_t* ptr = static_cast<uint32_t*>(external_pointer());
@@ -2479,13 +2534,18 @@
}
-float ExternalFloatArray::get(int index) {
+float ExternalFloatArray::get_scalar(int index) {
ASSERT((index >= 0) && (index < this->length()));
float* ptr = static_cast<float*>(external_pointer());
return ptr[index];
}
+MaybeObject* ExternalFloatArray::get(int index) {
+ return GetHeap()->NumberFromDouble(get_scalar(index));
+}
+
+
void ExternalFloatArray::set(int index, float value) {
ASSERT((index >= 0) && (index < this->length()));
float* ptr = static_cast<float*>(external_pointer());
@@ -2493,13 +2553,18 @@
}
-double ExternalDoubleArray::get(int index) {
+double ExternalDoubleArray::get_scalar(int index) {
ASSERT((index >= 0) && (index < this->length()));
double* ptr = static_cast<double*>(external_pointer());
return ptr[index];
}
+MaybeObject* ExternalDoubleArray::get(int index) {
+ return GetHeap()->NumberFromDouble(get_scalar(index));
+}
+
+
void ExternalDoubleArray::set(int index, double value) {
ASSERT((index >= 0) && (index < this->length()));
double* ptr = static_cast<double*>(external_pointer());
@@ -3469,35 +3534,14 @@
}
-BOOL_ACCESSORS(SharedFunctionInfo,
- compiler_hints,
- strict_mode,
+BOOL_ACCESSORS(SharedFunctionInfo, compiler_hints, strict_mode,
kStrictModeFunction)
-
-
-bool SharedFunctionInfo::native() {
- return BooleanBit::get(compiler_hints(), kNative);
-}
-
-
-void SharedFunctionInfo::set_native(bool value) {
- set_compiler_hints(BooleanBit::set(compiler_hints(),
- kNative,
- value));
-}
-
-
-bool SharedFunctionInfo::bound() {
- return BooleanBit::get(compiler_hints(), kBoundFunction);
-}
-
-
-void SharedFunctionInfo::set_bound(bool value) {
- set_compiler_hints(BooleanBit::set(compiler_hints(),
- kBoundFunction,
- value));
-}
-
+BOOL_ACCESSORS(SharedFunctionInfo, compiler_hints, native, kNative)
+BOOL_ACCESSORS(SharedFunctionInfo, compiler_hints,
+ name_should_print_as_anonymous,
+ kNameShouldPrintAsAnonymous)
+BOOL_ACCESSORS(SharedFunctionInfo, compiler_hints, bound, kBoundFunction)
+BOOL_ACCESSORS(SharedFunctionInfo, compiler_hints, is_anonymous, kIsAnonymous)
ACCESSORS(CodeCache, default_cache, FixedArray, kDefaultCacheOffset)
ACCESSORS(CodeCache, normal_type_cache, Object, kNormalTypeCacheOffset)
@@ -3796,6 +3840,15 @@
ACCESSORS(JSProxy, padding, Object, kPaddingOffset)
+ACCESSORS(JSWeakMap, table, ObjectHashTable, kTableOffset)
+ACCESSORS_GCSAFE(JSWeakMap, next, Object, kNextOffset)
+
+
+ObjectHashTable* JSWeakMap::unchecked_table() {
+ return reinterpret_cast<ObjectHashTable*>(READ_FIELD(this, kTableOffset));
+}
+
+
Address Foreign::address() {
return AddressFrom<Address>(READ_INTPTR_FIELD(this, kAddressOffset));
}
@@ -3981,6 +4034,11 @@
}
+ElementsAccessor* JSObject::GetElementsAccessor() {
+ return ElementsAccessor::ForKind(GetElementsKind());
+}
+
+
bool JSObject::HasFastElements() {
return GetElementsKind() == FAST_ELEMENTS;
}
@@ -4399,6 +4457,11 @@
}
+void ObjectHashTable::RemoveEntry(int entry) {
+ RemoveEntry(entry, GetHeap());
+}
+
+
void Map::ClearCodeCache(Heap* heap) {
// No write barrier is needed since empty_fixed_array is not in new space.
// Please note this function is used during marking:
diff --git a/src/objects-printer.cc b/src/objects-printer.cc
index 5cb5269..3573572 100644
--- a/src/objects-printer.cc
+++ b/src/objects-printer.cc
@@ -151,6 +151,9 @@
case JS_PROXY_TYPE:
JSProxy::cast(this)->JSProxyPrint(out);
break;
+ case JS_WEAK_MAP_TYPE:
+ JSWeakMap::cast(this)->JSWeakMapPrint(out);
+ break;
case FOREIGN_TYPE:
Foreign::cast(this)->ForeignPrint(out);
break;
@@ -289,7 +292,7 @@
if (p->is_the_hole(i)) {
PrintF(out, " %d: <the hole>", i);
} else {
- PrintF(out, " %d: %g", i, p->get(i));
+ PrintF(out, " %d: %g", i, p->get_scalar(i));
}
PrintF(out, "\n");
}
@@ -298,14 +301,14 @@
case EXTERNAL_PIXEL_ELEMENTS: {
ExternalPixelArray* p = ExternalPixelArray::cast(elements());
for (int i = 0; i < p->length(); i++) {
- PrintF(out, " %d: %d\n", i, p->get(i));
+ PrintF(out, " %d: %d\n", i, p->get_scalar(i));
}
break;
}
case EXTERNAL_BYTE_ELEMENTS: {
ExternalByteArray* p = ExternalByteArray::cast(elements());
for (int i = 0; i < p->length(); i++) {
- PrintF(out, " %d: %d\n", i, static_cast<int>(p->get(i)));
+ PrintF(out, " %d: %d\n", i, static_cast<int>(p->get_scalar(i)));
}
break;
}
@@ -313,14 +316,14 @@
ExternalUnsignedByteArray* p =
ExternalUnsignedByteArray::cast(elements());
for (int i = 0; i < p->length(); i++) {
- PrintF(out, " %d: %d\n", i, static_cast<int>(p->get(i)));
+ PrintF(out, " %d: %d\n", i, static_cast<int>(p->get_scalar(i)));
}
break;
}
case EXTERNAL_SHORT_ELEMENTS: {
ExternalShortArray* p = ExternalShortArray::cast(elements());
for (int i = 0; i < p->length(); i++) {
- PrintF(out, " %d: %d\n", i, static_cast<int>(p->get(i)));
+ PrintF(out, " %d: %d\n", i, static_cast<int>(p->get_scalar(i)));
}
break;
}
@@ -328,14 +331,14 @@
ExternalUnsignedShortArray* p =
ExternalUnsignedShortArray::cast(elements());
for (int i = 0; i < p->length(); i++) {
- PrintF(out, " %d: %d\n", i, static_cast<int>(p->get(i)));
+ PrintF(out, " %d: %d\n", i, static_cast<int>(p->get_scalar(i)));
}
break;
}
case EXTERNAL_INT_ELEMENTS: {
ExternalIntArray* p = ExternalIntArray::cast(elements());
for (int i = 0; i < p->length(); i++) {
- PrintF(out, " %d: %d\n", i, static_cast<int>(p->get(i)));
+ PrintF(out, " %d: %d\n", i, static_cast<int>(p->get_scalar(i)));
}
break;
}
@@ -343,21 +346,21 @@
ExternalUnsignedIntArray* p =
ExternalUnsignedIntArray::cast(elements());
for (int i = 0; i < p->length(); i++) {
- PrintF(out, " %d: %d\n", i, static_cast<int>(p->get(i)));
+ PrintF(out, " %d: %d\n", i, static_cast<int>(p->get_scalar(i)));
}
break;
}
case EXTERNAL_FLOAT_ELEMENTS: {
ExternalFloatArray* p = ExternalFloatArray::cast(elements());
for (int i = 0; i < p->length(); i++) {
- PrintF(out, " %d: %f\n", i, p->get(i));
+ PrintF(out, " %d: %f\n", i, p->get_scalar(i));
}
break;
}
case EXTERNAL_DOUBLE_ELEMENTS: {
ExternalDoubleArray* p = ExternalDoubleArray::cast(elements());
for (int i = 0; i < p->length(); i++) {
- PrintF(out, " %d: %f\n", i, p->get(i));
+ PrintF(out, " %d: %f\n", i, p->get_scalar(i));
}
break;
}
@@ -431,6 +434,7 @@
case CODE_TYPE: return "CODE";
case JS_ARRAY_TYPE: return "JS_ARRAY";
case JS_PROXY_TYPE: return "JS_PROXY";
+ case JS_WEAK_MAP_TYPE: return "JS_WEAK_MAP";
case JS_REGEXP_TYPE: return "JS_REGEXP";
case JS_VALUE_TYPE: return "JS_VALUE";
case JS_GLOBAL_OBJECT_TYPE: return "JS_GLOBAL_OBJECT";
@@ -584,6 +588,16 @@
}
+void JSWeakMap::JSWeakMapPrint(FILE* out) {
+ HeapObject::PrintHeader(out, "JSWeakMap");
+ PrintF(out, " - map = 0x%p\n", reinterpret_cast<void*>(map()));
+ PrintF(out, " - number of elements = %d\n", table()->NumberOfElements());
+ PrintF(out, " - table = ");
+ table()->ShortPrint(out);
+ PrintF(out, "\n");
+}
+
+
void JSFunction::JSFunctionPrint(FILE* out) {
HeapObject::PrintHeader(out, "Function");
PrintF(out, " - map = 0x%p\n", reinterpret_cast<void*>(map()));
diff --git a/src/objects-visiting.cc b/src/objects-visiting.cc
index 4cd795e..84ab57f 100644
--- a/src/objects-visiting.cc
+++ b/src/objects-visiting.cc
@@ -88,6 +88,9 @@
case JS_GLOBAL_PROPERTY_CELL_TYPE:
return kVisitPropertyCell;
+ case JS_WEAK_MAP_TYPE:
+ return kVisitJSWeakMap;
+
case JS_REGEXP_TYPE:
return kVisitJSRegExp;
diff --git a/src/objects-visiting.h b/src/objects-visiting.h
index cc64763..c96a8ef 100644
--- a/src/objects-visiting.h
+++ b/src/objects-visiting.h
@@ -121,6 +121,7 @@
kVisitPropertyCell,
kVisitSharedFunctionInfo,
kVisitJSFunction,
+ kVisitJSWeakMap,
kVisitJSRegExp,
kVisitorIdCount,
@@ -317,7 +318,9 @@
SharedFunctionInfo::BodyDescriptor,
int>::Visit);
- table_.Register(kVisitJSRegExp, &VisitJSRegExp);
+ table_.Register(kVisitJSWeakMap, &VisitJSObject);
+
+ table_.Register(kVisitJSRegExp, &VisitJSObject);
table_.Register(kVisitSeqAsciiString, &VisitSeqAsciiString);
@@ -356,15 +359,15 @@
return FixedDoubleArray::SizeFor(length);
}
+ static inline int VisitJSObject(Map* map, HeapObject* object) {
+ return JSObjectVisitor::Visit(map, object);
+ }
+
static inline int VisitSeqAsciiString(Map* map, HeapObject* object) {
return SeqAsciiString::cast(object)->
SeqAsciiStringSize(map->instance_type());
}
- static inline int VisitJSRegExp(Map* map, HeapObject* object) {
- return JSObjectVisitor::Visit(map, object);
- }
-
static inline int VisitSeqTwoByteString(Map* map, HeapObject* object) {
return SeqTwoByteString::cast(object)->
SeqTwoByteStringSize(map->instance_type());
diff --git a/src/objects.cc b/src/objects.cc
index e1318bc..e35274d 100644
--- a/src/objects.cc
+++ b/src/objects.cc
@@ -33,6 +33,7 @@
#include "codegen.h"
#include "debug.h"
#include "deoptimizer.h"
+#include "elements.h"
#include "execution.h"
#include "full-codegen.h"
#include "hydrogen.h"
@@ -602,36 +603,68 @@
MaybeObject* Object::GetElementWithReceiver(Object* receiver, uint32_t index) {
- Object* holder = NULL;
- if (IsSmi()) {
- Context* global_context = Isolate::Current()->context()->global_context();
- holder = global_context->number_function()->instance_prototype();
- } else {
- HeapObject* heap_object = HeapObject::cast(this);
+ Heap* heap = IsSmi()
+ ? Isolate::Current()->heap()
+ : HeapObject::cast(this)->GetHeap();
+ Object* holder = this;
- if (heap_object->IsJSObject()) {
- return JSObject::cast(this)->GetElementWithReceiver(receiver, index);
- }
- Heap* heap = heap_object->GetHeap();
- Isolate* isolate = heap->isolate();
-
- Context* global_context = isolate->context()->global_context();
- if (heap_object->IsString()) {
- holder = global_context->string_function()->instance_prototype();
- } else if (heap_object->IsHeapNumber()) {
+ // Iterate up the prototype chain until an element is found or the null
+ // prototype is encountered.
+ for (holder = this;
+ holder != heap->null_value();
+ holder = holder->GetPrototype()) {
+ if (holder->IsSmi()) {
+ Context* global_context = Isolate::Current()->context()->global_context();
holder = global_context->number_function()->instance_prototype();
- } else if (heap_object->IsBoolean()) {
- holder = global_context->boolean_function()->instance_prototype();
- } else if (heap_object->IsJSProxy()) {
- return heap->undefined_value(); // For now...
} else {
- // Undefined and null have no indexed properties.
- ASSERT(heap_object->IsUndefined() || heap_object->IsNull());
- return heap->undefined_value();
+ HeapObject* heap_object = HeapObject::cast(holder);
+ if (!heap_object->IsJSObject()) {
+ Isolate* isolate = heap->isolate();
+ Context* global_context = isolate->context()->global_context();
+ if (heap_object->IsString()) {
+ holder = global_context->string_function()->instance_prototype();
+ } else if (heap_object->IsHeapNumber()) {
+ holder = global_context->number_function()->instance_prototype();
+ } else if (heap_object->IsBoolean()) {
+ holder = global_context->boolean_function()->instance_prototype();
+ } else if (heap_object->IsJSProxy()) {
+ return heap->undefined_value(); // For now...
+ } else {
+ // Undefined and null have no indexed properties.
+ ASSERT(heap_object->IsUndefined() || heap_object->IsNull());
+ return heap->undefined_value();
+ }
+ }
+ }
+
+ // Inline the case for JSObjects. Doing so significantly improves the
+ // performance of fetching elements where checking the prototype chain is
+ // necessary.
+ JSObject* js_object = JSObject::cast(holder);
+
+ // Check access rights if needed.
+ if (js_object->IsAccessCheckNeeded()) {
+ Isolate* isolate = heap->isolate();
+ if (!isolate->MayIndexedAccess(js_object, index, v8::ACCESS_GET)) {
+ isolate->ReportFailedAccessCheck(js_object, v8::ACCESS_GET);
+ return heap->undefined_value();
+ }
+ }
+
+ if (js_object->HasIndexedInterceptor()) {
+ return js_object->GetElementWithInterceptor(receiver, index);
+ }
+
+ if (js_object->elements() != heap->empty_fixed_array()) {
+ MaybeObject* result = js_object->GetElementsAccessor()->GetWithReceiver(
+ js_object,
+ receiver,
+ index);
+ if (result != heap->the_hole_value()) return result;
}
}
- return JSObject::cast(holder)->GetElementWithReceiver(receiver, index);
+ return heap->undefined_value();
}
@@ -962,6 +995,11 @@
accumulator->Add("<JS array[%u]>", static_cast<uint32_t>(length));
break;
}
+ case JS_WEAK_MAP_TYPE: {
+ int elements = JSWeakMap::cast(this)->table()->NumberOfElements();
+ accumulator->Add("<JS WeakMap[%d]>", elements);
+ break;
+ }
case JS_REGEXP_TYPE: {
accumulator->Add("<JS RegExp>");
break;
@@ -1192,6 +1230,7 @@
case JS_CONTEXT_EXTENSION_OBJECT_TYPE:
case JS_VALUE_TYPE:
case JS_ARRAY_TYPE:
+ case JS_WEAK_MAP_TYPE:
case JS_REGEXP_TYPE:
case JS_GLOBAL_PROXY_TYPE:
case JS_GLOBAL_OBJECT_TYPE:
@@ -2923,7 +2962,7 @@
// exceed the capacity of new space, and we would fail repeatedly
// trying to convert the FixedDoubleArray.
MaybeObject* maybe_value_object =
- GetHeap()->AllocateHeapNumber(double_array->get(i), TENURED);
+ GetHeap()->AllocateHeapNumber(double_array->get_scalar(i), TENURED);
if (!maybe_value_object->ToObject(&value)) return maybe_value_object;
}
} else {
@@ -3101,48 +3140,6 @@
}
-MaybeObject* JSObject::DeleteElementPostInterceptor(uint32_t index,
- DeleteMode mode) {
- ASSERT(!HasExternalArrayElements());
- switch (GetElementsKind()) {
- case FAST_ELEMENTS: {
- Object* obj;
- { MaybeObject* maybe_obj = EnsureWritableFastElements();
- if (!maybe_obj->ToObject(&obj)) return maybe_obj;
- }
- uint32_t length = IsJSArray() ?
- static_cast<uint32_t>(Smi::cast(JSArray::cast(this)->length())->value()) :
- static_cast<uint32_t>(FixedArray::cast(elements())->length());
- if (index < length) {
- FixedArray::cast(elements())->set_the_hole(index);
- }
- break;
- }
- case DICTIONARY_ELEMENTS: {
- NumberDictionary* dictionary = element_dictionary();
- int entry = dictionary->FindEntry(index);
- if (entry != NumberDictionary::kNotFound) {
- Object* deleted = dictionary->DeleteProperty(entry, mode);
- if (deleted == GetHeap()->true_value()) {
- MaybeObject* maybe_elements = dictionary->Shrink(index);
- FixedArray* new_elements = NULL;
- if (!maybe_elements->To(&new_elements)) {
- return maybe_elements;
- }
- set_elements(new_elements);
- }
- return deleted;
- }
- break;
- }
- default:
- UNREACHABLE();
- break;
- }
- return GetHeap()->true_value();
-}
-
-
MaybeObject* JSObject::DeleteElementWithInterceptor(uint32_t index) {
Isolate* isolate = GetIsolate();
Heap* heap = isolate->heap();
@@ -3170,100 +3167,14 @@
ASSERT(result->IsBoolean());
return *v8::Utils::OpenHandle(*result);
}
- MaybeObject* raw_result =
- this_handle->DeleteElementPostInterceptor(index, NORMAL_DELETION);
+ MaybeObject* raw_result = GetElementsAccessor()->Delete(*this_handle,
+ index,
+ NORMAL_DELETION);
RETURN_IF_SCHEDULED_EXCEPTION(isolate);
return raw_result;
}
-MaybeObject* JSObject::DeleteFastElement(uint32_t index) {
- ASSERT(HasFastElements() || HasFastArgumentsElements());
- Heap* heap = GetHeap();
- FixedArray* backing_store = FixedArray::cast(elements());
- if (backing_store->map() == heap->non_strict_arguments_elements_map()) {
- backing_store = FixedArray::cast(backing_store->get(1));
- } else {
- Object* writable;
- MaybeObject* maybe = EnsureWritableFastElements();
- if (!maybe->ToObject(&writable)) return maybe;
- backing_store = FixedArray::cast(writable);
- }
- uint32_t length = static_cast<uint32_t>(
- IsJSArray()
- ? Smi::cast(JSArray::cast(this)->length())->value()
- : backing_store->length());
- if (index < length) {
- backing_store->set_the_hole(index);
- // If an old space backing store is larger than a certain size and
- // has too few used values, normalize it.
- // To avoid doing the check on every delete we require at least
- // one adjacent hole to the value being deleted.
- Object* hole = heap->the_hole_value();
- const int kMinLengthForSparsenessCheck = 64;
- if (backing_store->length() >= kMinLengthForSparsenessCheck &&
- !heap->InNewSpace(backing_store) &&
- ((index > 0 && backing_store->get(index - 1) == hole) ||
- (index + 1 < length && backing_store->get(index + 1) == hole))) {
- int num_used = 0;
- for (int i = 0; i < backing_store->length(); ++i) {
- if (backing_store->get(i) != hole) ++num_used;
- // Bail out early if more than 1/4 is used.
- if (4 * num_used > backing_store->length()) break;
- }
- if (4 * num_used <= backing_store->length()) {
- MaybeObject* result = NormalizeElements();
- if (result->IsFailure()) return result;
- }
- }
- }
- return heap->true_value();
-}
-
-
-MaybeObject* JSObject::DeleteDictionaryElement(uint32_t index,
- DeleteMode mode) {
- Isolate* isolate = GetIsolate();
- Heap* heap = isolate->heap();
- FixedArray* backing_store = FixedArray::cast(elements());
- bool is_arguments =
- (GetElementsKind() == JSObject::NON_STRICT_ARGUMENTS_ELEMENTS);
- if (is_arguments) {
- backing_store = FixedArray::cast(backing_store->get(1));
- }
- NumberDictionary* dictionary = NumberDictionary::cast(backing_store);
- int entry = dictionary->FindEntry(index);
- if (entry != NumberDictionary::kNotFound) {
- Object* result = dictionary->DeleteProperty(entry, mode);
- if (result == heap->true_value()) {
- MaybeObject* maybe_elements = dictionary->Shrink(index);
- FixedArray* new_elements = NULL;
- if (!maybe_elements->To(&new_elements)) {
- return maybe_elements;
- }
- if (is_arguments) {
- FixedArray::cast(elements())->set(1, new_elements);
- } else {
- set_elements(new_elements);
- }
- }
- if (mode == STRICT_DELETION && result == heap->false_value()) {
- // In strict mode, attempting to delete a non-configurable property
- // throws an exception.
- HandleScope scope(isolate);
- Handle<Object> holder(this);
- Handle<Object> name = isolate->factory()->NewNumberFromUint(index);
- Handle<Object> args[2] = { name, holder };
- Handle<Object> error =
- isolate->factory()->NewTypeError("strict_delete_property",
- HandleVector(args, 2));
- return isolate->Throw(*error);
- }
- }
- return heap->true_value();
-}
-
-
MaybeObject* JSObject::DeleteElement(uint32_t index, DeleteMode mode) {
Isolate* isolate = GetIsolate();
// Check access rights if needed.
@@ -3282,62 +3193,13 @@
if (HasIndexedInterceptor()) {
// Skip interceptor if forcing deletion.
- return (mode == FORCE_DELETION)
- ? DeleteElementPostInterceptor(index, FORCE_DELETION)
- : DeleteElementWithInterceptor(index);
+ if (mode != FORCE_DELETION) {
+ return DeleteElementWithInterceptor(index);
+ }
+ mode = JSReceiver::FORCE_DELETION;
}
- switch (GetElementsKind()) {
- case FAST_ELEMENTS:
- return DeleteFastElement(index);
-
- case DICTIONARY_ELEMENTS:
- return DeleteDictionaryElement(index, mode);
-
- case FAST_DOUBLE_ELEMENTS: {
- int length = IsJSArray()
- ? Smi::cast(JSArray::cast(this)->length())->value()
- : FixedDoubleArray::cast(elements())->length();
- if (index < static_cast<uint32_t>(length)) {
- FixedDoubleArray::cast(elements())->set_the_hole(index);
- }
- break;
- }
- case EXTERNAL_PIXEL_ELEMENTS:
- case EXTERNAL_BYTE_ELEMENTS:
- case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
- case EXTERNAL_SHORT_ELEMENTS:
- case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
- case EXTERNAL_INT_ELEMENTS:
- case EXTERNAL_UNSIGNED_INT_ELEMENTS:
- case EXTERNAL_FLOAT_ELEMENTS:
- case EXTERNAL_DOUBLE_ELEMENTS:
- // Pixel and external array elements cannot be deleted. Just
- // silently ignore here.
- break;
-
- case NON_STRICT_ARGUMENTS_ELEMENTS: {
- FixedArray* parameter_map = FixedArray::cast(elements());
- uint32_t length = parameter_map->length();
- Object* probe =
- index < (length - 2) ? parameter_map->get(index + 2) : NULL;
- if (probe != NULL && !probe->IsTheHole()) {
- // TODO(kmillikin): We could check if this was the last aliased
- // parameter, and revert to normal elements in that case. That
- // would enable GC of the context.
- parameter_map->set_the_hole(index + 2);
- } else {
- FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
- if (arguments->IsDictionary()) {
- return DeleteDictionaryElement(index, mode);
- } else {
- return DeleteFastElement(index);
- }
- }
- break;
- }
- }
- return isolate->heap()->true_value();
+ return GetElementsAccessor()->Delete(this, index, mode);
}
@@ -4775,51 +4637,7 @@
MaybeObject* FixedArray::AddKeysFromJSArray(JSArray* array) {
- ASSERT(!array->HasExternalArrayElements());
- switch (array->GetElementsKind()) {
- case JSObject::FAST_ELEMENTS:
- return UnionOfKeys(FixedArray::cast(array->elements()));
- case JSObject::FAST_DOUBLE_ELEMENTS:
- return UnionOfDoubleKeys(FixedDoubleArray::cast(array->elements()));
- break;
- case JSObject::DICTIONARY_ELEMENTS: {
- NumberDictionary* dict = array->element_dictionary();
- int size = dict->NumberOfElements();
-
- // Allocate a temporary fixed array.
- Object* object;
- { MaybeObject* maybe_object = GetHeap()->AllocateFixedArray(size);
- if (!maybe_object->ToObject(&object)) return maybe_object;
- }
- FixedArray* key_array = FixedArray::cast(object);
-
- int capacity = dict->Capacity();
- int pos = 0;
- // Copy the elements from the JSArray to the temporary fixed array.
- for (int i = 0; i < capacity; i++) {
- if (dict->IsKey(dict->KeyAt(i))) {
- key_array->set(pos++, dict->ValueAt(i));
- }
- }
- // Compute the union of this and the temporary fixed array.
- return UnionOfKeys(key_array);
- }
- case JSObject::NON_STRICT_ARGUMENTS_ELEMENTS:
- UNIMPLEMENTED();
- break;
- case JSObject::EXTERNAL_BYTE_ELEMENTS:
- case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
- case JSObject::EXTERNAL_SHORT_ELEMENTS:
- case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
- case JSObject::EXTERNAL_INT_ELEMENTS:
- case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS:
- case JSObject::EXTERNAL_FLOAT_ELEMENTS:
- case JSObject::EXTERNAL_DOUBLE_ELEMENTS:
- case JSObject::EXTERNAL_PIXEL_ELEMENTS:
- break;
- }
- UNREACHABLE();
- return GetHeap()->null_value(); // Failure case needs to "return" a value.
+ return array->GetElementsAccessor()->AddJSArrayKeysToFixedArray(array, this);
}
@@ -4877,69 +4695,6 @@
}
-MaybeObject* FixedArray::UnionOfDoubleKeys(FixedDoubleArray* other) {
- int len0 = length();
-#ifdef DEBUG
- if (FLAG_enable_slow_asserts) {
- for (int i = 0; i < len0; i++) {
- ASSERT(get(i)->IsString() || get(i)->IsNumber());
- }
- }
-#endif
- int len1 = other->length();
- // Optimize if 'other' is empty.
- // We cannot optimize if 'this' is empty, as other may have holes
- // or non keys.
- if (len1 == 0) return this;
-
- // Compute how many elements are not in this.
- int extra = 0;
- Heap* heap = GetHeap();
- Object* obj;
- for (int y = 0; y < len1; y++) {
- if (!other->is_the_hole(y)) {
- MaybeObject* maybe_obj = heap->NumberFromDouble(other->get(y));
- if (!maybe_obj->ToObject(&obj)) return maybe_obj;
- if (!HasKey(this, obj)) extra++;
- }
- }
-
- if (extra == 0) return this;
-
- // Allocate the result
- { MaybeObject* maybe_obj = GetHeap()->AllocateFixedArray(len0 + extra);
- if (!maybe_obj->ToObject(&obj)) return maybe_obj;
- }
- // Fill in the content
- FixedArray* result = FixedArray::cast(obj);
- {
- // Limit the scope of the AssertNoAllocation
- AssertNoAllocation no_gc;
- WriteBarrierMode mode = result->GetWriteBarrierMode(no_gc);
- for (int i = 0; i < len0; i++) {
- Object* e = get(i);
- ASSERT(e->IsString() || e->IsNumber());
- result->set(i, e, mode);
- }
- }
-
- // Fill in the extra keys.
- int index = 0;
- for (int y = 0; y < len1; y++) {
- if (!other->is_the_hole(y)) {
- MaybeObject* maybe_obj = heap->NumberFromDouble(other->get(y));
- if (!maybe_obj->ToObject(&obj)) return maybe_obj;
- if (!HasKey(this, obj)) {
- result->set(len0 + index, obj);
- index++;
- }
- }
- }
- ASSERT(extra == index);
- return result;
-}
-
-
MaybeObject* FixedArray::CopySize(int new_length) {
Heap* heap = GetHeap();
if (new_length == 0) return heap->empty_fixed_array();
@@ -7208,124 +6963,93 @@
PrintF(out, "%6s %6s %6s %12s\n", "index", "ast id", "argc", "commands");
for (int i = 0; i < deopt_count; i++) {
- int command_count = 0;
PrintF(out, "%6d %6d %6d",
i, AstId(i)->value(), ArgumentsStackHeight(i)->value());
+
+ if (!FLAG_print_code_verbose) continue;
+ // Print details of the frame translation.
int translation_index = TranslationIndex(i)->value();
TranslationIterator iterator(TranslationByteArray(), translation_index);
Translation::Opcode opcode =
static_cast<Translation::Opcode>(iterator.Next());
ASSERT(Translation::BEGIN == opcode);
int frame_count = iterator.Next();
- if (FLAG_print_code_verbose) {
- PrintF(out, " %s {count=%d}\n", Translation::StringFor(opcode),
- frame_count);
- }
+ PrintF(out, " %s {count=%d}\n", Translation::StringFor(opcode),
+ frame_count);
- for (int i = 0; i < frame_count; ++i) {
- opcode = static_cast<Translation::Opcode>(iterator.Next());
- ASSERT(Translation::FRAME == opcode);
- int ast_id = iterator.Next();
- int function_id = iterator.Next();
- JSFunction* function =
- JSFunction::cast(LiteralArray()->get(function_id));
- unsigned height = iterator.Next();
- if (FLAG_print_code_verbose) {
- PrintF(out, "%24s %s {ast_id=%d, function=",
- "", Translation::StringFor(opcode), ast_id);
- function->PrintName(out);
- PrintF(out, ", height=%u}\n", height);
+ while (iterator.HasNext() &&
+ Translation::BEGIN !=
+ (opcode = static_cast<Translation::Opcode>(iterator.Next()))) {
+ PrintF(out, "%24s %s ", "", Translation::StringFor(opcode));
+
+ switch (opcode) {
+ case Translation::BEGIN:
+ UNREACHABLE();
+ break;
+
+ case Translation::FRAME: {
+ int ast_id = iterator.Next();
+ int function_id = iterator.Next();
+ JSFunction* function =
+ JSFunction::cast(LiteralArray()->get(function_id));
+ unsigned height = iterator.Next();
+ PrintF(out, "{ast_id=%d, \nfunction=", ast_id);
+ function->PrintName(out);
+ PrintF(out, ", height=%u}", height);
+ break;
+ }
+
+ case Translation::DUPLICATE:
+ break;
+
+ case Translation::REGISTER: {
+ int reg_code = iterator.Next();
+ PrintF(out, "{input=%s}", converter.NameOfCPURegister(reg_code));
+ break;
+ }
+
+ case Translation::INT32_REGISTER: {
+ int reg_code = iterator.Next();
+ PrintF(out, "{input=%s}", converter.NameOfCPURegister(reg_code));
+ break;
+ }
+
+ case Translation::DOUBLE_REGISTER: {
+ int reg_code = iterator.Next();
+ PrintF(out, "{input=%s}",
+ DoubleRegister::AllocationIndexToString(reg_code));
+ break;
+ }
+
+ case Translation::STACK_SLOT: {
+ int input_slot_index = iterator.Next();
+ PrintF(out, "{input=%d}", input_slot_index);
+ break;
+ }
+
+ case Translation::INT32_STACK_SLOT: {
+ int input_slot_index = iterator.Next();
+ PrintF(out, "{input=%d}", input_slot_index);
+ break;
+ }
+
+ case Translation::DOUBLE_STACK_SLOT: {
+ int input_slot_index = iterator.Next();
+ PrintF(out, "{input=%d}", input_slot_index);
+ break;
+ }
+
+ case Translation::LITERAL: {
+ unsigned literal_index = iterator.Next();
+ PrintF(out, "{literal_id=%u}", literal_index);
+ break;
+ }
+
+ case Translation::ARGUMENTS_OBJECT:
+ break;
}
-
- // Size of translation is height plus all incoming arguments including
- // receiver.
- int size = height + function->shared()->formal_parameter_count() + 1;
- command_count += size;
- for (int j = 0; j < size; ++j) {
- opcode = static_cast<Translation::Opcode>(iterator.Next());
- if (FLAG_print_code_verbose) {
- PrintF(out, "%24s %s ", "", Translation::StringFor(opcode));
- }
-
- if (opcode == Translation::DUPLICATE) {
- opcode = static_cast<Translation::Opcode>(iterator.Next());
- if (FLAG_print_code_verbose) {
- PrintF(out, "%s ", Translation::StringFor(opcode));
- }
- --j; // Two commands share the same frame index.
- }
-
- switch (opcode) {
- case Translation::BEGIN:
- case Translation::FRAME:
- case Translation::DUPLICATE:
- UNREACHABLE();
- break;
-
- case Translation::REGISTER: {
- int reg_code = iterator.Next();
- if (FLAG_print_code_verbose) {
- PrintF(out, "{input=%s}", converter.NameOfCPURegister(reg_code));
- }
- break;
- }
-
- case Translation::INT32_REGISTER: {
- int reg_code = iterator.Next();
- if (FLAG_print_code_verbose) {
- PrintF(out, "{input=%s}", converter.NameOfCPURegister(reg_code));
- }
- break;
- }
-
- case Translation::DOUBLE_REGISTER: {
- int reg_code = iterator.Next();
- if (FLAG_print_code_verbose) {
- PrintF(out, "{input=%s}",
- DoubleRegister::AllocationIndexToString(reg_code));
- }
- break;
- }
-
- case Translation::STACK_SLOT: {
- int input_slot_index = iterator.Next();
- if (FLAG_print_code_verbose) {
- PrintF(out, "{input=%d}", input_slot_index);
- }
- break;
- }
-
- case Translation::INT32_STACK_SLOT: {
- int input_slot_index = iterator.Next();
- if (FLAG_print_code_verbose) {
- PrintF(out, "{input=%d}", input_slot_index);
- }
- break;
- }
-
- case Translation::DOUBLE_STACK_SLOT: {
- int input_slot_index = iterator.Next();
- if (FLAG_print_code_verbose) {
- PrintF(out, "{input=%d}", input_slot_index);
- }
- break;
- }
-
- case Translation::LITERAL: {
- unsigned literal_index = iterator.Next();
- if (FLAG_print_code_verbose) {
- PrintF(out, "{literal_id=%u}", literal_index);
- }
- break;
- }
-
- case Translation::ARGUMENTS_OBJECT:
- break;
- }
- if (FLAG_print_code_verbose) PrintF(out, "\n");
- }
+ PrintF(out, "\n");
}
- if (!FLAG_print_code_verbose) PrintF(out, " %12d\n", command_count);
}
}
@@ -7602,7 +7326,8 @@
// exceed the capacity of new space, and we would fail repeatedly
// trying to convert the FixedDoubleArray.
MaybeObject* maybe_value_object =
- GetHeap()->AllocateHeapNumber(old_elements->get(i), TENURED);
+ GetHeap()->AllocateHeapNumber(old_elements->get_scalar(i),
+ TENURED);
if (!maybe_value_object->ToObject(&obj)) return maybe_value_object;
// Force write barrier. It's not worth trying to exploit
// elems->GetWriteBarrierMode(), since it requires an
@@ -8945,71 +8670,6 @@
}
-MaybeObject* JSObject::GetElementPostInterceptor(Object* receiver,
- uint32_t index) {
- // Get element works for both JSObject and JSArray since
- // JSArray::length cannot change.
- switch (GetElementsKind()) {
- case FAST_ELEMENTS: {
- FixedArray* elms = FixedArray::cast(elements());
- if (index < static_cast<uint32_t>(elms->length())) {
- Object* value = elms->get(index);
- if (!value->IsTheHole()) return value;
- }
- break;
- }
- case FAST_DOUBLE_ELEMENTS: {
- FixedDoubleArray* elms = FixedDoubleArray::cast(elements());
- if (index < static_cast<uint32_t>(elms->length())) {
- if (!elms->is_the_hole(index)) {
- return GetHeap()->NumberFromDouble(elms->get(index));
- }
- }
- break;
- }
- case EXTERNAL_PIXEL_ELEMENTS:
- case EXTERNAL_BYTE_ELEMENTS:
- case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
- case EXTERNAL_SHORT_ELEMENTS:
- case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
- case EXTERNAL_INT_ELEMENTS:
- case EXTERNAL_UNSIGNED_INT_ELEMENTS:
- case EXTERNAL_FLOAT_ELEMENTS:
- case EXTERNAL_DOUBLE_ELEMENTS: {
- MaybeObject* maybe_value = GetExternalElement(index);
- Object* value;
- if (!maybe_value->ToObject(&value)) return maybe_value;
- if (!value->IsUndefined()) return value;
- break;
- }
- case DICTIONARY_ELEMENTS: {
- NumberDictionary* dictionary = element_dictionary();
- int entry = dictionary->FindEntry(index);
- if (entry != NumberDictionary::kNotFound) {
- Object* element = dictionary->ValueAt(entry);
- PropertyDetails details = dictionary->DetailsAt(entry);
- if (details.type() == CALLBACKS) {
- return GetElementWithCallback(receiver,
- element,
- index,
- this);
- }
- return element;
- }
- break;
- }
- case NON_STRICT_ARGUMENTS_ELEMENTS:
- UNIMPLEMENTED();
- break;
- }
-
- // Continue searching via the prototype chain.
- Object* pt = GetPrototype();
- if (pt->IsNull()) return GetHeap()->undefined_value();
- return pt->GetElementWithReceiver(receiver, index);
-}
-
-
MaybeObject* JSObject::GetElementWithInterceptor(Object* receiver,
uint32_t index) {
Isolate* isolate = GetIsolate();
@@ -9037,212 +8697,18 @@
if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
}
- MaybeObject* raw_result =
- holder_handle->GetElementPostInterceptor(*this_handle, index);
+ Heap* heap = holder_handle->GetHeap();
+ ElementsAccessor* handler = holder_handle->GetElementsAccessor();
+ MaybeObject* raw_result = handler->GetWithReceiver(*holder_handle,
+ *this_handle,
+ index);
+ if (raw_result != heap->the_hole_value()) return raw_result;
+
RETURN_IF_SCHEDULED_EXCEPTION(isolate);
- return raw_result;
-}
-
-MaybeObject* JSObject::GetElementWithReceiver(Object* receiver,
- uint32_t index) {
- // Check access rights if needed.
- if (IsAccessCheckNeeded()) {
- Heap* heap = GetHeap();
- if (!heap->isolate()->MayIndexedAccess(this, index, v8::ACCESS_GET)) {
- heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_GET);
- return heap->undefined_value();
- }
- }
-
- if (HasIndexedInterceptor()) {
- return GetElementWithInterceptor(receiver, index);
- }
-
- // Get element works for both JSObject and JSArray since
- // JSArray::length cannot change.
- switch (GetElementsKind()) {
- case FAST_ELEMENTS: {
- FixedArray* elms = FixedArray::cast(elements());
- if (index < static_cast<uint32_t>(elms->length())) {
- Object* value = elms->get(index);
- if (!value->IsTheHole()) return value;
- }
- break;
- }
- case FAST_DOUBLE_ELEMENTS: {
- FixedDoubleArray* elms = FixedDoubleArray::cast(elements());
- if (index < static_cast<uint32_t>(elms->length())) {
- if (!elms->is_the_hole(index)) {
- double double_value = elms->get(index);
- return GetHeap()->NumberFromDouble(double_value);
- }
- }
- break;
- }
- case EXTERNAL_PIXEL_ELEMENTS:
- case EXTERNAL_BYTE_ELEMENTS:
- case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
- case EXTERNAL_SHORT_ELEMENTS:
- case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
- case EXTERNAL_INT_ELEMENTS:
- case EXTERNAL_UNSIGNED_INT_ELEMENTS:
- case EXTERNAL_FLOAT_ELEMENTS:
- case EXTERNAL_DOUBLE_ELEMENTS: {
- MaybeObject* maybe_value = GetExternalElement(index);
- Object* value;
- if (!maybe_value->ToObject(&value)) return maybe_value;
- if (!value->IsUndefined()) return value;
- break;
- }
- case DICTIONARY_ELEMENTS: {
- NumberDictionary* dictionary = element_dictionary();
- int entry = dictionary->FindEntry(index);
- if (entry != NumberDictionary::kNotFound) {
- Object* element = dictionary->ValueAt(entry);
- PropertyDetails details = dictionary->DetailsAt(entry);
- if (details.type() == CALLBACKS) {
- return GetElementWithCallback(receiver,
- element,
- index,
- this);
- }
- return element;
- }
- break;
- }
- case NON_STRICT_ARGUMENTS_ELEMENTS: {
- FixedArray* parameter_map = FixedArray::cast(elements());
- uint32_t length = parameter_map->length();
- Object* probe =
- (index < length - 2) ? parameter_map->get(index + 2) : NULL;
- if (probe != NULL && !probe->IsTheHole()) {
- Context* context = Context::cast(parameter_map->get(0));
- int context_index = Smi::cast(probe)->value();
- ASSERT(!context->get(context_index)->IsTheHole());
- return context->get(context_index);
- } else {
- // Object is not mapped, defer to the arguments.
- FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
- if (arguments->IsDictionary()) {
- NumberDictionary* dictionary = NumberDictionary::cast(arguments);
- int entry = dictionary->FindEntry(index);
- if (entry != NumberDictionary::kNotFound) {
- Object* element = dictionary->ValueAt(entry);
- PropertyDetails details = dictionary->DetailsAt(entry);
- if (details.type() == CALLBACKS) {
- return GetElementWithCallback(receiver,
- element,
- index,
- this);
- }
- return element;
- }
- } else if (index < static_cast<uint32_t>(arguments->length())) {
- Object* value = arguments->get(index);
- if (!value->IsTheHole()) return value;
- }
- }
- break;
- }
- }
-
- Object* pt = GetPrototype();
- Heap* heap = GetHeap();
+ Object* pt = holder_handle->GetPrototype();
if (pt == heap->null_value()) return heap->undefined_value();
- return pt->GetElementWithReceiver(receiver, index);
-}
-
-
-MaybeObject* JSObject::GetExternalElement(uint32_t index) {
- // Get element works for both JSObject and JSArray since
- // JSArray::length cannot change.
- switch (GetElementsKind()) {
- case EXTERNAL_PIXEL_ELEMENTS: {
- ExternalPixelArray* pixels = ExternalPixelArray::cast(elements());
- if (index < static_cast<uint32_t>(pixels->length())) {
- uint8_t value = pixels->get(index);
- return Smi::FromInt(value);
- }
- break;
- }
- case EXTERNAL_BYTE_ELEMENTS: {
- ExternalByteArray* array = ExternalByteArray::cast(elements());
- if (index < static_cast<uint32_t>(array->length())) {
- int8_t value = array->get(index);
- return Smi::FromInt(value);
- }
- break;
- }
- case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
- ExternalUnsignedByteArray* array =
- ExternalUnsignedByteArray::cast(elements());
- if (index < static_cast<uint32_t>(array->length())) {
- uint8_t value = array->get(index);
- return Smi::FromInt(value);
- }
- break;
- }
- case EXTERNAL_SHORT_ELEMENTS: {
- ExternalShortArray* array = ExternalShortArray::cast(elements());
- if (index < static_cast<uint32_t>(array->length())) {
- int16_t value = array->get(index);
- return Smi::FromInt(value);
- }
- break;
- }
- case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
- ExternalUnsignedShortArray* array =
- ExternalUnsignedShortArray::cast(elements());
- if (index < static_cast<uint32_t>(array->length())) {
- uint16_t value = array->get(index);
- return Smi::FromInt(value);
- }
- break;
- }
- case EXTERNAL_INT_ELEMENTS: {
- ExternalIntArray* array = ExternalIntArray::cast(elements());
- if (index < static_cast<uint32_t>(array->length())) {
- int32_t value = array->get(index);
- return GetHeap()->NumberFromInt32(value);
- }
- break;
- }
- case EXTERNAL_UNSIGNED_INT_ELEMENTS: {
- ExternalUnsignedIntArray* array =
- ExternalUnsignedIntArray::cast(elements());
- if (index < static_cast<uint32_t>(array->length())) {
- uint32_t value = array->get(index);
- return GetHeap()->NumberFromUint32(value);
- }
- break;
- }
- case EXTERNAL_FLOAT_ELEMENTS: {
- ExternalFloatArray* array = ExternalFloatArray::cast(elements());
- if (index < static_cast<uint32_t>(array->length())) {
- float value = array->get(index);
- return GetHeap()->AllocateHeapNumber(value);
- }
- break;
- }
- case EXTERNAL_DOUBLE_ELEMENTS: {
- ExternalDoubleArray* array = ExternalDoubleArray::cast(elements());
- if (index < static_cast<uint32_t>(array->length())) {
- double value = array->get(index);
- return GetHeap()->AllocateHeapNumber(value);
- }
- break;
- }
- case FAST_DOUBLE_ELEMENTS:
- case FAST_ELEMENTS:
- case DICTIONARY_ELEMENTS:
- UNREACHABLE();
- break;
- case NON_STRICT_ARGUMENTS_ELEMENTS:
- UNIMPLEMENTED();
- break;
- }
- return GetHeap()->undefined_value();
+ return pt->GetElementWithReceiver(*this_handle, index);
}
@@ -9756,7 +9222,9 @@
}
ASSERT(storage->length() >= index);
} else {
- property_dictionary()->CopyKeysTo(storage, StringDictionary::UNSORTED);
+ property_dictionary()->CopyKeysTo(storage,
+ index,
+ StringDictionary::UNSORTED);
}
}
@@ -10505,6 +9973,7 @@
template void Dictionary<StringDictionaryShape, String*>::CopyKeysTo(
FixedArray*,
+ int,
Dictionary<StringDictionaryShape, String*>::SortMode);
template int
@@ -10728,7 +10197,7 @@
if (elements->is_the_hole(holes)) {
holes--;
} else {
- elements->set(i, elements->get(holes));
+ elements->set(i, elements->get_scalar(holes));
break;
}
}
@@ -11634,11 +11103,11 @@
template<typename Shape, typename Key>
void Dictionary<Shape, Key>::CopyKeysTo(
FixedArray* storage,
+ int index,
typename Dictionary<Shape, Key>::SortMode sort_mode) {
ASSERT(storage->length() >= NumberOfElementsFilterAttributes(
static_cast<PropertyAttributes>(NONE)));
int capacity = HashTable<Shape, Key>::Capacity();
- int index = 0;
for (int i = 0; i < capacity; i++) {
Object* k = HashTable<Shape, Key>::KeyAt(i);
if (HashTable<Shape, Key>::IsKey(k)) {
@@ -11859,10 +11328,9 @@
}
-void ObjectHashTable::RemoveEntry(int entry) {
- Object* null_value = GetHeap()->null_value();
- set(EntryToIndex(entry), null_value);
- set(EntryToIndex(entry) + 1, null_value);
+void ObjectHashTable::RemoveEntry(int entry, Heap* heap) {
+ set_null(heap, EntryToIndex(entry));
+ set_null(heap, EntryToIndex(entry) + 1);
ElementRemoved();
}
@@ -12093,7 +11561,7 @@
Handle<Object> break_point_object) {
// No break point.
if (break_point_info->break_point_objects()->IsUndefined()) return false;
- // Single beak point.
+ // Single break point.
if (!break_point_info->break_point_objects()->IsFixedArray()) {
return break_point_info->break_point_objects() == *break_point_object;
}
@@ -12112,7 +11580,7 @@
int BreakPointInfo::GetBreakPointCount() {
// No break point.
if (break_point_objects()->IsUndefined()) return 0;
- // Single beak point.
+ // Single break point.
if (!break_point_objects()->IsFixedArray()) return 1;
// Multiple break points.
return FixedArray::cast(break_point_objects())->length();
diff --git a/src/objects.h b/src/objects.h
index ba690ec..ff13aed 100644
--- a/src/objects.h
+++ b/src/objects.h
@@ -51,6 +51,7 @@
// - JSReceiver (suitable for property access)
// - JSObject
// - JSArray
+// - JSWeakMap
// - JSRegExp
// - JSFunction
// - GlobalObject
@@ -71,17 +72,19 @@
// - ExternalIntArray
// - ExternalUnsignedIntArray
// - ExternalFloatArray
-// - FixedArray
-// - DescriptorArray
-// - HashTable
-// - Dictionary
-// - SymbolTable
-// - CompilationCacheTable
-// - CodeCacheHashTable
-// - MapCache
-// - Context
-// - JSFunctionResultCache
-// - SerializedScopeInfo
+// - FixedArrayBase
+// - FixedArray
+// - DescriptorArray
+// - HashTable
+// - Dictionary
+// - SymbolTable
+// - CompilationCacheTable
+// - CodeCacheHashTable
+// - MapCache
+// - Context
+// - JSFunctionResultCache
+// - SerializedScopeInfo
+// - FixedDoubleArray
// - String
// - SeqString
// - SeqAsciiString
@@ -331,6 +334,7 @@
V(JS_GLOBAL_PROXY_TYPE) \
V(JS_ARRAY_TYPE) \
V(JS_PROXY_TYPE) \
+ V(JS_WEAK_MAP_TYPE) \
V(JS_REGEXP_TYPE) \
\
V(JS_FUNCTION_TYPE) \
@@ -568,6 +572,7 @@
JS_GLOBAL_PROXY_TYPE,
JS_ARRAY_TYPE,
JS_PROXY_TYPE,
+ JS_WEAK_MAP_TYPE,
JS_REGEXP_TYPE, // LAST_NONCALLABLE_SPEC_OBJECT_TYPE
@@ -630,8 +635,10 @@
WriteBarrierMode mode = UPDATE_WRITE_BARRIER); \
+class ElementsAccessor;
class StringStream;
class ObjectVisitor;
+class DictionaryElementsAccessor;
struct ValueInfo : public Malloced {
ValueInfo() : type(FIRST_TYPE), ptr(NULL), str(NULL), number(0) { }
@@ -748,6 +755,7 @@
V(JSArray) \
V(JSProxy) \
V(JSFunctionProxy) \
+ V(JSWeakMap) \
V(JSRegExp) \
V(HashTable) \
V(Dictionary) \
@@ -1488,6 +1496,7 @@
inline void initialize_elements();
MUST_USE_RESULT inline MaybeObject* ResetElements();
inline ElementsKind GetElementsKind();
+ inline ElementsAccessor* GetElementsAccessor();
inline bool HasFastElements();
inline bool HasFastDoubleElements();
inline bool HasDictionaryElements();
@@ -1730,14 +1739,8 @@
// Returns the index'th element.
// The undefined object if index is out of bounds.
- MaybeObject* GetElementWithReceiver(Object* receiver, uint32_t index);
MaybeObject* GetElementWithInterceptor(Object* receiver, uint32_t index);
- // Get external element value at index if there is one and undefined
- // otherwise. Can return a failure if allocation of a heap number
- // failed.
- MaybeObject* GetExternalElement(uint32_t index);
-
// Replace the elements' backing store with fast elements of the given
// capacity. Update the length for JSArrays. Returns the new backing
// store.
@@ -2001,6 +2004,8 @@
};
private:
+ friend class DictionaryElementsAccessor;
+
MUST_USE_RESULT MaybeObject* GetElementWithCallback(Object* receiver,
Object* structure,
uint32_t index,
@@ -2021,14 +2026,10 @@
StrictModeFlag strict_mode,
bool check_prototype);
- MaybeObject* GetElementPostInterceptor(Object* receiver, uint32_t index);
-
MUST_USE_RESULT MaybeObject* DeletePropertyPostInterceptor(String* name,
DeleteMode mode);
MUST_USE_RESULT MaybeObject* DeletePropertyWithInterceptor(String* name);
- MUST_USE_RESULT MaybeObject* DeleteElementPostInterceptor(uint32_t index,
- DeleteMode mode);
MUST_USE_RESULT MaybeObject* DeleteElementWithInterceptor(uint32_t index);
MUST_USE_RESULT MaybeObject* DeleteFastElement(uint32_t index);
@@ -2092,6 +2093,7 @@
inline Object* get(int index);
// Setter that uses write barrier.
inline void set(int index, Object* value);
+ inline bool is_the_hole(int index);
// Setter that doesn't need write barrier).
inline void set(int index, Smi* value);
@@ -2126,10 +2128,6 @@
// Compute the union of this and other.
MUST_USE_RESULT MaybeObject* UnionOfKeys(FixedArray* other);
- // Compute the union of this and other.
- MUST_USE_RESULT MaybeObject* UnionOfDoubleKeys(
- FixedDoubleArray* other);
-
// Copy a sub array from the receiver to dest.
void CopyTo(int pos, FixedArray* dest, int dest_pos, int len);
@@ -2197,7 +2195,8 @@
inline void Initialize(NumberDictionary* from);
// Setter and getter for elements.
- inline double get(int index);
+ inline double get_scalar(int index);
+ inline MaybeObject* get(int index);
inline void set(int index, double value);
inline void set_the_hole(int index);
@@ -2805,7 +2804,7 @@
PropertyAttributes filter,
SortMode sort_mode);
// Fill in details for properties into storage.
- void CopyKeysTo(FixedArray* storage, SortMode sort_mode);
+ void CopyKeysTo(FixedArray* storage, int index, SortMode sort_mode);
// Accessors for next enumeration index.
void SetNextEnumerationIndex(int index) {
@@ -2979,8 +2978,16 @@
MUST_USE_RESULT MaybeObject* Put(JSObject* key, Object* value);
private:
+ friend class MarkCompactCollector;
+
void AddEntry(int entry, JSObject* key, Object* value);
- void RemoveEntry(int entry);
+ void RemoveEntry(int entry, Heap* heap);
+ inline void RemoveEntry(int entry);
+
+ // Returns the index to the value of an entry.
+ static inline int EntryToValueIndex(int entry) {
+ return EntryToIndex(entry) + 1;
+ }
};
@@ -3129,6 +3136,8 @@
inline int length();
inline void set_length(int value);
+ inline bool is_the_hole(int index) { return false; }
+
// [external_pointer]: The pointer to the external memory area backing this
// external array.
DECL_ACCESSORS(external_pointer, void) // Pointer to the data store.
@@ -3164,7 +3173,8 @@
inline uint8_t* external_pixel_pointer();
// Setter and getter.
- inline uint8_t get(int index);
+ inline uint8_t get_scalar(int index);
+ inline MaybeObject* get(int index);
inline void set(int index, uint8_t value);
// This accessor applies the correct conversion from Smi, HeapNumber and
@@ -3192,7 +3202,8 @@
class ExternalByteArray: public ExternalArray {
public:
// Setter and getter.
- inline int8_t get(int index);
+ inline int8_t get_scalar(int index);
+ inline MaybeObject* get(int index);
inline void set(int index, int8_t value);
// This accessor applies the correct conversion from Smi, HeapNumber
@@ -3220,7 +3231,8 @@
class ExternalUnsignedByteArray: public ExternalArray {
public:
// Setter and getter.
- inline uint8_t get(int index);
+ inline uint8_t get_scalar(int index);
+ inline MaybeObject* get(int index);
inline void set(int index, uint8_t value);
// This accessor applies the correct conversion from Smi, HeapNumber
@@ -3248,7 +3260,8 @@
class ExternalShortArray: public ExternalArray {
public:
// Setter and getter.
- inline int16_t get(int index);
+ inline int16_t get_scalar(int index);
+ inline MaybeObject* get(int index);
inline void set(int index, int16_t value);
// This accessor applies the correct conversion from Smi, HeapNumber
@@ -3276,7 +3289,8 @@
class ExternalUnsignedShortArray: public ExternalArray {
public:
// Setter and getter.
- inline uint16_t get(int index);
+ inline uint16_t get_scalar(int index);
+ inline MaybeObject* get(int index);
inline void set(int index, uint16_t value);
// This accessor applies the correct conversion from Smi, HeapNumber
@@ -3304,7 +3318,8 @@
class ExternalIntArray: public ExternalArray {
public:
// Setter and getter.
- inline int32_t get(int index);
+ inline int32_t get_scalar(int index);
+ inline MaybeObject* get(int index);
inline void set(int index, int32_t value);
// This accessor applies the correct conversion from Smi, HeapNumber
@@ -3332,7 +3347,8 @@
class ExternalUnsignedIntArray: public ExternalArray {
public:
// Setter and getter.
- inline uint32_t get(int index);
+ inline uint32_t get_scalar(int index);
+ inline MaybeObject* get(int index);
inline void set(int index, uint32_t value);
// This accessor applies the correct conversion from Smi, HeapNumber
@@ -3360,7 +3376,8 @@
class ExternalFloatArray: public ExternalArray {
public:
// Setter and getter.
- inline float get(int index);
+ inline float get_scalar(int index);
+ inline MaybeObject* get(int index);
inline void set(int index, float value);
// This accessor applies the correct conversion from Smi, HeapNumber
@@ -3388,7 +3405,8 @@
class ExternalDoubleArray: public ExternalArray {
public:
// Setter and getter.
- inline double get(int index);
+ inline double get_scalar(int index);
+ inline MaybeObject* get(int index);
inline void set(int index, double value);
// This accessor applies the correct conversion from Smi, HeapNumber
@@ -4644,12 +4662,10 @@
inline void set_end_position(int end_position);
// Is this function a function expression in the source code.
- inline bool is_expression();
- inline void set_is_expression(bool value);
+ DECL_BOOLEAN_ACCESSORS(is_expression)
// Is this function a top-level function (scripts, evals).
- inline bool is_toplevel();
- inline void set_is_toplevel(bool value);
+ DECL_BOOLEAN_ACCESSORS(is_toplevel)
// Bit field containing various information collected by the compiler to
// drive optimization.
@@ -4705,13 +4721,21 @@
// These needs special threatment in .call and .apply since
// null passed as the receiver should not be translated to the
// global object.
- inline bool native();
- inline void set_native(bool value);
+ DECL_BOOLEAN_ACCESSORS(native)
+
+ // Indicates that the function was created by the Function function.
+ // Though it's anonymous, toString should treat it as if it had the name
+ // "anonymous". We don't set the name itself so that the system does not
+ // see a binding for it.
+ DECL_BOOLEAN_ACCESSORS(name_should_print_as_anonymous)
// Indicates whether the function is a bound function created using
// the bind function.
- inline bool bound();
- inline void set_bound(bool value);
+ DECL_BOOLEAN_ACCESSORS(bound)
+
+ // Indicates that the function is anonymous (the name field can be set
+ // through the API, which does not change this flag).
+ DECL_BOOLEAN_ACCESSORS(is_anonymous)
// Indicates whether or not the code in the shared function support
// deoptimization.
@@ -4893,7 +4917,6 @@
// Bit positions in compiler_hints.
static const int kCodeAgeSize = 3;
static const int kCodeAgeMask = (1 << kCodeAgeSize) - 1;
- static const int kBoundFunction = 9;
enum CompilerHints {
kHasOnlySimpleThisPropertyAssignments,
@@ -4904,7 +4927,11 @@
kStrictModeFunction,
kUsesArguments,
kHasDuplicateParameters,
- kNative
+ kNative,
+ kBoundFunction,
+ kIsAnonymous,
+ kNameShouldPrintAsAnonymous,
+ kCompilerHintsCount // Pseudo entry
};
private:
@@ -4918,6 +4945,9 @@
static const int kCompilerHintsSize = kIntSize;
#endif
+ STATIC_ASSERT(SharedFunctionInfo::kCompilerHintsCount <=
+ SharedFunctionInfo::kCompilerHintsSize * kBitsPerByte);
+
public:
// Constants for optimizing codegen for strict mode function and
// native tests.
@@ -6620,6 +6650,40 @@
};
+// The JSWeakMap describes EcmaScript Harmony weak maps
+class JSWeakMap: public JSObject {
+ public:
+ // [table]: the backing hash table mapping keys to values.
+ DECL_ACCESSORS(table, ObjectHashTable)
+
+ // [next]: linked list of encountered weak maps during GC.
+ DECL_ACCESSORS(next, Object)
+
+ // Unchecked accessors to be used during GC.
+ inline ObjectHashTable* unchecked_table();
+
+ // Casting.
+ static inline JSWeakMap* cast(Object* obj);
+
+#ifdef OBJECT_PRINT
+ inline void JSWeakMapPrint() {
+ JSWeakMapPrint(stdout);
+ }
+ void JSWeakMapPrint(FILE* out);
+#endif
+#ifdef DEBUG
+ void JSWeakMapVerify();
+#endif
+
+ static const int kTableOffset = JSObject::kHeaderSize;
+ static const int kNextOffset = kTableOffset + kPointerSize;
+ static const int kSize = kNextOffset + kPointerSize;
+
+ private:
+ DISALLOW_IMPLICIT_CONSTRUCTORS(JSWeakMap);
+};
+
+
// Foreign describes objects pointing from JavaScript to C structures.
// Since they cannot contain references to JS HeapObjects they can be
// placed in old_data_space.
diff --git a/src/parser.cc b/src/parser.cc
index ed6ff49..f32e917 100644
--- a/src/parser.cc
+++ b/src/parser.cc
@@ -659,8 +659,8 @@
0,
0,
source->length(),
- false,
- false);
+ FunctionLiteral::ANONYMOUS_EXPRESSION,
+ false); // Does not have duplicate parameters.
} else if (stack_overflow_) {
isolate()->StackOverflow();
}
@@ -729,12 +729,17 @@
top_scope_->EnableStrictMode();
}
- FunctionLiteralType type =
- shared_info->is_expression() ? EXPRESSION : DECLARATION;
+ FunctionLiteral::Type type = shared_info->is_expression()
+ ? (shared_info->is_anonymous()
+ ? FunctionLiteral::ANONYMOUS_EXPRESSION
+ : FunctionLiteral::NAMED_EXPRESSION)
+ : FunctionLiteral::DECLARATION;
bool ok = true;
result = ParseFunctionLiteral(name,
- false, // Strict mode name already checked.
- RelocInfo::kNoPosition, type, &ok);
+ false, // Strict mode name already checked.
+ RelocInfo::kNoPosition,
+ type,
+ &ok);
// Make sure the results agree.
ASSERT(ok == (result != NULL));
}
@@ -1471,7 +1476,7 @@
FunctionLiteral* fun = ParseFunctionLiteral(name,
is_strict_reserved,
function_token_position,
- DECLARATION,
+ FunctionLiteral::DECLARATION,
CHECK_OK);
// Even if we're not at the top-level of the global or a function
// scope, we treat is as such and introduce the function with it's
@@ -2842,8 +2847,14 @@
name = ParseIdentifierOrStrictReservedWord(&is_strict_reserved_name,
CHECK_OK);
}
- result = ParseFunctionLiteral(name, is_strict_reserved_name,
- function_token_position, NESTED, CHECK_OK);
+ FunctionLiteral::Type type = name.is_null()
+ ? FunctionLiteral::ANONYMOUS_EXPRESSION
+ : FunctionLiteral::NAMED_EXPRESSION;
+ result = ParseFunctionLiteral(name,
+ is_strict_reserved_name,
+ function_token_position,
+ type,
+ CHECK_OK);
} else {
result = ParsePrimaryExpression(CHECK_OK);
}
@@ -3412,7 +3423,7 @@
ParseFunctionLiteral(name,
false, // reserved words are allowed here
RelocInfo::kNoPosition,
- DECLARATION,
+ FunctionLiteral::ANONYMOUS_EXPRESSION,
CHECK_OK);
// Allow any number of parameters for compatiabilty with JSC.
// Specification only allows zero parameters for get and one for set.
@@ -3619,30 +3630,27 @@
}
-FunctionLiteral* Parser::ParseFunctionLiteral(Handle<String> var_name,
+FunctionLiteral* Parser::ParseFunctionLiteral(Handle<String> function_name,
bool name_is_strict_reserved,
int function_token_position,
- FunctionLiteralType type,
+ FunctionLiteral::Type type,
bool* ok) {
// Function ::
// '(' FormalParameterList? ')' '{' FunctionBody '}'
- bool is_named = !var_name.is_null();
- // The name associated with this function. If it's a function expression,
- // this is the actual function name, otherwise this is the name of the
- // variable declared and initialized with the function (expression). In
- // that case, we don't have a function name (it's empty).
- Handle<String> name =
- is_named ? var_name : isolate()->factory()->empty_symbol();
- // The function name, if any.
- Handle<String> function_name = isolate()->factory()->empty_symbol();
- if (is_named && (type == EXPRESSION || type == NESTED)) {
- function_name = name;
+ // Anonymous functions were passed either the empty symbol or a null
+ // handle as the function name. Remember if we were passed a non-empty
+ // handle to decide whether to invoke function name inference.
+ bool should_infer_name = function_name.is_null();
+
+ // We want a non-null handle as the function name.
+ if (should_infer_name) {
+ function_name = isolate()->factory()->empty_symbol();
}
int num_parameters = 0;
// Function declarations are hoisted.
- Scope* scope = (type == DECLARATION)
+ Scope* scope = (type == FunctionLiteral::DECLARATION)
? NewScope(top_scope_->DeclarationScope(), Scope::FUNCTION_SCOPE, false)
: NewScope(top_scope_, Scope::FUNCTION_SCOPE, inside_with());
ZoneList<Statement*>* body = new(zone()) ZoneList<Statement*>(8);
@@ -3655,7 +3663,7 @@
bool has_duplicate_parameters = false;
// Parse function body.
{ LexicalScope lexical_scope(this, scope, isolate());
- top_scope_->SetScopeName(name);
+ top_scope_->SetScopeName(function_name);
// FormalParameterList ::
// '(' (Identifier)*[','] ')'
@@ -3705,7 +3713,7 @@
// NOTE: We create a proxy and resolve it here so that in the
// future we can change the AST to only refer to VariableProxies
// instead of Variables and Proxis as is the case now.
- if (!function_name.is_null() && function_name->length() > 0) {
+ if (type == FunctionLiteral::NAMED_EXPRESSION) {
Variable* fvar = top_scope_->DeclareFunctionVar(function_name);
VariableProxy* fproxy =
top_scope_->NewUnresolved(function_name, inside_with());
@@ -3739,7 +3747,7 @@
end_pos = entry.end_pos();
if (end_pos <= function_block_pos) {
// End position greater than end of stream is safe, and hard to check.
- ReportInvalidPreparseData(name, CHECK_OK);
+ ReportInvalidPreparseData(function_name, CHECK_OK);
}
isolate()->counters()->total_preparse_skipped()->Increment(
end_pos - function_block_pos);
@@ -3769,7 +3777,7 @@
// Validate strict mode.
if (top_scope_->is_strict_mode()) {
- if (IsEvalOrArguments(name)) {
+ if (IsEvalOrArguments(function_name)) {
int position = function_token_position != RelocInfo::kNoPosition
? function_token_position
: (start_pos > 0 ? start_pos - 1 : start_pos);
@@ -3813,7 +3821,7 @@
FunctionLiteral* function_literal =
new(zone()) FunctionLiteral(isolate(),
- name,
+ function_name,
scope,
body,
materialized_literal_count,
@@ -3823,11 +3831,11 @@
num_parameters,
start_pos,
end_pos,
- (function_name->length() > 0),
+ type,
has_duplicate_parameters);
function_literal->set_function_token_position(function_token_position);
- if (fni_ != NULL && !is_named) fni_->AddFunction(function_literal);
+ if (fni_ != NULL && should_infer_name) fni_->AddFunction(function_literal);
return function_literal;
}
diff --git a/src/parser.h b/src/parser.h
index 13a3603..535b639 100644
--- a/src/parser.h
+++ b/src/parser.h
@@ -552,17 +552,11 @@
// in the object literal boilerplate.
Handle<Object> GetBoilerplateValue(Expression* expression);
- enum FunctionLiteralType {
- EXPRESSION,
- DECLARATION,
- NESTED
- };
-
ZoneList<Expression*>* ParseArguments(bool* ok);
FunctionLiteral* ParseFunctionLiteral(Handle<String> var_name,
bool name_is_reserved,
int function_token_position,
- FunctionLiteralType type,
+ FunctionLiteral::Type type,
bool* ok);
diff --git a/src/runtime.cc b/src/runtime.cc
index 8c43d64..82733a7 100644
--- a/src/runtime.cc
+++ b/src/runtime.cc
@@ -615,8 +615,7 @@
RUNTIME_FUNCTION(MaybeObject*, Runtime_IsJSProxy) {
ASSERT(args.length() == 1);
Object* obj = args[0];
- return obj->IsJSProxy()
- ? isolate->heap()->true_value() : isolate->heap()->false_value();
+ return isolate->heap()->ToBoolean(obj->IsJSProxy());
}
@@ -635,6 +634,43 @@
}
+RUNTIME_FUNCTION(MaybeObject*, Runtime_WeakMapInitialize) {
+ HandleScope scope(isolate);
+ ASSERT(args.length() == 1);
+ CONVERT_ARG_CHECKED(JSWeakMap, weakmap, 0);
+ ASSERT(weakmap->map()->inobject_properties() == 0);
+ Handle<ObjectHashTable> table = isolate->factory()->NewObjectHashTable(0);
+ weakmap->set_table(*table);
+ weakmap->set_next(Smi::FromInt(0));
+ return *weakmap;
+}
+
+
+RUNTIME_FUNCTION(MaybeObject*, Runtime_WeakMapGet) {
+ NoHandleAllocation ha;
+ ASSERT(args.length() == 2);
+ CONVERT_ARG_CHECKED(JSWeakMap, weakmap, 0);
+ // TODO(mstarzinger): Currently we cannot use JSProxy objects as keys
+ // because they cannot be cast to JSObject to get an identity hash code.
+ CONVERT_ARG_CHECKED(JSObject, key, 1);
+ return weakmap->table()->Lookup(*key);
+}
+
+
+RUNTIME_FUNCTION(MaybeObject*, Runtime_WeakMapSet) {
+ HandleScope scope(isolate);
+ ASSERT(args.length() == 3);
+ CONVERT_ARG_CHECKED(JSWeakMap, weakmap, 0);
+ // TODO(mstarzinger): See Runtime_WeakMapGet above.
+ CONVERT_ARG_CHECKED(JSObject, key, 1);
+ Handle<Object> value(args[2]);
+ Handle<ObjectHashTable> table(weakmap->table());
+ Handle<ObjectHashTable> new_table = PutIntoObjectHashTable(table, key, value);
+ weakmap->set_table(*new_table);
+ return *value;
+}
+
+
RUNTIME_FUNCTION(MaybeObject*, Runtime_ClassOf) {
NoHandleAllocation ha;
ASSERT(args.length() == 1);
@@ -1001,8 +1037,7 @@
ASSERT(proto->IsJSGlobalObject());
obj = JSObject::cast(proto);
}
- return obj->map()->is_extensible() ? isolate->heap()->true_value()
- : isolate->heap()->false_value();
+ return isolate->heap()->ToBoolean(obj->map()->is_extensible());
}
@@ -1068,8 +1103,7 @@
Map::cast(new_map)->set_is_access_check_needed(false);
object->set_map(Map::cast(new_map));
}
- return needs_access_checks ? isolate->heap()->true_value()
- : isolate->heap()->false_value();
+ return isolate->heap()->ToBoolean(needs_access_checks);
}
@@ -1880,6 +1914,24 @@
}
+RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionNameShouldPrintAsAnonymous) {
+ NoHandleAllocation ha;
+ ASSERT(args.length() == 1);
+ CONVERT_CHECKED(JSFunction, f, args[0]);
+ return isolate->heap()->ToBoolean(
+ f->shared()->name_should_print_as_anonymous());
+}
+
+
+RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionMarkNameShouldPrintAsAnonymous) {
+ NoHandleAllocation ha;
+ ASSERT(args.length() == 1);
+ CONVERT_CHECKED(JSFunction, f, args[0]);
+ f->shared()->set_name_should_print_as_anonymous(true);
+ return isolate->heap()->undefined_value();
+}
+
+
RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetBound) {
HandleScope scope(isolate);
ASSERT(args.length() == 1);
@@ -1967,6 +2019,24 @@
}
+// Creates a local, readonly, property called length with the correct
+// length (when read by the user). This effectively overwrites the
+// interceptor used to normally provide the length.
+RUNTIME_FUNCTION(MaybeObject*, Runtime_BoundFunctionSetLength) {
+ NoHandleAllocation ha;
+ ASSERT(args.length() == 2);
+ CONVERT_CHECKED(JSFunction, fun, args[0]);
+ CONVERT_CHECKED(Smi, length, args[1]);
+ MaybeObject* maybe_name =
+ isolate->heap()->AllocateStringFromAscii(CStrVector("length"));
+ String* name;
+ if (!maybe_name->To(&name)) return maybe_name;
+ PropertyAttributes attr =
+ static_cast<PropertyAttributes>(DONT_DELETE | DONT_ENUM | READ_ONLY);
+ return fun->AddProperty(name, length, attr, kNonStrictMode);
+}
+
+
RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetPrototype) {
NoHandleAllocation ha;
ASSERT(args.length() == 2);
@@ -2042,8 +2112,7 @@
ASSERT(args.length() == 1);
CONVERT_CHECKED(JSFunction, f, args[0]);
- return f->shared()->IsApiFunction() ? isolate->heap()->true_value()
- : isolate->heap()->false_value();
+ return isolate->heap()->ToBoolean(f->shared()->IsApiFunction());
}
@@ -2052,8 +2121,7 @@
ASSERT(args.length() == 1);
CONVERT_CHECKED(JSFunction, f, args[0]);
- return f->IsBuiltin() ? isolate->heap()->true_value() :
- isolate->heap()->false_value();
+ return isolate->heap()->ToBoolean(f->IsBuiltin());
}
@@ -4529,9 +4597,10 @@
// Get the property names.
jsproto = obj;
int proto_with_hidden_properties = 0;
+ int next_copy_index = 0;
for (int i = 0; i < length; i++) {
- jsproto->GetLocalPropertyNames(*names,
- i == 0 ? 0 : local_property_count[i - 1]);
+ jsproto->GetLocalPropertyNames(*names, next_copy_index);
+ next_copy_index += local_property_count[i];
if (jsproto->HasHiddenProperties()) {
proto_with_hidden_properties++;
}
@@ -9200,13 +9269,13 @@
if (elements_are_guaranteed_smis) {
for (uint32_t j = 0; j < len; j++) {
HandleScope loop_scope;
- Handle<Smi> e(Smi::FromInt(static_cast<int>(array->get(j))));
+ Handle<Smi> e(Smi::FromInt(static_cast<int>(array->get_scalar(j))));
visitor->visit(j, e);
}
} else {
for (uint32_t j = 0; j < len; j++) {
HandleScope loop_scope;
- int64_t val = static_cast<int64_t>(array->get(j));
+ int64_t val = static_cast<int64_t>(array->get_scalar(j));
if (Smi::IsValid(static_cast<intptr_t>(val))) {
Handle<Smi> e(Smi::FromInt(static_cast<int>(val)));
visitor->visit(j, e);
@@ -9220,7 +9289,7 @@
} else {
for (uint32_t j = 0; j < len; j++) {
HandleScope loop_scope(isolate);
- Handle<Object> e = isolate->factory()->NewNumber(array->get(j));
+ Handle<Object> e = isolate->factory()->NewNumber(array->get_scalar(j));
visitor->visit(j, e);
}
}
@@ -9406,7 +9475,7 @@
Handle<ExternalPixelArray> pixels(ExternalPixelArray::cast(
receiver->elements()));
for (uint32_t j = 0; j < length; j++) {
- Handle<Smi> e(Smi::FromInt(pixels->get(j)));
+ Handle<Smi> e(Smi::FromInt(pixels->get_scalar(j)));
visitor->visit(j, e);
}
break;
@@ -9924,9 +9993,7 @@
details->set(0, *value);
details->set(1, property_details);
if (hasJavaScriptAccessors) {
- details->set(2,
- caught_exception ? isolate->heap()->true_value()
- : isolate->heap()->false_value());
+ details->set(2, isolate->heap()->ToBoolean(caught_exception));
details->set(3, FixedArray::cast(*result_callback_obj)->get(0));
details->set(4, FixedArray::cast(*result_callback_obj)->get(1));
}
@@ -11378,7 +11445,11 @@
context->set_extension(*local_scope);
// Copy any with contexts present and chain them in front of this context.
Handle<Context> frame_context(Context::cast(frame->context()));
- Handle<Context> function_context(frame_context->declaration_context());
+ Handle<Context> function_context;
+ // Get the function's context if it has one.
+ if (scope_info->HasHeapAllocatedLocals()) {
+ function_context = Handle<Context>(frame_context->declaration_context());
+ }
context = CopyWithContextChain(isolate, go_between, frame_context, context);
if (additional_context->IsJSObject()) {
@@ -12109,8 +12180,7 @@
#ifdef LIVE_OBJECT_LIST
CONVERT_SMI_ARG_CHECKED(id, 0);
bool success = LiveObjectList::Delete(id);
- return success ? isolate->heap()->true_value() :
- isolate->heap()->false_value();
+ return isolate->heap()->ToBoolean(success);
#else
return isolate->heap()->undefined_value();
#endif
diff --git a/src/runtime.h b/src/runtime.h
index a42b3bc..a52672a 100644
--- a/src/runtime.h
+++ b/src/runtime.h
@@ -209,10 +209,13 @@
/* Reflection */ \
F(FunctionSetInstanceClassName, 2, 1) \
F(FunctionSetLength, 2, 1) \
+ F(BoundFunctionSetLength, 2, 1) \
F(FunctionSetPrototype, 2, 1) \
F(FunctionSetReadOnlyPrototype, 1, 1) \
F(FunctionGetName, 1, 1) \
F(FunctionSetName, 2, 1) \
+ F(FunctionNameShouldPrintAsAnonymous, 1, 1) \
+ F(FunctionMarkNameShouldPrintAsAnonymous, 1, 1) \
F(FunctionSetBound, 1, 1) \
F(FunctionRemovePrototype, 1, 1) \
F(FunctionGetSourceCode, 1, 1) \
@@ -287,6 +290,11 @@
F(GetHandler, 1, 1) \
F(Fix, 1, 1) \
\
+ /* Harmony weakmaps */ \
+ F(WeakMapInitialize, 1, 1) \
+ F(WeakMapGet, 2, 1) \
+ F(WeakMapSet, 3, 1) \
+ \
/* Statements */ \
F(NewClosure, 3, 1) \
F(NewObject, 1, 1) \
diff --git a/src/scanner-base.cc b/src/scanner-base.cc
index 16f8db5..e4590b1 100644
--- a/src/scanner-base.cc
+++ b/src/scanner-base.cc
@@ -89,10 +89,158 @@
Scan();
}
+
+// Ensure that tokens can be stored in a byte.
+STATIC_ASSERT(Token::NUM_TOKENS <= 0x100);
+
+// Table of one-character tokens, by character (0x00..0x7f only).
+static const byte one_char_tokens[] = {
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::LPAREN, // 0x28
+ Token::RPAREN, // 0x29
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::COMMA, // 0x2c
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::COLON, // 0x3a
+ Token::SEMICOLON, // 0x3b
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::CONDITIONAL, // 0x3f
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::LBRACK, // 0x5b
+ Token::ILLEGAL,
+ Token::RBRACK, // 0x5d
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::ILLEGAL,
+ Token::LBRACE, // 0x7b
+ Token::ILLEGAL,
+ Token::RBRACE, // 0x7d
+ Token::BIT_NOT, // 0x7e
+ Token::ILLEGAL
+};
+
+
Token::Value JavaScriptScanner::Next() {
current_ = next_;
has_line_terminator_before_next_ = false;
has_multiline_comment_before_next_ = false;
+ if (static_cast<unsigned>(c0_) <= 0x7f) {
+ Token::Value token = static_cast<Token::Value>(one_char_tokens[c0_]);
+ if (token != Token::ILLEGAL) {
+ int pos = source_pos();
+ next_.token = token;
+ next_.location.beg_pos = pos;
+ next_.location.end_pos = pos + 1;
+ Advance();
+ return current_.token;
+ }
+ }
Scan();
return current_.token;
}
@@ -171,7 +319,7 @@
Advance();
while (c0_ >= 0) {
- char ch = c0_;
+ uc32 ch = c0_;
Advance();
if (unicode_cache_->IsLineTerminator(ch)) {
// Following ECMA-262, section 7.4, a comment containing
@@ -662,10 +810,114 @@
}
+// ----------------------------------------------------------------------------
+// Keyword Matcher
+
+#define KEYWORDS(KEYWORD_GROUP, KEYWORD) \
+ KEYWORD_GROUP('b') \
+ KEYWORD("break", BREAK) \
+ KEYWORD_GROUP('c') \
+ KEYWORD("case", CASE) \
+ KEYWORD("catch", CATCH) \
+ KEYWORD("class", FUTURE_RESERVED_WORD) \
+ KEYWORD("const", CONST) \
+ KEYWORD("continue", CONTINUE) \
+ KEYWORD_GROUP('d') \
+ KEYWORD("debugger", DEBUGGER) \
+ KEYWORD("default", DEFAULT) \
+ KEYWORD("delete", DELETE) \
+ KEYWORD("do", DO) \
+ KEYWORD_GROUP('e') \
+ KEYWORD("else", ELSE) \
+ KEYWORD("enum", FUTURE_RESERVED_WORD) \
+ KEYWORD("export", FUTURE_RESERVED_WORD) \
+ KEYWORD("extends", FUTURE_RESERVED_WORD) \
+ KEYWORD_GROUP('f') \
+ KEYWORD("false", FALSE_LITERAL) \
+ KEYWORD("finally", FINALLY) \
+ KEYWORD("for", FOR) \
+ KEYWORD("function", FUNCTION) \
+ KEYWORD_GROUP('i') \
+ KEYWORD("if", IF) \
+ KEYWORD("implements", FUTURE_STRICT_RESERVED_WORD) \
+ KEYWORD("import", FUTURE_RESERVED_WORD) \
+ KEYWORD("in", IN) \
+ KEYWORD("instanceof", INSTANCEOF) \
+ KEYWORD("interface", FUTURE_STRICT_RESERVED_WORD) \
+ KEYWORD_GROUP('l') \
+ KEYWORD("let", FUTURE_STRICT_RESERVED_WORD) \
+ KEYWORD_GROUP('n') \
+ KEYWORD("new", NEW) \
+ KEYWORD("null", NULL_LITERAL) \
+ KEYWORD_GROUP('p') \
+ KEYWORD("package", FUTURE_STRICT_RESERVED_WORD) \
+ KEYWORD("private", FUTURE_STRICT_RESERVED_WORD) \
+ KEYWORD("protected", FUTURE_STRICT_RESERVED_WORD) \
+ KEYWORD("public", FUTURE_STRICT_RESERVED_WORD) \
+ KEYWORD_GROUP('r') \
+ KEYWORD("return", RETURN) \
+ KEYWORD_GROUP('s') \
+ KEYWORD("static", FUTURE_STRICT_RESERVED_WORD) \
+ KEYWORD("super", FUTURE_RESERVED_WORD) \
+ KEYWORD("switch", SWITCH) \
+ KEYWORD_GROUP('t') \
+ KEYWORD("this", THIS) \
+ KEYWORD("throw", THROW) \
+ KEYWORD("true", TRUE_LITERAL) \
+ KEYWORD("try", TRY) \
+ KEYWORD("typeof", TYPEOF) \
+ KEYWORD_GROUP('v') \
+ KEYWORD("var", VAR) \
+ KEYWORD("void", VOID) \
+ KEYWORD_GROUP('w') \
+ KEYWORD("while", WHILE) \
+ KEYWORD("with", WITH) \
+ KEYWORD_GROUP('y') \
+ KEYWORD("yield", FUTURE_STRICT_RESERVED_WORD)
+
+
+static Token::Value KeywordOrIdentifierToken(const char* input,
+ int input_length) {
+ ASSERT(input_length >= 1);
+ const int kMinLength = 2;
+ const int kMaxLength = 10;
+ if (input_length < kMinLength || input_length > kMaxLength) {
+ return Token::IDENTIFIER;
+ }
+ switch (input[0]) {
+ default:
+#define KEYWORD_GROUP_CASE(ch) \
+ break; \
+ case ch:
+#define KEYWORD(keyword, token) \
+ { \
+ /* 'keyword' is a char array, so sizeof(keyword) is */ \
+ /* strlen(keyword) plus 1 for the NUL char. */ \
+ const int keyword_length = sizeof(keyword) - 1; \
+ STATIC_ASSERT(keyword_length >= kMinLength); \
+ STATIC_ASSERT(keyword_length <= kMaxLength); \
+ if (input_length == keyword_length && \
+ input[1] == keyword[1] && \
+ (keyword_length <= 2 || input[2] == keyword[2]) && \
+ (keyword_length <= 3 || input[3] == keyword[3]) && \
+ (keyword_length <= 4 || input[4] == keyword[4]) && \
+ (keyword_length <= 5 || input[5] == keyword[5]) && \
+ (keyword_length <= 6 || input[6] == keyword[6]) && \
+ (keyword_length <= 7 || input[7] == keyword[7]) && \
+ (keyword_length <= 8 || input[8] == keyword[8]) && \
+ (keyword_length <= 9 || input[9] == keyword[9])) { \
+ return Token::token; \
+ } \
+ }
+ KEYWORDS(KEYWORD_GROUP_CASE, KEYWORD)
+ }
+ return Token::IDENTIFIER;
+}
+
+
Token::Value JavaScriptScanner::ScanIdentifierOrKeyword() {
ASSERT(unicode_cache_->IsIdentifierStart(c0_));
LiteralScope literal(this);
- KeywordMatcher keyword_match;
// Scan identifier start character.
if (c0_ == '\\') {
uc32 c = ScanIdentifierUnicodeEscape();
@@ -678,9 +930,6 @@
uc32 first_char = c0_;
Advance();
AddLiteralChar(first_char);
- if (!keyword_match.AddChar(first_char)) {
- return ScanIdentifierSuffix(&literal);
- }
// Scan the rest of the identifier characters.
while (unicode_cache_->IsIdentifierPart(c0_)) {
@@ -688,14 +937,20 @@
uc32 next_char = c0_;
Advance();
AddLiteralChar(next_char);
- if (keyword_match.AddChar(next_char)) continue;
+ continue;
}
- // Fallthrough if no loner able to complete keyword.
+ // Fallthrough if no longer able to complete keyword.
return ScanIdentifierSuffix(&literal);
}
+
literal.Complete();
- return keyword_match.token();
+ if (next_.literal_chars->is_ascii()) {
+ Vector<const char> chars = next_.literal_chars->ascii_literal();
+ return KeywordOrIdentifierToken(chars.start(), chars.length());
+ }
+
+ return Token::IDENTIFIER;
}
@@ -785,182 +1040,4 @@
return true;
}
-// ----------------------------------------------------------------------------
-// Keyword Matcher
-
-KeywordMatcher::FirstState KeywordMatcher::first_states_[] = {
- { "break", KEYWORD_PREFIX, Token::BREAK },
- { NULL, C, Token::ILLEGAL },
- { NULL, D, Token::ILLEGAL },
- { NULL, E, Token::ILLEGAL },
- { NULL, F, Token::ILLEGAL },
- { NULL, UNMATCHABLE, Token::ILLEGAL },
- { NULL, UNMATCHABLE, Token::ILLEGAL },
- { NULL, I, Token::ILLEGAL },
- { NULL, UNMATCHABLE, Token::ILLEGAL },
- { NULL, UNMATCHABLE, Token::ILLEGAL },
- { "let", KEYWORD_PREFIX, Token::FUTURE_STRICT_RESERVED_WORD },
- { NULL, UNMATCHABLE, Token::ILLEGAL },
- { NULL, N, Token::ILLEGAL },
- { NULL, UNMATCHABLE, Token::ILLEGAL },
- { NULL, P, Token::ILLEGAL },
- { NULL, UNMATCHABLE, Token::ILLEGAL },
- { "return", KEYWORD_PREFIX, Token::RETURN },
- { NULL, S, Token::ILLEGAL },
- { NULL, T, Token::ILLEGAL },
- { NULL, UNMATCHABLE, Token::ILLEGAL },
- { NULL, V, Token::ILLEGAL },
- { NULL, W, Token::ILLEGAL },
- { NULL, UNMATCHABLE, Token::ILLEGAL },
- { "yield", KEYWORD_PREFIX, Token::FUTURE_STRICT_RESERVED_WORD }
-};
-
-
-void KeywordMatcher::Step(unibrow::uchar input) {
- switch (state_) {
- case INITIAL: {
- // matching the first character is the only state with significant fanout.
- // Match only lower-case letters in range 'b'..'y'.
- unsigned int offset = input - kFirstCharRangeMin;
- if (offset < kFirstCharRangeLength) {
- state_ = first_states_[offset].state;
- if (state_ == KEYWORD_PREFIX) {
- keyword_ = first_states_[offset].keyword;
- counter_ = 1;
- keyword_token_ = first_states_[offset].token;
- }
- return;
- }
- break;
- }
- case KEYWORD_PREFIX:
- if (static_cast<unibrow::uchar>(keyword_[counter_]) == input) {
- counter_++;
- if (keyword_[counter_] == '\0') {
- state_ = KEYWORD_MATCHED;
- token_ = keyword_token_;
- }
- return;
- }
- break;
- case KEYWORD_MATCHED:
- token_ = Token::IDENTIFIER;
- break;
- case C:
- if (MatchState(input, 'a', CA)) return;
- if (MatchKeywordStart(input, "class", 1,
- Token::FUTURE_RESERVED_WORD)) return;
- if (MatchState(input, 'o', CO)) return;
- break;
- case CA:
- if (MatchKeywordStart(input, "case", 2, Token::CASE)) return;
- if (MatchKeywordStart(input, "catch", 2, Token::CATCH)) return;
- break;
- case CO:
- if (MatchState(input, 'n', CON)) return;
- break;
- case CON:
- if (MatchKeywordStart(input, "const", 3, Token::CONST)) return;
- if (MatchKeywordStart(input, "continue", 3, Token::CONTINUE)) return;
- break;
- case D:
- if (MatchState(input, 'e', DE)) return;
- if (MatchKeyword(input, 'o', KEYWORD_MATCHED, Token::DO)) return;
- break;
- case DE:
- if (MatchKeywordStart(input, "debugger", 2, Token::DEBUGGER)) return;
- if (MatchKeywordStart(input, "default", 2, Token::DEFAULT)) return;
- if (MatchKeywordStart(input, "delete", 2, Token::DELETE)) return;
- break;
- case E:
- if (MatchKeywordStart(input, "else", 1, Token::ELSE)) return;
- if (MatchKeywordStart(input, "enum", 1,
- Token::FUTURE_RESERVED_WORD)) return;
- if (MatchState(input, 'x', EX)) return;
- break;
- case EX:
- if (MatchKeywordStart(input, "export", 2,
- Token::FUTURE_RESERVED_WORD)) return;
- if (MatchKeywordStart(input, "extends", 2,
- Token::FUTURE_RESERVED_WORD)) return;
- break;
- case F:
- if (MatchKeywordStart(input, "false", 1, Token::FALSE_LITERAL)) return;
- if (MatchKeywordStart(input, "finally", 1, Token::FINALLY)) return;
- if (MatchKeywordStart(input, "for", 1, Token::FOR)) return;
- if (MatchKeywordStart(input, "function", 1, Token::FUNCTION)) return;
- break;
- case I:
- if (MatchKeyword(input, 'f', KEYWORD_MATCHED, Token::IF)) return;
- if (MatchState(input, 'm', IM)) return;
- if (MatchKeyword(input, 'n', IN, Token::IN)) return;
- break;
- case IM:
- if (MatchState(input, 'p', IMP)) return;
- break;
- case IMP:
- if (MatchKeywordStart(input, "implements", 3,
- Token::FUTURE_STRICT_RESERVED_WORD )) return;
- if (MatchKeywordStart(input, "import", 3,
- Token::FUTURE_RESERVED_WORD)) return;
- break;
- case IN:
- token_ = Token::IDENTIFIER;
- if (MatchKeywordStart(input, "interface", 2,
- Token::FUTURE_STRICT_RESERVED_WORD)) return;
- if (MatchKeywordStart(input, "instanceof", 2, Token::INSTANCEOF)) return;
- break;
- case N:
- if (MatchKeywordStart(input, "new", 1, Token::NEW)) return;
- if (MatchKeywordStart(input, "null", 1, Token::NULL_LITERAL)) return;
- break;
- case P:
- if (MatchKeywordStart(input, "package", 1,
- Token::FUTURE_STRICT_RESERVED_WORD)) return;
- if (MatchState(input, 'r', PR)) return;
- if (MatchKeywordStart(input, "public", 1,
- Token::FUTURE_STRICT_RESERVED_WORD)) return;
- break;
- case PR:
- if (MatchKeywordStart(input, "private", 2,
- Token::FUTURE_STRICT_RESERVED_WORD)) return;
- if (MatchKeywordStart(input, "protected", 2,
- Token::FUTURE_STRICT_RESERVED_WORD)) return;
- break;
- case S:
- if (MatchKeywordStart(input, "static", 1,
- Token::FUTURE_STRICT_RESERVED_WORD)) return;
- if (MatchKeywordStart(input, "super", 1,
- Token::FUTURE_RESERVED_WORD)) return;
- if (MatchKeywordStart(input, "switch", 1,
- Token::SWITCH)) return;
- break;
- case T:
- if (MatchState(input, 'h', TH)) return;
- if (MatchState(input, 'r', TR)) return;
- if (MatchKeywordStart(input, "typeof", 1, Token::TYPEOF)) return;
- break;
- case TH:
- if (MatchKeywordStart(input, "this", 2, Token::THIS)) return;
- if (MatchKeywordStart(input, "throw", 2, Token::THROW)) return;
- break;
- case TR:
- if (MatchKeywordStart(input, "true", 2, Token::TRUE_LITERAL)) return;
- if (MatchKeyword(input, 'y', KEYWORD_MATCHED, Token::TRY)) return;
- break;
- case V:
- if (MatchKeywordStart(input, "var", 1, Token::VAR)) return;
- if (MatchKeywordStart(input, "void", 1, Token::VOID)) return;
- break;
- case W:
- if (MatchKeywordStart(input, "while", 1, Token::WHILE)) return;
- if (MatchKeywordStart(input, "with", 1, Token::WITH)) return;
- break;
- case UNMATCHABLE:
- break;
- }
- // On fallthrough, it's a failure.
- state_ = UNMATCHABLE;
-}
-
} } // namespace v8::internal
diff --git a/src/scanner-base.h b/src/scanner-base.h
index 3d67d4e..d3776e5 100644
--- a/src/scanner-base.h
+++ b/src/scanner-base.h
@@ -542,151 +542,6 @@
bool has_multiline_comment_before_next_;
};
-
-// ----------------------------------------------------------------------------
-// Keyword matching state machine.
-
-class KeywordMatcher {
-// Incrementally recognize keywords.
-//
-// We distinguish between normal future reserved words and words that are
-// considered to be future reserved words only in strict mode as required by
-// ECMA-262 7.6.1.2.
-//
-// Recognized as keywords:
-// break, case, catch, const*, continue, debugger, default, delete, do,
-// else, finally, false, for, function, if, in, instanceof, new, null,
-// return, switch, this, throw, true, try, typeof, var, void, while, with.
-//
-// Recognized as Future Reserved Keywords:
-// class, enum, export, extends, import, super.
-//
-// Recognized as Future Reserved Keywords (strict mode only):
-// implements, interface, let, package, private, protected, public,
-// static, yield.
-//
-// *: Actually a "future reserved keyword". It's the only one we are
-// recognizing outside of ES5 strict mode, the remaining are allowed
-// as identifiers.
-//
- public:
- KeywordMatcher()
- : state_(INITIAL),
- token_(Token::IDENTIFIER),
- keyword_(NULL),
- counter_(0),
- keyword_token_(Token::ILLEGAL) {}
-
- Token::Value token() { return token_; }
-
- inline bool AddChar(unibrow::uchar input) {
- if (state_ != UNMATCHABLE) {
- Step(input);
- }
- return state_ != UNMATCHABLE;
- }
-
- void Fail() {
- token_ = Token::IDENTIFIER;
- state_ = UNMATCHABLE;
- }
-
- private:
- enum State {
- UNMATCHABLE,
- INITIAL,
- KEYWORD_PREFIX,
- KEYWORD_MATCHED,
- C,
- CA,
- CO,
- CON,
- D,
- DE,
- E,
- EX,
- F,
- I,
- IM,
- IMP,
- IN,
- N,
- P,
- PR,
- S,
- T,
- TH,
- TR,
- V,
- W
- };
-
- struct FirstState {
- const char* keyword;
- State state;
- Token::Value token;
- };
-
- // Range of possible first characters of a keyword.
- static const unsigned int kFirstCharRangeMin = 'b';
- static const unsigned int kFirstCharRangeMax = 'y';
- static const unsigned int kFirstCharRangeLength =
- kFirstCharRangeMax - kFirstCharRangeMin + 1;
- // State map for first keyword character range.
- static FirstState first_states_[kFirstCharRangeLength];
-
- // If input equals keyword's character at position, continue matching keyword
- // from that position.
- inline bool MatchKeywordStart(unibrow::uchar input,
- const char* keyword,
- int position,
- Token::Value token_if_match) {
- if (input != static_cast<unibrow::uchar>(keyword[position])) {
- return false;
- }
- state_ = KEYWORD_PREFIX;
- this->keyword_ = keyword;
- this->counter_ = position + 1;
- this->keyword_token_ = token_if_match;
- return true;
- }
-
- // If input equals match character, transition to new state and return true.
- inline bool MatchState(unibrow::uchar input, char match, State new_state) {
- if (input != static_cast<unibrow::uchar>(match)) {
- return false;
- }
- state_ = new_state;
- return true;
- }
-
- inline bool MatchKeyword(unibrow::uchar input,
- char match,
- State new_state,
- Token::Value keyword_token) {
- if (input != static_cast<unibrow::uchar>(match)) {
- return false;
- }
- state_ = new_state;
- token_ = keyword_token;
- return true;
- }
-
- void Step(unibrow::uchar input);
-
- // Current state.
- State state_;
- // Token for currently added characters.
- Token::Value token_;
-
- // Matching a specific keyword string (there is only one possible valid
- // keyword with the current prefix).
- const char* keyword_;
- int counter_;
- Token::Value keyword_token_;
-};
-
-
} } // namespace v8::internal
#endif // V8_SCANNER_BASE_H_
diff --git a/src/shell.h b/src/shell.h
deleted file mode 100644
index ca51040..0000000
--- a/src/shell.h
+++ /dev/null
@@ -1,55 +0,0 @@
-// Copyright 2006-2008 the V8 project authors. All rights reserved.
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following
-// disclaimer in the documentation and/or other materials provided
-// with the distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-//
-// A simple interactive shell. Enable with --shell.
-
-#ifndef V8_SHELL_H_
-#define V8_SHELL_H_
-
-#include "../public/debug.h"
-
-namespace v8 {
-namespace internal {
-
-// Debug event handler for interactive debugging.
-void handle_debug_event(v8::DebugEvent event,
- v8::Handle<v8::Object> exec_state,
- v8::Handle<v8::Object> event_data,
- v8::Handle<Value> data);
-
-
-class Shell {
- public:
- static void PrintObject(v8::Handle<v8::Value> obj);
- // Run the read-eval loop, executing code in the specified
- // environment.
- static void Run(v8::Handle<v8::Context> context);
-};
-
-} } // namespace v8::internal
-
-#endif // V8_SHELL_H_
diff --git a/src/spaces.cc b/src/spaces.cc
index 54361da..a782ba9 100644
--- a/src/spaces.cc
+++ b/src/spaces.cc
@@ -148,12 +148,12 @@
// CodeRange
-CodeRange::CodeRange()
- : code_range_(NULL),
+CodeRange::CodeRange(Isolate* isolate)
+ : isolate_(isolate),
+ code_range_(NULL),
free_list_(0),
allocation_list_(0),
- current_allocation_block_index_(0),
- isolate_(NULL) {
+ current_allocation_block_index_(0) {
}
@@ -279,8 +279,9 @@
const int kEstimatedNumberOfChunks = 270;
-MemoryAllocator::MemoryAllocator()
- : capacity_(0),
+MemoryAllocator::MemoryAllocator(Isolate* isolate)
+ : isolate_(isolate),
+ capacity_(0),
capacity_executable_(0),
size_(0),
size_executable_(0),
@@ -288,8 +289,7 @@
chunks_(kEstimatedNumberOfChunks),
free_chunk_ids_(kEstimatedNumberOfChunks),
max_nof_chunks_(0),
- top_(0),
- isolate_(NULL) {
+ top_(0) {
}
diff --git a/src/spaces.h b/src/spaces.h
index ac5d998..d8ed27e 100644
--- a/src/spaces.h
+++ b/src/spaces.h
@@ -408,6 +408,8 @@
// manages a range of virtual memory.
class CodeRange {
public:
+ explicit CodeRange(Isolate* isolate);
+
// Reserves a range of virtual memory, but does not commit any of it.
// Can only be called once, at heap initialization time.
// Returns false on failure.
@@ -417,9 +419,9 @@
// manage it.
void TearDown();
- bool exists() { return code_range_ != NULL; }
+ bool exists() { return this != NULL && code_range_ != NULL; }
bool contains(Address address) {
- if (code_range_ == NULL) return false;
+ if (this == NULL || code_range_ == NULL) return false;
Address start = static_cast<Address>(code_range_->address());
return start <= address && address < start + code_range_->size();
}
@@ -432,7 +434,7 @@
void FreeRawMemory(void* buf, size_t length);
private:
- CodeRange();
+ Isolate* isolate_;
// The reserved range of virtual memory that all code objects are put in.
VirtualMemory* code_range_;
@@ -466,10 +468,6 @@
static int CompareFreeBlockAddress(const FreeBlock* left,
const FreeBlock* right);
- friend class Isolate;
-
- Isolate* isolate_;
-
DISALLOW_COPY_AND_ASSIGN(CodeRange);
};
@@ -500,6 +498,8 @@
class MemoryAllocator {
public:
+ explicit MemoryAllocator(Isolate* isolate);
+
// Initializes its internal bookkeeping structures.
// Max capacity of the total space and executable memory limit.
bool Setup(intptr_t max_capacity, intptr_t capacity_executable);
@@ -657,10 +657,10 @@
#endif
private:
- MemoryAllocator();
-
static const int kChunkSize = kPagesPerChunk * Page::kPageSize;
+ Isolate* isolate_;
+
// Maximum space size in bytes.
intptr_t capacity_;
// Maximum subset of capacity_ that can be executable
@@ -753,10 +753,6 @@
Page* prev,
Page** last_page_in_use);
- friend class Isolate;
-
- Isolate* isolate_;
-
DISALLOW_COPY_AND_ASSIGN(MemoryAllocator);
};
diff --git a/src/token.cc b/src/token.cc
index feca7be..7ba7ed3 100644
--- a/src/token.cc
+++ b/src/token.cc
@@ -33,21 +33,21 @@
#define T(name, string, precedence) #name,
const char* const Token::name_[NUM_TOKENS] = {
- TOKEN_LIST(T, T, IGNORE_TOKEN)
+ TOKEN_LIST(T, T)
};
#undef T
#define T(name, string, precedence) string,
const char* const Token::string_[NUM_TOKENS] = {
- TOKEN_LIST(T, T, IGNORE_TOKEN)
+ TOKEN_LIST(T, T)
};
#undef T
#define T(name, string, precedence) precedence,
const int8_t Token::precedence_[NUM_TOKENS] = {
- TOKEN_LIST(T, T, IGNORE_TOKEN)
+ TOKEN_LIST(T, T)
};
#undef T
@@ -55,7 +55,7 @@
#define KT(a, b, c) 'T',
#define KK(a, b, c) 'K',
const char Token::token_type[] = {
- TOKEN_LIST(KT, KK, IGNORE_TOKEN)
+ TOKEN_LIST(KT, KK)
};
#undef KT
#undef KK
diff --git a/src/token.h b/src/token.h
index 77333bc..7e6c18c 100644
--- a/src/token.h
+++ b/src/token.h
@@ -41,7 +41,6 @@
//
// T: Non-keyword tokens
// K: Keyword tokens
-// F: Future (reserved) keyword tokens
// IGNORE_TOKEN is a convenience macro that can be supplied as
// an argument (at any position) for a TOKEN_LIST call. It does
@@ -49,7 +48,7 @@
#define IGNORE_TOKEN(name, string, precedence)
-#define TOKEN_LIST(T, K, F) \
+#define TOKEN_LIST(T, K) \
/* End of source indicator. */ \
T(EOS, "EOS", 0) \
\
@@ -182,7 +181,7 @@
// All token values.
#define T(name, string, precedence) name,
enum Value {
- TOKEN_LIST(T, T, IGNORE_TOKEN)
+ TOKEN_LIST(T, T)
NUM_TOKENS
};
#undef T
diff --git a/src/v8.cc b/src/v8.cc
index 36f835f..1e9b5dc 100644
--- a/src/v8.cc
+++ b/src/v8.cc
@@ -28,6 +28,7 @@
#include "v8.h"
#include "isolate.h"
+#include "elements.h"
#include "bootstrapper.h"
#include "debug.h"
#include "deoptimizer.h"
@@ -212,6 +213,8 @@
// Peephole optimization might interfere with deoptimization.
FLAG_peephole_optimization = !use_crankshaft_;
+
+ ElementsAccessor::InitializeOncePerProcess();
}
} } // namespace v8::internal
diff --git a/src/v8natives.js b/src/v8natives.js
index be9b297..88525f6 100644
--- a/src/v8natives.js
+++ b/src/v8natives.js
@@ -1,4 +1,4 @@
-// Copyright 2006-2008 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:
@@ -1428,7 +1428,9 @@
}
}
- var name = %FunctionGetName(func);
+ var name = %FunctionNameShouldPrintAsAnonymous(func)
+ ? 'anonymous'
+ : %FunctionGetName(func);
return 'function ' + name + source;
}
@@ -1498,9 +1500,9 @@
// Set the correct length.
var length = (this.length - argc_bound) > 0 ? this.length - argc_bound : 0;
- %FunctionSetLength(result, length);
%FunctionRemovePrototype(result);
%FunctionSetBound(result);
+ %BoundFunctionSetLength(result, length);
return result;
}
@@ -1523,7 +1525,7 @@
// The call to SetNewFunctionAttributes will ensure the prototype
// property of the resulting function is enumerable (ECMA262, 15.3.5.2).
var f = %CompileString(source)();
- %FunctionSetName(f, "anonymous");
+ %FunctionMarkNameShouldPrintAsAnonymous(f);
return %SetNewFunctionAttributes(f);
}
diff --git a/src/v8threads.cc b/src/v8threads.cc
index c9a8bb6..52f82e2 100644
--- a/src/v8threads.cc
+++ b/src/v8threads.cc
@@ -94,6 +94,11 @@
}
+bool Locker::IsActive() {
+ return active_;
+}
+
+
Locker::~Locker() {
ASSERT(isolate_->thread_manager()->IsLockedByCurrentThread());
if (has_lock_) {
diff --git a/src/version.cc b/src/version.cc
index 16579df..42bb2fe 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 5
-#define BUILD_NUMBER 3
+#define BUILD_NUMBER 4
#define PATCH_LEVEL 0
// Use 1 for candidates and 0 otherwise.
// (Boolean macro values are not supported by all preprocessors.)
diff --git a/src/weakmap.js b/src/weakmap.js
new file mode 100644
index 0000000..15056c7
--- /dev/null
+++ b/src/weakmap.js
@@ -0,0 +1,95 @@
+// 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:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+// This file relies on the fact that the following declaration has been made
+// in runtime.js:
+// const $Object = global.Object;
+const $WeakMap = global.WeakMap;
+
+// -------------------------------------------------------------------
+
+// Set the WeakMap function and constructor.
+%SetCode($WeakMap, function(x) {
+ if (%_IsConstructCall()) {
+ %WeakMapInitialize(this);
+ } else {
+ return new $WeakMap();
+ }
+});
+
+
+function WeakMapGet(key) {
+ if (!IS_SPEC_OBJECT(key)) {
+ throw %MakeTypeError('invalid_weakmap_key', [this, key]);
+ }
+ return %WeakMapGet(this, key);
+}
+
+
+function WeakMapSet(key, value) {
+ if (!IS_SPEC_OBJECT(key)) {
+ throw %MakeTypeError('invalid_weakmap_key', [this, key]);
+ }
+ return %WeakMapSet(this, key, value);
+}
+
+
+function WeakMapHas(key) {
+ if (!IS_SPEC_OBJECT(key)) {
+ throw %MakeTypeError('invalid_weakmap_key', [this, key]);
+ }
+ return !IS_UNDEFINED(%WeakMapGet(this, key));
+}
+
+
+function WeakMapDelete(key) {
+ if (!IS_SPEC_OBJECT(key)) {
+ throw %MakeTypeError('invalid_weakmap_key', [this, key]);
+ }
+ if (!IS_UNDEFINED(%WeakMapGet(this, key))) {
+ %WeakMapSet(this, key, void 0);
+ return true;
+ } else {
+ return false;
+ }
+}
+
+// -------------------------------------------------------------------
+
+function SetupWeakMap() {
+ // Setup the non-enumerable functions on the WeakMap prototype object.
+ InstallFunctionsOnHiddenPrototype($WeakMap.prototype, DONT_ENUM, $Array(
+ "get", WeakMapGet,
+ "set", WeakMapSet,
+ "has", WeakMapHas,
+ "delete", WeakMapDelete
+ ));
+}
+
+
+SetupWeakMap();
diff --git a/src/x64/deoptimizer-x64.cc b/src/x64/deoptimizer-x64.cc
index 2a31f28..b52e659 100644
--- a/src/x64/deoptimizer-x64.cc
+++ b/src/x64/deoptimizer-x64.cc
@@ -38,7 +38,7 @@
namespace internal {
-int Deoptimizer::table_entry_size_ = 10;
+const int Deoptimizer::table_entry_size_ = 10;
int Deoptimizer::patch_size() {
@@ -605,8 +605,6 @@
output_frame->SetContinuation(
reinterpret_cast<intptr_t>(continuation->entry()));
}
-
- if (output_count_ - 1 == frame_index) iterator->Done();
}
diff --git a/src/x64/disasm-x64.cc b/src/x64/disasm-x64.cc
index 14c95bc..1b8871f 100644
--- a/src/x64/disasm-x64.cc
+++ b/src/x64/disasm-x64.cc
@@ -58,7 +58,7 @@
};
-static ByteMnemonic two_operands_instr[] = {
+static const ByteMnemonic two_operands_instr[] = {
{ 0x00, BYTE_OPER_REG_OP_ORDER, "add" },
{ 0x01, OPER_REG_OP_ORDER, "add" },
{ 0x02, BYTE_REG_OPER_OP_ORDER, "add" },
@@ -105,7 +105,7 @@
};
-static ByteMnemonic zero_operands_instr[] = {
+static const ByteMnemonic zero_operands_instr[] = {
{ 0xC3, UNSET_OP_ORDER, "ret" },
{ 0xC9, UNSET_OP_ORDER, "leave" },
{ 0xF4, UNSET_OP_ORDER, "hlt" },
@@ -125,14 +125,14 @@
};
-static ByteMnemonic call_jump_instr[] = {
+static const ByteMnemonic call_jump_instr[] = {
{ 0xE8, UNSET_OP_ORDER, "call" },
{ 0xE9, UNSET_OP_ORDER, "jmp" },
{ -1, UNSET_OP_ORDER, "" }
};
-static ByteMnemonic short_immediate_instr[] = {
+static const ByteMnemonic short_immediate_instr[] = {
{ 0x05, UNSET_OP_ORDER, "add" },
{ 0x0D, UNSET_OP_ORDER, "or" },
{ 0x15, UNSET_OP_ORDER, "adc" },
@@ -145,7 +145,7 @@
};
-static const char* conditional_code_suffix[] = {
+static const char* const conditional_code_suffix[] = {
"o", "no", "c", "nc", "z", "nz", "na", "a",
"s", "ns", "pe", "po", "l", "ge", "le", "g"
};
@@ -193,7 +193,7 @@
InstructionDesc instructions_[256];
void Clear();
void Init();
- void CopyTable(ByteMnemonic bm[], InstructionType type);
+ void CopyTable(const ByteMnemonic bm[], InstructionType type);
void SetTableRange(InstructionType type, byte start, byte end, bool byte_size,
const char* mnem);
void AddJumpConditionalShort();
@@ -228,7 +228,8 @@
}
-void InstructionTable::CopyTable(ByteMnemonic bm[], InstructionType type) {
+void InstructionTable::CopyTable(const ByteMnemonic bm[],
+ InstructionType type) {
for (int i = 0; bm[i].b >= 0; i++) {
InstructionDesc* id = &instructions_[bm[i].b];
id->mnem = bm[i].mnem;